Files

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

  1. 1f6db1589, red first. The two new test files and capture.mjs. Its product files are base's: git diff --stat 1e629c892 1f6db1589 lists only this packet, capture.mjs and the two tests.
  2. 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. interfaceVersion stays 1 (DESIGN.md "interfaceVersion stays 1").
  • New packages/plugins/harness/pi/compactions.mjs: base's scanPi, readRange, digest, STREAM, TAIL, the chunk size, PI_VERSION and claudeHistory, unchanged in behaviour, plus the export. scanPi is no longer exported and takes no defaults: its one caller passes all four arguments.
  • pi/index.mjs re-exports it. claude-code/index.mjs answers harness-unsupported with version null.
  • packages/seat/src/compactions.mjs: keeps the ledger. readLedger sets unsupported on r.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: the compactions closure takes the loaded module and calls the export directly, with the N1 comment on why it skips call(). Both call sites pass harness.
  • packages/plugins/README.md: the Harness section gains the compactions bullet.

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 compactionCount and 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).
  • packages/plugins/tests/harness-compactions.test.mjs: CASES plain, budget (100 bytes), cap (1 stream of 2), shrank and header against pi; pi's first with and without Claude history; claude-code; and a module re-exporting every pi export but compactions, refused missing-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's scanPi per case and compares the answer under base's reason order (:301 at base) and PI_VERSION. It prints base's compactionCount per 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 collected without 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 first test and the claude-code test fail with a TypeError (compactions isn'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:78 privateDirs, 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 printed all 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 with TypeError: pi.compactions is not a function or claude.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.