Darkwing'sef8b4439e(darkwing/row245), Duckworth round 1 APPROVE (rev 2849, comment 30043), manifest 69bc05f4f706, 5 paths. Slot run sage-1961 (darkwing-0107): singles 23/0, mutants 16/16 killed, N1 and N3 among them. DESIGN.md:336-338 stays unedited, superseded by gosalyn-0087. Sage gate on856c1826bplus these 5 paths (12:24-12:35Z): case1-accept.test.mjs alone 23/0, cli 681/0, every scripts/test-*.sh 429/0.
5.5 KiB
Row 245 build: Duckworth's N1-N3 on scripts/case1-accept.sh (row 195 follow-up)
Duckworth approved row 195's manifest round 1 (duckworth-0088, agents/duckworth/work/row195/REVIEW-m1.md
at 6afcee2a5) with three notes that don't block. Row 195's code landed as b65014647, and the notes are in
docs/plans/DEFERRED.md (d6cff0cdd). Row 245 carries them: brief docs/plans/2026-10-20_hub-own-uid.md §
"Row 195 follow-up" at 62ddc96cc, owner Darkwing, reviewer Duckworth, gate owner Sage (sage-1923).
The branch is darkwing/row245, on 62ddc96cc. Its first commit is a cherry-pick of darkwing/row195-n1
1e3c4767c, which was written on 37171f65b and never run. The script, test and TOOLS.md blobs are the same
as in 1e3c4767c, and none of those paths changed between 37171f65b and 62ddc96cc.
What changes
N1. F9 ran $ROOT$NODE as root (case1-accept.sh:298 at 37171f65b) before F10 checked that --node is
the pinned path. Duckworth offered two fixes: F9's parse through AS_USER, or F10's path check first. I
took the path check, plus one more:
- F9 now runs node only when
--nodeequals/opt/mosaic-stack/node-<--node-pin>/bin/node. - Then
not_root_onlywalks from that file up to/. Each entry must be the running user's (root's on the host) with no group or other write, the rulecase2-unit.shroot_onlyapplied when it rendered the units. A symlink fails it, because its mode is 777. The first entry that breaks the rule goes in the evidence.
I didn't run the parse through AS_USER. That would hand a check about a root file to the stack's user,
and a process running as mosaic shares that node's uid. Whether it could change what node prints then
turns on the host's ptrace setting, and the root-only check doesn't depend on that. Sage agreed in
sage-1877. Rechecking ownership costs one loop and doesn't depend on
how the host was installed.
N2. The header (:9-15) and the docs/TOOLS.md entry now list what root runs: systemctl show and
is-enabled (F1, P11), curl on the loopback healthz (F2), sudo -l (P1, P3), sudo -u jarvis bwrap --version and hostcheck.sh --check (P9), and node for F9 under the rule above.
N3. F6 matched --claude by prefix, so /opt/mosaic-stack/claude-<pin>/../claude-2.0.9/... passed the
path check. F6 now fails on any .. segment, before it runs --version. F10 compares for equality, so
it needed no change.
Row 195's BUILD.md gets a correction entry for deviation 6. Row 195's DESIGN.md is unchanged. Its "either
works" wording at DESIGN.md:336-338 is superseded by gosalyn-0087 (root writes dev.args at W10), and
it stays in place: an approved design isn't edited (sage-1877).
Tests
packages/cli/tests/case1-accept.test.mjs:
- The node stub touches
node-as-rootin the state directory when something runs it outside the fakesudo(which sets HOME to the stack's home).host()sets the node file's directories and the scratch root to 0755, so the umask can't fail F9. - "every check passing" also asserts that root ran the pinned node.
- New: "F9 won't run --node as root off the pin path or with a writable directory above it". Another node
path fails F9 and F10, with no root run. A group-writable
bin/and a symlinked node each fail F9 alone, with the bad path in the evidence and no root run. - The F6 test gains a
..case: a path underclaude-<pin>/by prefix that names 2.0.9's binary, which prints the pin. F6 alone fails, with "has a .. segment".
That makes 23 tests. All 23 pass on Sage's slot (results below).
Mutants
The twelve from row 195 still apply, unchanged. These four are new, each one exact replacement:
| # | Mutant | Expected killer |
|---|---|---|
| 13 | F9 runs any --node (the pin check becomes true) |
F9 won't run (another node) |
| 14 | F9 skips the ownership walk (bad="") |
F9 won't run (writable bin/, symlink) |
| 15 | not_root_only checks only the file, not the directories above it |
F9 won't run (writable bin/) |
| 16 | F6 accepts a .. segment |
F6 stub, path and .. |
The brief's gate asks for a mutant for each of N1 and N3. Mutants 13-15 are N1's, and 16 is N3's.
Slot plan
Same shape as row 195's steps, on this row's tip: the single test file, then the sixteen mutants, then
the gate (the cli suite and every scripts/test-*.sh), each behind the busy checks and chained with
&&. The scripts are in /mnt/storage/scratch/darkwing-245-out/.
Slot results (grant sage-1961, 2026-10-21)
All three steps ran on 0590a29fc with node v26.8.1, launched from /. Both busy checks were CLEAR
before each step.
- Singles, 11:27:46-11:27:59Z:
case1-accept.test.mjspassed 23, failed 0. - Mutants, 11:28:10-11:31:20Z: all 16 killed, each with exit 1. The runner restored the script, and its sha256 875bb5b7 matches the committed blob. Rows 1-12 died as in row 195. 13, 14 and 15 died on "F9 won't run --node as root off the pin path or with a writable directory above it". 16 died on "F6 fails on a stub that prints nothing, on a path outside claude- and on a .. segment".
- Gate, 11:31:20-11:42:51Z: the cli suite passed 664, failed 0, skipped 0. Every
scripts/test-*.shexited 0: auth 15, conductor 17, config 31, discord 78, extension-package 18, foundation 44, land-work 86, queue 28 (its node part 156/0), release 14, task 98. That's 429 selftests, none failed. - Afterwards no process had its cwd in the worktree, the out dir or TMPDIR, and the
darkwing-r245_defaultnetwork was gone.
Logs: /mnt/storage/scratch/darkwing-245-out/ (step1.log, mut.out, mut/m1-16.log, gate.out).