diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 23cfec5795..f85a568161 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -85,3 +85,17 @@ jobs: - name: Test (deterministic shard) run: pnpm test:ci:shard --shard ${{ matrix.shard }} --total 4 + + # U1 (R4): each shard emits per-file vitest JSON timing reporter output + # under .timings/. Upload as an artifact so the timing snapshot can be + # refreshed locally/from the default branch via + # `node scripts/ci-test-shard.mjs --write-timings`. We do NOT commit the + # snapshot from PR branches — refresh is manual/scheduled only. + - name: Upload per-shard test timings + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-timings-shard-${{ matrix.shard }} + path: .timings/timings-*.json + if-no-files-found: ignore + retention-days: 14 diff --git a/.gitignore b/.gitignore index 7362b6f83b..e04843033e 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,7 @@ fusion.db-shm # Capacitor mobile platform directories (generated by `cap add`) packages/dashboard/ios/ packages/dashboard/android/ + +# Per-shard vitest JSON timing reporter outputs (raw; merged into +# scripts/test-timings.json via `ci-test-shard.mjs --write-timings`). +.timings/ diff --git a/docs/test-speed-audit-FN-5048.md b/docs/test-speed-audit-FN-5048.md index eb4b75c678..24f99daaf8 100644 --- a/docs/test-speed-audit-FN-5048.md +++ b/docs/test-speed-audit-FN-5048.md @@ -1,5 +1,7 @@ # FN-5048 Test-Speed Audit +> **Refreshed baseline (2026-06-03):** see `docs/test-speed-baseline-2026-06-03.md` for the U1 machine-readable per-file timing snapshot, refreshed top-10 offenders, and the cold-start/transform-cost probe feeding the U8 vitest-4 gate. + ## Scope and method - Related baseline context: - `docs/test-audit-report.md` (prior workspace test audit baseline) diff --git a/docs/test-speed-baseline-2026-06-03.md b/docs/test-speed-baseline-2026-06-03.md new file mode 100644 index 0000000000..f3730d147a --- /dev/null +++ b/docs/test-speed-baseline-2026-06-03.md @@ -0,0 +1,149 @@ +# Test-Speed Baseline — 2026-06-03 (U1 refresh) + +Successor to `docs/test-speed-audit-FN-5048.md`. This baseline is captured from the +machine-readable per-file timing telemetry added in U1 of +`docs/plans/2026-06-03-001-perf-test-suite-speedup-plan.md`. It feeds the U6 +(duration-based sharding), U7 (slow-test triage), and U8 (vitest 4.x gate) +decisions. + +## Method + +- Per-file durations come from vitest's `--reporter=json` output + (`endTime − startTime` per test file), merged into `scripts/test-timings.json` + via `node scripts/ci-test-shard.mjs --write-timings`. +- Cold-start overhead comes from `node scripts/ci-test-shard.mjs --cold-start-probe `, + which runs one cheap test file and reports `wallClock − sum(testDurations)`. +- Worker caps were left at defaults (no `FUSION_TEST_*` / `VITEST_MAX_WORKERS` + overrides), per FN-5048. +- Capture invocations (one per package/lane): + - `pnpm --filter @fusion/core exec vitest run --silent=passed-only --reporter=dot --reporter=json --outputFile.json=...` + - `pnpm --filter @fusion/engine exec vitest run ... --project=engine-default --project=engine-reliability` + - `pnpm --filter @runfusion/fusion exec vitest run ...` + - dashboard curated lanes via `run-vitest-with-heap.mjs` for + `dashboard-api-quality` and `dashboard-app-quality-components-a` + (the dashboard `test` script is a 14-lane chain; two representative lanes + were captured for the snapshot — a full lane sweep is a follow-up). + +Note: per-file durations are summed wall-clock per file; because files run in +parallel, the **sum across files exceeds the run wall-clock**. The per-file +numbers are correct for *relative ranking* (which file is heaviest), which is +what U6/U7 consume. The "run wall-clock" column below is the real elapsed time. + +## Per-package run totals (wall-clock, this capture) + +| Package | Run wall-clock | Test files | Σ per-file (parallel) | Notes | +|---|---:|---:|---:|---| +| `@fusion/core` | **41.1s** | 264 | 185.2s | default project | +| `@fusion/engine` | **178.7s** | 521 | 273.3s | engine-default + engine-reliability | +| `@runfusion/fusion` (cli) | **48.9s** | 92 | 32.0s | default project | +| `@fusion/dashboard` (api-quality lane) | 46.7s | 58 | — | one curated lane | +| `@fusion/dashboard` (app components-a lane) | 27.6s | 44 | — | one curated lane | + +Snapshot (`scripts/test-timings.json`) `capturedAt`: `2026-06-03T23:45:49Z`, +covering 4 packages. + +For context, the prior FN-5048 baseline measured core ~26s, engine ~93s, +cli ~14s, dashboard ~360s (full multi-project). These were captured on a +different machine/load; treat the two baselines as independent snapshots, not a +trend line. Engine and core are larger here because the executed test inventory +has grown (engine now 521 files across default+reliability). + +## Top-10 slowest files per major package + +(Σ per-file wall-clock, bucketed to 100ms in the snapshot.) + +### @fusion/core +| File | Σ duration | +|---|---:| +| src/__tests__/agent-store.test.ts | 11.6s | +| src/__tests__/mission-store.test.ts | 10.7s | +| src/__tests__/db.test.ts | 10.1s | +| src/__tests__/task-documents.test.ts | 8.3s | +| src/__tests__/run-audit.test.ts | 6.9s | +| src/__tests__/store-merge-queue.test.ts | 5.2s | +| src/__tests__/mission-integration.test.ts | 4.8s | +| src/__tests__/run-audit.integration.test.ts | 4.6s | +| src/__tests__/plugin-loader.test.ts | 4.5s | +| src/__tests__/mission-factory-parity.integration.test.ts | 4.2s | + +### @fusion/engine +| File | Σ duration | +|---|---:| +| src/__tests__/reliability-interactions/shared-branch-group-lifecycle.test.ts | 13.9s | +| src/__tests__/reliability-interactions/branch-group-automerge-precedence.test.ts | 9.0s | +| src/__tests__/merger-ai.test.ts | 8.7s | +| src/__tests__/reliability-interactions/branch-group-merge-routing.test.ts | 8.4s | +| src/__tests__/reliability-interactions/branch-group-promotion-gate.test.ts | 8.4s | +| src/runtimes/__tests__/in-process-runtime.test.ts | 7.8s | +| src/__tests__/reliability-interactions/branch-group-promotion.test.ts | 6.1s | +| src/__tests__/reliability-interactions/integration-worktree-state.test.ts | 4.9s | +| src/__tests__/self-healing-already-merged.real-git.test.ts | 4.9s | +| src/__tests__/branch-conflicts-recovery.test.ts | 4.5s | + +### @runfusion/fusion (cli) +| File | Σ duration | +|---|---:| +| src/__tests__/extension.test.ts | 7.0s | +| src/commands/__tests__/init.test.ts | 3.4s | +| src/__tests__/bin.test.ts | 3.2s | +| src/__tests__/extension-task-tools.test.ts | 1.7s | +| src/commands/dashboard-tui/__tests__/app.test.tsx | 1.6s | +| src/__tests__/vitest-workspace-resolution.test.ts | 1.4s | +| src/commands/__tests__/chat.test.ts | 1.3s | +| src/__tests__/research-extension-tools.test.ts | 1.1s | +| src/__tests__/extension-github-tracking.test.ts | 0.5s | +| src/commands/__tests__/dashboard.test.ts | 0.5s | + +### @fusion/dashboard (captured curated lanes) +| File | Σ duration | +|---|---:| +| src/__tests__/routes-agents.test.ts | 11.2s | +| src/__tests__/routes-git.test.ts | 9.4s | +| src/__tests__/routes-planning.test.ts | 5.6s | +| app/components/__tests__/FileEditor.test.tsx | 5.1s | +| app/components/__tests__/NewTaskModal.test.tsx | 3.4s | +| app/components/__tests__/ChatView.rooms.test.tsx | 2.8s | +| src/__tests__/routes-github.test.ts | 2.8s | +| src/__tests__/setup-routes.test.ts | 2.6s | +| src/__tests__/routes-secrets-sync.test.ts | 2.5s | +| src/__tests__/websocket.test.ts | 2.1s | + +## Cold-start / transform-cost probe (U8 gate input) + +`overhead = wallClock − sum(per-file test durations)` for a single cheap test file. + +| Package | Probe file | Wall | Test time | Overhead | +|---|---|---:|---:|---:| +| `@fusion/engine` | src/__tests__/pi.test.ts | 1843ms | 23ms | **1820ms** | +| `@fusion/core` | src/__tests__/db.test.ts | 13944ms | 12337ms | 1607ms | +| `@fusion/dashboard` | src/__tests__/sse.test.ts | 1349ms | 24ms | **1325ms** | +| `@runfusion/fusion` (cli) | src/__tests__/bin.test.ts | 6292ms | 5354ms | 938ms | + +The cleanest signals are engine and dashboard, where the probe file's own test +time is ~24ms so almost all wall-clock is startup: **~1.3–1.8s of fixed +per-process overhead** (vitest boot + transform + collect + worker spawn). The +engine run breakdown confirms this is dominated by transform (~0.8s) and collect +(~1.0s). The core/cli probes auto-selected heavier files (path-length heuristic, +not runtime), so their overhead figure is conservative but consistent (~0.9–1.6s). + +## Conclusion — U8 gate signal + +Fixed per-process startup/transform overhead is **~1.3–1.8s per vitest +invocation**. In the inner loop (one or two packages) and full per-package runs +this is a small fraction of total wall-clock (engine 178s, core 41s), so it is +**not the top contributor** for those paths. However, the repo runs **~25 +separate vitest processes** across packages, plugins, and the dashboard's 14-lane +chain; at ~1.5s each that is **~35–40s of pure cold-start tax aggregated across a +full CI/`test:full` sweep**, paid on every run with no cross-process sharing in +vitest 3.2. + +Read against the U8 gate ("is cold-start/transform cost a top contributor +blocking the targets?"): for single-package inner-loop runs, **no** — wall-clock +is dominated by individual heavy integration tests (engine branch-group/real-git +suites, core stores, dashboard route suites), which U7 triage targets. For the +aggregate full-suite/CI path the cold-start tax is **material but second-order** +(~10% of full-suite wall-clock), making the vitest-4 `fsModuleCache` upgrade a +**worthwhile-but-not-urgent** lever — recommend proceeding with U3 (overhead +trim), U5 (config tuning), U6 (duration sharding), and U7 (slow-test triage) +first, then re-evaluating the U8 gate once those land, since they shrink both the +per-process count and the heavy-test tail that currently dominate. diff --git a/scripts/__tests__/ci-test-shard-timings.test.mjs b/scripts/__tests__/ci-test-shard-timings.test.mjs new file mode 100644 index 0000000000..e3b8c5241c --- /dev/null +++ b/scripts/__tests__/ci-test-shard-timings.test.mjs @@ -0,0 +1,205 @@ +/** + * Unit tests for the U1 timing-telemetry aggregation built into + * scripts/ci-test-shard.mjs. + * + * Runner: node --test scripts/__tests__/ci-test-shard-timings.test.mjs + */ + +import test from "node:test"; +import assert from "node:assert/strict"; +import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; + +import { + bucketDuration, + attributeTestFile, + extractFileDurations, + buildTimingsSnapshot, + writeTimings, + TIMINGS_SNAPSHOT_RELATIVE, +} from "../ci-test-shard.mjs"; + +const PACKAGES = [ + { name: "@fusion/core", dir: "packages/core" }, + { name: "@fusion/engine", dir: "packages/engine" }, +]; + +function makeReport(projectRoot, files) { + // files: Array<{ rel: string, durationMs: number }> + return { + testResults: files.map(({ rel, durationMs }) => ({ + name: path.join(projectRoot, rel), + startTime: 1000, + endTime: 1000 + durationMs, + assertionResults: [], + })), + }; +} + +function tmpRoot() { + return mkdtempSync(path.join(tmpdir(), "fusion-timings-test-")); +} + +test("bucketDuration rounds to nearest 100ms, floors non-zero to one bucket", () => { + assert.equal(bucketDuration(0), 0); + assert.equal(bucketDuration(40), 100); // sub-bucket non-zero floors up + assert.equal(bucketDuration(149), 100); + assert.equal(bucketDuration(150), 200); + assert.equal(bucketDuration(1234), 1200); + assert.equal(bucketDuration(-5), 0); +}); + +test("attributeTestFile maps absolute paths to owning package, repo-relative", () => { + const root = "/repo"; + const got = attributeTestFile("/repo/packages/core/src/__tests__/a.test.ts", PACKAGES, root); + assert.deepEqual(got, { pkg: "@fusion/core", file: "packages/core/src/__tests__/a.test.ts" }); + assert.equal(attributeTestFile("/repo/tools/x.test.ts", PACKAGES, root), null); +}); + +test("extractFileDurations sums per-file durations and tolerates bad rows", () => { + const root = "/repo"; + const report = { + testResults: [ + { name: "/repo/packages/core/a.test.ts", startTime: 0, endTime: 250 }, + { name: "/repo/packages/core/a.test.ts", startTime: 250, endTime: 500 }, // same file, summed + { name: "/repo/packages/engine/b.test.ts", startTime: 0, endTime: 700 }, + { name: 42, startTime: 0, endTime: 1 }, // bad name + { name: "/repo/packages/core/c.test.ts", startTime: 500, endTime: 100 }, // end { + const root = tmpRoot(); + try { + const f1 = path.join(root, "s1.json"); + const f2 = path.join(root, "s2.json"); + writeFileSync(f1, JSON.stringify(makeReport(root, [ + { rel: "packages/core/src/__tests__/a.test.ts", durationMs: 240 }, + { rel: "packages/engine/src/__tests__/b.test.ts", durationMs: 1010 }, + ]))); + writeFileSync(f2, JSON.stringify(makeReport(root, [ + // same file as f1 → durations sum across shards before bucketing + { rel: "packages/core/src/__tests__/a.test.ts", durationMs: 60 }, + ]))); + + const snap = buildTimingsSnapshot([f1, f2], { projectRoot: root, packages: PACKAGES, capturedAt: "2026-06-03T00:00:00.000Z" }); + assert.equal(snap.capturedAt, "2026-06-03T00:00:00.000Z"); + // 240 + 60 = 300 → bucketed to 300 + assert.equal(snap.packages["@fusion/core"].files["packages/core/src/__tests__/a.test.ts"], 300); + // 1010 → 1000 + assert.equal(snap.packages["@fusion/engine"].files["packages/engine/src/__tests__/b.test.ts"], 1000); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("buildTimingsSnapshot tolerates a corrupt shard file: skips it, keeps others", () => { + const root = tmpRoot(); + try { + const good = path.join(root, "good.json"); + const bad = path.join(root, "bad.json"); + writeFileSync(good, JSON.stringify(makeReport(root, [ + { rel: "packages/core/x.test.ts", durationMs: 300 }, + ]))); + writeFileSync(bad, "{not valid json"); + + const snap = buildTimingsSnapshot([bad, good, path.join(root, "missing.json")], { + projectRoot: root, + packages: PACKAGES, + capturedAt: "2026-06-03T00:00:00.000Z", + }); + assert.equal(snap.packages["@fusion/core"].files["packages/core/x.test.ts"], 300); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("buildTimingsSnapshot omits a zero-test package entirely (no zero entry)", () => { + const root = tmpRoot(); + try { + const f = path.join(root, "s.json"); + writeFileSync(f, JSON.stringify(makeReport(root, [ + { rel: "packages/core/y.test.ts", durationMs: 200 }, + ]))); + const snap = buildTimingsSnapshot([f], { projectRoot: root, packages: PACKAGES, capturedAt: "2026-06-03T00:00:00.000Z" }); + assert.ok(snap.packages["@fusion/core"]); + assert.ok(!("@fusion/engine" in snap.packages)); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("writeTimings writes snapshot to scripts/test-timings.json under a project root", () => { + const root = tmpRoot(); + try { + const inputDir = path.join(root, ".timings"); + mkdirSync(inputDir, { recursive: true }); + writeFileSync(path.join(inputDir, "timings-shard1-0.json"), JSON.stringify(makeReport(root, [ + { rel: "packages/core/z.test.ts", durationMs: 500 }, + ]))); + const snapshotPath = path.join(root, TIMINGS_SNAPSHOT_RELATIVE); + const result = writeTimings({ + projectRoot: root, + inputDir, + snapshotPath, + packages: PACKAGES, + capturedAt: "2026-06-03T00:00:00.000Z", + }); + assert.equal(result.written, true); + const written = JSON.parse(readFileSync(snapshotPath, "utf8")); + assert.equal(written.packages["@fusion/core"].files["packages/core/z.test.ts"], 500); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("writeTimings refuses to overwrite a newer snapshot", () => { + const root = tmpRoot(); + try { + const inputDir = path.join(root, ".timings"); + mkdirSync(inputDir, { recursive: true }); + writeFileSync(path.join(inputDir, "timings-shard1-0.json"), JSON.stringify(makeReport(root, [ + { rel: "packages/core/z.test.ts", durationMs: 500 }, + ]))); + const snapshotPath = path.join(root, "snap.json"); + // Existing snapshot dated in the future. + writeFileSync(snapshotPath, JSON.stringify({ capturedAt: "2999-01-01T00:00:00.000Z", packages: { keep: { files: {} } } })); + + const result = writeTimings({ + projectRoot: root, + inputDir, + snapshotPath, + packages: PACKAGES, + capturedAt: "2026-06-03T00:00:00.000Z", + }); + assert.equal(result.written, false); + assert.equal(result.reason, "newer-snapshot"); + // Original untouched. + const after = JSON.parse(readFileSync(snapshotPath, "utf8")); + assert.equal(after.capturedAt, "2999-01-01T00:00:00.000Z"); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("writeTimings warns and does not write when there are no input files", () => { + const root = tmpRoot(); + try { + const result = writeTimings({ + projectRoot: root, + inputDir: path.join(root, ".timings-empty"), + snapshotPath: path.join(root, "snap.json"), + }); + assert.equal(result.written, false); + assert.equal(result.reason, "no-inputs"); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/scripts/__tests__/test-changed.test.mjs b/scripts/__tests__/test-changed.test.mjs index 1b78343ef9..225ebcc5ad 100644 --- a/scripts/__tests__/test-changed.test.mjs +++ b/scripts/__tests__/test-changed.test.mjs @@ -27,6 +27,7 @@ import { cleanupIsolatedHomePath, knownIsolatedHomeBasenames, __setCleanupRmSyncForTests, + emitModeDecision, } from "../test-changed.mjs"; import { mkdirSync, writeFileSync, mkdtempSync, rmSync, existsSync } from "node:fs"; @@ -826,3 +827,33 @@ test("createIsolatedHomeEnv: records raw/realpath basenames in allow-list set", cleanupIsolatedHomePath(isolatedHome); }); + +// --------------------------------------------------------------------------- +// R5: mode-decision telemetry +// --------------------------------------------------------------------------- + +test("emitModeDecision: changed plan reports changed-packages reason + package count", () => { + const lines = []; + const line = emitModeDecision({ mode: "changed", packages: ["a", "b", "c"] }, (l) => lines.push(l)); + assert.equal(line, "[test-changed] mode=changed reason=changed-packages packages=3"); + assert.deepEqual(lines, [line]); +}); + +test("emitModeDecision: full plan surfaces the decideExecutionPlan reason, packages=0", () => { + assert.equal( + emitModeDecision({ mode: "full", reason: "missing-comparison-base" }, () => {}), + "[test-changed] mode=full reason=missing-comparison-base packages=0", + ); + assert.equal( + emitModeDecision({ mode: "full", reason: "shared-infra-changed" }, () => {}), + "[test-changed] mode=full reason=shared-infra-changed packages=0", + ); +}); + +test("emitModeDecision: distinct full reasons round-trip from decideExecutionPlan", () => { + const full = decideExecutionPlan({ forceFullSuite: false, comparisonBase: null }); + assert.equal(emitModeDecision(full, () => {}), "[test-changed] mode=full reason=missing-comparison-base packages=0"); + + const forced = decideExecutionPlan({ forceFullSuite: true }); + assert.equal(emitModeDecision(forced, () => {}), "[test-changed] mode=full reason=forced packages=0"); +}); diff --git a/scripts/ci-test-shard.mjs b/scripts/ci-test-shard.mjs index ba48ba57a1..cd7e85299e 100644 --- a/scripts/ci-test-shard.mjs +++ b/scripts/ci-test-shard.mjs @@ -14,7 +14,7 @@ */ import { spawnSync } from "node:child_process"; -import { globSync } from "node:fs"; +import { globSync, readFileSync, writeFileSync, readdirSync, mkdirSync, renameSync } from "node:fs"; import { cpus } from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -361,7 +361,310 @@ function entryLabel(entry) { return entry.name; } +// --------------------------------------------------------------------------- +// Timing telemetry aggregation (U1 / R4) +// --------------------------------------------------------------------------- + +/** @type {string} Repo-relative path of the committed timing snapshot. */ +export const TIMINGS_SNAPSHOT_RELATIVE = "scripts/test-timings.json"; + +/** @type {number} Durations are rounded to this bucket (ms) to suppress noise. */ +export const DURATION_BUCKET_MS = 100; + +/** + * Round a raw duration (ms) to the nearest DURATION_BUCKET_MS, with a floor of + * one bucket for any non-zero duration so sub-bucket files are not lost. + * + * @param {number} durationMs + * @returns {number} + */ +export function bucketDuration(durationMs, bucket = DURATION_BUCKET_MS) { + if (!Number.isFinite(durationMs) || durationMs <= 0) return 0; + const rounded = Math.round(durationMs / bucket) * bucket; + return rounded === 0 ? bucket : rounded; +} + +/** + * Map an absolute or repo-relative test-file path to its owning package name, + * using the workspace dir→name table. Returns { pkg, file } where `file` is + * repo-relative, or null when the file is outside any known package. + * + * @param {string} filePath + * @param {Array<{ name: string, dir: string }>} packages + * @param {string} projectRoot + */ +export function attributeTestFile(filePath, packages, projectRoot = process.cwd()) { + const relative = path.isAbsolute(filePath) + ? path.relative(projectRoot, filePath) + : filePath; + const normalized = relative.split(path.sep).join("/"); + // Longest dir first so nested packages win over their parents. + const sorted = [...packages].sort((a, b) => b.dir.length - a.dir.length); + for (const pkg of sorted) { + if (normalized === pkg.dir || normalized.startsWith(`${pkg.dir}/`)) { + return { pkg: pkg.name, file: normalized }; + } + } + return null; +} + +/** + * Parse one vitest `--reporter=json` output object and return per-file + * durations attributed to packages. Tolerant of partial/odd shapes. + * + * @param {unknown} report Parsed JSON reporter output. + * @param {Array<{ name: string, dir: string }>} packages + * @param {string} projectRoot + * @returns {Map>} pkg → (file → durationMs) + */ +export function extractFileDurations(report, packages, projectRoot = process.cwd()) { + const byPackage = new Map(); + const results = report && typeof report === "object" ? report.testResults : null; + if (!Array.isArray(results)) return byPackage; + + for (const entry of results) { + if (!entry || typeof entry.name !== "string") continue; + const start = Number(entry.startTime); + const end = Number(entry.endTime); + if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) continue; + const attributed = attributeTestFile(entry.name, packages, projectRoot); + if (!attributed) continue; + const { pkg, file } = attributed; + if (!byPackage.has(pkg)) byPackage.set(pkg, new Map()); + const files = byPackage.get(pkg); + files.set(file, (files.get(file) ?? 0) + (end - start)); + } + + return byPackage; +} + +/** + * Build a fresh timing snapshot object from a set of per-shard JSON reporter + * files. Missing/corrupt files are warned about and skipped (exit 0 path). + * + * @param {string[]} outputFiles Absolute paths to vitest JSON reporter outputs. + * @param {{ projectRoot?: string, capturedAt?: string, packages?: Array<{name:string,dir:string}> }} [options] + * @returns {{ capturedAt: string, packages: Record }> }} + */ +export function buildTimingsSnapshot(outputFiles, options = {}) { + const projectRoot = options.projectRoot ?? process.cwd(); + const packages = options.packages ?? listWorkspaceTestPackages({ projectRoot }); + const capturedAt = options.capturedAt ?? new Date().toISOString(); + + /** @type {Map>} */ + const merged = new Map(); + + for (const outputFile of outputFiles) { + let report; + try { + report = JSON.parse(readFileSync(outputFile, "utf8")); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + console.warn(`[ci-test-shard] skipping unreadable timing file ${outputFile}: ${message}`); + continue; + } + + const perFile = extractFileDurations(report, packages, projectRoot); + for (const [pkg, files] of perFile) { + if (!merged.has(pkg)) merged.set(pkg, new Map()); + const target = merged.get(pkg); + for (const [file, duration] of files) { + target.set(file, (target.get(file) ?? 0) + duration); + } + } + } + + const packagesOut = {}; + for (const pkg of [...merged.keys()].sort()) { + const files = merged.get(pkg); + if (files.size === 0) continue; // zero-test package → no entry + const filesOut = {}; + for (const file of [...files.keys()].sort()) { + filesOut[file] = bucketDuration(files.get(file)); + } + packagesOut[pkg] = { files: filesOut }; + } + + return { capturedAt, packages: packagesOut }; +} + +/** + * Read an existing snapshot (or null when absent/corrupt). + * @param {string} snapshotPath + */ +export function readTimingsSnapshot(snapshotPath) { + try { + const parsed = JSON.parse(readFileSync(snapshotPath, "utf8")); + if (parsed && typeof parsed === "object" && typeof parsed.capturedAt === "string") { + return parsed; + } + return null; + } catch { + return null; + } +} + +/** + * Discover candidate vitest JSON reporter output files in a directory. + * Looks for files matching `*timings*.json` (the convention CI shards write). + * + * @param {string} dir + * @returns {string[]} absolute paths + */ +export function discoverTimingFiles(dir) { + let entries = []; + try { + entries = readdirSync(dir, { withFileTypes: true }); + } catch { + return []; + } + return entries + .filter((e) => e.isFile() && /timings.*\.json$/.test(e.name)) + .map((e) => path.join(dir, e.name)) + .sort(); +} + +/** + * Merge per-shard JSON reporter outputs into the committed snapshot. + * Refuses to overwrite a snapshot whose capturedAt is newer than this run's. + * + * @param {{ inputDir?: string, inputs?: string[], projectRoot?: string, snapshotPath?: string, capturedAt?: string }} [options] + * @returns {{ written: boolean, snapshot: object, reason?: string }} + */ +export function writeTimings(options = {}) { + const projectRoot = options.projectRoot ?? process.cwd(); + const snapshotPath = options.snapshotPath ?? path.join(projectRoot, TIMINGS_SNAPSHOT_RELATIVE); + const inputs = options.inputs + ?? discoverTimingFiles(options.inputDir ?? path.join(projectRoot, ".timings")); + + if (inputs.length === 0) { + console.warn("[ci-test-shard] no timing input files found; snapshot unchanged."); + return { written: false, snapshot: readTimingsSnapshot(snapshotPath) ?? null, reason: "no-inputs" }; + } + + const capturedAt = options.capturedAt ?? new Date().toISOString(); + const snapshot = buildTimingsSnapshot(inputs, { projectRoot, capturedAt, packages: options.packages }); + + if (Object.keys(snapshot.packages).length === 0) { + console.warn("[ci-test-shard] timing inputs yielded zero packages; snapshot unchanged."); + return { written: false, snapshot, reason: "empty" }; + } + + const existing = readTimingsSnapshot(snapshotPath); + if (existing && new Date(existing.capturedAt).getTime() > new Date(capturedAt).getTime()) { + console.warn( + `[ci-test-shard] existing snapshot (${existing.capturedAt}) is newer than this run (${capturedAt}); refusing to overwrite.`, + ); + return { written: false, snapshot: existing, reason: "newer-snapshot" }; + } + + mkdirSync(path.dirname(snapshotPath), { recursive: true }); + const tmp = `${snapshotPath}.tmp.${process.pid}`; + writeFileSync(tmp, `${JSON.stringify(snapshot, null, 2)}\n`, "utf8"); + renameSync(tmp, snapshotPath); + const pkgCount = Object.keys(snapshot.packages).length; + console.log(`[ci-test-shard] wrote ${TIMINGS_SNAPSHOT_RELATIVE} (${pkgCount} packages, capturedAt ${capturedAt}).`); + return { written: true, snapshot }; +} + +/** + * Cold-start probe: measure per-package vitest startup-to-first-test overhead. + * Runs `vitest run ` with the JSON reporter, then estimates + * overhead = totalWallClockMs − sum(per-file test durations). + * + * @param {string} packageName + * @param {{ projectRoot?: string, env?: NodeJS.ProcessEnv, testFile?: string }} [options] + * @returns {{ packageName: string, wallClockMs: number, testDurationMs: number, overheadMs: number, testFile: string|null }} + */ +export function runColdStartProbe(packageName, options = {}) { + const projectRoot = options.projectRoot ?? process.cwd(); + const env = options.env ?? process.env; + const packages = listWorkspaceTestPackages({ projectRoot }); + const pkg = packages.find((p) => p.name === packageName); + if (!pkg) { + throw new Error(`[ci-test-shard] cold-start-probe: unknown package "${packageName}"`); + } + + // Pick the cheapest (smallest) test file as the probe target unless given. + let testFile = options.testFile ?? null; + if (!testFile) { + const candidates = globSync("**/__tests__/**/*.test.{ts,tsx,mjs}", { + cwd: path.join(projectRoot, pkg.dir), + nodir: true, + exclude: (p) => p.startsWith("dist/") || p.includes("/dist/") || /\.slow\./.test(p), + }); + testFile = candidates.sort((a, b) => a.length - b.length)[0] ?? null; + } + if (!testFile) { + throw new Error(`[ci-test-shard] cold-start-probe: no test file found for ${packageName}`); + } + + const outputFile = path.join(projectRoot, ".timings", `coldstart-${packageName.replace(/[^a-z0-9]+/gi, "-")}.json`); + mkdirSync(path.dirname(outputFile), { recursive: true }); + + const start = Date.now(); + // NB: no `--` before flags (cac mis-parse); mirror the virtual-shard pattern. + spawnSync( + "pnpm", + [ + "--filter", + packageName, + "exec", + "vitest", + "run", + testFile, + "--reporter=dot", + "--reporter=json", + `--outputFile.json=${outputFile}`, + ], + { cwd: projectRoot, stdio: "inherit", env }, + ); + const wallClockMs = Date.now() - start; + + let testDurationMs = 0; + const perFile = (() => { + try { + return extractFileDurations(JSON.parse(readFileSync(outputFile, "utf8")), packages, projectRoot); + } catch { + return new Map(); + } + })(); + for (const files of perFile.values()) { + for (const duration of files.values()) testDurationMs += duration; + } + + return { + packageName, + testFile, + wallClockMs, + testDurationMs: Math.round(testDurationMs), + overheadMs: Math.max(0, Math.round(wallClockMs - testDurationMs)), + }; +} + export function main(argv = process.argv.slice(2), env = process.env) { + if (argv.includes("--write-timings")) { + const dirIdx = argv.indexOf("--inputs-dir"); + const inputDir = dirIdx >= 0 ? argv[dirIdx + 1] : undefined; + writeTimings({ inputDir }); + return; + } + + if (argv.includes("--cold-start-probe")) { + const pkgIdx = argv.indexOf("--cold-start-probe"); + const packageName = argv[pkgIdx + 1]; + if (!packageName || packageName.startsWith("--")) { + throw new Error("Usage: node scripts/ci-test-shard.mjs --cold-start-probe "); + } + const result = runColdStartProbe(packageName, { env }); + console.log( + `[ci-test-shard] cold-start probe ${result.packageName}: wall=${result.wallClockMs}ms ` + + `tests=${result.testDurationMs}ms overhead=${result.overheadMs}ms (file ${result.testFile})`, + ); + console.log(JSON.stringify(result)); + return; + } + const { shard, total } = parseShardArgs(argv, env); const shardEntries = selectShardPackages(listWorkspaceTestPackages(), shard, total); @@ -382,6 +685,20 @@ export function main(argv = process.argv.slice(2), env = process.env) { run("pnpm", ["sync:fusion-skill:check"], { env: shardEnv }); ensureTestArtifacts(process.cwd()); + // Per-shard timing telemetry (U1 / R4): each test invocation also emits a + // vitest JSON reporter file under .timings/. These are uploaded as CI + // artifacts and consumed by `--write-timings` to refresh the snapshot. + // Reporters are appended as CLI flags following the same no-`--` quirk as the + // virtual `--shard` forwarding; package `test` scripts already pass + // `--reporter=dot`, and vitest accepts multiple `--reporter` flags. + const timingsDir = path.join(process.cwd(), ".timings"); + mkdirSync(timingsDir, { recursive: true }); + let invocationIndex = 0; + const timingFlags = () => { + const outputFile = path.join(timingsDir, `timings-shard${shard}-${invocationIndex++}.json`); + return ["--reporter=json", `--outputFile.json=${outputFile}`]; + }; + // Group entries: plain packages run together in one pnpm invocation; // virtual (sharded) entries each get their own vitest --shard invocation. const plain = shardEntries.filter((e) => !e.shardCount); @@ -389,7 +706,7 @@ export function main(argv = process.argv.slice(2), env = process.env) { if (plain.length > 0) { const filters = plain.flatMap((e) => ["--filter", e.name]); - run("pnpm", [...filters, "test"], { env: shardEnv }); + run("pnpm", [...filters, "test", ...timingFlags()], { env: shardEnv }); } for (const entry of virtual) { @@ -402,7 +719,7 @@ export function main(argv = process.argv.slice(2), env = process.env) { // silently disabled and every shard runs the full suite. run( "pnpm", - ["--filter", entry.name, "test", `--shard=${entry.shardIndex}/${entry.shardCount}`], + ["--filter", entry.name, "test", `--shard=${entry.shardIndex}/${entry.shardCount}`, ...timingFlags()], { env: shardEnv }, ); } diff --git a/scripts/test-changed.mjs b/scripts/test-changed.mjs index 140a9100f8..615f03e39d 100644 --- a/scripts/test-changed.mjs +++ b/scripts/test-changed.mjs @@ -840,6 +840,25 @@ export function decideExecutionPlan({ }; } +/** + * R5: Emit one structured line describing why the inner loop chose its mode. + * Shape: `[test-changed] mode= reason= packages=`. + * + * For changed plans the reason is `changed-packages`; for full plans the + * reason mirrors decideExecutionPlan's reason field. + * + * @param {{ mode: string, reason?: string, packages?: string[] }} plan + * @param {(line: string) => void} [log] + * @returns {string} the emitted line (for testing) + */ +export function emitModeDecision(plan, log = console.log) { + const reason = plan.mode === "changed" ? (plan.reason ?? "changed-packages") : (plan.reason ?? "unknown"); + const packageCount = plan.mode === "changed" ? (plan.packages?.length ?? 0) : 0; + const line = `[test-changed] mode=${plan.mode} reason=${reason} packages=${packageCount}`; + log(line); + return line; +} + export function normalizeForwardedArgs(argv) { const normalized = []; @@ -864,6 +883,26 @@ export function main(argv = process.argv.slice(2)) { const forwardedArgs = normalizeForwardedArgs(argv); + // Dry mode-decision probe (R5): compute and print the mode/reason line without + // running tests. Used by `node scripts/test-changed.mjs --print-mode`. + if (argv.includes("--print-mode") || argv.includes("--help")) { + const baseBranch = getBaseBranch(); + const comparisonBase = detectComparisonBase(baseBranch); + const changedFiles = comparisonBase ? changedFilesSince(comparisonBase) : null; + const workspacePackages = listWorkspacePackageInfos(); + const packageNameByDir = listWorkspacePackages(workspacePackages); + const reverseDependencyMap = buildReverseDependencyMap(workspacePackages); + const plan = decideExecutionPlan({ + forceFullSuite, + comparisonBase, + changedFiles, + packageNameByDir, + reverseDependencyMap, + }); + emitModeDecision(plan); + return; + } + run("pnpm", ["sync:fusion-skill:check"]); ensureTestArtifacts(rootDir); @@ -891,6 +930,9 @@ export function main(argv = process.argv.slice(2)) { reverseDependencyMap, }); + // R5: structured mode-decision telemetry so fast-path hit rate is observable. + emitModeDecision(plan); + if (plan.mode === "full") { if (plan.reason === "missing-comparison-base") { console.log(`[test-changed] could not resolve merge-base with ${baseBranch}; running full suite.`); diff --git a/scripts/test-timings.json b/scripts/test-timings.json new file mode 100644 index 0000000000..e5441d5ae1 --- /dev/null +++ b/scripts/test-timings.json @@ -0,0 +1,1000 @@ +{ + "capturedAt": "2026-06-03T23:45:49.672Z", + "packages": { + "@fusion/core": { + "files": { + "packages/core/src/__tests__/activity-log-no-op-moved.test.ts": 500, + "packages/core/src/__tests__/agent-companies-exporter.test.ts": 100, + "packages/core/src/__tests__/agent-companies-parser.test.ts": 200, + "packages/core/src/__tests__/agent-companies-types.test.ts": 100, + "packages/core/src/__tests__/agent-instructions-bundle.test.ts": 500, + "packages/core/src/__tests__/agent-instructions.test.ts": 500, + "packages/core/src/__tests__/agent-log-file-store.test.ts": 100, + "packages/core/src/__tests__/agent-log-migration.test.ts": 600, + "packages/core/src/__tests__/agent-log-retention.test.ts": 600, + "packages/core/src/__tests__/agent-memory-mode.test.ts": 100, + "packages/core/src/__tests__/agent-permission-policy-resolution.test.ts": 100, + "packages/core/src/__tests__/agent-permission-policy.test.ts": 100, + "packages/core/src/__tests__/agent-permissions.test.ts": 100, + "packages/core/src/__tests__/agent-prompts.test.ts": 100, + "packages/core/src/__tests__/agent-provisioning-policy.test.ts": 100, + "packages/core/src/__tests__/agent-role-policy.test.ts": 100, + "packages/core/src/__tests__/agent-store-central-claim.test.ts": 600, + "packages/core/src/__tests__/agent-store.test.ts": 11600, + "packages/core/src/__tests__/agent-token-usage.test.ts": 400, + "packages/core/src/__tests__/ai-engine-loader.test.ts": 100, + "packages/core/src/__tests__/ai-summarize.test.ts": 100, + "packages/core/src/__tests__/app-version.test.ts": 100, + "packages/core/src/__tests__/approval-request-store.test.ts": 700, + "packages/core/src/__tests__/architecture-hot-paths.test.ts": 100, + "packages/core/src/__tests__/architecture-schema-compat.test.ts": 200, + "packages/core/src/__tests__/archive-db-title-id-drift.test.ts": 100, + "packages/core/src/__tests__/automation-store.test.ts": 2500, + "packages/core/src/__tests__/automation.test.ts": 100, + "packages/core/src/__tests__/backup.test.ts": 900, + "packages/core/src/__tests__/blocker-fanout.test.ts": 100, + "packages/core/src/__tests__/board.test.ts": 100, + "packages/core/src/__tests__/branch-assignment.test.ts": 100, + "packages/core/src/__tests__/branch-group-store.test.ts": 1200, + "packages/core/src/__tests__/builtin-coding-workflow-ir.test.ts": 100, + "packages/core/src/__tests__/capacity.test.ts": 100, + "packages/core/src/__tests__/central-claim-mutex.test.ts": 100, + "packages/core/src/__tests__/central-core-docker-node.test.ts": 100, + "packages/core/src/__tests__/central-core-ensure-project.test.ts": 100, + "packages/core/src/__tests__/central-core.test.ts": 1600, + "packages/core/src/__tests__/central-db.test.ts": 200, + "packages/core/src/__tests__/central-identity-recovery.test.ts": 300, + "packages/core/src/__tests__/central-integration.test.ts": 100, + "packages/core/src/__tests__/central-project-node-mappings.test.ts": 100, + "packages/core/src/__tests__/chat-store.rooms.test.ts": 500, + "packages/core/src/__tests__/chat-store.test.ts": 100, + "packages/core/src/__tests__/checkout-claim-mutex.test.ts": 700, + "packages/core/src/__tests__/custom-provider-key.test.ts": 100, + "packages/core/src/__tests__/daemon-token.test.ts": 100, + "packages/core/src/__tests__/db-init-perf.test.ts": 200, + "packages/core/src/__tests__/db-migrate.test.ts": 2100, + "packages/core/src/__tests__/db-mission-base-branch.test.ts": 100, + "packages/core/src/__tests__/db-paused-done-backfill.test.ts": 200, + "packages/core/src/__tests__/db.test.ts": 10100, + "packages/core/src/__tests__/dependency-blocked-todo-report.test.ts": 100, + "packages/core/src/__tests__/distributed-task-id.test.ts": 300, + "packages/core/src/__tests__/docker-client.test.ts": 100, + "packages/core/src/__tests__/docker-node-config.test.ts": 100, + "packages/core/src/__tests__/docker-provisioning.test.ts": 100, + "packages/core/src/__tests__/duplicate-detection.test.ts": 100, + "packages/core/src/__tests__/duplicate-guard.test.ts": 100, + "packages/core/src/__tests__/duplicate-intake-tombstone-window.test.ts": 500, + "packages/core/src/__tests__/duplicate-intake.test.ts": 100, + "packages/core/src/__tests__/duplicate-lineage.test.ts": 100, + "packages/core/src/__tests__/eval-automation.test.ts": 300, + "packages/core/src/__tests__/eval-scoring.test.ts": 100, + "packages/core/src/__tests__/eval-settings.test.ts": 100, + "packages/core/src/__tests__/eval-signal-collector.test.ts": 100, + "packages/core/src/__tests__/eval-store.test.ts": 400, + "packages/core/src/__tests__/experiment-session-store.test.ts": 400, + "packages/core/src/__tests__/experiment-session-types.test.ts": 100, + "packages/core/src/__tests__/explicit-duplicate-marker.test.ts": 100, + "packages/core/src/__tests__/first-run.test.ts": 200, + "packages/core/src/__tests__/fn-binary-probe.test.ts": 100, + "packages/core/src/__tests__/fn-binary.test.ts": 100, + "packages/core/src/__tests__/fts5-guard.test.ts": 1500, + "packages/core/src/__tests__/gh-cli.test.ts": 100, + "packages/core/src/__tests__/github-tracking-settings.test.ts": 100, + "packages/core/src/__tests__/github-tracking.test.ts": 100, + "packages/core/src/__tests__/global-settings-guard.test.ts": 100, + "packages/core/src/__tests__/global-settings.test.ts": 100, + "packages/core/src/__tests__/goal-citation-audit-aggregation.test.ts": 100, + "packages/core/src/__tests__/goal-citation-extractor.test.ts": 100, + "packages/core/src/__tests__/goal-citations-store.test.ts": 600, + "packages/core/src/__tests__/goal-store.test.ts": 400, + "packages/core/src/__tests__/goals-schema.test.ts": 400, + "packages/core/src/__tests__/in-review-stall.test.ts": 100, + "packages/core/src/__tests__/in-review-stalled.test.ts": 100, + "packages/core/src/__tests__/index-exports.test.ts": 100, + "packages/core/src/__tests__/insight-run-executor.test.ts": 200, + "packages/core/src/__tests__/insight-store.test.ts": 2500, + "packages/core/src/__tests__/interactive-ai-session-seam.test.ts": 100, + "packages/core/src/__tests__/is-secret-scope.test.ts": 100, + "packages/core/src/__tests__/logger.test.ts": 100, + "packages/core/src/__tests__/manual-retry-reset.test.ts": 100, + "packages/core/src/__tests__/master-key.test.ts": 100, + "packages/core/src/__tests__/memory-backend.test.ts": 200, + "packages/core/src/__tests__/memory-backup.test.ts": 300, + "packages/core/src/__tests__/memory-compaction.test.ts": 100, + "packages/core/src/__tests__/memory-dreams.test.ts": 100, + "packages/core/src/__tests__/memory-insights.test.ts": 200, + "packages/core/src/__tests__/merge-conflict-strategy.test.ts": 100, + "packages/core/src/__tests__/merge-details.test.ts": 100, + "packages/core/src/__tests__/merge-request-record.test.ts": 600, + "packages/core/src/__tests__/mesh-config-generator.test.ts": 100, + "packages/core/src/__tests__/mesh-replication-protocol.test.ts": 100, + "packages/core/src/__tests__/mesh-task-replication.test.ts": 100, + "packages/core/src/__tests__/message-store.test.ts": 1800, + "packages/core/src/__tests__/migration-orchestrator.test.ts": 300, + "packages/core/src/__tests__/migration.test.ts": 600, + "packages/core/src/__tests__/mission-factory-parity.integration.test.ts": 4200, + "packages/core/src/__tests__/mission-goals-link.test.ts": 200, + "packages/core/src/__tests__/mission-integration.test.ts": 4800, + "packages/core/src/__tests__/mission-planning-context.integration.test.ts": 1800, + "packages/core/src/__tests__/mission-store.test.ts": 10700, + "packages/core/src/__tests__/model-resolution.test.ts": 100, + "packages/core/src/__tests__/move-task-preserve-status.test.ts": 200, + "packages/core/src/__tests__/multi-node-dashboard.test.ts": 800, + "packages/core/src/__tests__/near-duplicate.test.ts": 100, + "packages/core/src/__tests__/no-op-moved-cleanup-migration.test.ts": 200, + "packages/core/src/__tests__/node-connection.test.ts": 100, + "packages/core/src/__tests__/node-discovery.test.ts": 100, + "packages/core/src/__tests__/node-override-guard.test.ts": 100, + "packages/core/src/__tests__/notification-dispatcher.test.ts": 100, + "packages/core/src/__tests__/oauth-credential-interop.test.ts": 100, + "packages/core/src/__tests__/pi-extensions-format.test.ts": 100, + "packages/core/src/__tests__/pi-extensions.test.ts": 200, + "packages/core/src/__tests__/plugin-contribution-types.test.ts": 100, + "packages/core/src/__tests__/plugin-hot-reload.test.ts": 200, + "packages/core/src/__tests__/plugin-loader-contributions.test.ts": 100, + "packages/core/src/__tests__/plugin-loader.route-context.test.ts": 100, + "packages/core/src/__tests__/plugin-loader.test.ts": 4500, + "packages/core/src/__tests__/plugin-store.test.ts": 3000, + "packages/core/src/__tests__/plugin-types.test.ts": 100, + "packages/core/src/__tests__/process-supervisor.test.ts": 1400, + "packages/core/src/__tests__/project-identity.test.ts": 100, + "packages/core/src/__tests__/project-isolation-transition.test.ts": 100, + "packages/core/src/__tests__/project-memory.test.ts": 100, + "packages/core/src/__tests__/project-root-guard.test.ts": 100, + "packages/core/src/__tests__/project-root.linked-worktree.test.ts": 800, + "packages/core/src/__tests__/prompt-overrides.test.ts": 100, + "packages/core/src/__tests__/reconcile-claude-cli-paths.test.ts": 100, + "packages/core/src/__tests__/reconcile-droid-cli-paths.test.ts": 100, + "packages/core/src/__tests__/reflection-store.test.ts": 100, + "packages/core/src/__tests__/research-settings.test.ts": 100, + "packages/core/src/__tests__/research-store.test.ts": 400, + "packages/core/src/__tests__/resolvePersistAgentThinkingLog.test.ts": 100, + "packages/core/src/__tests__/retry-summary.test.ts": 100, + "packages/core/src/__tests__/routine-store.test.ts": 1800, + "packages/core/src/__tests__/run-audit.integration.test.ts": 4600, + "packages/core/src/__tests__/run-audit.test.ts": 6900, + "packages/core/src/__tests__/run-command.test.ts": 100, + "packages/core/src/__tests__/sandbox-prompt-override.test.ts": 100, + "packages/core/src/__tests__/sandbox-provisioning-policy.test.ts": 100, + "packages/core/src/__tests__/sandbox-settings.test.ts": 100, + "packages/core/src/__tests__/secret-access-policy.test.ts": 100, + "packages/core/src/__tests__/secrets-crypto.test.ts": 100, + "packages/core/src/__tests__/secrets-env.test.ts": 100, + "packages/core/src/__tests__/secrets-schema.test.ts": 300, + "packages/core/src/__tests__/secrets-store.test.ts": 400, + "packages/core/src/__tests__/secrets-sync-passphrase.test.ts": 600, + "packages/core/src/__tests__/secrets-sync.test.ts": 400, + "packages/core/src/__tests__/settings-defaults.test.ts": 100, + "packages/core/src/__tests__/settings-export.test.ts": 2800, + "packages/core/src/__tests__/settings-parity.test.ts": 100, + "packages/core/src/__tests__/settings-precedence.test.ts": 100, + "packages/core/src/__tests__/settings-schema-agent-permission-policy.test.ts": 100, + "packages/core/src/__tests__/settings-schema-agent-provisioning.test.ts": 100, + "packages/core/src/__tests__/settings-schema-sandbox-provisioning.test.ts": 100, + "packages/core/src/__tests__/settings-validation.test.ts": 100, + "packages/core/src/__tests__/setup-test-isolation.test.ts": 600, + "packages/core/src/__tests__/shared-mesh-state.test.ts": 100, + "packages/core/src/__tests__/soft-delete-agent-logs.test.ts": 500, + "packages/core/src/__tests__/soft-delete-audit-and-column.test.ts": 600, + "packages/core/src/__tests__/soft-delete-checked-out-tasks.test.ts": 600, + "packages/core/src/__tests__/soft-delete-lineage-children.test.ts": 1200, + "packages/core/src/__tests__/soft-delete-qa-FN-5124.test.ts": 700, + "packages/core/src/__tests__/soft-delete-resurrection-FN-5208.test.ts": 700, + "packages/core/src/__tests__/soft-delete-resurrection-FN-5233.test.ts": 400, + "packages/core/src/__tests__/soft-delete-tasks.test.ts": 700, + "packages/core/src/__tests__/sqlite-validation.test.ts": 100, + "packages/core/src/__tests__/stale-paused-review.test.ts": 100, + "packages/core/src/__tests__/stale-paused-todo.test.ts": 100, + "packages/core/src/__tests__/stalled-review-detector.test.ts": 100, + "packages/core/src/__tests__/store-activity.test.ts": 3600, + "packages/core/src/__tests__/store-agent-log-file.test.ts": 400, + "packages/core/src/__tests__/store-archive-search.test.ts": 3600, + "packages/core/src/__tests__/store-attachments.test.ts": 500, + "packages/core/src/__tests__/store-comments.test.ts": 3500, + "packages/core/src/__tests__/store-concurrent-writes.test.ts": 1300, + "packages/core/src/__tests__/store-create-collision.test.ts": 400, + "packages/core/src/__tests__/store-create.test.ts": 3000, + "packages/core/src/__tests__/store-delete-task-blocker-residue.test.ts": 600, + "packages/core/src/__tests__/store-dependency-cycle.test.ts": 700, + "packages/core/src/__tests__/store-effective-node-fields.test.ts": 200, + "packages/core/src/__tests__/store-engine-active-since.test.ts": 100, + "packages/core/src/__tests__/store-execution-timing.test.ts": 300, + "packages/core/src/__tests__/store-get-task-columns.test.ts": 900, + "packages/core/src/__tests__/store-github-tracking-reconcile.test.ts": 600, + "packages/core/src/__tests__/store-github-tracking.test.ts": 1300, + "packages/core/src/__tests__/store-handoff-to-review.test.ts": 800, + "packages/core/src/__tests__/store-health.test.ts": 200, + "packages/core/src/__tests__/store-in-review-stall.test.ts": 200, + "packages/core/src/__tests__/store-in-review-stalled.test.ts": 300, + "packages/core/src/__tests__/store-list-modified.test.ts": 600, + "packages/core/src/__tests__/store-merge-queue.test.ts": 5200, + "packages/core/src/__tests__/store-migration.test.ts": 800, + "packages/core/src/__tests__/store-movement.test.ts": 2900, + "packages/core/src/__tests__/store-ops.test.ts": 1100, + "packages/core/src/__tests__/store-parent-task-dedup.test.ts": 100, + "packages/core/src/__tests__/store-parsing.test.ts": 2300, + "packages/core/src/__tests__/store-persistence.test.ts": 2000, + "packages/core/src/__tests__/store-plugin-routing.test.ts": 100, + "packages/core/src/__tests__/store-pr-infos.test.ts": 300, + "packages/core/src/__tests__/store-pr-merged-transition.test.ts": 300, + "packages/core/src/__tests__/store-priority.test.ts": 300, + "packages/core/src/__tests__/store-prompt-generation.test.ts": 200, + "packages/core/src/__tests__/store-reliability-aggregations.test.ts": 700, + "packages/core/src/__tests__/store-resilience.test.ts": 2900, + "packages/core/src/__tests__/store-review-comments.test.ts": 200, + "packages/core/src/__tests__/store-run-mutation-context.test.ts": 500, + "packages/core/src/__tests__/store-scheduling.test.ts": 1500, + "packages/core/src/__tests__/store-self-defeating-dep.test.ts": 200, + "packages/core/src/__tests__/store-settings-sync-passphrase-probe.test.ts": 400, + "packages/core/src/__tests__/store-settings.test.ts": 1200, + "packages/core/src/__tests__/store-snapshots.test.ts": 300, + "packages/core/src/__tests__/store-sort.test.ts": 100, + "packages/core/src/__tests__/store-source-metadata-patch.test.ts": 400, + "packages/core/src/__tests__/store-stale-paused-review.test.ts": 300, + "packages/core/src/__tests__/store-stale-paused-todo.test.ts": 300, + "packages/core/src/__tests__/store-stalled-review.test.ts": 100, + "packages/core/src/__tests__/store-task-age-staleness.test.ts": 300, + "packages/core/src/__tests__/store-task-id-integrity.test.ts": 200, + "packages/core/src/__tests__/store-test-helpers.shared.test.ts": 100, + "packages/core/src/__tests__/store-token-usage.test.ts": 600, + "packages/core/src/__tests__/store-update-step-order.test.ts": 100, + "packages/core/src/__tests__/store-update.test.ts": 800, + "packages/core/src/__tests__/store-upsert.test.ts": 2800, + "packages/core/src/__tests__/store-watcher.test.ts": 500, + "packages/core/src/__tests__/store-workflow-steps.test.ts": 500, + "packages/core/src/__tests__/store.experiment-session-accessor.test.ts": 200, + "packages/core/src/__tests__/stranded-refinements.test.ts": 200, + "packages/core/src/__tests__/system-metrics.test.ts": 100, + "packages/core/src/__tests__/task-age-staleness.test.ts": 100, + "packages/core/src/__tests__/task-creation-hook.test.ts": 1000, + "packages/core/src/__tests__/task-dependency-mutation.test.ts": 400, + "packages/core/src/__tests__/task-documents.test.ts": 8300, + "packages/core/src/__tests__/task-helpers.test.ts": 100, + "packages/core/src/__tests__/task-id-integrity.test.ts": 200, + "packages/core/src/__tests__/task-lineage.test.ts": 100, + "packages/core/src/__tests__/task-merge.test.ts": 100, + "packages/core/src/__tests__/task-node-override.test.ts": 600, + "packages/core/src/__tests__/task-priority.test.ts": 100, + "packages/core/src/__tests__/task-title-id-drift.test.ts": 100, + "packages/core/src/__tests__/test-project.test.ts": 900, + "packages/core/src/__tests__/todo-store.test.ts": 1400, + "packages/core/src/__tests__/unavailable-node-policy.test.ts": 100, + "packages/core/src/__tests__/use-droid-cli-settings.test.ts": 100, + "packages/core/src/__tests__/use-llama-cpp-settings.test.ts": 100, + "packages/core/src/__tests__/vitest-processes.test.ts": 100, + "packages/core/src/__tests__/vitest-workers.test.ts": 100, + "packages/core/src/__tests__/workflow-parity.test.ts": 100, + "packages/core/src/__tests__/workflow-step-templates-verdict.test.ts": 100, + "packages/core/src/__tests__/workspace-dependency-acyclicity.test.ts": 100, + "packages/core/src/__tests__/worktrunk-settings.test.ts": 100 + } + }, + "@fusion/dashboard": { + "files": { + "packages/dashboard/app/components/__tests__/ActiveAgentsPanel.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ActivityLogModal.test.tsx": 300, + "packages/dashboard/app/components/__tests__/AgentMentionPopup.test.tsx": 100, + "packages/dashboard/app/components/__tests__/AgentMetricsBar.test.tsx": 100, + "packages/dashboard/app/components/__tests__/AgentOnboardingModal.test.tsx": 200, + "packages/dashboard/app/components/__tests__/AgentReflectionsTab.test.tsx": 500, + "packages/dashboard/app/components/__tests__/AgentTokenStatsPanel.test.tsx": 100, + "packages/dashboard/app/components/__tests__/AuthTokenRecoveryDialog.test.tsx": 100, + "packages/dashboard/app/components/__tests__/Board.test.tsx": 200, + "packages/dashboard/app/components/__tests__/BranchGroupCard.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ChatView.autosize.test.tsx": 1500, + "packages/dashboard/app/components/__tests__/ChatView.chat-input-autosize.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ChatView.default-model-icon.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ChatView.draft.test.tsx": 600, + "packages/dashboard/app/components/__tests__/ChatView.hash-mention.test.tsx": 200, + "packages/dashboard/app/components/__tests__/ChatView.rooms.test.tsx": 2800, + "packages/dashboard/app/components/__tests__/ChatView.scroll-to-top.test.tsx": 200, + "packages/dashboard/app/components/__tests__/ChatView.swipe-back.test.tsx": 100, + "packages/dashboard/app/components/__tests__/Column.test.tsx": 600, + "packages/dashboard/app/components/__tests__/ConfirmDialog.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ConversationHistory.test.tsx": 100, + "packages/dashboard/app/components/__tests__/DashboardLoader.test.tsx": 100, + "packages/dashboard/app/components/__tests__/DataBoundary.test.tsx": 100, + "packages/dashboard/app/components/__tests__/DevServerView.mobile.test.tsx": 100, + "packages/dashboard/app/components/__tests__/DirectoryPicker.test.tsx": 200, + "packages/dashboard/app/components/__tests__/DuplicateWarningModal.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ErrorBoundary.test.tsx": 100, + "packages/dashboard/app/components/__tests__/ExecutorStatusBar.test.tsx": 300, + "packages/dashboard/app/components/__tests__/FileBrowser.test.tsx": 400, + "packages/dashboard/app/components/__tests__/FileEditor.test.tsx": 5100, + "packages/dashboard/app/components/__tests__/GitHubBadge.test.tsx": 100, + "packages/dashboard/app/components/__tests__/GroupTaskModal.test.tsx": 200, + "packages/dashboard/app/components/__tests__/InlineCreateCard.test.tsx": 1700, + "packages/dashboard/app/components/__tests__/LoginInstructions.test.tsx": 100, + "packages/dashboard/app/components/__tests__/MemoryView.test.tsx": 600, + "packages/dashboard/app/components/__tests__/MergeAdvanceNotice.test.tsx": 100, + "packages/dashboard/app/components/__tests__/MessageComposer.autosize.test.tsx": 200, + "packages/dashboard/app/components/__tests__/MessageComposer.test.tsx": 100, + "packages/dashboard/app/components/__tests__/MobileNavBar.test.tsx": 900, + "packages/dashboard/app/components/__tests__/NewTaskModal.shared-cache.test.tsx": 100, + "packages/dashboard/app/components/__tests__/NewTaskModal.test.tsx": 3400, + "packages/dashboard/app/components/__tests__/NodeCard.test.tsx": 100, + "packages/dashboard/app/components/__tests__/board-mobile-view-switch.test.tsx": 100, + "packages/dashboard/app/components/__tests__/board-mobile.test.tsx": 400, + "packages/dashboard/scripts/__tests__/run-vitest-with-heap.test.ts": 300, + "packages/dashboard/src/__tests__/api-error.test.ts": 100, + "packages/dashboard/src/__tests__/auth-middleware-integration.test.ts": 100, + "packages/dashboard/src/__tests__/auth-middleware.test.ts": 100, + "packages/dashboard/src/__tests__/chat-attachment-routes.test.ts": 400, + "packages/dashboard/src/__tests__/chat-routes.test.ts": 1000, + "packages/dashboard/src/__tests__/dashboard-test-config-guard.test.ts": 100, + "packages/dashboard/src/__tests__/file-service.test.ts": 100, + "packages/dashboard/src/__tests__/github-webhooks.test.ts": 100, + "packages/dashboard/src/__tests__/github.test.ts": 900, + "packages/dashboard/src/__tests__/initialize.test.ts": 100, + "packages/dashboard/src/__tests__/planning-flow-diagnostics-guardrail.test.ts": 100, + "packages/dashboard/src/__tests__/pr-routes-auto-merge.test.ts": 100, + "packages/dashboard/src/__tests__/pr-routes.contract.test.ts": 200, + "packages/dashboard/src/__tests__/project-routes.test.ts": 2000, + "packages/dashboard/src/__tests__/project-store-resolver.test.ts": 200, + "packages/dashboard/src/__tests__/recover-branch-binding-route.test.ts": 100, + "packages/dashboard/src/__tests__/register-git-github.pr-options-preflight-metadata.test.ts": 100, + "packages/dashboard/src/__tests__/register-git-github.pr-resolve-conflicts.test.ts": 100, + "packages/dashboard/src/__tests__/remote-access-routes.test.ts": 100, + "packages/dashboard/src/__tests__/remote-auth.test.ts": 100, + "packages/dashboard/src/__tests__/routes-agent-budget.test.ts": 100, + "packages/dashboard/src/__tests__/routes-agent-keys.test.ts": 100, + "packages/dashboard/src/__tests__/routes-agent-permissions.test.ts": 1900, + "packages/dashboard/src/__tests__/routes-agent-ratings.test.ts": 100, + "packages/dashboard/src/__tests__/routes-agent-runs.test.ts": 2000, + "packages/dashboard/src/__tests__/routes-agent-soul-memory.test.ts": 200, + "packages/dashboard/src/__tests__/routes-agents.test.ts": 11200, + "packages/dashboard/src/__tests__/routes-automation.test.ts": 700, + "packages/dashboard/src/__tests__/routes-branch-groups.test.ts": 100, + "packages/dashboard/src/__tests__/routes-git.test.ts": 9400, + "packages/dashboard/src/__tests__/routes-github.test.ts": 2800, + "packages/dashboard/src/__tests__/routes-merge-advance-push-origin.test.ts": 100, + "packages/dashboard/src/__tests__/routes-nodes-sync-contract.test.ts": 300, + "packages/dashboard/src/__tests__/routes-nodes.test.ts": 200, + "packages/dashboard/src/__tests__/routes-planning.test.ts": 5600, + "packages/dashboard/src/__tests__/routes-secrets-sync.test.ts": 2500, + "packages/dashboard/src/__tests__/routes-settings.test.ts": 1000, + "packages/dashboard/src/__tests__/routes-task-commit-associations.test.ts": 100, + "packages/dashboard/src/__tests__/routes-tasks-deterministic-dedup.test.ts": 100, + "packages/dashboard/src/__tests__/routes-tasks-duplicate-check.test.ts": 100, + "packages/dashboard/src/__tests__/routes-tasks-explicit-duplicate-marker.test.ts": 100, + "packages/dashboard/src/__tests__/routes-tasks.test.ts": 500, + "packages/dashboard/src/__tests__/server-static-assets.test.ts": 100, + "packages/dashboard/src/__tests__/server-webhook.test.ts": 100, + "packages/dashboard/src/__tests__/server.events.test.ts": 100, + "packages/dashboard/src/__tests__/server.test.ts": 1300, + "packages/dashboard/src/__tests__/setup-routes.test.ts": 2600, + "packages/dashboard/src/__tests__/sse-buffer.test.ts": 100, + "packages/dashboard/src/__tests__/sse.test.ts": 100, + "packages/dashboard/src/__tests__/test-isolation-guard.test.ts": 100, + "packages/dashboard/src/__tests__/update-check-route.test.ts": 100, + "packages/dashboard/src/__tests__/websocket.test.ts": 2100, + "packages/dashboard/src/routes/__tests__/custom-provider-routes.test.ts": 100, + "packages/dashboard/src/routes/__tests__/custom-providers.test.ts": 600, + "packages/dashboard/src/routes/__tests__/register-diagnostics-routes.test.ts": 100, + "packages/dashboard/src/routes/__tests__/register-docker-node-routes.test.ts": 200, + "packages/dashboard/src/routes/__tests__/stash-recovery-routes.test.ts": 100 + } + }, + "@fusion/engine": { + "files": { + "packages/engine/src/__tests__/active-merger-status.test.ts": 200, + "packages/engine/src/__tests__/active-session-registry.test.ts": 100, + "packages/engine/src/__tests__/agent-action-gate-project-default.test.ts": 100, + "packages/engine/src/__tests__/agent-action-gate.test.ts": 100, + "packages/engine/src/__tests__/agent-assignment.test.ts": 100, + "packages/engine/src/__tests__/agent-document-tools.test.ts": 100, + "packages/engine/src/__tests__/agent-heartbeat-memory-mode.test.ts": 400, + "packages/engine/src/__tests__/agent-heartbeat-procedures.test.ts": 100, + "packages/engine/src/__tests__/agent-heartbeat-worktree.test.ts": 100, + "packages/engine/src/__tests__/agent-instructions.test.ts": 100, + "packages/engine/src/__tests__/agent-logger.test.ts": 100, + "packages/engine/src/__tests__/agent-memory-index.test.ts": 100, + "packages/engine/src/__tests__/agent-reflection.test.ts": 100, + "packages/engine/src/__tests__/agent-runtime-layers.test.ts": 100, + "packages/engine/src/__tests__/agent-self-improve.test.ts": 100, + "packages/engine/src/__tests__/agent-session-helpers-mock.test.ts": 100, + "packages/engine/src/__tests__/agent-session-helpers-test-mode.test.ts": 100, + "packages/engine/src/__tests__/agent-session-helpers.test.ts": 100, + "packages/engine/src/__tests__/agent-skills-flow.test.ts": 100, + "packages/engine/src/__tests__/agent-task-creation-github-tracking-flag.test.ts": 200, + "packages/engine/src/__tests__/agent-tools-config.test.ts": 100, + "packages/engine/src/__tests__/agent-tools-delegation.test.ts": 100, + "packages/engine/src/__tests__/agent-tools-github-tracking-end-to-end.test.ts": 100, + "packages/engine/src/__tests__/agent-tools-github-tracking.test.ts": 500, + "packages/engine/src/__tests__/agent-tools-provisioning-approval.test.ts": 100, + "packages/engine/src/__tests__/agent-tools-web-fetch.test.ts": 100, + "packages/engine/src/__tests__/agent-tools.test.ts": 400, + "packages/engine/src/__tests__/auth-storage.test.ts": 100, + "packages/engine/src/__tests__/auto-claim-snapshot-soft-delete.test.ts": 500, + "packages/engine/src/__tests__/auto-claim-snapshot.test.ts": 100, + "packages/engine/src/__tests__/auto-recovery-branch-worktree.test.ts": 400, + "packages/engine/src/__tests__/auto-recovery-contamination.test.ts": 100, + "packages/engine/src/__tests__/auto-recovery-message-delivery.test.ts": 100, + "packages/engine/src/__tests__/auto-recovery.test.ts": 100, + "packages/engine/src/__tests__/backlog-pressure-reporter.test.ts": 100, + "packages/engine/src/__tests__/branch-attribution.test.ts": 100, + "packages/engine/src/__tests__/branch-autocorrect.test.ts": 100, + "packages/engine/src/__tests__/branch-conflicts-foreign-only.test.ts": 2300, + "packages/engine/src/__tests__/branch-conflicts-ghost-references.test.ts": 1900, + "packages/engine/src/__tests__/branch-conflicts-misrouted-foreign.test.ts": 900, + "packages/engine/src/__tests__/branch-conflicts-recovery.test.ts": 4500, + "packages/engine/src/__tests__/branch-conflicts-self-owned.test.ts": 100, + "packages/engine/src/__tests__/branch-conflicts-zero-unique.test.ts": 2200, + "packages/engine/src/__tests__/branch-conflicts.test.ts": 100, + "packages/engine/src/__tests__/compound-engineering-skill-resolution.test.ts": 100, + "packages/engine/src/__tests__/concurrency.test.ts": 200, + "packages/engine/src/__tests__/context-limit-detector.test.ts": 100, + "packages/engine/src/__tests__/cron-runner.test.ts": 1400, + "packages/engine/src/__tests__/cross-node-claim-mutex.integration.test.ts": 200, + "packages/engine/src/__tests__/custom-providers-openai-completions.test.ts": 100, + "packages/engine/src/__tests__/custom-providers-openai-responses.test.ts": 100, + "packages/engine/src/__tests__/custom-providers.test.ts": 100, + "packages/engine/src/__tests__/dependency-blocked-todo-reporter.test.ts": 100, + "packages/engine/src/__tests__/derive-subject-summary.test.ts": 100, + "packages/engine/src/__tests__/detect-pseudo-pause.test.ts": 100, + "packages/engine/src/__tests__/distributed-claim-mutex.integration.test.ts": 200, + "packages/engine/src/__tests__/droid-runtime-e2e.test.ts": 300, + "packages/engine/src/__tests__/effective-node.test.ts": 100, + "packages/engine/src/__tests__/engine-public-api.test.ts": 100, + "packages/engine/src/__tests__/engine-singleton-lock.test.ts": 100, + "packages/engine/src/__tests__/error-classifier.test.ts": 100, + "packages/engine/src/__tests__/eval-followups.test.ts": 100, + "packages/engine/src/__tests__/evaluator-evidence.test.ts": 100, + "packages/engine/src/__tests__/evaluator.test.ts": 100, + "packages/engine/src/__tests__/executor-abort-all-in-flight.test.ts": 100, + "packages/engine/src/__tests__/executor-base-commit-capture.real-git.test.ts": 1200, + "packages/engine/src/__tests__/executor-base-commit-capture.test.ts": 100, + "packages/engine/src/__tests__/executor-branch-canonicalization.test.ts": 100, + "packages/engine/src/__tests__/executor-capture-modified-files-attribution.test.ts": 100, + "packages/engine/src/__tests__/executor-contamination-base.test.ts": 100, + "packages/engine/src/__tests__/executor-core.test.ts": 100, + "packages/engine/src/__tests__/executor-current-run-context-isolation.test.ts": 100, + "packages/engine/src/__tests__/executor-implicit-task-done-budget.test.ts": 100, + "packages/engine/src/__tests__/executor-implicit-task-done-revise-guard.test.ts": 100, + "packages/engine/src/__tests__/executor-missing-task-json-transient.test.ts": 100, + "packages/engine/src/__tests__/executor-pause.test.ts": 200, + "packages/engine/src/__tests__/executor-plan-only-scope-leak.test.ts": 100, + "packages/engine/src/__tests__/executor-prompt.test.ts": 500, + "packages/engine/src/__tests__/executor-recovery.test.ts": 100, + "packages/engine/src/__tests__/executor-reset-steps-if-work-lost.test.ts": 100, + "packages/engine/src/__tests__/executor-retry-storm.test.ts": 100, + "packages/engine/src/__tests__/executor-review-step-indexing.test.ts": 100, + "packages/engine/src/__tests__/executor-review-verdicts.test.ts": 100, + "packages/engine/src/__tests__/executor-runtime-env.test.ts": 100, + "packages/engine/src/__tests__/executor-soft-delete-abort.test.ts": 100, + "packages/engine/src/__tests__/executor-soft-delete-guard.test.ts": 100, + "packages/engine/src/__tests__/executor-step-session.test.ts": 400, + "packages/engine/src/__tests__/executor-task-done-bulk-step-guard.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-case-insensitive-branch.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-dissent-guard.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-invariant.test.ts": 300, + "packages/engine/src/__tests__/executor-task-done-premise-stale.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-revise-verdict-guard.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-shared-helper.test.ts": 100, + "packages/engine/src/__tests__/executor-task-done-summary.test.ts": 100, + "packages/engine/src/__tests__/executor-token-usage.test.ts": 100, + "packages/engine/src/__tests__/executor-user-cancel.test.ts": 100, + "packages/engine/src/__tests__/executor-workflow-revision-scope.test.ts": 100, + "packages/engine/src/__tests__/executor-workflow-step-scope.test.ts": 100, + "packages/engine/src/__tests__/executor-worktree-conflict.test.ts": 100, + "packages/engine/src/__tests__/executor-worktree-liveness.test.ts": 100, + "packages/engine/src/__tests__/executor-worktree.test.ts": 2100, + "packages/engine/src/__tests__/experiment-benchmark-runner.test.ts": 700, + "packages/engine/src/__tests__/experiment-executor.test.ts": 600, + "packages/engine/src/__tests__/experiment-finalize-plan.test.ts": 100, + "packages/engine/src/__tests__/experiment-finalize-service.test.ts": 100, + "packages/engine/src/__tests__/experiment-git-policy.test.ts": 100, + "packages/engine/src/__tests__/experiment-metric-parser.test.ts": 100, + "packages/engine/src/__tests__/external-integration-manifest.test.ts": 100, + "packages/engine/src/__tests__/external-integrations-registry.test.ts": 100, + "packages/engine/src/__tests__/fallback-model-observer.test.ts": 100, + "packages/engine/src/__tests__/finalize-git-ops.test.ts": 700, + "packages/engine/src/__tests__/gating-classifications-provisioning.test.ts": 100, + "packages/engine/src/__tests__/gating-classifications.test.ts": 100, + "packages/engine/src/__tests__/goal-anchoring-audit.test.ts": 100, + "packages/engine/src/__tests__/goal-citation-proof.test.ts": 100, + "packages/engine/src/__tests__/goal-context-injection.test.ts": 100, + "packages/engine/src/__tests__/goal-context-injector.test.ts": 100, + "packages/engine/src/__tests__/goal-injection-diagnostics-wiring.test.ts": 100, + "packages/engine/src/__tests__/goal-injection-diagnostics.test.ts": 100, + "packages/engine/src/__tests__/gridlock-detector.test.ts": 100, + "packages/engine/src/__tests__/group-merge-coordinator.test.ts": 900, + "packages/engine/src/__tests__/heartbeat-executor.test.ts": 500, + "packages/engine/src/__tests__/heartbeat-monitor-per-agent-config.test.ts": 100, + "packages/engine/src/__tests__/heartbeat-monitor.test.ts": 100, + "packages/engine/src/__tests__/heartbeat-procedure-resolver.test.ts": 100, + "packages/engine/src/__tests__/heartbeat-prompt-trim.test.ts": 100, + "packages/engine/src/__tests__/heartbeat-room-messages.test.ts": 2200, + "packages/engine/src/__tests__/heartbeat-scheduler.test.ts": 300, + "packages/engine/src/__tests__/heartbeat-session-prompt.test.ts": 200, + "packages/engine/src/__tests__/heartbeat-skills.test.ts": 100, + "packages/engine/src/__tests__/hermes-runtime-e2e.test.ts": 300, + "packages/engine/src/__tests__/hermes-runtime-integration.test.ts": 100, + "packages/engine/src/__tests__/hybrid-executor-gate.test.ts": 100, + "packages/engine/src/__tests__/hybrid-executor-multi-node-routing.test.ts": 100, + "packages/engine/src/__tests__/hybrid-executor-startup.integration.test.ts": 100, + "packages/engine/src/__tests__/hybrid-executor.test.ts": 100, + "packages/engine/src/__tests__/identity-snapshot.test.ts": 100, + "packages/engine/src/__tests__/in-process-runtime.test.ts": 100, + "packages/engine/src/__tests__/in-review-merge-stall-deadlock-recovery.test.ts": 100, + "packages/engine/src/__tests__/integration-branch.test.ts": 100, + "packages/engine/src/__tests__/interactive-ai-session.test.ts": 100, + "packages/engine/src/__tests__/invariant-paused-todo-normalization.test.ts": 200, + "packages/engine/src/__tests__/invariant-stranded-in-review-recovery.test.ts": 100, + "packages/engine/src/__tests__/invariant-wrong-checkout-completion.test.ts": 100, + "packages/engine/src/__tests__/logger.test.ts": 100, + "packages/engine/src/__tests__/manual-merge-bypass.test.ts": 100, + "packages/engine/src/__tests__/merge-error-recovery.test.ts": 100, + "packages/engine/src/__tests__/merger-ai-merge-body.test.ts": 100, + "packages/engine/src/__tests__/merger-ai.test.ts": 8700, + "packages/engine/src/__tests__/merger-ancestor-shortcircuit.test.ts": 2500, + "packages/engine/src/__tests__/merger-auto-prerebase.real-git.test.ts": 400, + "packages/engine/src/__tests__/merger-auto-prerebase.test.ts": 1200, + "packages/engine/src/__tests__/merger-autostash-cleanup.test.ts": 4300, + "packages/engine/src/__tests__/merger-autostash-orphan-surface.test.ts": 3600, + "packages/engine/src/__tests__/merger-classify-owned-landed-evidence.test.ts": 2100, + "packages/engine/src/__tests__/merger-commit-strategy.real-git.test.ts": 1900, + "packages/engine/src/__tests__/merger-conflict-resolution.test.ts": 100, + "packages/engine/src/__tests__/merger-cwd-fallback-removed.test.ts": 3700, + "packages/engine/src/__tests__/merger-diff-scope.test.ts": 100, + "packages/engine/src/__tests__/merger-empty-cherry-pick-fallback.test.ts": 2400, + "packages/engine/src/__tests__/merger-empty-cherry-pick.test.ts": 3200, + "packages/engine/src/__tests__/merger-file-scope-invariant.test.ts": 100, + "packages/engine/src/__tests__/merger-finalize-unproven.real-git.test.ts": 2000, + "packages/engine/src/__tests__/merger-gitignored-path-guard.test.ts": 2800, + "packages/engine/src/__tests__/merger-integration-worktree.test.ts": 100, + "packages/engine/src/__tests__/merger-landed-files-capture.test.ts": 100, + "packages/engine/src/__tests__/merger-layer3-scope-partition.test.ts": 100, + "packages/engine/src/__tests__/merger-merge-attempt-audit.test.ts": 100, + "packages/engine/src/__tests__/merger-merge-details.test.ts": 100, + "packages/engine/src/__tests__/merger-merge-lifecycle.test.ts": 100, + "packages/engine/src/__tests__/merger-no-op-fix-finalize.test.ts": 1600, + "packages/engine/src/__tests__/merger-orphan-rehome.test.ts": 2200, + "packages/engine/src/__tests__/merger-post-merge-audit-rangebase.test.ts": 2100, + "packages/engine/src/__tests__/merger-post-merge.test.ts": 100, + "packages/engine/src/__tests__/merger-post-push-stats-refresh.test.ts": 100, + "packages/engine/src/__tests__/merger-prompt-and-utils.test.ts": 100, + "packages/engine/src/__tests__/merger-rebase-base-sha.test.ts": 100, + "packages/engine/src/__tests__/merger-ref-update-advance.test.ts": 2600, + "packages/engine/src/__tests__/merger-scope-auto-widen.test.ts": 100, + "packages/engine/src/__tests__/merger-session-recovery.test.ts": 100, + "packages/engine/src/__tests__/merger-skills.test.ts": 100, + "packages/engine/src/__tests__/merger-skip-already-done.test.ts": 100, + "packages/engine/src/__tests__/merger-squash-audit.test.ts": 3700, + "packages/engine/src/__tests__/merger-verification-fix-already-on-main.test.ts": 1100, + "packages/engine/src/__tests__/merger-verification.test.ts": 100, + "packages/engine/src/__tests__/mesh-lease-manager.test.ts": 100, + "packages/engine/src/__tests__/message-notification-pipeline.integration.test.ts": 400, + "packages/engine/src/__tests__/message-notification-pipeline.test.ts": 100, + "packages/engine/src/__tests__/mission-autopilot-end-to-end.test.ts": 100, + "packages/engine/src/__tests__/mission-autopilot.test.ts": 100, + "packages/engine/src/__tests__/mission-execution-loop.test.ts": 100, + "packages/engine/src/__tests__/mission-factory-parity.integration.test.ts": 100, + "packages/engine/src/__tests__/mission-scheduler.test.ts": 100, + "packages/engine/src/__tests__/mock-provider.test.ts": 100, + "packages/engine/src/__tests__/node-dispatch-validation.test.ts": 100, + "packages/engine/src/__tests__/node-health-monitor.test.ts": 100, + "packages/engine/src/__tests__/node-routing-policy.test.ts": 100, + "packages/engine/src/__tests__/notification-service.test.ts": 600, + "packages/engine/src/__tests__/notifier.test.ts": 100, + "packages/engine/src/__tests__/ntfy-provider.test.ts": 100, + "packages/engine/src/__tests__/openclaw-runtime-e2e.test.ts": 100, + "packages/engine/src/__tests__/openclaw-runtime-integration.test.ts": 100, + "packages/engine/src/__tests__/owning-node-handoff-policy.test.ts": 100, + "packages/engine/src/__tests__/owning-node-handoff.integration.test.ts": 300, + "packages/engine/src/__tests__/paperclip-runtime-e2e.test.ts": 100, + "packages/engine/src/__tests__/paperclip-runtime-integration.test.ts": 100, + "packages/engine/src/__tests__/parse-porcelain-z.test.ts": 100, + "packages/engine/src/__tests__/peer-exchange-service.test.ts": 100, + "packages/engine/src/__tests__/permanent-agent-gating.test.ts": 100, + "packages/engine/src/__tests__/persist-thinking-routing.test.ts": 100, + "packages/engine/src/__tests__/pi-create-fn-agent.test.ts": 300, + "packages/engine/src/__tests__/pi-layers-wiring.test.ts": 100, + "packages/engine/src/__tests__/pi-prompt-section-compaction.test.ts": 100, + "packages/engine/src/__tests__/pi-prompt-session-and-check-recursion.test.ts": 700, + "packages/engine/src/__tests__/pi-prompt-with-fallback-recursion.test.ts": 100, + "packages/engine/src/__tests__/pi-session-shutdown.test.ts": 100, + "packages/engine/src/__tests__/pi.test.ts": 100, + "packages/engine/src/__tests__/plan-review-unavailable-recovery.test.ts": 100, + "packages/engine/src/__tests__/plugin-runner.test.ts": 300, + "packages/engine/src/__tests__/plugin-skill-integration.test.ts": 100, + "packages/engine/src/__tests__/post-merge-audit-action.test.ts": 100, + "packages/engine/src/__tests__/post-merge-audit-emission.test.ts": 100, + "packages/engine/src/__tests__/pr-changes-requested.test.ts": 100, + "packages/engine/src/__tests__/pr-comment-handler.test.ts": 100, + "packages/engine/src/__tests__/pr-monitor.test.ts": 100, + "packages/engine/src/__tests__/project-engine-manager.test.ts": 200, + "packages/engine/src/__tests__/project-engine-soft-delete-merge-abort.test.ts": 100, + "packages/engine/src/__tests__/project-engine.test.ts": 600, + "packages/engine/src/__tests__/project-manager.test.ts": 100, + "packages/engine/src/__tests__/project-runtime.test.ts": 100, + "packages/engine/src/__tests__/prompt-cache-integration.test.ts": 100, + "packages/engine/src/__tests__/prompt-layers-backward-compat.test.ts": 100, + "packages/engine/src/__tests__/prompt-layers.test.ts": 100, + "packages/engine/src/__tests__/provider-adapters.test.ts": 100, + "packages/engine/src/__tests__/rate-limit-retry.test.ts": 100, + "packages/engine/src/__tests__/real-git/commit-msg-trailer.real-git.test.ts": 1400, + "packages/engine/src/__tests__/real-git/integration-branch-master.real-git.test.ts": 600, + "packages/engine/src/__tests__/real-git/prepare-commit-msg-empty-guard.real-git.test.ts": 1700, + "packages/engine/src/__tests__/reconcile-step-regex.test.ts": 100, + "packages/engine/src/__tests__/recovery-policy.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/active-worktree-removal-liveness.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/ai-merge-ff-landed-files.test.ts": 1300, + "packages/engine/src/__tests__/reliability-interactions/audit-and-recovery.test.ts": 1800, + "packages/engine/src/__tests__/reliability-interactions/auto-prerebase-interactions.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/auto-recovery-contamination.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/auto-recovery-dispatch.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/auto-recovery-message-delivery.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/auto-revive-and-watchdog.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/backward-move-triple-proof.test.ts": 1900, + "packages/engine/src/__tests__/reliability-interactions/board-stall-auto-recovery.test.ts": 300, + "packages/engine/src/__tests__/reliability-interactions/branch-autocorrect-no-create-from-head.real-git.test.ts": 1200, + "packages/engine/src/__tests__/reliability-interactions/branch-group-automerge-precedence.test.ts": 9000, + "packages/engine/src/__tests__/reliability-interactions/branch-group-merge-routing.test.ts": 8400, + "packages/engine/src/__tests__/reliability-interactions/branch-group-promotion-gate.test.ts": 8400, + "packages/engine/src/__tests__/reliability-interactions/branch-group-promotion.test.ts": 6100, + "packages/engine/src/__tests__/reliability-interactions/branch-recovery-live-zero-commits.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/branch-recovery-stale-cached-base.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/branch-worktree-auto-recovery.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/completion-fanout-x-self-healing.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/completion-handoff-limbo.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/concurrent-execute-race.test.ts": 200, + "packages/engine/src/__tests__/reliability-interactions/cross-node-assignment-wake.test.ts": 200, + "packages/engine/src/__tests__/reliability-interactions/cwd-integration-fallback-removed.test.ts": 0, + "packages/engine/src/__tests__/reliability-interactions/dashboard-diff-boundary.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/dependency-cycle-reconcile.test.ts": 1100, + "packages/engine/src/__tests__/reliability-interactions/dirty-integration-worktree.real-git.test.ts": 1100, + "packages/engine/src/__tests__/reliability-interactions/done-task-verification-benign.real-git.test.ts": 800, + "packages/engine/src/__tests__/reliability-interactions/dual-observe-merge-seam.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/duplicate-task-auto-archive.test.ts": 300, + "packages/engine/src/__tests__/reliability-interactions/engine-active-since-floor.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/engine-stop-aborts-execution.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/executing-task-lock.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/executor-liveness-gate.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/executor-no-task-done-vs-worktree-reclaim.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/executor-pending-review-skip-retry.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/explicit-duplicate-marker-sweep.test.ts": 4100, + "packages/engine/src/__tests__/reliability-interactions/foreign-only-contamination-recovery.real-git.test.ts": 1300, + "packages/engine/src/__tests__/reliability-interactions/foreign-start-point-no-owned-commit.real-git.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/ghost-bug-preflight.test.ts": 700, + "packages/engine/src/__tests__/reliability-interactions/in-progress-limbo-recovery.test.ts": 1300, + "packages/engine/src/__tests__/reliability-interactions/in-review-automerge-off.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/in-review-branch-rebind.test.ts": 2600, + "packages/engine/src/__tests__/reliability-interactions/in-review-handoff-atomic.test.ts": 500, + "packages/engine/src/__tests__/reliability-interactions/in-review-retry-exhausted-policy-convergence.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/in-review-stall-deadlock-disposition.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/in-review-stalled-detector.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/integration-worktree-state.test.ts": 4900, + "packages/engine/src/__tests__/reliability-interactions/integrity-warning-persisted-dedup.test.ts": 1100, + "packages/engine/src/__tests__/reliability-interactions/landed-content-soft-blocker.real-git.test.ts": 700, + "packages/engine/src/__tests__/reliability-interactions/landed-files-attribution.test.ts": 2100, + "packages/engine/src/__tests__/reliability-interactions/layer3-ai-arbiter-file-scope.real-git.test.ts": 800, + "packages/engine/src/__tests__/reliability-interactions/lease-recovery-central-claim.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/merge-request-cancel-on-hard-cancel.test.ts": 300, + "packages/engine/src/__tests__/reliability-interactions/merge-request-shadow-handoff.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/merge-strategy-and-overlap.test.ts": 1800, + "packages/engine/src/__tests__/reliability-interactions/meta-archive-guard-composition.test.ts": 700, + "packages/engine/src/__tests__/reliability-interactions/meta-chain-auto-close.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/misrouted-foreign-commit.real-git.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/mission-stranded-feature-retriage.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/mission-validation-trigger-gap.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/mission-validator-run-reaper.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/multi-node-claim-mutex-interactions.test.ts": 200, + "packages/engine/src/__tests__/reliability-interactions/near-duplicate-intake.test.ts": 900, + "packages/engine/src/__tests__/reliability-interactions/no-changes-finalized.real-git.test.ts": 400, + "packages/engine/src/__tests__/reliability-interactions/node-settings-sync-auth.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/non-progress-churn.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/orphan-detected-no-requeue.test.ts": 1700, + "packages/engine/src/__tests__/reliability-interactions/owning-node-unavailable-interactions.test.ts": 1200, + "packages/engine/src/__tests__/reliability-interactions/paused-scope-decay.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/post-completion-stale-self-owned-binding.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/post-done-continuation-no-wedge.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/post-finalize-verification-noop-status-write.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/post-finalize-verification-noop.real-git.test.ts": 1200, + "packages/engine/src/__tests__/reliability-interactions/pr-changes-requested-reexecution.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/pr-conflict-reclaim.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/pr-merged-auto-transition.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/pr-mode-worktree-invariants.test.ts": 1800, + "packages/engine/src/__tests__/reliability-interactions/precommit-identity-guard.real-git.test.ts": 3400, + "packages/engine/src/__tests__/reliability-interactions/reap-unregistered-orphans-defers-active-session.test.ts": 400, + "packages/engine/src/__tests__/reliability-interactions/reclaim-defers-on-active-session.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/reclaim-defers-on-in-flight-executor.test.ts": 800, + "packages/engine/src/__tests__/reliability-interactions/reclaim-self-owned-resume-limbo-escalation.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/scheduler-overlap-priority-inversion.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/scope-auto-widen.real-git.test.ts": 2400, + "packages/engine/src/__tests__/reliability-interactions/secrets-env-materialization.test.ts": 300, + "packages/engine/src/__tests__/reliability-interactions/secrets-sync-cross-node.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/self-defeating-dep-reconcile.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/self-healing-interactions.test.ts": 500, + "packages/engine/src/__tests__/reliability-interactions/self-healing-multi-pr.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/shared-branch-group-lifecycle.test.ts": 13900, + "packages/engine/src/__tests__/reliability-interactions/shared-branch-group-working-branch.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/shared-group-member-integration.test.ts": 4300, + "packages/engine/src/__tests__/reliability-interactions/soft-blocker-auto-finalize-interactions.real-git.test.ts": 2000, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-audit-and-column.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-blocker-residue.test.ts": 500, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-deadlock-scan-exclusion.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-end-to-end.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-in-flight-abort.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/soft-delete-stickiness-FN-5233.test.ts": 400, + "packages/engine/src/__tests__/reliability-interactions/stale-self-owned-active-session-recovery.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/stale-self-owned-session-registry.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/starved-refinement-x-approval-gate.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/starved-refinement-x-triage-poll.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/task-done-refusal-x-invariant.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/verification-fix-already-on-main.real-git.test.ts": 1100, + "packages/engine/src/__tests__/reliability-interactions/verification-followup-dedup.test.ts": 300, + "packages/engine/src/__tests__/reliability-interactions/verification-spawn-supervision.real-git.test.ts": 1200, + "packages/engine/src/__tests__/reliability-interactions/workflow-and-file-scope.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/workflow-interpreter-dual-observe.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/worktree-contamination-attribution.real-git.test.ts": 1700, + "packages/engine/src/__tests__/reliability-interactions/worktree-incomplete-session-start.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/worktree-init-stderr-surfacing.test.ts": 600, + "packages/engine/src/__tests__/reliability-interactions/worktree-metadata-reconcile.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/worktree-pool-merger-release.test.ts": 2000, + "packages/engine/src/__tests__/reliability-interactions/worktree-stale-lock-recovery.test.ts": 400, + "packages/engine/src/__tests__/reliability-interactions/worktree-stale-registration-recovery.real-git.test.ts": 1000, + "packages/engine/src/__tests__/reliability-interactions/worktrunk-audit.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/worktrunk-failure.test.ts": 500, + "packages/engine/src/__tests__/reliability-interactions/worktrunk-self-healing.test.ts": 100, + "packages/engine/src/__tests__/reliability-interactions/worktrunk-worktree-removal.test.ts": 100, + "packages/engine/src/__tests__/research-dispatcher.test.ts": 200, + "packages/engine/src/__tests__/research-orchestrator.test.ts": 100, + "packages/engine/src/__tests__/research-step-runner.test.ts": 100, + "packages/engine/src/__tests__/restart-recovery-coordinator.test.ts": 100, + "packages/engine/src/__tests__/restart.integration.test.ts": 300, + "packages/engine/src/__tests__/retry-burned-logger.test.ts": 100, + "packages/engine/src/__tests__/reviewer-prompt-layers.test.ts": 100, + "packages/engine/src/__tests__/reviewer.test.ts": 100, + "packages/engine/src/__tests__/room-ambiguity.test.ts": 100, + "packages/engine/src/__tests__/room-coordination.test.ts": 100, + "packages/engine/src/__tests__/routine-runner-sandbox-audit.test.ts": 100, + "packages/engine/src/__tests__/routine-runner.test.ts": 400, + "packages/engine/src/__tests__/routine-scheduler.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/executor-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/heartbeat-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/merger-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/mission-exec-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/no-auditor-backcompat.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/reviewer-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-agent-session/triage-emit.test.ts": 100, + "packages/engine/src/__tests__/run-audit-secret-taxonomy.test.ts": 100, + "packages/engine/src/__tests__/run-audit-session-runtime-resolved.test.ts": 100, + "packages/engine/src/__tests__/run-audit-worktrunk.test.ts": 100, + "packages/engine/src/__tests__/run-audit.integration.test.ts": 100, + "packages/engine/src/__tests__/run-audit.sandbox.test.ts": 100, + "packages/engine/src/__tests__/run-audit.test.ts": 100, + "packages/engine/src/__tests__/run-verification-command.test.ts": 100, + "packages/engine/src/__tests__/runtime-resolution.test.ts": 100, + "packages/engine/src/__tests__/runtime-selection-regression.test.ts": 100, + "packages/engine/src/__tests__/sandbox-wiring-audit.test.ts": 200, + "packages/engine/src/__tests__/sandbox-wiring.test.ts": 100, + "packages/engine/src/__tests__/sandbox/bubblewrap-backend.test.ts": 900, + "packages/engine/src/__tests__/sandbox/bubblewrap-detect.test.ts": 100, + "packages/engine/src/__tests__/sandbox/bubblewrap-policy.test.ts": 100, + "packages/engine/src/__tests__/sandbox/sandbox-exec-backend.test.ts": 100, + "packages/engine/src/__tests__/sandbox/sandbox-exec-detect.test.ts": 100, + "packages/engine/src/__tests__/sandbox/sandbox-exec-policy.test.ts": 100, + "packages/engine/src/__tests__/scheduler-auto-claim-invalidation.test.ts": 100, + "packages/engine/src/__tests__/scheduler-ephemeral-toggle.test.ts": 100, + "packages/engine/src/__tests__/scheduler-node-routing.test.ts": 100, + "packages/engine/src/__tests__/scheduler-node-unreachable-audit.test.ts": 100, + "packages/engine/src/__tests__/scheduler-overlap-requeue.test.ts": 100, + "packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts": 100, + "packages/engine/src/__tests__/scheduler.test.ts": 100, + "packages/engine/src/__tests__/scope-leak-changeset-allowlist.test.ts": 100, + "packages/engine/src/__tests__/secrets-env-writer.test.ts": 100, + "packages/engine/src/__tests__/self-healing-agent-link-drift.test.ts": 100, + "packages/engine/src/__tests__/self-healing-already-merged.real-git.test.ts": 4900, + "packages/engine/src/__tests__/self-healing-chat-cleanup.test.ts": 100, + "packages/engine/src/__tests__/self-healing-completion-fanout.test.ts": 100, + "packages/engine/src/__tests__/self-healing-db-corruption.test.ts": 300, + "packages/engine/src/__tests__/self-healing-fn-5488-fast-path-regressions.test.ts": 100, + "packages/engine/src/__tests__/self-healing-foreign-only-contamination.test.ts": 100, + "packages/engine/src/__tests__/self-healing-ghost-branch-recovery.test.ts": 100, + "packages/engine/src/__tests__/self-healing-in-progress-limbo.test.ts": 100, + "packages/engine/src/__tests__/self-healing-mail-cleanup.test.ts": 300, + "packages/engine/src/__tests__/self-healing-meta-archive-guards.test.ts": 2700, + "packages/engine/src/__tests__/self-healing-orphan-only-scope.real-git.test.ts": 300, + "packages/engine/src/__tests__/self-healing-orphan-only-scope.test.ts": 100, + "packages/engine/src/__tests__/self-healing-pr-conflict.test.ts": 300, + "packages/engine/src/__tests__/self-healing-rebind.test.ts": 2500, + "packages/engine/src/__tests__/self-healing-reclaim-live-zero-commits.test.ts": 100, + "packages/engine/src/__tests__/self-healing-reclaim-paused-review.test.ts": 300, + "packages/engine/src/__tests__/self-healing-stale-merge-fanout.test.ts": 100, + "packages/engine/src/__tests__/self-healing-stale-merge-stats.real-git.test.ts": 2700, + "packages/engine/src/__tests__/self-healing-stale-merger-status.test.ts": 100, + "packages/engine/src/__tests__/self-healing-starved-refinement.test.ts": 100, + "packages/engine/src/__tests__/self-healing-worktree-metadata.test.ts": 1300, + "packages/engine/src/__tests__/self-healing.test.ts": 200, + "packages/engine/src/__tests__/session-skill-context.test.ts": 100, + "packages/engine/src/__tests__/session-token-usage.test.ts": 100, + "packages/engine/src/__tests__/shell-utils.test.ts": 100, + "packages/engine/src/__tests__/skill-resolver.test.ts": 100, + "packages/engine/src/__tests__/spec-staleness.test.ts": 100, + "packages/engine/src/__tests__/spec-validation-external-integration-evidence.test.ts": 100, + "packages/engine/src/__tests__/spec-validation-task-document-references.test.ts": 100, + "packages/engine/src/__tests__/stale-task-reporter.test.ts": 100, + "packages/engine/src/__tests__/step-session-executor.test.ts": 100, + "packages/engine/src/__tests__/streaming-delta.test.ts": 100, + "packages/engine/src/__tests__/stuck-task-detector.test.ts": 100, + "packages/engine/src/__tests__/task-agent-sync.test.ts": 100, + "packages/engine/src/__tests__/task-completion.test.ts": 100, + "packages/engine/src/__tests__/test-isolation-guard.test.ts": 100, + "packages/engine/src/__tests__/token-budget-enforcer.test.ts": 100, + "packages/engine/src/__tests__/token-cap-detector.test.ts": 100, + "packages/engine/src/__tests__/token-usage-cache-ratio.test.ts": 100, + "packages/engine/src/__tests__/transient-error-detector.test.ts": 100, + "packages/engine/src/__tests__/triage-duplicate-search-regression.test.ts": 100, + "packages/engine/src/__tests__/triage-explicit-duplicate-marker.test.ts": 100, + "packages/engine/src/__tests__/triage-finalize-duplicate-lineage.test.ts": 100, + "packages/engine/src/__tests__/triage-preflight.test.ts": 100, + "packages/engine/src/__tests__/triage-refinement-routing.test.ts": 100, + "packages/engine/src/__tests__/triage-review-spec-dangling-refs.test.ts": 100, + "packages/engine/src/__tests__/triage-review-spec-external-integration.test.ts": 100, + "packages/engine/src/__tests__/triage-soft-delete-abort.test.ts": 100, + "packages/engine/src/__tests__/triage-soft-delete-write-abort.test.ts": 100, + "packages/engine/src/__tests__/triage-split-into-subtasks-delete.test.ts": 100, + "packages/engine/src/__tests__/triage.test.ts": 400, + "packages/engine/src/__tests__/tunnel-process-manager.test.ts": 100, + "packages/engine/src/__tests__/usage-limit-detector.test.ts": 100, + "packages/engine/src/__tests__/verification-followup-dedup.test.ts": 300, + "packages/engine/src/__tests__/verification-utils.test.ts": 900, + "packages/engine/src/__tests__/verify-worktree-invariants-missing.test.ts": 100, + "packages/engine/src/__tests__/web-fetch-universal.test.ts": 100, + "packages/engine/src/__tests__/web-fetch.test.ts": 100, + "packages/engine/src/__tests__/webhook-provider.test.ts": 100, + "packages/engine/src/__tests__/workflow-graph-executor-handlers.test.ts": 100, + "packages/engine/src/__tests__/workflow-graph-executor-parity.test.ts": 100, + "packages/engine/src/__tests__/workflow-node-handlers.test.ts": 100, + "packages/engine/src/__tests__/workflow-step-readonly-allowlist.test.ts": 100, + "packages/engine/src/__tests__/workflow-step-template-verdicts.test.ts": 100, + "packages/engine/src/__tests__/workflow-step-verdict-parsing.test.ts": 100, + "packages/engine/src/__tests__/worktree-acquisition-backend.test.ts": 100, + "packages/engine/src/__tests__/worktree-acquisition-secrets-env.test.ts": 100, + "packages/engine/src/__tests__/worktree-acquisition-worktrunk.test.ts": 100, + "packages/engine/src/__tests__/worktree-acquisition.test.ts": 300, + "packages/engine/src/__tests__/worktree-admin-entry-prune.test.ts": 900, + "packages/engine/src/__tests__/worktree-backend-no-execsync.test.ts": 100, + "packages/engine/src/__tests__/worktree-backend.test.ts": 100, + "packages/engine/src/__tests__/worktree-db-hydrate.test.ts": 1900, + "packages/engine/src/__tests__/worktree-desktop-artifacts.test.ts": 100, + "packages/engine/src/__tests__/worktree-hooks-cross-platform.test.ts": 100, + "packages/engine/src/__tests__/worktree-hooks.test.ts": 1200, + "packages/engine/src/__tests__/worktree-names.test.ts": 100, + "packages/engine/src/__tests__/worktree-paths.test.ts": 100, + "packages/engine/src/__tests__/worktree-pool-double-lease.test.ts": 100, + "packages/engine/src/__tests__/worktree-pool-liveness.test.ts": 2100, + "packages/engine/src/__tests__/worktree-pool-secrets-env-cleanup.test.ts": 200, + "packages/engine/src/__tests__/worktree-pool.test.ts": 100, + "packages/engine/src/__tests__/worktree-reanchor-nested-root.test.ts": 100, + "packages/engine/src/__tests__/worktree-stale-lock.test.ts": 100, + "packages/engine/src/__tests__/worktree-stale-registration.test.ts": 100, + "packages/engine/src/__tests__/worktrunk-failure-handler.test.ts": 100, + "packages/engine/src/__tests__/worktrunk-installer.test.ts": 100, + "packages/engine/src/ipc/__tests__/ipc-host.test.ts": 100, + "packages/engine/src/ipc/__tests__/ipc-protocol.test.ts": 100, + "packages/engine/src/ipc/__tests__/ipc-worker.test.ts": 200, + "packages/engine/src/notification/__tests__/notification-service.test.ts": 100, + "packages/engine/src/notification/__tests__/oauth-alert-state.test.ts": 100, + "packages/engine/src/notification/__tests__/oauth-expiry-monitor.test.ts": 100, + "packages/engine/src/notification/__tests__/oauth-validity-logger.test.ts": 100, + "packages/engine/src/research/__tests__/provider-registry.test.ts": 100, + "packages/engine/src/research/providers/__tests__/github-provider.test.ts": 100, + "packages/engine/src/research/providers/__tests__/llm-synthesis-provider.test.ts": 100, + "packages/engine/src/research/providers/__tests__/local-docs-provider.test.ts": 100, + "packages/engine/src/research/providers/__tests__/page-fetch-provider.test.ts": 100, + "packages/engine/src/research/providers/__tests__/web-search-provider.test.ts": 100, + "packages/engine/src/runtimes/__tests__/child-process-runtime.test.ts": 100, + "packages/engine/src/runtimes/__tests__/child-process-worker.test.ts": 100, + "packages/engine/src/runtimes/__tests__/in-process-runtime.test.ts": 7800, + "packages/engine/src/runtimes/__tests__/remote-node-client.test.ts": 100, + "packages/engine/src/runtimes/__tests__/remote-node-runtime.test.ts": 100, + "packages/engine/src/sandbox/__tests__/audit.test.ts": 100, + "packages/engine/src/sandbox/__tests__/container-argv.test.ts": 100, + "packages/engine/src/sandbox/__tests__/container.test.ts": 100, + "packages/engine/src/sandbox/__tests__/native-streaming.test.ts": 100, + "packages/engine/src/sandbox/__tests__/native.test.ts": 200, + "packages/engine/src/sandbox/__tests__/provisioning-gate.test.ts": 100, + "packages/engine/src/sandbox/__tests__/resolve.test.ts": 100, + "packages/engine/src/sandbox/__tests__/types.test.ts": 100 + } + }, + "@runfusion/fusion": { + "files": { + "packages/cli/src/__tests__/bin-pr-router.test.ts": 100, + "packages/cli/src/__tests__/bin-targets.test.ts": 100, + "packages/cli/src/__tests__/bin.test.ts": 3200, + "packages/cli/src/__tests__/bundle-output-helpers.test.ts": 100, + "packages/cli/src/__tests__/bundle-output.test.ts": 200, + "packages/cli/src/__tests__/ci-workflow.test.ts": 100, + "packages/cli/src/__tests__/dev-with-memory-lib.test.ts": 100, + "packages/cli/src/__tests__/docker.test.ts": 100, + "packages/cli/src/__tests__/docs-readme-index.test.ts": 100, + "packages/cli/src/__tests__/experiment-finalize.test.ts": 100, + "packages/cli/src/__tests__/extension-agent-provisioning.test.ts": 100, + "packages/cli/src/__tests__/extension-experiment-finalize.test.ts": 100, + "packages/cli/src/__tests__/extension-fn-secret-get.test.ts": 100, + "packages/cli/src/__tests__/extension-format-task-line.test.ts": 100, + "packages/cli/src/__tests__/extension-github-tracking.test.ts": 500, + "packages/cli/src/__tests__/extension-goal-tools-audit.test.ts": 100, + "packages/cli/src/__tests__/extension-goal-tools.test.ts": 300, + "packages/cli/src/__tests__/extension-insights.test.ts": 300, + "packages/cli/src/__tests__/extension-integration.test.ts": 0, + "packages/cli/src/__tests__/extension-mission-goal-tools.test.ts": 200, + "packages/cli/src/__tests__/extension-task-tools.test.ts": 1700, + "packages/cli/src/__tests__/extension-web-fetch.test.ts": 100, + "packages/cli/src/__tests__/extension.test.ts": 7000, + "packages/cli/src/__tests__/goal-store-resolution.test.ts": 100, + "packages/cli/src/__tests__/goals-citations-cli.test.ts": 100, + "packages/cli/src/__tests__/goals-commands.test.ts": 100, + "packages/cli/src/__tests__/package-config.test.ts": 100, + "packages/cli/src/__tests__/plugin-dev.test.ts": 100, + "packages/cli/src/__tests__/plugin-pack-shape.test.ts": 100, + "packages/cli/src/__tests__/plugin-scaffold.test.ts": 100, + "packages/cli/src/__tests__/plugin-sdk-export.test.ts": 100, + "packages/cli/src/__tests__/project-context.test.ts": 300, + "packages/cli/src/__tests__/project-resolver.test.ts": 100, + "packages/cli/src/__tests__/research-extension-tools.test.ts": 1100, + "packages/cli/src/__tests__/root-test-command.test.ts": 100, + "packages/cli/src/__tests__/skill-sync.test.ts": 100, + "packages/cli/src/__tests__/task-delete-allow-resurrection.test.ts": 300, + "packages/cli/src/__tests__/task-plan.test.ts": 100, + "packages/cli/src/__tests__/task-retry.test.ts": 100, + "packages/cli/src/__tests__/task-steer.test.ts": 100, + "packages/cli/src/__tests__/update-cache.test.ts": 100, + "packages/cli/src/__tests__/version.test.ts": 100, + "packages/cli/src/__tests__/vitest-workspace-resolution.test.ts": 1400, + "packages/cli/src/commands/__tests__/agent-export.test.ts": 0, + "packages/cli/src/commands/__tests__/agent-import.test.ts": 200, + "packages/cli/src/commands/__tests__/agent.test.ts": 100, + "packages/cli/src/commands/__tests__/auth-paths.test.ts": 100, + "packages/cli/src/commands/__tests__/backup.test.ts": 100, + "packages/cli/src/commands/__tests__/chat.test.ts": 1300, + "packages/cli/src/commands/__tests__/claude-cli-extension.test.ts": 100, + "packages/cli/src/commands/__tests__/claude-skills.test.ts": 100, + "packages/cli/src/commands/__tests__/custom-provider-registry.test.ts": 100, + "packages/cli/src/commands/__tests__/daemon.test.ts": 100, + "packages/cli/src/commands/__tests__/dashboard.test.ts": 500, + "packages/cli/src/commands/__tests__/db.test.ts": 100, + "packages/cli/src/commands/__tests__/desktop.test.ts": 100, + "packages/cli/src/commands/__tests__/droid-cli-extension.test.ts": 100, + "packages/cli/src/commands/__tests__/ensure-project-registered.test.ts": 100, + "packages/cli/src/commands/__tests__/git.test.ts": 100, + "packages/cli/src/commands/__tests__/init.test.ts": 3400, + "packages/cli/src/commands/__tests__/llama-cpp-extension.test.ts": 100, + "packages/cli/src/commands/__tests__/memory-backup.test.ts": 100, + "packages/cli/src/commands/__tests__/message.test.ts": 100, + "packages/cli/src/commands/__tests__/mission.test.ts": 300, + "packages/cli/src/commands/__tests__/node.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard-autolaunch-backcompat-e2e.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard-autolaunch-backcompat.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard-autolaunch-bypass.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard-autolaunch.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard-docs.test.ts": 100, + "packages/cli/src/commands/__tests__/onboard.test.ts": 100, + "packages/cli/src/commands/__tests__/plugin.test.ts": 400, + "packages/cli/src/commands/__tests__/project.test.ts": 100, + "packages/cli/src/commands/__tests__/provider-auth.test.ts": 100, + "packages/cli/src/commands/__tests__/provider-settings.test.ts": 100, + "packages/cli/src/commands/__tests__/research.test.ts": 100, + "packages/cli/src/commands/__tests__/serve.test.ts": 400, + "packages/cli/src/commands/__tests__/settings-export.test.ts": 100, + "packages/cli/src/commands/__tests__/settings-import.test.ts": 100, + "packages/cli/src/commands/__tests__/settings.test.ts": 100, + "packages/cli/src/commands/__tests__/skills.test.ts": 500, + "packages/cli/src/commands/__tests__/startup-model-sync.test.ts": 100, + "packages/cli/src/commands/__tests__/task-lifecycle.test.ts": 100, + "packages/cli/src/commands/__tests__/task.test.ts": 100, + "packages/cli/src/commands/__tests__/update.test.ts": 100, + "packages/cli/src/commands/dashboard-tui/__tests__/app.test.tsx": 1600, + "packages/cli/src/commands/dashboard-tui/__tests__/available-memory.test.ts": 100, + "packages/cli/src/commands/dashboard-tui/__tests__/log-ring-buffer.test.ts": 100, + "packages/cli/src/commands/dashboard-tui/__tests__/log-sink.test.ts": 100, + "packages/cli/src/commands/dashboard-tui/__tests__/startup-yield.test.ts": 100, + "packages/cli/src/plugins/__tests__/bundled-plugin-install.test.ts": 100, + "packages/cli/src/test/mockCoreEngine.test.ts": 100 + } + } + } +}