Files
stack/agents/darkwing/work/queue-55/FOLLOWUP-transport-code.md
T
jason.woltjeandClaude Opus 5.5 fa6d889cb7 queue-55: round 2 candidate packet (darkwing)
Answers Filbert's comment 27251 and Dewey's comment 27253: R1 type-ahead
window, R2 terminal cell widths, B1 cut inside the question, 30 mutants
killed, N1-N8. Candidate manifest sha256 3f2d8f8e. Gate on c506c6ec:
cli 106/106 and every scripts/test-*.sh exit 0. The feature stays
uncommitted.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 13:39:05 -05:00

2.7 KiB

Follow-up: the transport's "did not finish" error has no code

Found while building row 55 (#1544). It is not part of row 55. Sage will queue it with the 2026-10-12 batch. The code was already like this at fe5c68fa.

What happens

humanTransport in packages/cli/src/transport.mjs (line 60 at fe5c68fa) throws this when the bus CLI child errors or times out (30 s) and no exit status comes back:

throw new CliError("outcome-unknown: the bus transport did not finish", 1);

Every other error it throws sets error.code. This one doesn't. resolveDecision in packages/cli/src/cli.mjs checks e.code === "outcome-unknown" to choose its sentence:

outcome unknown: the broker may have recorded it. Check mosaic inbox or mosaic trail <id> before trying again

That check misses the transport error. So if decision.resolve times out, mosaic decide prints mosaic: outcome-unknown: the bus transport did not finish and exits 1. The exit code is right. The text is wrong: it doesn't tell the user the decision may already be recorded, or where to look. A retry could resolve a decision that already went through. The bus should refuse a second resolve, but the user hasn't been told to check first.

The row 55 app is not affected. It matches the message text (/^outcome[ -]unknown/) and shows its outcome-unknown overlay, which has no retry.

No other check in packages/cli/src compares .code against outcome-unknown. The launcher and notifier errors have their own codes.

Suggested fix

  1. Set error.code = "outcome-unknown" on the transport's did-not-finish error, the same way the other two throws do.
  2. Add a test in packages/cli/tests/cli.test.mjs: a transport whose decision.resolve throws that error makes mosaic decide print the "may have recorded it" sentence, exit 1.
  3. Extend the hang case in packages/cli/tests/transport.test.mjs to check e.code === "outcome-unknown".

Files: packages/cli/src/transport.mjs, packages/cli/tests/cli.test.mjs, packages/cli/tests/transport.test.mjs.

resolveDecision reads the inbox before it sends anything. If that read hits the same did-not-finish error, the app shows its outcome-unknown overlay ("the broker may have recorded it"), though no choice was sent. Once the transport sets error.code = "outcome-unknown", mosaic decide would print the same sentence for that read. The fix should tell the two apart: only an error from decision.resolve is outcome unknown. A failed inbox read before it is a plain failure, exit 1, with nothing sent. A test for each, in packages/cli/tests/cli.test.mjs and packages/cli/tests/app.test.mjs.