From 0307476f3583772d869638ececae80be9483eb24 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 23 Jul 2026 17:27:59 -0700 Subject: [PATCH] fix(tests): restore listTasks hot-path contract and PG harness fs isolation - usage-limit-detector + provider-health-monitor: make three bare listTasks() callers explicit with { slim: true }, restoring the architecture-hot-paths contract (they only read scalar pause/column/model-provider fields). - pg-test-harness beforeEach: wipe /.fusion/tasks after TRUNCATE ... RESTART IDENTITY so filesystem isolation matches the id reset; stale task dirs from prior tests no longer collide with reused IDs (fixes store-reservation-atomicity rollback assertions). --- packages/core/src/__test-utils__/pg-test-harness.ts | 13 +++++++++++++ packages/dashboard/src/provider-health-monitor.ts | 3 ++- packages/engine/src/usage-limit-detector.ts | 6 ++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/core/src/__test-utils__/pg-test-harness.ts b/packages/core/src/__test-utils__/pg-test-harness.ts index affd881f1a..6845f30fd1 100644 --- a/packages/core/src/__test-utils__/pg-test-harness.ts +++ b/packages/core/src/__test-utils__/pg-test-harness.ts @@ -1004,6 +1004,19 @@ export function createSharedPgTaskStoreTestHarness(options?: { ON CONFLICT (project_id) DO UPDATE SET next_id = 1, next_workflow_step_id = 1, settings = EXCLUDED.settings, workflow_steps = '[]'::jsonb, updated_at = now()`, ), ); + /* + FNXC:PgTestHarnessIsolation 2026-07-22-17:40: + TRUNCATE ... RESTART IDENTITY resets next_id so the next created task reuses + the same ID (KB-001) as prior tests in this describe. The DB reset is not + enough on its own: task creation also materializes an on-disk + `/.fusion/tasks//` directory (task.json + PROMPT.md), which the + truncate leaves behind. A later test that reuses that ID then sees a stale + canonical directory it never created, so rollback/atomicity assertions like + store-reservation-atomicity's `existsSync(.fusion/tasks/)` toBe(false) + fail on leftover files. Wipe the task-directory tree so filesystem isolation + matches the identity reset. + */ + await rm(join(harness.rootDir, ".fusion", "tasks"), { recursive: true, force: true }); // Drop any in-memory caches so the store doesn't serve stale rows. resetStorePrivateState(store); // Force allocator reconciliation to re-seed the distributed state row. diff --git a/packages/dashboard/src/provider-health-monitor.ts b/packages/dashboard/src/provider-health-monitor.ts index 5172b88698..a5f9b04f5c 100644 --- a/packages/dashboard/src/provider-health-monitor.ts +++ b/packages/dashboard/src/provider-health-monitor.ts @@ -134,7 +134,8 @@ export class ProviderHealthMonitor { await Promise.all(stores.map(async (store) => { try { - const tasks = await store.listTasks(); + // FNXC:ArchitectureHotPath 2026-07-22-17:20: listTasks() must declare payload shape (architecture-hot-paths contract). Health scan reads only paused/userPaused/pausedReason scalars, so request slim rows. + const tasks = await store.listTasks({ slim: true }); for (const task of tasks) { if (task.paused !== true || task.userPaused === true) continue; const providerId = providerIdFromRateLimitReason(task.pausedReason); diff --git a/packages/engine/src/usage-limit-detector.ts b/packages/engine/src/usage-limit-detector.ts index f81193e99a..0f886e5a85 100644 --- a/packages/engine/src/usage-limit-detector.ts +++ b/packages/engine/src/usage-limit-detector.ts @@ -93,7 +93,8 @@ export class UsageLimitPauser { if (!providerId) return 0; const pausedReason = `provider-rate-limit:${providerId}`; - const tasks = await this.store.listTasks(); + // FNXC:ArchitectureHotPath 2026-07-22-17:20: listTasks() must be explicit about payload shape (architecture-hot-paths contract). Recovery only reads scalar pause fields, so request slim rows to avoid loading heavy log/steps/comments for every task. + const tasks = await this.store.listTasks({ slim: true }); const recoverableTasks = tasks.filter((task) => task.paused === true && task.userPaused !== true @@ -166,7 +167,8 @@ export class UsageLimitPauser { const [settings, tasks] = await Promise.all([ this.store.getSettings(), - this.store.listTasks(), + // FNXC:ArchitectureHotPath 2026-07-22-17:20: slim payload — this scan only reads column/pause/model-provider scalars, never heavy detail fields. + this.store.listTasks({ slim: true }), ]); const affectedTasks = tasks.filter((task) => task.column !== "done"