Self-healing
Healing a failed cached step. For engineers reasoning about healed runs.
When a cached step fails, the failure is classified first; the classification verdict decides the path. A step executing inside a group block never takes this path: its failure routes to the group recovery — see Groups.
Classification categories
| Category | Meaning | Consequence |
|---|---|---|
rot |
the UI changed: selectors, texts, structure | the step is regenerated from the current page and retried |
fixable |
the step code is at fault (an ambiguous or wrong locator or strategy) while the intent stays satisfiable | the step is regenerated for the same intent, the request carrying the classification recommendation |
product_defect |
the expectation legitimately failed | the test fails loudly — never healed green |
incurable |
regeneration cannot help: budget exhausted, text no longer matches reality, ambiguity | the incurable failure carries step, reason, recommendation |
Heal
healed = healer.heal(
step=failed_step,
error="element not found: button «Sign in»",
step_text="click the «Sign in» button", # the raw sentence as written by the engineer
step_type="action", # action | assertion
previous_steps=scenario_records, # the typed scenario records of the test, execution order
page=page,
attempt_history=history, # the per-step attempt records — record 0 anchors the failed cached code
window=window, # the settle window of the current step execution
)
The classification verdict decides the path:
| Category | Path |
|---|---|
rot, fixable |
regenerate from the current page within the healing budget (default 2), execute, pass the compliance gate, save back to the cache, report loudly |
product_defect |
raise ProductDefectError carrying the verdict — category, explanation and recommendation all reach the exception message, the on_step_verdict hook and the log |
incurable |
raise IncurableStepError carrying the verdict; the reason names the incurability cause |
Rules
- A healed candidate passes the compliance gate before the write-back: a
highfinding in either dimension fails the healing attempt — the violation text joins the attempt record's error and the retry carries the grown attempt history —mediumandlowfindings pass with aWARNING, and a malformed verdict (ComplianceVerdictError) or provider unavailability (LLMUnavailableError) is a hard failure — nothing is cached unchecked - Anti-masking: healing never turns a product defect into a green test
- The healed code replaces the cached code only after a successful execution
- Generation and healing attempts live in one per-test registry — owned by the runtime of the test — with separate per-step limits (default 3 and 2)
- Every failed attempt inside the regeneration loop retries with the grown attempt history and the fresh snapshot — a failed check included — with no per-attempt classification: the entry classification already guards the anti-masking
- A regeneration budget exhaustion after
rotorfixableraisesIncurableStepErrorcarrying the verdict of the entry classification — no extra LLM request - Provider unavailability during the classification raises
LLMUnavailableError— an explicit infrastructure failure - Healing never runs in strict mode: a failed cached step is at most classified, never regenerated
- A step inside a group block never heals in isolation. Routing precedence: strict mode keeps the classification-only path (no recovery, no group framing), a failing group step on a non-strict run routes to the group recovery — see Groups — and only an ordinary failed cached step takes the per-step heal of this page; a still-terminal group failure reaches the steering gate like any terminal failure — see Interactive steering
- The group recovery reports its rows through the same
on_healing_started/on_healedevents with the categoryrecoverable— the label distinguishes a recovered group row from an ordinaryrot/fixableheal - Every candidate execution runs under the settle window of the current step execution — see Settle polling
Verdicts
Every terminal failure carries its verdict in full and the full underlying
error in the error field: the exception message is the structured render — the
class-name first line, the --- separated step/error block, the conditional
details section and the column-zero verdict block; the same text reaches
on_step_verdict (structured fields) and
the log record. The render format is specified in
Failure taxonomy.
When the LLM is unavailable the verdict is skipped quietly (WARNING in the
log) — the failure itself never waits for it.