FN-8497: reduce merge gate wall time
Keep merge-gate coverage focused while running its independent test lanes concurrently. - Limit PostgreSQL gate coverage to lifecycle and transactional-handoff canaries. - Run engine and PostgreSQL gate lanes concurrently while preserving failure propagation. - Enforce canary coverage policy and refresh velocity documentation and history. Files changed: docs/test-velocity-baseline.md | 16 +-- docs/testing.md | 5 +- package.json | 2 +- packages/core/package.json | 2 +- .../__tests__/engine-vitest-gate-policy.test.mjs | 79 +++++++++++++- scripts/test-velocity-history.json | 115 +++++++++++++++++++++ 6 files changed, 204 insertions(+), 15 deletions(-) Fusion-Task-Id: FN-8497 Fusion-Task-Lineage: 8777959c-6d8c-4686-a975-d91af2c169ea Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
@@ -58,10 +58,17 @@ test("engine-core remains an explicit allow-listed merge gate", () => {
|
||||
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");
|
||||
assert.ok(includeEntries.length >= 18, "engine-core allow-list must not be gutted to avoid the runtime abort");
|
||||
/*
|
||||
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-task-runner.test.ts"'),
|
||||
"engine-core must keep workflow graph gate coverage",
|
||||
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"'),
|
||||
@@ -78,6 +85,70 @@ test("root and package gate scripts still propagate real Vitest failures", () =>
|
||||
"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) ?? [];
|
||||
const expectedCanaries = [
|
||||
"src/__tests__/postgres/handoff-to-review-atomicity.pg.test.ts",
|
||||
"src/__tests__/postgres/task-lifecycle-e2e.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");
|
||||
});
|
||||
|
||||
@@ -1930,6 +1930,121 @@
|
||||
"Timing snapshot is 25 days old; verify slowest-file attribution before treating the table as the current culprit.",
|
||||
"9 of the listed slowest files no longer exist at the recorded paths: `packages/dashboard/src/__tests__/insights-routes.test.ts`, `packages/engine/src/runtimes/__tests__/in-process-runtime.test.ts`, `packages/dashboard/src/__tests__/workflow-routes.test.ts`, `packages/core/src/__tests__/db.test.ts`, `packages/core/src/__tests__/mission-store.test.ts`, …. Refresh scripts/test-timings.json before choosing a slow-test rewrite."
|
||||
]
|
||||
},
|
||||
{
|
||||
"capturedAt": "2026-07-22T22:40:53.357Z",
|
||||
"gateMs": 9144,
|
||||
"bootSmokeMs": 18454,
|
||||
"testMs": 14943,
|
||||
"quarantineCount": 2,
|
||||
"slowestTop20": [
|
||||
{
|
||||
"file": "packages/dashboard/src/__tests__/insights-routes.test.ts",
|
||||
"ms": 26500,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/engine/src/runtimes/__tests__/in-process-runtime.test.ts",
|
||||
"ms": 24700,
|
||||
"package": "@fusion/engine"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/src/__tests__/workflow-routes.test.ts",
|
||||
"ms": 22000,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/core/src/__tests__/db.test.ts",
|
||||
"ms": 21200,
|
||||
"package": "@fusion/core"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/GitManagerModal.test.tsx",
|
||||
"ms": 16900,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/core/src/__tests__/mission-store.test.ts",
|
||||
"ms": 16000,
|
||||
"package": "@fusion/core"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/src/__tests__/extension.test.ts",
|
||||
"ms": 15700,
|
||||
"package": "@runfusion/fusion"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/AgentPromptsManager.test.tsx",
|
||||
"ms": 14800,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/App.test.tsx",
|
||||
"ms": 14600,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx",
|
||||
"ms": 14100,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx",
|
||||
"ms": 13700,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/src/__tests__/routes-auth.test.ts",
|
||||
"ms": 13600,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/core/src/__tests__/agent-store.test.ts",
|
||||
"ms": 13400,
|
||||
"package": "@fusion/core"
|
||||
},
|
||||
{
|
||||
"file": "packages/engine/src/__tests__/workspace-merger-idempotency.test.ts",
|
||||
"ms": 12700,
|
||||
"package": "@fusion/engine"
|
||||
},
|
||||
{
|
||||
"file": "packages/engine/src/__tests__/self-healing-workspace.test.ts",
|
||||
"ms": 11800,
|
||||
"package": "@fusion/engine"
|
||||
},
|
||||
{
|
||||
"file": "packages/engine/src/__tests__/pr-response-run.test.ts",
|
||||
"ms": 11600,
|
||||
"package": "@fusion/engine"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/ListView.test.tsx",
|
||||
"ms": 11300,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "plugins/fusion-plugin-compound-engineering/src/__tests__/sync.test.ts",
|
||||
"ms": 11000,
|
||||
"package": "@fusion-plugin-examples/compound-engineering"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/AgentDetailView.settings.test.tsx",
|
||||
"ms": 10700,
|
||||
"package": "@fusion/dashboard"
|
||||
},
|
||||
{
|
||||
"file": "packages/dashboard/app/components/__tests__/SecretsView.test.tsx",
|
||||
"ms": 10700,
|
||||
"package": "@fusion/dashboard"
|
||||
}
|
||||
],
|
||||
"measurementFailures": [],
|
||||
"timingSnapshotCapturedAt": "2026-06-27T05:41:42.568Z",
|
||||
"timingNotes": [
|
||||
"Timing snapshot is 25 days old; verify slowest-file attribution before treating the table as the current culprit.",
|
||||
"9 of the listed slowest files no longer exist at the recorded paths: `packages/dashboard/src/__tests__/insights-routes.test.ts`, `packages/engine/src/runtimes/__tests__/in-process-runtime.test.ts`, `packages/dashboard/src/__tests__/workflow-routes.test.ts`, `packages/core/src/__tests__/db.test.ts`, `packages/core/src/__tests__/mission-store.test.ts`, …. Refresh scripts/test-timings.json before choosing a slow-test rewrite."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user