feat(test): the serial tree-mutating shard dissolves — TREE_MUTATING is empty

Zero mutators remain (all eight render into out-dirs now), so the four
ratchet READERS (parity caps, size budgets, carve parity/ordering) get
a quiet tree by construction in any shard and rejoin the parallel
phase. The ~35-40s serial tail on every full-suite run is gone. The
mechanism stays: a future test that genuinely must write shared
artifacts in place earns an entry with a reason and is serialized
again; the census pin still fails on renamed keys.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-29 05:33:49 +00:00
co-authored by Claude Fable 5
parent 9887f4c769
commit dadb0a4cb1
+14 -24
View File
@@ -367,33 +367,23 @@ export const WORKER_HOSTILE: Record<string, string> = {
/** /**
* TREE-SERIAL files: run in ONE serial shard AFTER the parallel shards. * TREE-SERIAL files: run in ONE serial shard AFTER the parallel shards.
* Two kinds live here: * EMPTY since the 2026-08 dissolution — kept as a mechanism, not a museum:
* - MUTATORS: tests that regenerate shared repo artifacts in place (skill * a test that must regenerate shared repo artifacts IN PLACE (and cannot
* SKILL.md files or the .agents/ host outputs). A shard reading those * render into an out-dir instead) earns an entry here with a reason, and
* files concurrently sees a moving target — this family produced an * the runner will serialize it again.
* exactly-doubled catalog estimate, golden-file drift, and a spec-sync *
* mismatch before serialization. * How it emptied: gen-skill-docs gained a main() guard (imports stopped
* - RATCHET READERS: tests that MEASURE the shared tree (parity caps, * regenerating 71 files at load) and --out-dir grew to every host, so all
* size budgets). Measuring while any concurrent test regenerates is * eight mutators now render into mkdtemps — the live tree is never written
* undefined behavior — two runs failed with byte-identical inflated * by the suite (pinned by gen-skill-docs-import-purity + each migrated
* skeletons while the tree was clean before and after, so rather than * file's own porcelain/mtime assertions). With zero mutators, the four
* hunt every present and future mutator, the measurers get a quiet * ratchet READERS (parity caps, size budgets, carve parity/ordering) get a
* tree by construction. * quiet tree by construction in any shard, so they rejoined the parallel
* Order within the serial shard is alphabetical (the file census is sorted * phase — the ~35-40s serial tail on every full-suite run is gone.
* and the serial shard is a filter over it) — safety does NOT depend on
* mutators-before-readers ordering; it rests on every mutator restoring
* default state itself. (CI's --shards matrix is unaffected: each CI shard
* has its own checkout.)
* Keys are pinned against the live file census by test-free-shards.test.ts — * Keys are pinned against the live file census by test-free-shards.test.ts —
* a renamed file fails the suite instead of silently dropping serialization. * a renamed file fails the suite instead of silently dropping serialization.
*/ */
export const TREE_MUTATING: Record<string, string> = { export const TREE_MUTATING: Record<string, string> = {};
// Ratchet readers (measure the tree; need it quiet):
'test/parity-suite.test.ts': 'RATCHET READER — parity caps measure live SKILL.md/section bytes',
'test/skill-size-budget.test.ts': 'RATCHET READER — per-skill and corpus size budgets measure the live tree',
'test/carve-guard-completeness.test.ts': 'RATCHET READER — registry-vs-disk parity reads live sections/manifest.json files',
'test/carve-section-ordering.test.ts': 'RATCHET READER — checkOrdering(ROOT) reads live skeletons and sections',
};
export function normalizeRelativePath(filePath: string): string { export function normalizeRelativePath(filePath: string): string {
return filePath.replace(/\\/g, '/'); return filePath.replace(/\\/g, '/');