Skip to content

fix(flow): a save that was sent but not confirmed never resumes as a retry - #1484

Closed
abrichr wants to merge 2 commits into
mainfrom
fix/resume-post-delivery-unverified
Closed

abrichr wants to merge 2 commits into
mainfrom
fix/resume-post-delivery-unverified

Conversation

@abrichr

@abrichr abrichr commented Oct 21, 2026

Copy link
Copy Markdown
Member

Problem

A durable pause carried delivery_uncertainty only when the delivery itself raised (runtime/durable/controller.py). A save could also be sent cleanly and then fail its record check: the read-back timed out, refuted a write that landed late, or couldn't read the record. That pause came with the ordinary "Approve and RESUME" option, and the resume guard (resume.py) let it through. The approved resume pressed Save again, creating a duplicate record.

This is a silent fail-open. The realism audit found it (#1467, rank 2; issue #1470), and test_resume_continues_from_last_checkpoint asserted this behaviour as correct.

Fix

  • Stamp uncertainty after a sent save. DurableRun.record stamps delivery_uncertainty (cause post_delivery_unverified) on a consequential step that halted after its delivery. A step counts as consequential if it has a record check or is marked irreversible.
  • The existing gate then applies. An ordinary resume is refused. The pause offers reconcile, a read-only check of the record as it is now through the attended path, or an approval that explicitly authorizes one retry (approve --authorize-uncertain-retry).
  • The pause keeps its category (effect_refuted, effect_indeterminate, …). Only the plain resume option is swapped for the reconcile options.
  • Steps that never sent their action (delivery_attempted=False) and steps that ended verified resume as before.

Tests

  • New test_realism_durable_resume.py: the backend writes a row for each Save press, and the read-back times out once.
    • test_resume_never_repeats_a_save_whose_readback_timed_out: resume is refused, and the row stays single.
    • test_reconcile_finds_the_saved_record_and_finishes_without_saving_again: reconcile reads the record and completes, still with one row.
  • test_durable_runtime.py:
    • New test_resume_never_repeats_a_delivered_save_without_authorization: the default approval never presses Save.
    • test_resume_continues_from_last_checkpoint and six other tests that retry a refuted save now use an approval that explicitly authorizes one retry. They model an operator who confirmed the record is missing.
  • Local: test_durable_runtime.py and the new file, 30 passed. The wider durable, attended and approval suites are running in CI.

Copy

packages/flow/docs/CAPABILITIES.md and EFFECT_KIT.md now say that a save which was sent but not confirmed pauses as delivery-uncertain and is reconciled or explicitly retried. No public copy claimed more than that.

🤖 Generated with Claude Code

…retry

A durable pause carried delivery_uncertainty only when the delivery itself
raised. A save sent cleanly and then not confirmed by its record check
(the read-back timed out, refuted a write that landed late, or couldn't
read the record) paused with the ordinary "Approve and RESUME" option, and
an approved resume pressed Save again: a duplicate record.

DurableRun.record now stamps delivery_uncertainty (cause
post_delivery_unverified) on a consequential step (one with a record check,
or marked irreversible) that halted after its delivery. The existing gate
then applies: an ordinary resume is refused, and the pause offers
reconciliation (a read-only check of the record as it is now) or an
approval that explicitly authorizes one retry. The pause keeps its own
category; only the plain resume option is swapped for the reconcile
options. A step that never sent its action resumes as before.

Tests:
- test_realism_durable_resume.py: a backend that writes a row per Save and
  a read-back that times out once. Resume refuses and the row stays single;
  reconcile reads the record back and finishes without saving again.
- test_durable_runtime.py: test_resume_continues_from_last_checkpoint
  asserted the old re-press. A new test asserts the default approval never
  presses Save; resume tests that retry a refuted save now use an approval
  that authorizes one uncertain retry.

Docs: CAPABILITIES.md and EFFECT_KIT.md say a sent but unconfirmed save
pauses as delivery-uncertain and is reconciled or explicitly retried.

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

abrichr commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

Replaced by #1485: same final tree as one commit, so the gitleaks history scan is clean.

@abrichr abrichr closed this Oct 21, 2026
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