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

120 lines
6.3 KiB
Markdown

# 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?