AutomatorsDocs
Getting started

Resilience and healing

Fallback selectors and degraded matches when the app drifts, waiting on slow operations, and healing a stale trace.

Replay walks each step's recorded selector ladder in order: the native id first, then structural (control type + accessible name), then a text anchor. If the primary selector is dead but a fallback rung still finds the element, the step runs and the flow stays green, but the step and the run are marked degraded in result.json (with the matched tier in selector_tier), the CLI prints a DEGRADED: line pointing at heal, and RunResult.degraded is set in Python. Degraded-but-passing is the signal to heal the trace before the remaining rungs die too:

  [PASS] s0002 Press plus (matched via structural fallback)
PASS: Add two numbers (2154 ms) -> .flowproof\runs\...\report.html
DEGRADED: fallback selectors were needed, the app drifted; run `flowproof heal calc.flow.yaml`

Waiting on slow operations (no sleeps, still deterministic)

Assertions auto-wait: the engine polls until the expectation holds or a bounded timeout elapses (default 10s), during recording and at every replay. The bound is recorded into the trace, so replay waits exactly as long as authoring allowed: deterministic, no sleeps in specs. For slow backend operations, use an explicit wait step (default bound 60s) or a within qualifier on either form:

steps:
  - Press the generate button
  - Wait until page shows Generation complete within 120s
  - assert: page shows 100 rows within 5s

Repair a spec while recording

When an authoring model is configured, record can repair a failing spec step. It asks the model for a minimal edit, changes only the .flow.yaml being recorded, and reruns the flow. Repair stops after three attempts, or earlier when the same failure recurs without progress. Each attempt and edit is written to <flow>.repair.json beside the trace.

Set a different limit, from 1 to 10, with --repair-attempts:

flowproof record shop.flow.yaml --repair-attempts 5

Disable automatic repair when you want the original failure immediately:

flowproof record shop.flow.yaml --no-repair

A model verdict that identifies an engine limitation without trying a fix is provisional. Flowproof gives the whole flow one independent attempt in a fresh driver session. If that attempt fails the same way, the repair report retains both failures as evidence. A repair that exhausted its edit budget does not get the extra attempt. The fresh attempt does not reset the limit: if it fails, the repair loop gets only the attempts the first round left unused.

Healing a stale trace

When the app changes and replay fails, heal re-authors the flow from the spec against the live app and proposes a reviewable diff; it never touches the trace on its own:

$ flowproof heal calc.flow.yaml
  [CHANGED] s0002 Press plus (selectors)
REVIEW: calc.heal.html (before/after with frames)
PROPOSED: review calc.proposed.jsonl then apply it with --apply-proposal
$ flowproof heal calc.flow.yaml --apply-proposal   # explicit opt-in

--apply-proposal copies the proposal you reviewed over the trace and removes it, without touching the app. --apply instead re-records and applies the result straight away; since re-authoring can come out differently the second time, it is for when you don't need to review first.

Heal re-records the way record does, so it takes the same --vars <file>, --var KEY=VALUE (repeatable) and --headed / --headless flags, and loads the flow's sibling .values.yaml the same way.

Alongside the machine-readable proposal, heal writes <name>.heal.html: a self-contained review page with a before/after pair per changed step: the frames each execution's recording captured for that step (recorded run vs. re-authored run) plus the step JSON, rendered entirely from the structured report. Open it to see what the app looked like when each version of the step ran, then decide on --apply.

Healing only the fallback steps

When the run passed but was degraded, re-authoring is more than the drift needs: the run already knows which rung found each drifted step. Point heal at that run and it promotes the matched rung to the top of each degraded step's ladder, keeps the dead one below it, and leaves every other step byte-for-byte alone. Nothing is re-recorded, so no app or model is needed:

$ flowproof heal calc.flow.yaml --from-run .flowproof/runs/20260924T100048.993Z
  [CHANGED] s0002 Press plus (selectors)
PROPOSED: review calc.proposed.jsonl then apply it with --apply-proposal

The run must have replayed this trace (trace_id must match). --apply and --apply-proposal work the same way. --step <id> (repeatable) repairs only the steps you name, so a reviewer can accept some repairs and leave the rest; naming a step the run did not reach through a fallback is an error.

Exit codes: 0 healthy (or applied), 1 changes proposed for review, 2 error. --json emits the structured report (including diff_html); the Python API returns a HealResult (with diff_html: Path | None) and the MCP tool mirrors it. --author <auto|rules|llm> picks the authoring backend for the re-record, same meaning and same default (auto) as record's flag of the same name.

On this page