Skip to content

fix(flow): halt a relabelled Save on the Save, not the scroll before it - #1337

Merged
abrichr merged 4 commits into
mainfrom
claude/relabelled-save-halt-1331
Oct 19, 2026
Merged

abrichr merged 4 commits into
mainfrom
claude/relabelled-save-halt-1331

Conversation

@abrichr

@abrichr abrichr commented Oct 19, 2026

Copy link
Copy Markdown
Member

Refs #1331. This PR fixes both causes in code. It does not re-run the openIMIS drift row live (see "Not done").

What was wrong

1. The halt lands on the scroll. The cause is locator resolution, not settle or step order. A closed-loop scroll stops when the next step's anchor resolves. After the relabel, the Save never resolves, so step_014 uses its 2.5x budget and the run halts there. _repairable then refuses it because a scroll is not a click.

I replayed the readiness probe offline on the recorded frames of all three item-50 attempts (~/.cache/openadapt-scoreboard/.../2026-10-19-a/item-050-{1,2,3}), against the launch-4 bundle. On every frame before and after the scroll, the Save resolves by geometry only. Scroll readiness rightly rejects that rung. On the healthy item 49 it resolves by template at the recorded point.

2. RECONCILIATION_REQUIRED is correct, so I didn't relax it. step_002 (Tab) and step_012 (unlabelled picker click) carry risk_review_required. They acted, and nothing proves they wrote nothing. Calling that HALTED_BEFORE_EFFECT would be a false claim of no effect. I found no outcome that was labelled wrong. The existing reviewed-risk binding (openadapt-flow qualify set-risk) clears it. Once a person classifies both steps, the same halt is HALTED_BEFORE_EFFECT and _repairable returns the Save. The test covers this.

Changes

  • runtime/replayer.py: when every readiness probe of the next click missed because no direct rung found it, a non-consequential scroll in a linear run hands the miss to that click. The click then accepts only direct rungs (structural, template, OCR, no model). It halts with the usual Could not resolve target for step ... error, delivery_attempted=False and no input. These cases still halt on the scroll as before: a target that resolved but was out of position or failed its identity check, a consequential scroll, and a scroll in a program graph.
  • repair/self_repair.py: the not_repairable reason for a run that ended RECONCILIATION_REQUIRED names the unsettled steps. When all of them are unreviewed-risk steps, it points to qualify set-risk.
  • benchmark/reliability.py: the handed-off halt is classified as resolution_failed.
  • Docs: SELF_REPAIR.md (halt rules), CAPABILITIES.md row, regenerated llms-full.txt. No new commands.

Tests

  • New tests/test_relabelled_save_halt.py, a synthetic openIMIS-shaped fixture: Tab and picker (both unreviewed), a scroll up, and a relabelled icon-only Save. It checks three things: the halt is on the Save with no Save input; an unreviewed run stays RECONCILIATION_REQUIRED with an explanatory refusal; a reviewed run is HALTED_BEFORE_EFFECT and repairable. Two of the three fail on main (checked in a detached worktree). The fail-closed one passes on both, as intended.
  • tests/test_replayer.py: two exhaustion tests now expect the halt on the click. A new test checks that an identity miss keeps the halt on the scroll.
  • Targeted only, because of host load: test_replayer.py, test_program_ir_phase1.py, test_transaction_outcome.py, test_relabelled_save_halt.py, test_capabilities_map.py (213 passed). CI runs the full suite.

Not done

  • The openIMIS drift row was not re-run. Its colima VM (openadapt-demo) is stopped. Starting it plus the compose stack under a load average of about 190 would delay the timed measurements, so I left it.
  • The re-run needs a person's review first. Before re-running, someone has to classify step_002 and step_012 on the launch-4 bundle (qualify init, then qualify set-risk ... --classification state_changing). In the scoreboard, a scripted reviewer would stand in for that person and should be disclosed in meta.json (demo: CUA to program on openIMIS claims, plus the scoreboard (arms 1-3) #1303).
  • Expected result, not measured. With that review in place, I expect item 50 to halt on step_015 and go to self-repair. The Save's identity template has tokens, so frame campaigns apply rather than needs_fault_probes.
  • The feat(flow): self-repair a halt with a short bridge of new steps #1325 bridge isn't needed. The relabel is a one-click replacement.

🤖 Generated with Claude Code

abrichr and others added 3 commits October 19, 2026 09:52
…it (#1331)

A closed-loop scroll stops when the next step's anchor resolves. When the
vendor relabels that control, the scroll used up its budget and the run
halted on the scroll, so self-repair refused it ("not a click").

Now, when every readiness probe missed because no direct deterministic
rung found the target, a non-consequential scroll hands the miss to the
next click. That click accepts only direct rungs (structural, template,
OCR; no model) and halts with the ordinary "Could not resolve target"
error and no input. A target that resolved but was out of place or failed
its identity check still halts on the scroll, as does a consequential
scroll or one in a program graph.

The RECONCILIATION_REQUIRED outcome on openIMIS is correct: the Tab key
and the unlabelled picker click carry risk_review_required, so a write
cannot be ruled out. Self-repair's refusal now names the unsettled steps
and says a person can review them with `qualify set-risk`; once reviewed,
the same halt is HALTED_BEFORE_EFFECT and repairable (tested).

The reliability classifier files the handed-off halt as resolution_failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-halt-1331

# Conflicts:
#	packages/flow/openadapt_flow/runtime/replayer.py
abrichr added a commit that referenced this pull request Oct 19, 2026
MockMed, all 22 drift modes, 3 trials, a real Claude repair agent and a
scripted approver: 30 stops, 21 reached repair, 6 resumed and verified
(relink and redesign 3 of 3 each), 0 wrong saves in 66 runs. Not repaired:
a save moved into a closed menu, a new interstitial, a new required choice,
and font/zoom false stops of a pixel postcondition. The worklist run
(vendor change after the pre-flight): 10 stopped items, 2 repairs on the
test record, 2 person decisions, 10 of 10 resumed and verified.

Routed offline: the 8 recorded OpenEMR stops behind #1347 and the 3
openIMIS relabel stops of #1331 (before #1337) were all
RECONCILIATION_REQUIRED, so none reached repair.

Docs: SELF_REPAIR (repair is the default, Measured), REPAIR_LIFECYCLE,
LIMITS, JIT (reuse binding), CAPABILITIES; llms-full.txt and the public
artifact inventory regenerated with their scripts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abrichr added a commit that referenced this pull request Oct 19, 2026
…enIMIS live

The live openIMIS run of the relabelled Save (#1331, with #1337 merged
locally and a scripted risk review) found two self-repair bugs:

- a re-targeted save that carries a submit_binding got the DOM locator under
  the new point, and a step may not carry both, so the patched bundle failed
  to load even though the agent found the right control. The patch now keeps
  such a step visual and keeps its binding.
- the halted session stays open while a probe opens another, and two
  Playwright drivers can't share a thread. Tests hid it behind their fixture's
  shared browser. run now shares one browser for every session of a repair.

Measured: with the review, the stop reaches repair 3 of 3 (0 of 3 before);
the agent found SAVE CLAIM 2 of 3; no fix passed the probe, because the
replay sees the Save disabled where the template was cropped from the
enabled button. Nothing was written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-halt-1331

# Conflicts:
#	CAPABILITIES.md
#	packages/flow/openadapt_flow/repair/self_repair.py
#	packages/flow/openadapt_flow/runtime/replayer.py
@abrichr
abrichr merged commit e483530 into main Oct 19, 2026
41 checks passed
@abrichr
abrichr deleted the claude/relabelled-save-halt-1331 branch October 19, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant