Problem
ctx.done(reason: FlowCompletionReason) (packages/surface/src/context.ts:81) accepts only the reason. When a flow ends with done("step_failed") after every step succeeded, the recorded error is always the generic text from packages/sdk/src/cli/run.ts:450:
Flow "software-factory" declared done("step_failed"): its own checks did not pass. No step failed, so there is no step-level evidence to inspect; …
The flow knows exactly why it failed; the message throws that away.
Evidence: Cloud run f92bf832-7848-58d8-b5ca-da8e3b849f1c (cloud#3919). All 20 steps succeeded and a PR was opened. The second reviewer then reported "One P2 remains: cleanup can report success while an ambiguous allocation stays invisible through all three sweeps … review.clean was not created", and the flow declared step_failed. Neither the run record nor flows status --cloud shows that reason. Finding it took reading the Codex reviewer's raw transcript.
Proposal
- Extend the surface API to
ctx.done(reason, { detail?: string }), with the detail bounded, for example to 2,000 chars. Keep the one-argument form working.
- Journal the detail with the completion. Carry it into the
flows run --json report's step_failed diagnostic, replacing the generic sentence when present.
- Cloud already stores the diagnostic message as the run error, so
flows status --cloud shows it without a Cloud change. Confirm this and add a test.
- Follow-up outside this repo: the software-factory preset (agentrelay.com
web/lib/flow-workflows.ts) should pass the reviewer's remaining findings, for example the review.md summary or P-level list, as the detail.
Acceptance
- A flow that calls
done("step_failed", { detail: "review found 1 P2: …" }) produces that text in the run report and in flows status / flows status --cloud.
- The detail is redacted and bounded.
- Existing one-argument calls are unchanged.
- The
spec_hash / lowering stays stable for flows that don't pass a detail.
Problem
ctx.done(reason: FlowCompletionReason)(packages/surface/src/context.ts:81) accepts only the reason. When a flow ends withdone("step_failed")after every step succeeded, the recorded error is always the generic text frompackages/sdk/src/cli/run.ts:450:The flow knows exactly why it failed; the message throws that away.
Evidence: Cloud run
f92bf832-7848-58d8-b5ca-da8e3b849f1c(cloud#3919). All 20 steps succeeded and a PR was opened. The second reviewer then reported "One P2 remains: cleanup can report success while an ambiguous allocation stays invisible through all three sweeps …review.cleanwas not created", and the flow declaredstep_failed. Neither the run record norflows status --cloudshows that reason. Finding it took reading the Codex reviewer's raw transcript.Proposal
ctx.done(reason, { detail?: string }), with the detail bounded, for example to 2,000 chars. Keep the one-argument form working.flows run --jsonreport'sstep_faileddiagnostic, replacing the generic sentence when present.flows status --cloudshows it without a Cloud change. Confirm this and add a test.web/lib/flow-workflows.ts) should pass the reviewer's remaining findings, for example thereview.mdsummary or P-level list, as the detail.Acceptance
done("step_failed", { detail: "review found 1 P2: …" })produces that text in the run report and inflows status/flows status --cloud.spec_hash/ lowering stays stable for flows that don't pass a detail.