Files
stack/agents/darkwing/work/queue-56-review/review-r1.md
T

6.7 KiB

Row 56, runs and releases reader, round 1 review (Darkwing)

Issue #1545, packet comment 27109, request comment 27113, queue revs 343-347. Brief: docs/plans/2026-10-10_design-implementation.md, section "Runs and releases reader module". Base dc96f87b. Candidate manifest sha256 ed3c5392ae43e1c3541c6bab6a2f25826514124f5f68536e5cc330a39cc5d7a3, build.patch sha256 dd7b469b…. Both match comment 27109, and the packet manifest checks clean.

Verdict: approve. The module reads and never writes, nothing it returns comes from outside the data root, and list and show print the same bytes as before on Rocko's seeded data root. Every suite is green. Nothing blocks. The notes below are test gaps and README wording, plus one disagreement with the packet: mutant M31 is not equivalent.

Method

  • I read the whole patch: the five src/ files, the three test files, the README, the mosaic-task.mjs change, and Rocko's seed.sh, byte-check.sh and delta-check.sh. I compared the pointer and log readers against scripts/release.sh (append_log, the activate printf, rollback's log scan and status).
  • Detached worktrees at dc96f87b: base unchanged, cand with git apply --index build.patch, then sha256sum -c on the manifest, 15 OK. A third worktree, built the same way, for mutants. It checks 15 OK after the runs (r1/mut/manifest-after.txt).
  • grep for any write, mkdir, rename, unlink, chmod, open or symlink call in packages/runs/src: none. The patch touches no Q14-frozen path.
  • Rocko's byte-check.sh and delta-check.sh, base against candidate, with work directories in my scratch rather than /tmp.
  • 22 mutants of my own (r1/mut/mutate.py, exact text that must match once), each run against the packages/runs suite.
  • Six probes for cases the packet doesn't cover (r1/probes.sh, output in r1/mut/probes.txt), run against base, candidate and a candidate carrying mutant D01.

Node v26.8.1, TMPDIR=~/darkwing-scratch/r56a/tmp. gate.sh with DOCKER_HOST=unix:///nonexistent.sock ran 16:55:29Z to 16:57:50Z. Mutants ran 16:57:19Z to 16:57:40Z in the other worktree, then probes, then test-release with Docker, which finished at 16:58:33Z.

Suites

Suite Result
packages/runs (node) 37/0
test-auth 15/0
test-conductor 17/0
test-config 24/0
test-discord 66/0
test-extension-package 18/0
test-foundation 44/0
test-queue 27/0
test-release 4/0 without Docker, 14/0 with it (test-release-docker.txt)
test-task, Docker unreachable 26/0, four skip lines
byte-check.sh 16 cases identical, data root unchanged
delta-check.sh same output as Rocko's apart from the scratch path in one stack trace

I didn't run test-task with real Docker, because it makes live model calls. Rocko's gate ran it at 98/0, and the change to mosaic-task.mjs is limited to list and show, which the package's CLI tests and the byte check cover.

Mutants

17 of 22 killed (r1/mut/summary.txt). The five survivors:

Mutant Change Observable?
D01 the CLI's isRunId check before loadConfig removed (Rocko's M31) yes, probe P1
D10 isInside treats a path equal to the data root as outside only when a link resolves to the data root itself
D17 listRunRecords reads through readRunDocument, which checks the id yes, probe P3: list exits 4 on a run named r-
D20 listRunIds keeps isRunId names only yes, probe P3: list hides r- and r-.bad
D22 a log entry without imageTag accepted yes, by reading the log

Probes

Probe Base Candidate
P1 show ../x with no config file exit 4, invalid run id the same. With D01: exit 3, configuration problem
P2 show of a run directory with mode 000 prints two lines, then a stack trace, exit 1 cannot read ...: EACCES, exit 4
P3 list with runs named r- and r-.bad lists both the same
P4 runs/ a link inside the data root, plus a run linked to . lists both the same
P5 state/ linked out, no files there not in base pointer null, log empty. With active.json there: refuses, exit 4
P6 log lines with an extra key, and a numeric imageTag not in base both counted in malformed

Notes (not blocking)

  1. M31 isn't equivalent. The isRunId check in showRun is the only id check that runs before loadConfig, so it decides the exit code and message when the config is bad (P1: 4 against 3). The candidate keeps the base order, so nothing regresses, but a test of show ../x with MOSAIC_CONFIG pointing at a missing file would pin it. I agree that M04 can't be reached on POSIX.
  2. No test lists a run whose name starts with r- but isn't a valid id, so D17 and D20 survive. runs.mjs says such names are still listed, and base does list them. One listRunRecords case with r- or r-.bad would kill both.
  3. logEntry accepts an entry with no imageTag (D22). The malformed cases test a wrong type, a null note and an extra key, but not a missing key.
  4. README wording, three places:
    • "runs/ or state/ resolving outside refuses" holds for runs/. For state/, the module resolves only the file, so a state/ link out with no files behind it reads as no release and an empty log (P5). Nothing outside is read, so the invariant holds and only the sentence is wrong.
    • "the way release.sh rollback skips them": rollback skips only lines that don't parse. P6's two lines would still be used by rollback and are counted malformed here. append_log writes only the five keys, so real logs don't hit this. The stricter reader is fine. The comparison in the README and in state.mjs isn't accurate.
    • The delta table has no row for P2. show of a run directory it can't read used to crash after printing two lines. It now refuses with exit 4. That's an improvement and the package test covers it, but delta-check.sh doesn't record it.
  5. D10 needs no test. It matters only for a link that resolves to the data root itself, which is inside by any reading.
  6. The padEnd crash in list that Rocko reported is still there and still predates this row. Sage files it as a follow-up.

Files

  • r1/candidate-manifest.sha256: copy of Rocko's.
  • r1/gate.sh, r1/out/: suite runs, summary.txt, byte and delta checks, test-release with Docker.
  • r1/mut/: mutant definitions, runner, diffs, outputs, summary.txt and the manifest check after the runs.
  • r1/probes.sh, r1/mut/probes.txt: the six probes. In that run the third tree (mutwt) carries D01, and the D17 and D20 runs of P3 follow at the end.