Files
jason.woltje 6bad02612a lead: commit dewey's untracked evidence (721 files: queue-124-review queue-143 queue-149 queue-165-review queue-170 queue-175 queue-177 queue-184 queue-191)
Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
2026-11-02 15:05:14 -06:00

4.9 KiB

Dewey review, row 124 (#1618), token accounting per run. Verdict: CHANGES.

Base 9098c33f7. Candidate manifest b7139ea3909c49449436daee2eb45f542bca0ffce2515870e1f49ba27e918016 (37 files), applied to a detached worktree; sha256sum -c passed before and after the runs. Packet: agents/dewey/work/queue-124-review/ (run.sh, probes.mjs, run.log, single/, mutants/).

Runs, in Sage's slot (sage-0723), 2026-10-18T15:39:29Z to 15:40:18Z:

  • The 20 candidate and touched test files, one node --test each (launcher with TMPDIR outside /tmp): all rc=0, 150 tests, 150 pass, 0 fail, 0 skipped. Per-file counts are in run.log.
  • probes.mjs, on scratch temp dirs only: rc=0, output in probes.log.
  • One mutant, d1: SURVIVED (see (b)). The script restored transcript/index.mjs and checked its hash against the manifest (d09ae19db3eb...).

Changes

(a) usage_records has no timestamp guard. packages/bus/src/store.mjs:55 timedTables lists every other table with an at column. Row 141 added instance_names when it added that table. usage_records is not in the list, and its DDL in 3g-3h.sql has no CHECK on at. #verifyTimes therefore never sees it: not at open, not at migration, not at commit. Probe p1: a non-canonical at (2026-10-04T00:00:00Z) is refused in events (invalid-timestamp, the control), but usage_records accepts it. The row is stored, and the store reopens with it in place. Needed: add usage_records to timedTables, a test that a non-canonical at refuses invalid-timestamp, and a mutant that removes the entry.

(b) The brief's claude-code fixtures are missing. The acceptance line asks for "fixture transcripts for both harnesses, including a cut line, a symlink and an oversized file". In packages/plugins/tests/transcript.test.mjs only the dedup test (line 22) loops over both harnesses. The guard table (lines 29-43) and the symlink-root test (line 44) use fixture(t), which defaults to pi. The claude-code walk has its own code path: at depth 0 it opens each project directory with openSync(at(fd, entry.name), DIR) (transcript/index.mjs:90). No test puts a symlink there. Probe p2 shows the code itself handles claude-code correctly: a symlinked project dir and a symlinked session file give transcript-path, a cut line gives transcript-parse, and an oversized file gives transcript-size. The gap is that no test checks any of this. Mutant d1 drops O_NOFOLLOW from that open (constants.O_RDONLY | constants.O_DIRECTORY). transcript.test.mjs still passes 24/24. From reading the code, d1 is not equivalent: readdir reports the symlink as a non-file, so the open follows it, and the session files under the target are anchored and read normally. Needed: run the guard table over both harnesses (or add claude-code cases for the cut line, a symlinked project directory, a symlinked session file and the oversized file), with the project-directory symlink case killing d1.

Verified

  • MIGRATION.md's claim that nothing earlier changes. usage-migration.test.mjs compares every prior column, row and sequence counter on a copy built from the pinned 3g DDL. The schema digest covers all of sqlite_master, so views and triggers are pinned too. 3g-3h.sql only creates usage_records and its three triggers.
  • No transcript text is stored. The reader returns counters and ids only. Ids are capped at 512 chars, unknown codes go through a fixed whitelist (anything else becomes source-unknown), and the begin cursor holds the entries map (keys are relative file name and message id).
  • Replays are idempotent: UNIQUE(business,run,turn,source,phase), and perform() returns early when a row exists.
  • The webui route is read-only. serve.mjs adds usage as GET only (405 otherwise), returns 400 on any query string, and checks the shape (502 on a malformed value). bus.js tokenUsage() escapes every value through txt().
  • Rocko's evidence matches their logs: 914 tests, land-work 86, config 24, 64/64 mutants killed.

Notes (not blocking)

  1. A turn skipped because the state read failed (unread) still calls usage.end. It is recorded unknown (baseline-unknown) though no harness ran. That is the safe direction, but the bus README says unknown means a harness turn whose usage could not be read.
  2. Once a thread's transcript passes 8 MiB in total, or holds any line over 1 MiB, every later turn in it is unknown. That is fail-closed and correct, but long threads will lose accounting for good. Worth a line in the README or a follow-up.
  3. Each begin row stores the full entries map as its cursor. Storage grows with the square of thread length.
  4. With two sources enabled for one harness, both report the same turn and totals count it twice ("Totals sum reported records"). Only transcript ships now; worth a note before a second source.
  5. Doc-only, follow-up: MIGRATION.md calls Mos "his". It's a packet doc that no test reads.

Landing the webui route and public/ changes still needs Mos's decision 123 go after approval. Activation (offline 3g→3h migration and re-pin) is Mos's separate downtime window.