Filbert's R1 (comment 28188): the brief requires the packet to name what the Console would need to show the stranded list. Added as a Console follow-up section by the subagent, read-only, with unchecked items named. Also N1 (M12 note) and N2 (round 1 title). Candidate unchanged, manifest 52c41526. Sage corrected one count: M12 failed 6 of 11 tests, not 13 (the 13 was the count of x-marker lines). Co-Authored-By: Claude Opus 5.5 <[email protected]>
11 KiB
Row 80 (#1574) build, round 1
Status: Phase B ran three times on this packet. Run 1 failed in bus (119/120). Run 2 passed bus (120/120) and business (60/60) after the fix, then stopped at cli (exit 1) because the worktree had no node_modules. Run 3 was the full gate with a node_modules symlink in place: all 14 node suites and the nine scripts/test-*.sh exited 0, and mutants.py (15 mutants) exited 0 with all 15 killed. Not committed, not pushed, queue row not moved.
Identity
- Row 80: bus, "stranded delivery" display. Brief:
docs/plans/2026-10-11_bus-stranded-delivery.md(not edited). - Owner: researcher (decisions 122, 129). Reviewer: Filbert (approved, comment 28188). Dispatch: Sage (lead decision 129).
- BASE:
57a2ddc5978b05b780dc0e69fb4e6c2a60ab5877(seebase.txt). Phase A used2b2a9e14eec4ff81cdada5dc42bbf1b8063b29b4; the rebase to57a2ddc59changed none of the three paths. - Worktree:
.claude/worktrees/agent-abe72e00ca2bcdf7e, detached at BASE, changes uncommitted. No commit, no push, no queue move. - Candidate manifest:
candidate-manifest.sha256, checked withsha256sum -cfrom the worktree root: all three paths OK.
| Path | sha256 |
|---|---|
packages/bus/README.md |
02fae2939accd20f1032b0f5d4a3f4f3ca3b5da29606a6f4cee2b15a1da985b0 |
packages/bus/src/broker.mjs |
f685af1c5c496f0f1907995919017b9b098f7d84d9aa1047d126f3f4cc4991ef |
packages/bus/tests/agents.test.mjs |
076137bca90b6594cc0888fb0daa2c57903fff5f1035122c00dd5540de65f6eb |
build.patch is git diff against BASE, limited to these three paths.
Changes
- Fix (Sage's direction, in
broker.mjs, not the test): the stranded query at L1047 to L1052 ends with).map((m) => ({ id: m.id, from: m.from, run: m.run, at: m.at }));. The.mapis on L1052. Cause:node:sqlitereturns rows with a null prototype, soassert.deepStrictEqualagainst plain objects fails although the values match. The test expectation is unchanged. node --test tests/agents.test.mjspasses 11/11 after the fix.- Mutant M15 added (
.mapremoved, expected killeragents.test.mjs:174 prototype check). The table has 15 entries. phase-b.shstops on any nonzero step exit. A stop writesSTOP: <step> exited <rc>, skips the rest, runs the cwd scan and endsPHASE-B-STOPPED. A full pass endsPHASE-B-DONE.
Phase B runs
Run 1
busexit 1, 119/120.agents.test.mjs:164failed at L174 (null prototype, as above).- Stopped on TERM (exit 143) on purpose, before the fix was applied. A
/proccheck found no leftover test process.
Run 2
- Run after the
.mapfix. busexit 0, 120/120.businessexit 0, 60/60.cliexit 1: 131 total, 121 pass, 8 fail, 2 cancelled. The stop rule fired. The remaining 11 suites, the nine scripts and the mutants did not run.- Cause: no
node_modulesin the worktree. The seat sandbox (packages/seat/src/sandbox.mjs:95,binds) callsrealpathSyncon<worktree>/node_modules, which fails with ENOENT. The failing trace runs throughpackages/seat/src/session.mjs:122andpackages/cli/src/launcher.mjs:237. Two launcher tests then time out at 30 s (tests/launcher.test.mjs:471). The rest of the failures are the same ENOENT. - Scope: the candidate touches only
packages/bus, and no package imports another workspace package (checked in Phase A). The cli failure is a property of the worktree layout, not of row 80. I did not run cli on57a2ddc59in a clean tree to prove this on BASE. - The cwd scan reported three processes with a cwd in the worktree at the stop (pids 1353827, 1359345, 1362919). A re-check a few seconds later found none.
Run 3
node_modulessymlinked from the canonical root into the worktree.git status --porcelainshowed the three candidate paths,?? node_modules(expected:.gitignoreline 2 isnode_modules/, which matches directories only, so a symlink shows as untracked), and?? agents/researcher/work/queue-80/. Nothing else. Sage's ruling on this status is recorded in the coordinator message, not decided here.- Full phase B from the top. Summary in
out/phase-b-summary.txt, end markerPHASE-B-DONE. - Node suites, all exit 0: bus (120/120), business (60/60), cli (passes with the link; count in
out/), control-board, conversation, discord, harness, ledger, mosaic, queue, runs, seat, tasks, webui. - Scripts, all exit 0:
test-auth,test-conductor,test-config,test-discord,test-extension-package,test-foundation,test-queue,test-release,test-task. - The cli pass confirms the run 2 cli failure was the missing
node_modules. - Two attempts did not run phase B. A symlink attempt in the earlier round was stopped by the untracked-link rule. A later chained command was refused by the worktree guard. Neither changed the candidate.
Cleanup after run 3
rm <worktree>/node_modules(plain rm, the link only).git status --porcelainshows only the three candidate paths and the packet.build.patchcovers the three paths only.sha256sum -cverifies all three candidate hashes.- A scan from
/finds zero processes with a cwd in the worktree.
Mutants (15), phase B run 3
Each mutant is one exact-once replacement in broker.mjs. The "Observed" column lists the agents.test.mjs line numbers that appear in the stack frames of out/M<nn>.log. The expected killer line appears in every log.
| ID | Site | Expected killer | Observed assertion frames |
|---|---|---|---|
| M01 | broker.mjs:47 (STRANDED cap) |
:203 length 50 |
203 |
| M02 | broker.mjs:1048 (sort order) | :204 oldest-first ids |
204 |
| M03 | broker.mjs:1048 (cap) | :203 length 50 |
203 |
| M04 | broker.mjs:1048 (current holder) | :189 current holder keeps unread |
189 |
| M05 | broker.mjs:1048 (released run) | :174 released-run entry |
174, 189, 203, 221 |
| M06 | broker.mjs:1048 (read filter) | :192 read message not listed |
192 |
| M07 | broker.mjs:1048 (business scope) | :230 per business |
230 |
| M08 | broker.mjs:1048 (role scope) | :221 per role |
221 |
| M09 | broker.mjs:1048 (run renamed) |
:174 entry shape |
174, 205 |
| M10 | broker.mjs:1048 (from renamed) |
:174 entry shape |
174, 205 |
| M11 | broker.mjs:1048 (at dropped) |
:174 entry shape |
174 |
| M12 | broker.mjs:1053 (stranded key removed) |
:58 key list |
58, 174, 189, 203, 221, 239 |
| M13 | broker.mjs:932 (role session rows) | :62 role session keys |
62 |
| M14 | broker.mjs:1048 (routed, not received) | :239 routed, not yet received |
239 |
| M15 | broker.mjs:1052 (.map removed) |
:174 prototype check |
174 |
Verdicts: baseline green, manifest clean after restore, all 15 KILLED.
M12 note: the L58 key-list assertion does catch M12, at agents.test.mjs:58:32. The run also shows TypeErrors at :203 and :221, because the test reads stranded as undefined in those assertions. The first failing test header in that log is :49, with 6 of 11 tests failing (ℹ fail 6; the 13 ✖ lines are each failure twice plus the "failing tests:" header). The kill is real and the expected killer is correct. The mechanism is partly TypeErrors, not only the L58 check.
Console follow-up
Scope: read-only research of packages/webui and packages/cli. No code changed. Line numbers are from the current worktree.
Not checked, listed once here: a live read of /api/bus/agents (no run was made); the bus-browser test run; the contents of the "Not shown here yet" gap list at the end of agentsView; whether packages/webui references stranded anywhere (I did not grep for it, and the render functions below do not use it); whether #/messages/<id> exists as a detail route (grep found only list pages); the text of decision 123 in the repo; which session type (human or reader) the Console's humanCall opens; and whether the human-cli agents verb passes broker rows through unchanged.
(a) Which read carries stranded to the Console
- Route:
packages/webui/src/serve.mjs:52(BUS_VERBSincludesagents);busReadat L54; the GET-only/api/bus/route at L223-227 returns 404 for unknown verbs. - Transport:
packages/webui/src/bus.mjs:27humanCallruns the human transportpackages/bus/src/human-cli.mjs(header L1-2; lead decision 70). - Broker:
packages/bus/src/broker.mjs:932returns#agentState(c)rows whens.human || s.reader, and claim rows otherwise.#agentStateat L1053 returns{ ...c, state, working, inputNeeded, stranded }. The stranded query is at L1047-1052. - Result: for a human or reader session, the broker already puts
strandedon theagentsread. No read-path change is needed for the Console to receive it, subject to the unchecked items above.bus.test.mjs:77already asserts thatinputNeededcomes through the reader view.strandedsits on the same object, so the same path applies, but no test covers it yet. - CLI:
packages/cli/src/cli.mjs:188printsagentsthroughformatAgents.packages/cli/src/format.mjs:52-55prints role, holder run, harness andsince.packages/cli/src/app.mjs:433prints the detail lines (held by, harness, since). None of these readinputNeededorstranded(grep ofpackages/cli/srcfor both names: no matches). A cli change is optional and not needed for the Console.
(b) Where a list or count would render, and what inputNeeded does
- Render path:
packages/webui/src/public/bus.js.fetchRead(verb, subject)at L34, and thegethelper at L59-62. attention(c)at L421-428 is the existinginputNeededrenderer. It links the first ask to#/inbox/<id>, shows a blocking chip, and shows a "+N" link to#/inbox.heldTable(claims)at L435 builds the table.paintHeld(err)at L440-460 draws the Board held count, the refusal banner and the table.agentsView(get)at L462-470 renders the Held roles table with columns Role, State, Attention, Holder, Harness and Held since.- The Board refresh at L706-717 reads inbox, agents and messages, then calls
paintHeld. - Natural fit for a follow-up: a stranded count in the Attention cell, built the same way as
attention(c), with a link per message. The link target would be#/messages/<id>, which is not confirmed to exist (see unchecked list). A separate "Stranded" column is the alternative.
(c) What the follow-up row would test, and public/
- Existing test patterns to extend:
packages/webui/tests/bus.test.mjs:77(reader-viewinputNeededassertion) andpackages/webui/tests/bus-browser.test.mjs:248-259(browser check of the Agents table: headers, state mark, "Input needed:" text,#/inbox/link). - A follow-up would need, at minimum: stranded entries present in the reader rows; rendered count or links; the link target; no change to the read when nothing is stranded; and a check that listing writes nothing (no delivery row changes).
- Public path: any render change touches
packages/webui/src/public/bus.js, and any stylesheet underpublic/would too. Per decision 123 that needs Mos's go. The read-path files (serve.mjs,bus.mjs) and the cli files are not underpublic/.
Open items
- Not committed, not pushed, queue row not moved.
- Sage to review the corrected M12 note above.
- Console follow-up is research only. It needs a separate queue row, and Mos's go for any
public/change. - Phase A (superseded): base
2b2a9e14, 14 mutants, manifest sha2564c91e42d71ff9a95e336db57f6c5821f3ef94f6e3dbf07ef860d71145d664c8a, broker hashcc949cea…. Superseded by the broker hash above.