Files
stack/agents/dewey/work/wui/evidence/s5-mutants.md
T
jason.woltjeandClaude Opus 5.5 08b428ecf1 feat(webui,conversation): S5 WebUI views and CHAT-03 follow-ups (row 40, #1522)
Dewey's round 3 candidate, manifest
agents/dewey/work/queue-40/candidate-manifest-r3.sha256 (d0aa0ded,
27 files, checked OK in the canonical tree).

- WebUI inbox, tasks, agents and trail views, read-only over /api/bus.
  The README says the bus proof ends at the Console process.
- CHAT-03 seal: the engine command is fixed, the engine environment is
  explicit, SEAL_FLAGS has --no-approve, escalating is cleared on throw.
- Terminal input typed after Ctrl-T or Ctrl-O is held. Only the run whose
  own parse set held drains it (T1), and #run catches errors per action.
- DEFERRED keeps N2 and moves F2 to done, citing T1.

Reviews: Filbert approve (comment 27011, rev 260), Darkwing approve
(27013, rev 264). Landing gate on 8cad7722 plus the candidate: webui 22,
conversation 161, control-board 124, every scripts/test-*.sh green,
test-task 98/0. Mutant Mr survives; its flows test is the first
follow-up row.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 22:05:43 -05:00

7.2 KiB

Slice 1 S5 mutation check (row 40, #1522)

Run 2026-10-09 by Dewey, finished 2026-10-10T00:01Z. Each mutant ran on a fresh scratch copy (~/dewey-scratch/s5/mut) of packages/conversation, control-board, discord, seat, package.json, package-lock.json and docs/plans/chat-01, with node_modules symlinked. Every mutant got the full conversation suite. The working tree was never mutated. The tools are ~/dewey-scratch/s5/mut-tools/ (mutants.py, run.sh).

Mutant Change Result Killed by
base none 157/157 (baseline)
esc the force stop no longer clears escalating when the fence throws killed races: a force stop whose fence throws leaves no escalation flag behind
seal the seal check at bind always passes killed N24b
keys the envKeys check never finds a bad name killed N24b, N24
envall the engine environment copies every name in the source killed N24b
credname envKeys skips the credential-name test killed N24b
restart start() skips the seal check killed N24b
hold no action holds input killed terminal: Ctrl-T then Enter in one chunk
holdreload only Ctrl-T holds input killed the same test's Ctrl-O case
throwdrain an action that throws drops the input held behind it killed terminal: an action that throws still releases the input held behind it
manager ScopeLauncher passes the engine environment without MANAGER_ENV killed K19

Two fixes came out of the runs:

  • manager survived the first run, since no test launched a scope with only the engine environment (the cohort fixtures pass the whole test environment). K19 now launches /bin/sleep through ScopeLauncher with engineEnv([]) and checks that the engine's environment names come only from ENGINE_ENV, MANAGER_ENV and the names systemd and the shim's shell set (INVOCATION_ID, PWD, SHLVL).
  • Under seal and restart, N24b failed but then held its controller's socket open, so turns.test.mjs ran until the 900 s timeout. The bind-time part of N24b now closes the controller in finally, and a regression there fails in seconds.

The first full run's baseline failed 2 tests because the copy lacked docs/plans/chat-01/contracts.schema.json. The runner now copies it. Results from that run were discarded.

Round 2 (Filbert's comment 26993)

The same runner, the round 2 candidate, and every mutant from round 1, plus three for the round 2 changes. Each mutant ran the full conversation suite on a fresh scratch copy.

Mutant Change Result Killed by
base none 159/159 (baseline)
noapprove --no-approve removed from SEAL_FLAGS killed smoke: sealed, pinned Pi ignores a trusted project's .pi resources
queuecatch key() chains on the queue without catching the previous chunk's throw killed terminal: after an action throws, later input still runs
inputcatch input() rethrows instead of setting the status line killed the same test
esc as round 1 killed races: a force stop whose fence throws leaves no escalation flag behind
seal as round 1 killed N24b
keys as round 1 killed N24b, N24
envall as round 1 killed N24b, K19
credname as round 1 killed N24b
restart as round 1 killed N24b
hold as round 1 killed terminal: Ctrl-T then Enter in one chunk; after an action throws
holdreload as round 1 killed terminal: Ctrl-T then Enter in one chunk (Ctrl-O case)
throwdrain as round 1 killed terminal: an action that throws still releases the input held behind it; after an action throws
manager as round 1 killed K19

noapprove is checked against the real pinned Pi 0.85.1 with no model call. The test's control runs the same trusted project with --approve after the seal, and that offers skill:probe, so the sealed assertion can see a load when one happens.

Round 3 (Darkwing's comment 27001, Filbert's comment 27005)

The same runner on the round 3 candidate. The terminal mutants were rewritten for the new #run/#feed code, and the rest are as in round 2. Each mutant ran the full conversation suite on a fresh scratch copy.

Mutant Change Result Killed by
base none 161/161 (baseline)
holdowner every run drains held, as in round 2 (T1) killed, 160/161 terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending
heldcatch held input's key() returns the holder's promise (N4) killed, 160/161 terminal: input() reports an error when it happens …
chunkstop one try around the chunk's actions, so a throw skips the rest of the chunk killed, 160/161 the same test
reportlate input() catches at the end, as in round 2 (N4) killed, 160/161 the same test
reportdrop input()'s error is thrown and swallowed, never shown killed, 159/161 terminal: after an action throws, later input still runs; input() reports an error when it happens
throwdrain a throw leaves #run before the held input killed, 158/161 terminal: an action that throws still releases the input held behind it; after an action throws; input() reports an error when it happens
queuecatch as round 2 killed, 160/161 terminal: after an action throws, later input still runs
noapprove as round 2 killed, 160/161 smoke: sealed, pinned Pi ignores a trusted project's .pi resources
esc as round 1 killed, 160/161 races: a force stop whose fence throws leaves no escalation flag behind
seal as round 1 killed, 160/161 N24b
keys as round 1 killed, 159/161 N24b, N24
envall as round 1 killed, 159/161 N24b, K19
credname as round 1 killed, 160/161 N24b
restart as round 1 killed, 160/161 N24b
hold as round 1 killed, 157/161 terminal: Ctrl-T then Enter in one chunk; input held behind Ctrl-T waits for that takeover while an earlier action is still pending; after an action throws; input() reports an error when it happens
holdreload as round 1 killed, 160/161 terminal: Ctrl-T then Enter in one chunk (Ctrl-O case)
manager as round 1 killed, 160/161 K19

Round 2's inputcatch (input() rethrows) has no counterpart here: input() no longer catches a rejection, and with a reporter #run never throws. reportdrop and reportlate cover its two halves.

WebUI (Darkwing's note 1). run.sh copies only the conversation packages, so these ran packages/webui/tests/bus.test.mjs on a scratch copy of the packages it imports:

Mutant Change Result Killed by
base none 7/7 (baseline)
Mm humanCall's timeout rejects without child.kill('SIGKILL') killed, 6/7 humanCall kills a transport that runs past its timeout
Mp serve --business takes any value killed, 6/7 serve refuses a --business value that is not a business id

Correction: the first Mm run hung, because the surviving child held the test process open. I stopped the child by PID. The test now kills a surviving child on cleanup, and the rerun failed the assertion in 1.5 s. Under Mp, serve started a real server on port 0 until spawnSync's 10 s timeout ended it.