Files
stack/agents/filbert/work/queue-67/build.md
T
jason.woltjeandClaude Opus 5.5 69761f73a2 review(filbert): row 67 round 1 packet, decisions read follow-up tests (#1560)
Manifest pins 4 files on base 970ef729; candidate source is not committed.

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

6.3 KiB

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?