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 <rootDir>/.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).
This commit is contained in:
@@ -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
|
||||
`<rootDir>/.fusion/tasks/<ID>/` 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/<ID>)` 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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user