11 KiB
Row 307 (#1814, Vikunja 598): move row 270's pi compaction reading behind the harness kind
Owner Gizmoduck. Reviewer Duckworth. Gate owner Sage. Brief:
docs/plans/2026-10-23_harness-kind-compactions.md. Base 1e629c892. Design: DESIGN.md beside this file,
approved (static) by Duckworth on 67daf6403 (duckworth-0280), with C1, C2, N1 and N2 folded in at
cb048b93c. Mos ruled go on the four old-test edits in mos-1459, with the bounds below.
Commits
1f6db1589, red first. The two new test files and capture.mjs. Its product files are base's:git diff --stat 1e629c892 1f6db1589lists only this packet, capture.mjs and the two tests.44104adb1, the build. The product files and the four old-test edits.
What the build does
packages/plugins/src/kinds.mjs:52-57: the harness kind's exports end in"compactions", and the comment gains its contract line.interfaceVersionstays 1 (DESIGN.md "interfaceVersion stays 1").- New
packages/plugins/harness/pi/compactions.mjs: base'sscanPi,readRange,digest,STREAM,TAIL, the chunk size,PI_VERSIONandclaudeHistory, unchanged in behaviour, plus the export.scanPiis no longer exported and takes no defaults: its one caller passes all four arguments. pi/index.mjsre-exports it.claude-code/index.mjsanswers harness-unsupported with version null.packages/seat/src/compactions.mjs: keeps the ledger.readLedgersetsunsupportedonr.reason === "harness-unsupported"only (:113).checkAnswer(:147-164) refuses an answer out of contract.collectCompactions(store, { name, compactions }, opts)(:174-205) calls the export, checks it, and writes the same lines in the same order as base.packages/cli/src/launcher.mjs: thecompactionsclosure takes the loaded module and calls the export directly, with the N1 comment on why it skipscall(). Both call sites passharness.packages/plugins/README.md: the Harness section gains thecompactionsbullet.
Old-test edits (mos-1459 bounds)
| File | Edit | Bound |
|---|---|---|
| plugins/tests/kinds.test.mjs | "compactions" appended to the pinned list |
:17-21, append only |
| seat/tests/compactions.test.mjs | two module imports; collect passes { name, compactions } |
:11/:21, helper only |
| seat/tests/compactions-budget.test.mjs | pi import; collect passes { name, compactions } |
:13/:24-25, helper only |
| cli/tests/compactions-launch.test.mjs | pi import; base :344's call (now :345) passes { name: "pi", compactions: pi } |
call only, .count === 1 kept |
No call or expected value in those files changed. harness.test.mjs, cli helpers.mjs:133-151, launch-routes.test.mjs:17-23 and launcher.test.mjs:694-697 are unedited.
New tests
packages/seat/tests/compactions-ledger.test.mjs:- FIXTURES: seven ledgers row 270's code writes (known, store-incomplete, store-unreadable,
not-collected, harness-unsupported from claude-code, harness-unsupported from Claude history, and
torn), each with its streams, projects and steps. Per fixture, test A reads
compactionCountand test B runs one collection through{ name: "pi", compactions: pi.compactions }. - Test B runs over the fixture's own streams, not an empty session as DESIGN.md:189 says. Over an empty session every fixture with a cursor would go store-incomplete (the stream went away), so "the others go known" could not hold. The expected answers: known stays known (1), store-unreadable goes known with 0 (the cursor is at the end), not-collected goes known with 1, and store-incomplete, torn and both harness-unsupported fixtures stay unknown.
- The malformed-answer test (17 answers, plus a module that throws, over a fresh store and over the known fixture) and the argument test (exact keys; core passes a copy of the cursors).
- FIXTURES: seven ledgers row 270's code writes (known, store-incomplete, store-unreadable,
not-collected, harness-unsupported from claude-code, harness-unsupported from Claude history, and
torn), each with its streams, projects and steps. Per fixture, test A reads
packages/plugins/tests/harness-compactions.test.mjs: CASES plain, budget (100 bytes), cap (1 stream of 2), shrank and header against pi; pi'sfirstwith and without Claude history; claude-code; and a module re-exporting every pi export butcompactions, refusedmissing-export.- capture.mjs reads both capture blocks from the test files. It replays each fixture with base's
collectCompactions(store, "<name>", ...)and compares the ledger byte for byte, and it runs base'sscanPiper case and compares the answer under base's reason order (:301 at base) andPI_VERSION. It prints base'scompactionCountper fixture: that is the before half.
Expected red on 1f6db1589
- seat compactions-ledger: the seven test A pass (the ledger rules are base's). Test B fails for known,
store-unreadable and not-collected: base takes the object as a harness that isn't pi and writes
harness-unsupported. Test B passes on base for the other four, whose expected answer is unknown with
the same reason. The malformed-answer and argument tests fail: base never calls the module.
Correction after the run: test B fails on base for claude-history too, so the reds are known,
store-unreadable, not-collected and claude-history. On base the object harness takes :304, which
writes
collectedwithout a scan, so the count stays null. Pi on the tip scans on a later collection, finds c1 and answers 1, still unknown with harness-unsupported. The test is right and this list was wrong (Duckworth agreed, duckworth-0287). - plugins harness-compactions: the five CASES, the
firsttest and the claude-code test fail with a TypeError (compactionsisn't exported on base). The missing-export test fails: base's loader loads the module. - harness.test.mjs:192 is already red on base. That's the brief's starting point.
Run plan (mos-1275, timeout -k 10)
All on a CLEAR from Sage. TMPDIR comes from mktemp -d /mnt/storage/scratch/tmp/gXXX. Gate worktrees
under /mnt/storage/scratch, node_modules linked right after git worktree add, pipefail and tee.
| Run | Longest recorded | LIMIT |
|---|---|---|
capture.mjs on a 1f6db1589 worktree (base and candidate both it) |
none | 120 s |
red first: the two new files on 1f6db1589, each whole |
none (seat suite 7 s) | 300 s |
the touched test files whole on 44104adb1, one at a time |
compactions-launch alone: none; other files 15 s | 600 s |
| bus suite | 25 s (270 r5) | 900 s |
| cli suite | 682 s (270 r5) | 2100 s |
| plugins suite | none recorded | 900 s |
| webui suite | 58.2 s (294) | 600 s |
| business suite | none recorded | 900 s |
seat suite whole, node --test tests/ (Duckworth C1) |
7 s (270 r5) | 600 s |
| each scripts/test-*.sh | 42 s (test-foundation) | 900 s |
| each mutant, its kill files whole | 1 s (264a probes) | 300 s |
- In the cli run, compactions-launch's T3 tests (base :206, and :305 with the :344 edit; :207, :306
and :345 after the import line) must show as run, not skipped on
sandboxProblem()(base :36, now :37). The report names every skip (Duckworth C2). - Plugins must have zero failures.
- A timeout with no failed test is a hang and goes to Sage. A timeout in the shell phase goes to Mos unplaced. A first-run red in a new 307 test is placed and reported after (mos-1272). A red in an old test goes to Sage, unfixed.
Mutants
Each on an isolated copy of the file, restore checked by sha256, only on a green base.
| # | Change | Kill files |
|---|---|---|
| M1 | readLedger: if (r.harness !== "pi" || r.reason === "harness-unsupported") restored |
plugins harness.test.mjs (:192) |
| M2 | pi compactions drops the first && claudeHistory(store) branch |
seat compactions-budget.test.mjs (base :86, now :87), plugins harness-compactions.test.mjs |
| M3 | readLedger never sets unsupported |
seat compactions-ledger.test.mjs, seat compactions.test.mjs (base :197, now :199) |
| M4 | collectCompactions skips checkAnswer |
seat compactions-ledger.test.mjs |
Runs
Sage's CLEARs: sage-3455 for steps 1-3, sage-3465 for steps 4-6. Gate worktrees at
/mnt/storage/scratch/g307-base (1f6db1589), g307-tip and g307-mut (1f00d4f91), with node_modules
linked. TMPDIR was /mnt/storage/scratch/tmp/gTIK. Outputs went to /mnt/storage/scratch/gizmo-307-out/s1 and s2.
Steps 1-3 (13:31:21Z-13:31:36Z, then the capture rerun at 13:32Z)
- capture.mjs crashed with ENOENT on its first run. Base
sessionStore(session.mjs:78privateDirs, called from :117) makes its directories one level at a time, and :44 passed a per-fixture root that didn't exist yet. The fix is one line before :44,mkdirSync(join(root, `f-${name}`)). A copy with that line, run on g307-base as both base and candidate, exited rc 0 and printedall match: 7 ledgers byte for byte, 7 base counts and 5 scans. Base counts: known 1 known; store-incomplete, store-unreadable and not-collected null, unknown with their own reason; claude-code and claude-history null, harness-unsupported; torn 1, store-incomplete. - Red first on
1f6db1589, both rc 1. Seat compactions-ledger: 9 pass, 7 fail (the corrected list above, plus the malformed-answer and argument tests). Plugins harness-compactions: 0 pass, 8 fail. Seven fail withTypeError: pi.compactions is not a functionorclaude.compactions is not a function. The missing-export test fails because base loads the module. - Touched files whole on
1f00d4f91, all rc 0: compactions-ledger 16/16, harness-compactions 8/8, kinds 5/5, harness 9/9 (:192 green), compactions 20/20, compactions-budget 10/10, compactions-launch 5/5 with 0 skipped.
Steps 4-6 (14:00:10Z-14:14:00Z, on 1f00d4f91)
| Run | rc | Time | Result |
|---|---|---|---|
| bus | 0 | 24 s | 890 pass, 0 fail, 0 skipped |
| cli | 0 | 631 s | 927 pass, 0 fail, 0 skipped; T3 :207, :306, :345 ran |
| plugins | 0 | 0 s | 119 pass, 0 fail, 0 skipped |
| webui | 0 | 57 s | 374 pass, 0 fail, 1 skipped (below) |
| business | 0 | 2 s | 231 pass, 0 fail, 0 skipped |
| seat | 0 | 7 s | 218 pass, 0 fail, 0 skipped |
| test-auth | 0 | 0 s | 15 passed, 0 failed |
| test-conductor | 0 | 7 s | |
| test-config | 0 | 3 s | |
| test-discord | 0 | 7 s | |
| test-extension-package | 0 | 2 s | |
| test-foundation | 0 | 39 s | |
| test-land-work | 0 | 12 s | |
| test-queue | 0 | 20 s | one skip (below) |
| test-release | 0 | 3 s | 15 passed, 0 failed |
| test-task | 0 | 14 s | 92 passed, 0 failed, two skips (below) |
Skips:
- webui: "rebuilding from the source gives the same bytes" needs the pinned esbuild. 307 doesn't touch the editor.
- test-queue: "queue verify and render --check", because the gate worktree isn't the queue's canonical root.
- test-task: "live provider cases" twice (row 244, no provider call in the gate).
Mutants ran in g307-mut. Each restore matched its sha256, and the tree was clean after M4.
| # | Killed by |
|---|---|
| M1 | plugins harness.test.mjs:192 |
| M2 | seat compactions-budget.test.mjs:87 and :104; plugins harness-compactions.test.mjs:47 |
| M3 | seat compactions-ledger.test.mjs:123 (test B, claude-code and claude-history); seat compactions.test.mjs:199 |
| M4 | seat compactions-ledger.test.mjs:151 (the malformed-answer test) |
There were no reds, so nothing was placed under mos-1272. The sweep found no node or chromium left in my cwds.