Skip to content

feat(01KVW2GD): retry a thrown courier hiccup on a read-only setup seam#445

Merged
jackmcintyre merged 1 commit into
mainfrom
story/native-01kvw2gd-retry-thrown-courier-on-readonly-seam
Jun 24, 2026
Merged

feat(01KVW2GD): retry a thrown courier hiccup on a read-only setup seam#445
jackmcintyre merged 1 commit into
mainfrom
story/native-01kvw2gd-retry-thrown-courier-on-readonly-seam

Conversation

@jackmcintyre

Copy link
Copy Markdown
Owner

What this fixes

An unattended run could die at the starting line. One of the run's read-only setup checks (the pre-flight getStatus/standards check) relies on a one-shot AI courier to relay its result. If that courier hiccups — emits its result as plain text instead of through the structured tool, so nothing comes back — the run used to abort immediately, before claiming or building a single story.

The setup check already advertised "3 attempts," but a thrown courier error skipped the retry loop entirely and bubbled up on the first try. This change makes a thrown courier error retry just like a garbled-but-returned one: a read-only setup check now quietly retries and recovers, and the run carries on to claim and build.

Crucially, this only affects read-only / idempotent steps. A state-changing step (e.g. recording a verdict) is never retried — it still stops loudly on the first failure, so no state-changing action is ever repeated.

Acceptance criteria

  • AC1 (integration): an operator's unattended run hits a one-off courier hiccup on a read-only setup check that drops its result → the run quietly RETRIES, the check succeeds, and the run carries on to claim and build (rather than aborting pre-claim).
  • AC2 (integration): the same one-off hiccup instead hits a STATE-CHANGING step → the run stops loudly on the FIRST failure and never silently retries, so no state-changing action is ever repeated.

How it was tested

Both ACs are demonstrated by two new integration cases in run-fault-injection.test.ts, which run the real run.workflow.js body verbatim through the existing AsyncFunction harness (no production behaviour mocked, only the seam surface stubbed):

  • Extended the harness with a throwSeamTimes knob (a courier that throws the first N calls then succeeds), modelling a transient hiccup the retry loop can recover from.
  • AC1 case: a transient throw at the retryable read-only preflight:standards seam → asserts the seam is invoked twice (throw + recovering retry), the retry is narrated, the story is claimed, and the run reaches queue-emptied. Verified this case goes RED against the old code (which aborts pre-claim).
  • AC2 case: a transient throw at the non-retryable mutating verdict: seam → asserts the story buckets as worker-threw on the first failure and the verdict courier is invoked exactly once (no double-apply).

Full suite green: 3830 tests pass, coverage lines 86.26% (≥ 86% CI gate). pnpm -r build green; no dist drift (the fix is in the non-bundled run.workflow.js + the test file). Nothing under .flow/ touched.

https://claude.ai/code/session_01EE2ncqkqh3u5af93Uf3bDA

A thrown courier error (the courier emitted its StructuredOutput call as
literal text and never returned a structured result -> agent() throws) used to
hit the seam() catch and re-throw on attempt #1, bypassing the retryable
seam's attempts=3 loop. A read-only preflight seam (preflight:standards,
retryable=true) therefore died on the first hiccup, aborting the whole run
before any story was claimed.

Treat a thrown courier error like a garbled relay: for a retryable seam with
attempts remaining, record the sentinel and retry; only propagate after
attempts are exhausted. SAFE because retryable is set only on read-only /
idempotent seams. A non-retryable (mutating) seam has attempts=1, so it still
re-throws on the FIRST failure with no retry (no double-apply).

Extends the run-fault-injection harness with a transient-throw knob
(throwSeamTimes) and two cases: AC1 a transient throw at the read-only
preflight seam is retried + recovers (run proceeds to claim + build); AC2 the
same hiccup at the mutating verdict seam stops loudly on the first failure,
invoked exactly once.

Claude-Session: https://claude.ai/code/session_01EE2ncqkqh3u5af93Uf3bDA
@jackmcintyre jackmcintyre merged commit 2ea3c8a into main Jun 24, 2026
1 check passed
@jackmcintyre jackmcintyre deleted the story/native-01kvw2gd-retry-thrown-courier-on-readonly-seam branch June 24, 2026 06:03
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