Folds Filbert's N1 per Sage's comment 28355: the envelope test sends a role cap with a tester proof. The narrowing mutant at server.mjs:50 survives the full bus suite on round 1 and is killed on round 2. Full gate passed with the real bwrap tester case running. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.5 KiB
Row 110 (#1604) round 2: one more envelope case
Sage asked for changes in comment 28355 (rev 1093) and folded Filbert's note N1 into this round. Round 1 is agents/darkwing/work/queue-110/r1/. Everything in it still holds except the one test file below.
BASE: badfa52b9d, unchanged. Since BASE, the branch has changed only packet files, docs/SESSIONS.md, docs/plans/QUEUE.md and docs/plans/queue.json. No manifest path moved.
Candidate: build.patch against BASE. candidate-manifest.sha256 lists the same 19 files as round 1. I applied the patch to a fresh git archive badfa52b9 export and every digest matched.
What changed
One file, packages/bus/tests/tester.test.mjs, in the test "an envelope carries exactly one of cap, human and tester; no tester authenticator refuses". The envelope loop gains a role cap beside the reader cap. r1-to-r2.diff is the whole change between the two candidates' applied trees:
const cap = b.bindReader({ business: 'demo' });
- for (const r of [{ tester: p, cap }, { tester: p, human: p }, { tester: p, human: p, cap }])
+ const role = b.bindLaunch({ business: 'demo', role: 'pm', run: 'pm-run', harness: 'pi' });
+ for (const r of [{ tester: p, cap }, { tester: p, cap: role }, { tester: p, human: p }, { tester: p, human: p, cap }])
The manifest line for that file goes from 39c225c5... to 167aa918.... The other 18 lines match round 1 byte for byte.
The narrowing mutant
mutant-n1.py in this packet. It narrows the conflict check at packages/bus/src/server.mjs:50 so a cap counts only when it is the envelope's sole credential or is a reader cap (broker.identity gives role null and no human). With the mutant, a role cap sent with a tester proof passes the envelope, and the request runs as the tester. The script swaps that one line, runs the whole bus suite (node --test tests/*.test.mjs in packages/bus), and puts server.mjs back from its .orig copy. Both runs report restored=True.
| Candidate | Bus suite under the mutant | Result |
|---|---|---|
| round 1 (01:21:34Z) | 147 pass, 0 fail | survived |
| round 2 (01:21:50Z) | 146 pass, 1 fail | killed |
On round 1 it survives every bus test, which is the gap Sage named. On round 2 the only failure is the envelope test. The new tuple gets { ok: true, result: [] } where the test expects { ok: false, error: 'invalid-envelope' } (mutant-n1-r2.log, the assertion at tester.test.mjs:337). The reader-cap tuple still refuses under the mutant, so the failure comes from the role-cap case.
The assertion message is Object.keys(r).join('+'), so both cap tuples print tester+cap. Sage's scope said nothing else changes, so I left the label alone. The actual value in the log shows which tuple failed.
Gate
gate.sh in this packet, run on the round-2 candidate with the slot from Sage, 01:22:27-01:27:55Z, on BASE badfa52b9 with DOCKER_HOST unset and docker 29.7.2. It runs every package's node suite and every scripts/test-*.sh. GATE_PASSED, exit 0. gate-run.log has the summary, and gate/ has one log per step. The worktree still matched the manifest after the run.
| Step | Passed | Failed |
|---|---|---|
| bus | 147 | 0 |
| business | 67 | 0 |
| cli | 184 | 0 |
| control-board | 124 | 0 |
| conversation | 182 | 0 |
| discord | 178 | 0 |
| harness | 80 | 0 |
| ledger | 78 | 0 |
| mosaic | 69 | 0 |
| queue | 156 | 0 |
| runs | 43 | 0 |
| seat | 120 (0 skipped) | 0 |
| tasks | 92 | 0 |
| webui | 108 | 0 |
| scripts | auth 15, conductor 17, config 24, discord 66, extension-package 18, foundation 44, queue 28 (node 156), release 14, task 98 | 0 |
The counts match round 1. Bus stays at 147 because the new case sits inside an existing test.
The real bwrap tester case ran and passed. It did not skip. From gate/pkg-seat.log:77:
✔ a confined session that runs tester-cli.mjs is refused as tester, and the same shim outside the sandbox binds (262.780721ms)
Neither the review.test.mjs:123 flake (#261) nor the release active.json flake (#258) came back. The release step made wt_default at 01:27:13Z with no containers, and I removed it after the run.
Mutants from round 1
I didn't rerun the 96 round-1 mutants. The only change adds one more assertion to an existing test. A test with an extra assertion fails on everything it failed on before, so this round can only kill more mutants, never fewer. Two of them, s00 and s01, touch server.mjs:50, and round 1 killed both. Round 1's mutants-run.log (94 killed, b44 and b45 equivalent) ran on the round-1 candidate.