Files
stack/agents/filbert/work/queue-67/build.md
T
jason.woltjeandClaude Opus 5.5 7d032da5b4 filbert: row 67 round 2 packet, rebase onto f38b7f46 (#1560)
Manifest 4387c8d5. Rebase only: same added and removed lines, three files
re-digested after rows 58, 60 and 59. Gate green, round 1 mutants all killed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 20:53:36 -05:00

11 KiB
Raw Blame History

Row 67 (#1560): decisions read follow-up, round 2

Filbert, 2026-10-12. Brief: docs/plans/2026-10-11_decisions-read-follow-up.md, "Decisions read follow-up: seen-then-resolve, list-before-503 and full-row tests" (blob 7674ff40, unchanged). Darkwing and Dewey review. Sage commits after the gate. Nothing in the candidate is committed, staged or pushed.

Base f38b7f46, origin/refactor's tip when I rebased. build.patch applies there with git apply --index, and candidate-manifest.sha256 pins all 4 files after the patch. Round 1 was manifest 8959e615…7369 on 970ef729, approved by Dewey (27452) and Darkwing (27627).

Round 2: rebase only

Sage set the scope: a rebase onto the current tip, the merged hunks named here, a fresh manifest, and a digest re-approval. Nothing new goes in, so the round 1 description, mutants and questions below still apply. Dewey's N1 (an assertion that test 4's new decisions are listed) is not folded in; it stays a follow-up.

What landed on the manifest paths

Since 970ef729, three rows changed 3 of the 4 files. packages/bus/tests/decisions.test.mjs is untouched.

  • Row 58 (aaf87213): the bus README, broker.mjs and webui bus.test.mjs.
  • Row 60 (1771bf98): the bus README, broker.mjs and webui bus.test.mjs.
  • Row 59 (a8512007): the bus README and broker.mjs.

Digest check

Round 1's patch no longer applies plain (README line 205), as Darkwing found. It applies to f38b7f46 with git apply --index --3way with no conflicts. I compared the round 1 and round 2 patches:

  • The added and removed lines are byte-identical (106 lines each).
  • The hunk headers moved: README 205 to 235, broker.mjs 837 to 861, webui bus.test.mjs 163 to 191. The decisions.test.mjs hunks are unchanged.
  • One context line differs, below.

decisions.test.mjs keeps its digest (9477cfa7…). The other three have new digests because their bases changed.

Merged hunks

Line numbers are in the round 2 tree.

  • packages/bus/README.md, lines 235–243: the "Every row is…" sentence is rewritten as in round 1. In round 1 the hunk's last context line was the ## Shared reads and adapter boundary heading. Row 60 has since put its credentials paragraph between the two, so that paragraph's first line is the context now. The sentence and the paragraph share no lines.
  • packages/bus/src/broker.mjs, lines 864–867: the comment above case 'decisions' (line 868). Row 59's agents block ends above it (line 852 on), and row 60's case 'credentials' follows it (line 889). Neither touches the comment or the case.
  • packages/webui/tests/bus.test.mjs, lines 194–198: the three no-bus requests still follow the /api/bus/agents not-configured check, inside "bus refusals map to statuses…". Row 58 and row 60's additions sit above.

Gate (round 2)

Run in a worktree of f38b7f46 with the round 2 patch staged and node_modules linked, in sequence, with TMPDIR in my scratch and DOCKER_HOST pointed at a missing socket, 2026-10-12T01:47:57Z to 01:52:03Z.

  • Packages: webui 62/0, bus 95/0, cli 114/0, control-board 124/0.
  • All nine scripts/test-*.sh exit 0: auth 15, conductor 17, config 24, discord 66, extension-package 18, foundation 44, queue 27, release 4, task 26. test-queue skipped verify and render --check, because the worktree isn't the queue's canonical root. test-release skipped its Docker cases without a daemon.
  • Afterwards git status showed only the four staged paths and the node_modules link, and the tree checked 4/4 against the manifest.

Mutants (round 2)

I reran round 1's nine mutants (mut/run.mjs) on the round 2 tree, 2026-10-12T01:52Z to 01:53Z. All nine are killed, each by the same test as in round 1. The bus suite now has 95 tests and the webui file 9, so the counts read 94/1, 92/3 for view-blocking-raw and 8/1 for web-503-first, where round 1 read 80/1, 78/3 and 7/1. One edit changed: row 59 added a second blocking: !!d.blocking, in the agents read (broker.mjs line 930), and the runner refuses a target that isn't unique. So view-blocking-raw ran from a copy of the runner that anchors on its whole line (line 297, inside the decisions view), and the edit is the same. After each run git diff was unchanged, and the tree checked 4/4 against the manifest afterwards.


The round 1 packet follows unchanged: the description, files, round 1 mutants, round 1 gate and questions. Its base and line numbers are round 1's.

Row 67 (#1560): decisions read follow-up, round 1

Filbert, 2026-10-11. Brief: docs/plans/2026-10-11_decisions-read-follow-up.md, "Decisions read follow-up: seen-then-resolve, list-before-503 and full-row tests" (blob 7674ff40). Darkwing and Dewey review. Sage commits after the gate; nothing is committed, staged or pushed yet.

Base 970ef729. build.patch applies there with git apply --index; candidate-manifest.sha256 pins all 4 files after the patch.

No behaviour changes. No new test found a defect; the only non-test edits are the broker comment and the README sentence that repeats it.

What ships

  • Seen, then closed (decisions.test.mjs, new test after recent). The human marks the human-routed decision seen and resolves it; cto does the same for its decision; pm marks its decision seen and the raiser withdraws it. For each, the store holds exactly seen then the closing op, and the recent row's closed has that op, the closing event's seq and its by. The test also pins the recent order by close. Mutant recent-closed-first-event fails it.
  • List before 503 (webui/tests/bus.test.mjs, the no-bus server in "bus refusals map to statuses…"). With no bus configured, /api/bus/decisions?list=bad answers 400 invalid-request, and ?list=roles answers 503 not-configured, so a good list still reaches the bus check. Trail checks subject the same way, so the same loop pins /api/bus/trail?subject=%3C at 400. Mutant web-503-first fails it.
  • The whole row (test 4, "every row is what trail already gives…"). For every roles and recent row, for human and reader sessions, the row minus authorization and closed deep-equals trail's decisions row for that id minus table, with blocking as a boolean. authorization deep-equals {action, target, approvalChoice} from trail's one action.allowed decision.raise event for the id. closed is present on recent rows only, and equals trail's decision_events row as before. The seed left project, requirement_ref and supersedes null and every approval choice at the default yes, so a test of them would pass on a mutant that nulled them. Test 4 now raises two more decisions: one with a project and a requirement ref, then one that supersedes it, blocking, on a task, with approval choice no. The first closes as withdrawn by the supersede, so it lands in recent; the second is in roles.
  • The comment above the decisions case in broker.mjs now says which part each row equals: inbox's view of the decision, which is trail's decisions row with blocking as a boolean plus authorization from the raise's action.allowed event (trail gives that too); a recent row adds closed, the closing decision_events row.
  • README (packages/bus/README.md): the sentence "Every row is the decision as trail gives…" said the same imprecise thing, so it now says what the comment says. The brief allows this edit only if the comment fix changes what the README says; it does.

Out of scope, unchanged: no LIMIT on roles; roles order stays seq.

Files

  • packages/bus/src/broker.mjs: comment only.
  • packages/bus/README.md: one sentence.
  • packages/bus/tests/decisions.test.mjs: one new test; test 4 rewritten.
  • packages/webui/tests/bus.test.mjs: three requests in the no-bus case.

Mutants

mut/run.mjs (not shipped): one edit per mutant in the worktree, then the owning suite (packages/bus/tests/*.test.mjs, or packages/webui/tests/bus.test.mjs for web-503-first), then a restore. git diff was unchanged after each run.

Mutant Edit Base 970ef729 Candidate
recent-closed-first-event closed is the first event for the id survives killed: seen-then-closed
recent-join-any-event recent joins any event, not only closing ops survives killed: seen-then-closed
web-503-first busRead answers 503 before checking the request survives killed: refusals test
view-requirement-null row drops requirement_ref survives killed: test 4
view-supersedes-null row drops supersedes survives killed: test 4
view-project-null row drops project survives killed: test 4
view-task-ref-null row drops task_ref survives killed: test 4
view-approval-fixed approvalChoice always yes survives killed: test 4
view-blocking-raw blocking left as 0/1 killed: tests 1, 2 killed: tests 1, 2, 4

Candidate: 9 of 9 killed, each by the test this row adds or rewrites. Base: 8 of 9 survive. Each mutant fails only the tests named above; no other test moved.

Gate

gate.sh (not shipped) on the candidate worktree, sequentially, with TMPDIR in scratch and DOCKER_HOST pointed at a missing socket:

Suite Result
node --test packages/bus/tests/*.test.mjs 81 pass, 0 fail
node --test packages/control-board/tests/*.test.mjs 124 pass, 0 fail
node --test packages/webui/tests/*.test.mjs 40 pass, 0 fail
node --test packages/cli/tests/*.test.mjs 112 pass, 0 fail
scripts/test-auth.sh 15 passed, 0 failed
scripts/test-conductor.sh 17 passed, 0 failed
scripts/test-config.sh 24 passed, 0 failed
scripts/test-discord.sh 66 passed, 0 failed
scripts/test-extension-package.sh 18 passed, 0 failed
scripts/test-foundation.sh 44 passed, 0 failed
scripts/test-queue.sh 27 passed, 0 failed
scripts/test-release.sh 4 passed, 0 failed
scripts/test-task.sh 26 passed, 0 failed

Every suite exited 0. sha256sum -c candidate-manifest.sha256 passes in the worktree, and git diff 970ef729 there hashes the same as build.patch. No commit since 970ef729 touches packages/.

Rows 59 and 60, both in review, also edit packages/bus. On a fresh 970ef729 worktree, build.patch applies after row 59's patch with plain git apply, and after row 60's (alone, or after 59 then 60) with --3way and no conflicts. Whichever lands first, this one re-bases cleanly; the gate above is for this patch alone.

Questions for reviewers

  1. The webui check also pins trail?subject= before the 503. The brief names only list; the order is the same code path one branch up, and the line is in a file this row owns. Keep it or drop it?