From 71b13e7888bab42aa7b7dcbf75f207ce90c3fc73 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 4 Aug 2026 17:03:44 -0700 Subject: [PATCH] test(engine): memoize corpus scans in lifecycle-column gate tests Both gate-admitted census tests re-scanned the whole ~1200-file corpus redundantly: legacy-column-literal-census ran census() twice in full (~900ms each) and no-legacy-move-targets re-read the entire tree a second time in its anti-vacuity case. Memoize the census result and share a comment-stripped read cache so each tree is scanned once per run. Fusion-Task-Id: none --- .../legacy-column-literal-census.test.ts | 14 ++++++- .../__tests__/no-legacy-move-targets.test.ts | 37 ++++++++++++------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/packages/engine/src/__tests__/legacy-column-literal-census.test.ts b/packages/engine/src/__tests__/legacy-column-literal-census.test.ts index d56f0c9395..ef03107881 100644 --- a/packages/engine/src/__tests__/legacy-column-literal-census.test.ts +++ b/packages/engine/src/__tests__/legacy-column-literal-census.test.ts @@ -196,7 +196,18 @@ function productionSources(): string[] { .filter((f) => !f.includes("__tests__") && !/\.(test|spec)\.tsx?$/.test(f)); } +/* +FNXC:LegacyColumnCensus 2026-08-05-00:02 (gate cost): +MEMOISED, for the same reason its sibling no-legacy-move-targets.test.ts memoises countByFile(). +census() re-read and re-scanned the whole ~1200-file corpus, and two cases each call it in full +("never grows" and "reports when the count has fallen") — so the heaviest scan in this suite ran +twice for one tree, ~900ms each, buying nothing because the tree cannot change mid-run. A guard that +is gratuitously slow is a guard someone eventually moves back out of the gate. +*/ +let censusCache: { total: number; byFile: Map } | undefined; + function census(): { total: number; byFile: Map } { + if (censusCache) return censusCache; const byFile = new Map(); let total = 0; for (const file of productionSources()) { @@ -221,7 +232,8 @@ function census(): { total: number; byFile: Map } { total += n; } } - return { total, byFile }; + censusCache = { total, byFile }; + return censusCache; } describe("legacy column-literal census — the unconverted lifecycle surface", () => { diff --git a/packages/engine/src/__tests__/no-legacy-move-targets.test.ts b/packages/engine/src/__tests__/no-legacy-move-targets.test.ts index 7f76ef7e4d..2b71405520 100644 --- a/packages/engine/src/__tests__/no-legacy-move-targets.test.ts +++ b/packages/engine/src/__tests__/no-legacy-move-targets.test.ts @@ -72,6 +72,27 @@ function stripComments(source: string): string { .replace(/\/\/[^\n]*/g, ""); } +/* +FNXC:WorkflowResolvedColumns 2026-08-05-00:02 (gate cost): +SHARED comment-stripped read cache. countByFile() already memoised its scan, but the anti-vacuity +case ("scans a real corpus") re-read the ENTIRE corpus a second time with its own readFileSync loop +to find moveTask( callers — measured ~270ms of a second full pass over the same unchanging tree. Both +consumers want the same comment-stripped source, so read+strip each file once and share it. +*/ +const strippedSourceCache = new Map(); +function strippedSource(file: string): string { + const cached = strippedSourceCache.get(file); + if (cached !== undefined) return cached; + let stripped: string; + try { + stripped = stripComments(readFileSync(resolve(REPO_ROOT, file), "utf8")); + } catch { + stripped = ""; + } + strippedSourceCache.set(file, stripped); + return stripped; +} + /* FNXC:WorkflowResolvedColumns 2026-07-31-23:59: MEMOISED for gate admission. Each case called this independently and every call re-read the whole @@ -87,13 +108,7 @@ function countByFile(): Record { if (countsCache) return countsCache; const counts: Record = {}; for (const file of sourceFiles()) { - let source: string; - try { - source = readFileSync(resolve(REPO_ROOT, file), "utf8"); - } catch { - continue; - } - const hits = stripComments(source).match(MOVE_TARGET); + const hits = strippedSource(file).match(MOVE_TARGET); if (hits && hits.length > 0) counts[file] = hits.length; } countsCache = counts; @@ -115,13 +130,7 @@ describe("moveTask targets resolve the board's own lane", () => { const files = sourceFiles(); expect(files.length).toBeGreaterThan(200); - const callers = files.filter((file) => { - try { - return /moveTask\s*\(/.test(stripComments(readFileSync(resolve(REPO_ROOT, file), "utf8"))); - } catch { - return false; - } - }); + const callers = files.filter((file) => /moveTask\s*\(/.test(strippedSource(file))); expect(callers.length).toBeGreaterThan(5); expect(callers).toContain("packages/engine/src/self-healing.ts"); });