FN-6447: rescue session reconnect teardown

Rescue the session reconnect SSE test by shutting down route-owned background work before temp cleanup.

- Isolate the focused API harness from TaskStore EventEmitter startup workers.
- Dispose API routes and scheduled AI session cleanup before deleting the test temp root.
- Remove session-reconnect from the dashboard quarantine ledger and vitest skip list.

Files changed:
 .../src/__tests__/session-reconnect.test.ts        | 22 ++++++++++++++++++----
 packages/dashboard/vitest.config.ts                |  6 ++++--
 scripts/lib/test-quarantine.json                   |  5 -----
 3 files changed, 22 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-6447

Fusion-Task-Lineage: a3fef28c-b92b-4f47-9181-a63bb31e4f48
This commit is contained in:
gsxdsm
2026-06-14 11:25:54 -07:00
parent 12efd3fd3f
commit e526ad2b2c
3 changed files with 22 additions and 11 deletions

View File

@@ -9,7 +9,6 @@ import express from "express";
import { mkdtempSync } from "node:fs";
import { rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { setImmediate } from "node:timers";
import { join } from "node:path";
import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
import { Database, TaskStore } from "@fusion/core";
@@ -105,6 +104,7 @@ describe("session reconnect + replay", () => {
let db: Database;
let aiSessionStore: AiSessionStore;
let app: express.Express;
let apiRouter: express.Router & { dispose?: () => void };
beforeEach(async () => {
vi.clearAllMocks();
@@ -129,7 +129,16 @@ describe("session reconnect + replay", () => {
app = express();
app.use(express.json());
app.use("/api", createApiRoutes(store, { aiSessionStore }));
/*
FNXC:DashboardSessionTests 2026-06-14-12:05:
These SSE replay tests exercise planning/subtask/mission routes, not the EventEmitter-driven GitHub tracking services that createApiRoutes starts for a full TaskStore. Hide on/off for this focused harness so unrelated startup reconcile work cannot touch the temp .fusion tree after the test-owned store closes.
*/
Object.defineProperties(store, {
on: { value: undefined, configurable: true },
off: { value: undefined, configurable: true },
});
apiRouter = createApiRoutes(store, { aiSessionStore }) as express.Router & { dispose?: () => void };
app.use("/api", apiRouter);
});
afterEach(async () => {
@@ -138,6 +147,12 @@ describe("session reconnect + replay", () => {
__resetSubtaskBreakdownState();
__resetMissionInterviewState();
try {
apiRouter.dispose?.();
} catch {
// no-op
}
aiSessionStore.stopScheduledCleanup();
try {
store.close();
} catch {
@@ -148,8 +163,7 @@ describe("session reconnect + replay", () => {
} catch {
// no-op
}
// FNXC:DashboardSessionTests 2026-06-14-09:20: TaskStore.close() closes watcher/database handles synchronously but their filesystem close callbacks settle on the next event-loop turn; drain that turn before deleting .fusion.
await new Promise<void>((resolve) => setImmediate(resolve));
// FNXC:DashboardSessionTests 2026-06-14-12:07: FN-6447 requires teardown to remove tmpRoot only after route-owned background workers are prevented/disposed and both TaskStore/AiSession DB handles are closed; do not use retry-rm loops that can mask a live writer.
await rm(tmpRoot, { recursive: true, force: true });
});

View File

@@ -246,7 +246,10 @@ const quarantinedDashboardTests: string[] = [
FN-6441 removed the dashboard component orphan batch from the curated skip-list so passing rescues run in backfill and still-failing tests are excluded only through the dated quarantine ledger. Keep these one-line excludes mirrored with scripts/lib/test-quarantine.json until each file is rescued or deleted under the deletion ratchet.
FNXC:DashboardTests 2026-06-14-09:58:
FN-6444 applies the same no-silent-orphan invariant to dashboard src route/API tests: rescued files run in backfill, while broad stale mission/planning suites plus the newly observed FN-6447 reconnect temp-cleanup flake are represented only by the dated quarantine ledger.
FN-6444 applies the same no-silent-orphan invariant to dashboard src route/API tests: rescued files run in backfill, while broad stale mission/planning suites are represented only by the dated quarantine ledger.
FNXC:DashboardSessionTests 2026-06-14-12:10:
FN-6447 rescued session-reconnect by isolating the SSE harness from unrelated route background workers, so it must stay out of this quarantine list and run in dashboard-api-quality-backfill.
*/
"app/components/__tests__/ChatView.regular-composer-no-right-line.test.tsx",
"app/components/__tests__/MissionManager.test.tsx",
@@ -261,7 +264,6 @@ const quarantinedDashboardTests: string[] = [
"app/components/__tests__/mobile-css.test.tsx",
"src/__tests__/mission-e2e.test.ts",
"src/__tests__/planning.test.ts",
"src/__tests__/session-reconnect.test.ts",
];
const qualityApiTests = [

View File

@@ -65,11 +65,6 @@
"file": "packages/dashboard/src/__tests__/planning.test.ts",
"reason": "FN-6444: orphaned dashboard planning route/API test is slow and fails standalone across stale agent/session mocks plus temp cleanup leakage. Quarantined instead of widening waits/timeouts or weakening assertions.",
"quarantinedAt": "2026-06-14"
},
{
"file": "packages/dashboard/src/__tests__/session-reconnect.test.ts",
"reason": "FN-6444/FN-6447: dashboard API backfill shard 1 observed ENOTEMPTY temp cleanup leakage while replaying planning buffered events. Quarantined on sight for focused rescue/delete review instead of adding waits or weakening assertions.",
"quarantinedAt": "2026-06-14"
}
]
}