Files
stack/agents/researcher/work/queue-97/build.md
T
jason.woltjeandClaude Sonnet 5.5 81c2906c68 researcher: row 97 build packet (#1591)
Packet commit, agents/researcher/work/queue-97 only. Secrets scan clean. Not pushed.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-12 18:12:57 -05:00

95 lines
4.8 KiB
Markdown

# Row 97 (#1591): Row 95 follow-up, Board tests fail fast, README lists every redirect
Owner: Researcher. Reviewers: Darkwing and Filbert. Brief: `docs/plans/2026-10-12_pm-test-fixes.md`,
"Row 95 follow-up". Built in a scratch worktree at base 3bd3f85c (a baseline worktree at the same
commit for the before column). Between 3bd3f85c and HEAD 646e3f77 nothing changed on the three
candidate paths. Nothing under `packages/webui/src/` changes; nothing goes live; no restart.
## Candidate
`candidate-manifest.sha256` lists three files, repo-relative, hashed from the candidate worktree.
`build.patch` is `git diff` of the same three against 3bd3f85c (sha256
22150cee5aad48de22a041e78d7263d91f1f44959c78720b35393757b054ea24).
- `packages/webui/tests/browser-edge.test.mjs`
- `packages/webui/tests/board-held.test.mjs`
- `packages/webui/README.md`
## N1: the toggle step fails fast
The wait for the first `/api/board` request after the toggle is raced against a 5 s timer. On a miss
the test throws "Show machine sessions made no /api/board request in 5 s", and the existing
`finally` closes the held responses, the browser and both servers.
Proof, mutant 19 (toggle on reads nothing), `browser-edge.test.mjs` alone, 30 s limit:
| | result |
|---|---|
| baseline | STALLED, no exit at 30 s |
| candidate | exit 1 in 5.8 s |
After each run, no browser or node process was left (checked through /proc cwd links, 0 found).
## N2: option taken, the test reaches a poll tick, plus the timers themselves
Reaching a tick alone cannot kill mutants 13 and 27. After a tick, the guards downstream of
`schedule()` (`refresh()`'s `!machine`, `render()`'s `out()`) stop the fetch, so nothing the page
sends changes. What the mutants do change is whether the 10 s timer is armed. So the test does two
things:
1. The page stub wraps `window.setTimeout`. A call with a delay of 10000 is recorded in
`window.__polls` ('board' for `refresh`, 'bus' otherwise), and in test 2 it is run after 150 ms.
The 600 ms settle in test 2 then spans several ticks, so the comment and README claim about polls
is true.
2. Both tests assert on the recorded timers. Test 1: none for the board with the toggle off, also
across Pause and Resume and after the `?off` reload, while the bus views do poll. Test 2: no new
timer after sign-out, including after a Pause and a Resume forced past `disabled`. The second
click is needed: the first only pauses, and the bus `schedule()` is reached with `paused()` false
only on the resume.
Mutants (`mutants.py`, outputs `mut-base.txt` and `mut-candidate.txt`):
| mutant | baseline | candidate |
|---|---|---|
| 13 schedule polls with the toggle off | ALIVE | killed |
| 27 bus schedule polls signed out | ALIVE | killed |
| 12 refresh reads with the toggle off | killed | killed |
| 26 bus render without its signed-out guard | killed | killed |
| 19 toggle on reads nothing | STALLED (30 s) | killed (5.8 s) |
| 14 refresh without its signed-out guard | ALIVE | ALIVE |
Mutant 14 is an equivalent mutant and is not claimed: the guard in `refresh()` is redundant behind
`api()`, which already returns early when signed out, so no observable differs. It was alive in the
baseline for the same reason and is outside N2's list. Sources were restored byte for byte
(sha256 of `app.js` and `bus.js` checked at the end of both runs).
## N3: the README
The test paragraph now names the six redirected requests: the board (`/api/board`), `agents`,
`/api/conversations`, `/api/seen`, `/api/queue` and the send. It also says that the tests record the
10 s poll timers, that test 2's timers fire after 150 ms, and that `browser-edge.test.mjs` fails in
5 s if the toggle makes no board request.
## Suites (candidate worktree, sequential, `suites.txt`)
- webui `node --test tests/`: 101 pass, 0 fail.
- control-board `node --test tests/`: 124 pass, 0 fail.
- `scripts/test-auth.sh` 15/0, `test-conductor.sh` 17/0, `test-config.sh` 24/0,
`test-extension-package.sh` 18/0, `test-foundation.sh` 44/0, `test-queue.sh` 27/0,
`test-release.sh` 14/0, `test-task.sh` 98/0.
- `scripts/test-discord.sh`: 57 pass, 1 fail: "pi binary present at node_modules/.bin/pi for the
extension checks". The same single failure on the baseline worktree. A scratch worktree has no
`node_modules`; this is not caused by the candidate. Sage's gate rerun in the canonical checkout
is the real check.
- `test-queue.sh` skips its verify/render check because a worktree is not the queue's canonical root.
## Secrets scan
`build.patch`, `mutants.py`, the mutant outputs and `suites.txt` were scanned for token, secret,
password, api key and private key markers. The only match is a test title ("seeded secrets ...").
## Assumptions
- Test 2's 150 ms is a test-only value; the 10 s in the product is untouched.
- The forced Pause click is a deliberate poke at a disabled control, commented in the test.