Files
fusion/scripts/__tests__/engine-vitest-gate-policy.test.mjs
gsxdsm b01a2026a0 test(ci): record the third PG gate canary — the policy ledger has been red since #2759 (#3044)
## The PG gate ledger has been red since #2759

```
AssertionError: the PG gate must stay a narrow, explicit canary list
+   'src/__tests__/postgres/sync-workflow-ir-is-always-default.pg.test.ts'
```

#2759 (`ae4ff9c111`) added that test **and** its entry in
`packages/core`'s `test:pg-gate` script in one commit, without updating
the ledger this assertion compares against.

## Recorded, not approved — and that distinction is why I touched it
carefully

My first instinct was to leave it: ratifying someone else's gate
admission is exactly the "make it green" move I have refused elsewhere
in this sweep.

What changed my mind is that **a red policy test protects nothing**.
While it fails, the *next* gate admission is invisible too — which is
the opposite of what a narrow-canary ledger exists for. The admission is
already live; the gate runs three tests today whatever this file says.
Restoring the ledger re-arms the guard for everything after it.

And the admission does carry the evidence of value AGENTS.md requires,
so recording it is not a rubber stamp. The test pins that
`resolveTaskWorkflowIrSync` returns the **default** IR for every task in
production, which means a guard written as:

```ts
resolveLifecycleColumns(store.resolveTaskWorkflowIrSync(id))?.hold
```

reads as converted, counts as census progress, and is **silently wrong
for every custom workflow** — the non-optional return type hides the
substitution from every caller. Ten call sites depend on that fact
today. Catching that class at the gate is cheaper than catching it in
review; I would have argued for admission had I been asked.

**If the gate's owner disagrees with a third canary, the fix is to
remove it from `test:pg-gate` and shorten this ledger again — not to
leave the assertion red.** I have said so in the code comment too, so
the next reader gets the choice rather than the fait accompli.

## The guard is bidirectional — verified against the gate, not the
ledger

A ledger synced to whatever the gate currently says would be worthless,
so I mutated the **gate script**:

```
removed a canary from packages/core test:pg-gate  →  ℹ pass 3   ℹ fail 1
restored                                          →  ℹ pass 4   ℹ fail 0
```

So it still catches silent gate **shrinkage** as well as growth — a
canary quietly dropping out of the merge gate would fail here.
`package.json` is restored; the diff is the test file only.

## One thing worth passing on

That test names a *class*, not a single bug: ten call sites resolve
lanes through the sync resolver and read as converted while always
getting the default IR. I checked where they live — **all in
`packages/core` and `packages/engine`, none in `packages/cli` or
`plugins`** — so my own territory is clear of it, but whoever owns those
two packages may want the list.

## Verification (measured)

- this suite — **4 passed / 0 failed** (was 1 failed)
- `eslint` — clean

Fourth of the red `scripts/__tests__` suites. Test-only. No changeset.
2026-07-31 02:11:31 -07:00

175 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from "node:test";
import assert from "node:assert/strict";
import { readdirSync, readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "../..");
function read(relativePath) {
return readFileSync(path.join(repoRoot, relativePath), "utf8");
}
function readJson(relativePath) {
return JSON.parse(read(relativePath));
}
test("engine-core gate keeps a Node 24/macOS-safe Vitest pool without changing broad engine lanes", () => {
const config = read("packages/engine/vitest.config.ts");
const projectsIndex = config.indexOf("projects:");
const rootTestConfig = projectsIndex === -1 ? config : config.slice(0, projectsIndex);
const engineCoreBlock = config.match(/name:\s*"engine-core"[\s\S]*?include:\s*\[/)?.[0] ?? "";
const engineDefaultBlock = config.match(/name:\s*"engine-default"[\s\S]*?include:\s*\[/)?.[0] ?? "";
assert.match(
engineCoreBlock,
/pool:\s*"forks"/,
"engine-core must use fork workers; thread workers abort with Node 24/macOS libuv kqueue",
);
assert.doesNotMatch(
rootTestConfig,
/pool:\s*"forks"/,
"fork workers must not be configured at root scope because that slows the broad engine-default lane",
);
assert.match(
rootTestConfig,
/pool:\s*"threads"/,
"root engine config must explicitly keep broad lanes on threads because Vitest 4 defaults to forks",
);
assert.doesNotMatch(
engineDefaultBlock,
/pool:\s*"forks"/,
"engine-default must keep inheriting Vitest's default thread pool for broad src/**/*.test.ts runs",
);
assert.doesNotMatch(
config,
/NODE_NO_WARNINGS/,
"the gate must not hide unmanaged-fd warnings by suppressing Node warnings",
);
assert.match(config, /maxWorkers,/, "worker budgeting must still flow through computeMaxWorkers");
assert.match(config, /fileParallelism:\s*true/, "engine-core should preserve file-level parallelism");
});
test("engine-core remains an explicit allow-listed merge gate", () => {
const config = read("packages/engine/vitest.config.ts");
const engineCoreBlock = config.match(/name:\s*"engine-core"[\s\S]*?exclude:\s*\[/)?.[0] ?? "";
const includeEntries = [...engineCoreBlock.matchAll(/"src\/__tests__\/[^"\n]+\.test\.ts"/g)].map((match) => match[0]);
assert.equal(new Set(includeEntries).size, includeEntries.length, "engine-core allow-list must not contain duplicates");
/*
FNXC:MergeGatePerformance 2026-07-22-15:36:
FN-8497 exercises this policy after profiling the complete gate. The current
curated engine lane has 16 explicit files after the documented SQLite and
obsolete graph-runner retirements; guard its real floor instead of the stale
18-file count, while still requiring the replacement graph executor seam.
*/
assert.ok(includeEntries.length >= 16, "engine-core allow-list must not be gutted to avoid the runtime abort");
assert.ok(
includeEntries.includes('"src/__tests__/workflow-graph-executor-parity.test.ts"'),
"engine-core must keep workflow graph executor gate coverage",
);
assert.ok(
includeEntries.includes('"src/__tests__/heartbeat-monitor.test.ts"'),
"engine-core must keep heartbeat monitor gate coverage while avoiding FN-779 scope changes",
);
});
test("root and package gate scripts still propagate real Vitest failures", () => {
const root = readJson("package.json");
const engine = readJson("packages/engine/package.json");
assert.equal(
engine.scripts?.["test:core"],
"vitest run --silent=passed-only --reporter=dot --project=engine-core",
);
assert.match(root.scripts?.["test:gate"] ?? "", /pnpm --filter @fusion\/engine test:core/);
assert.match(root.scripts?.["test:gate"] ?? "", /wait \$engine_pid \|\| status=1/);
assert.match(root.scripts?.["test:gate"] ?? "", /wait \$pg_pid \|\| status=1/);
assert.doesNotMatch(root.scripts?.["test:gate"] ?? "", /NODE_NO_WARNINGS/);
assert.doesNotMatch(root.scripts?.["test"] ?? "", /NODE_NO_WARNINGS/);
});
/*
FNXC:MergeGatePerformance 2026-07-22-15:35:
FN-8497 keeps only lifecycle and transactional-handoff PostgreSQL canaries in
`test:pg-gate`: 23 independent PG files each create/copy a real database, so
putting the whole integration inventory on every PR made the sequential merge
gate take 26–45 seconds. The other PG files must remain ordinary enabled core
tests; this structural guard prevents a future package-script/config change
from silently converting the speed fix into lost coverage.
*/
test("pg gate canaries remain a subset of the enabled non-blocking PG suite", () => {
const core = readJson("packages/core/package.json");
const coreConfig = read("packages/core/vitest.config.ts");
const pgDirectory = path.join(repoRoot, "packages/core/src/__tests__/postgres");
const discoveredPgFiles = new Set(
readdirSync(pgDirectory)
.filter((file) => file.endsWith(".pg.test.ts"))
.map((file) => `src/__tests__/postgres/${file}`),
);
const gateMembers = core.scripts?.["test:pg-gate"]?.match(/src\/__tests__\/postgres\/[^ ]+\.pg\.test\.ts/g) ?? [];
/*
FNXC:TestInfrastructure 2026-07-31-20:30:
The third canary is RECORDED here, not approved here — and the distinction is the point.
#2759 (`ae4ff9c111`) added `sync-workflow-ir-is-always-default.pg.test.ts` and its gate entry in one
commit without updating this list, so the assertion has been red on `main` since. A red policy test
protects nothing: while it fails, the NEXT gate admission is invisible too, which is the opposite of
what a narrow-canary ledger is for. Restoring it re-arms that protection.
The admission carries the evidence of value AGENTS.md requires, which is why recording it is not a
rubber stamp. It pins that `resolveTaskWorkflowIrSync` returns the DEFAULT IR for every task in
production — so a guard written as `resolveLifecycleColumns(store.resolveTaskWorkflowIrSync(id))?.hold`
reads as converted, counts as census progress, and is silently wrong for every custom workflow
because the non-optional return type hides the substitution. Ten call sites depend on that fact
today. A whole class of inert conversions is cheaper to catch at the gate than in review.
If the gate's owner disagrees with a third canary, the fix is to remove it from
`packages/core`'s `test:pg-gate` script and shorten this list again — not to leave the ledger red.
*/
const expectedCanaries = [
"src/__tests__/postgres/handoff-to-review-atomicity.pg.test.ts",
"src/__tests__/postgres/task-lifecycle-e2e.pg.test.ts",
"src/__tests__/postgres/sync-workflow-ir-is-always-default.pg.test.ts",
];
const formerGateMembers = [
...expectedCanaries,
"src/__tests__/postgres/store-list.pg.test.ts",
"src/__tests__/postgres/soft-delete-resurrection-FN-5233.pg.test.ts",
"src/__tests__/postgres/agent-logs-and-monitor.pg.test.ts",
"src/__tests__/postgres/todo-store.pg.test.ts",
"src/__tests__/postgres/workflow-definitions.pg.test.ts",
"src/__tests__/postgres/message-store.pg.test.ts",
"src/__tests__/postgres/insight-store.pg.test.ts",
"src/__tests__/postgres/insight-run-execution.pg.test.ts",
"src/__tests__/postgres/research-store.pg.test.ts",
"src/__tests__/postgres/mission-store.pg.test.ts",
"src/__tests__/postgres/goal-store.pg.test.ts",
"src/__tests__/postgres/artifacts-documents-evals.pg.test.ts",
"src/__tests__/postgres/command-center-analytics.pg.test.ts",
"src/__tests__/postgres/command-center-remaining-analytics.pg.test.ts",
"src/__tests__/postgres/research-execution.pg.test.ts",
"src/__tests__/postgres/async-store-events.pg.test.ts",
"src/__tests__/postgres/signal-ingestion.pg.test.ts",
"src/__tests__/postgres/mission-autopilot.pg.test.ts",
"src/__tests__/postgres/workflow-create.pg.test.ts",
"src/__tests__/postgres/monitor-trait-storm-guard.pg.test.ts",
"src/__tests__/postgres/agent-wake-getagent.pg.test.ts",
];
assert.deepEqual(gateMembers, expectedCanaries, "the PG gate must stay a narrow, explicit canary list");
assert.match(core.scripts?.test ?? "", /^vitest run\b/, "the non-blocking core lane must execute Vitest");
assert.doesNotMatch(core.scripts?.test ?? "", /\s(?:--exclude|--include)\b/, "the non-blocking core lane must not narrow discovery");
assert.match(coreConfig, /include:\s*\["src\/\*\*\/\*.test\.ts"\]/, "the default core config must discover PG tests");
assert.match(coreConfig, /const quarantinedCoreTests: string\[\] = \[\]/, "no PG test may be hidden by quarantine exclusion");
for (const file of formerGateMembers) {
assert.ok(discoveredPgFiles.has(file), `former PG gate member must remain discovered: ${file}`);
}
const removedFromGate = formerGateMembers.filter((file) => !gateMembers.includes(file));
assert.equal(removedFromGate.length, 21, "all non-canary former gate members must remain in the non-blocking lane");
assert.ok(removedFromGate.every((file) => discoveredPgFiles.has(file)), "removed PG members must remain discoverable");
});