Files

5.4 KiB

Row 163 r1 review (Filbert): changes requested

What I reviewed:

  • Candidate 4be3f6aec on 580500699, base 4f02486d5.
  • Manifest 430212299beb: all 10 files match (sha256sum -c).
  • candidate.diff in packet 51f67f1f8 is byte-identical to git diff 4f02486d5 4be3f6aec.
  • stack-release.sh blob 0053f35d13.
  • Base drift: nothing has landed on these files on refactor since the base.
  • Brief: docs/plans/2026-10-18_stack-release.md section D2 (:271), blob b1500d96ad. I also checked BUILD.md rulings mos-0961, mos-0962 and mos-0963, and deviations 1-7.

Tests I ran (my own worktree, 14:53-15:04Z, TMPDIR ~/fs163, totals summed by script):

  • stack-release.test.mjs: 164/164
  • launcher.test.mjs: 29/29
  • host.test.mjs: 42/42
  • session.test.mjs: 12/12
  • Total: 247 pass, 0 fail.

Mutants I ran: six mutants of my own, each against the R tests (--test-name-pattern "^R[0-9]+ ", 13 tests). All six survived with 13/13 passing:

  • M1: live-config-unchanged always passes (stack-release.sh:1215).
  • M2: backup-unchanged always passes (stack-release.sh:1214).
  • M3: credential-ref-live accepts an env reference (stack-release.sh:1301).
  • M4: the data-root-scratch check is dropped (stack-release.sh:1288).
  • M5: no-session ignores a launches directory (stack-release.sh:1389).
  • M6: there is no INT/TERM/HUP trap (stack-release.sh:1395).

Each behavior is in the brief or a ruling, and each lacks a killing test. The brief says "Mutants: one per behavior above", so I'm treating each gap as a change (decision 137: a missing test the brief requires is a change).

F1. The after-checks on the backup and the live config never fail in any test (M1, M2).

  • Brief item 1: "The backup's sums are checked before and after."
  • The R tests do prove the files stay byte-identical, through untouched(e) from outside the script. But nothing makes the script's own backup-unchanged or live-config-unchanged print FAIL.
  • A broken compare would print PASS to the operator even when the backup or the live business file changed.
  • Suggested test: a stand-in fault that makes the fixture host append to the backup's bus.sqlite, and then to the live business file. Expect FAIL backup-unchanged and FAIL live-config-unchanged by name, plus REHEARSAL_FAIL.
  • The tested path could be named in the fault file, because the host only gets HOME, PATH and MOSAIC_CONFIG.

F2. Three guard and session branches have no test (M3, M4, M5).

  • M3: under mos-0963, credential-ref-live refuses an env reference. Only the outside-placeholders file case is tested (R9). Suggested test: an ownScript rewrite that leaves one role's {env:...} reference in place. Expect FAIL credential-ref-live: <role> <service> is env <NAME>.
  • M4: data-root-scratch refuses a scratch config that resolves somewhere other than $R/data. Suggested test: an ownScript that points c.dataRoot at another existing directory that isn't the live one. Expect FAIL data-root-scratch.
  • M5: no-session also fails on $R/data/launches. Only the sessions.json half is tested (R4 host-launches). Suggested test: a fault that makes the stand-in host create launches/. Expect FAIL no-session: found launches.

F3. Nothing tests that an interrupted rehearsal stops its host and Console (M6).

  • Brief item 3 says it "stops both", and deviation 7 makes both processes children of the script.
  • If the INT/TERM/HUP trap goes, a Ctrl-C at the gate leaves a host and Console running on the scratch root and the scratch port.
  • Suggested test: start a rehearsal, wait for the host's "launches disabled" line in host.log, then SIGTERM the script. Expect:
    • FAIL signal
    • PASS console-stopped and PASS host-stopped
    • REHEARSAL_FAIL with exit 1
    • neither recorded pid alive afterwards.

Nit (doesn't block):

  • N1: Registry.remove() (packages/seat/src/session.mjs:208) still calls #write() when the registry is read-only.
  • Its only caller is launcher.mjs:469, which runs after add(), and add() already refuses under read-only, so it can't be reached today.
  • A one-line read-only guard would make the "never writes sessions.json" contract hold for the whole class rather than only for the current callers.

Checked, nothing to report:

  • --no-launch: it refuses launches in start(), refuses session launch requests (with the refuse op and a record event), starts no ticker, makes the Registry read-only, and leaves an earlier host's sessions alone in recover() and close(). --pm with --no-launch is a usage error. No unit renders it (host.test).
  • Processes: both start under env -i HOME PATH MOSAIC_CONFIG. scripts/mosaic execs node, so $! is the host itself, and the copy-match and pid checks hold. The Console starts with no --send, so it can't send.
  • Credentials: they exist only at roles.<instance>.credentials and tracker.sync.credentials (packages/business/src/business.mjs:63, :111). The rewrite swaps both. Instance names pass requireId, so a placeholder filename can't escape placeholders/.
  • Ports: they're checked before anything is made. A race after the check just fails console-up; no other port is taken.
  • Rehearsal directory: it and its config/ and placeholders/ are made under umask 077 (R1 checks 0700). The backup is read only through cp and sums; the migration runs on $R/refuse and $R/data.
  • Hash pins: no test pins a 64-hex hash of any changed file. stack-release.sh and TOOLS.md are read only by stack-release.test.mjs.