Skip to content

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 high finding in either dimension fails the healing attempt — the violation text joins the attempt record's error and the retry carries the grown attempt history — medium and low findings pass with a WARNING, 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 rot or fixable raises IncurableStepError carrying 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_healed events with the category recoverable — the label distinguishes a recovered group row from an ordinary rot/fixable heal
  • 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.