From e7d0c37c4ed6f7d8d321da73e1d016c258bbf968 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 12 Aug 2026 17:03:11 -0700 Subject: [PATCH] test(sse): drive agent-activity durable poll via env seam instead of 2.1s real sleep Replace the fixed ~2.1s real time-wait in the agent-activity SSE durable integration test with a bounded FUSION_AGENT_ACTIVITY_POLL_MS env test-seam (default 2000ms unchanged in production) and poll for the delivered frame. Removes an FN-5048 real time-wait anti-pattern; production behavior unchanged. --- .../src/__tests__/sse-agent-activity.test.ts | 22 ++++++++++++++----- packages/dashboard/src/sse.ts | 20 ++++++++++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/dashboard/src/__tests__/sse-agent-activity.test.ts b/packages/dashboard/src/__tests__/sse-agent-activity.test.ts index d5e56c8d25..6dfbc8f8ae 100644 --- a/packages/dashboard/src/__tests__/sse-agent-activity.test.ts +++ b/packages/dashboard/src/__tests__/sse-agent-activity.test.ts @@ -289,6 +289,10 @@ pgDescribe("agent activity SSE durable integration", () => { afterAll(h.afterAll); it("delivers an out-of-process-shaped persisted append through the seq tail", async () => { + // FNXC:AgentActivityStream 2026-08-12-00:00: drive the real durable poll fast via its + // bounded env test-seam instead of sleeping a full 2s production cycle (FN-5048). + const priorPollMs = process.env.FUSION_AGENT_ACTIVITY_POLL_MS; + process.env.FUSION_AGENT_ACTIVITY_POLL_MS = "20"; const realCore = await vi.importActual("@fusion/core"); getMaxAgentActivitySeq.mockReset().mockImplementation((layer) => realCore.getMaxAgentActivitySeq(layer)); queryAgentActivityEvents.mockReset().mockImplementation((layer, query) => realCore.queryAgentActivityEvents(layer, query)); @@ -311,15 +315,23 @@ pgDescribe("agent activity SSE durable integration", () => { discriminator: "external-exec-after-connect", metadata: { runId: "exec-FN-8864-1234567891-abcd" }, }); - // No store.emit: the poll is the delivery guarantee for external writers. - await new Promise((resolve) => setTimeout(resolve, 2_100)); - const frames = response.write.mock.calls - .map(([frame]) => String(frame)) - .filter((frame) => frame.startsWith("event: agent:activity")); + // No store.emit: the poll is the delivery guarantee for external writers. Poll for the + // frame rather than sleeping a fixed cycle so the test tracks real delivery, not a timer. + const agentActivityFrames = () => + response.write.mock.calls + .map(([frame]) => String(frame)) + .filter((frame) => frame.startsWith("event: agent:activity")); + const deadline = Date.now() + 5_000; + while (agentActivityFrames().length < 1 && Date.now() < deadline) { + await new Promise((resolve) => setTimeout(resolve, 20)); + } + const frames = agentActivityFrames(); expect(frames).toHaveLength(1); expect(JSON.parse(frames[0]!.split("data: ")[1]!.trim())).toMatchObject({ seq: "1", taskId: "FN-8864" }); } finally { response.emit("close"); + if (priorPollMs === undefined) delete process.env.FUSION_AGENT_ACTIVITY_POLL_MS; + else process.env.FUSION_AGENT_ACTIVITY_POLL_MS = priorPollMs; } }); }); diff --git a/packages/dashboard/src/sse.ts b/packages/dashboard/src/sse.ts index 09234647a4..f2858a249d 100644 --- a/packages/dashboard/src/sse.ts +++ b/packages/dashboard/src/sse.ts @@ -53,6 +53,24 @@ function sseDebug(message: string): void { sseLog.debug(message); } +/* +FNXC:AgentActivityStream 2026-08-12-00:00: +The durable agent-activity seq tail polls every 2s in production — that interval IS the +cross-process delivery guarantee for short-lived out-of-process writers that never emit an +in-process nudge. The PG integration test for that path could only prove delivery by sleeping +a full real poll cycle (~2.1s), which is exactly the kind of real time-wait FN-5048 forbids. +Expose a bounded env test-seam (FUSION_AGENT_ACTIVITY_POLL_MS) so that test can drive the poll +fast without weakening the real 2s default or the delivery contract. Read per-connection so a +test can set it before opening the SSE; clamp to >=10ms so a bad value can never busy-spin. +*/ +function resolveAgentActivityPollMs(): number { + const raw = process.env.FUSION_AGENT_ACTIVITY_POLL_MS?.trim(); + if (!raw) return 2_000; + const parsed = Number(raw); + if (!Number.isFinite(parsed) || parsed <= 0) return 2_000; + return Math.max(10, Math.floor(parsed)); +} + const SSE_CLIENT_ID_MAX_LENGTH = 128; /* * FNXC:DashboardSSE 2026-06-23-15:08: @@ -705,7 +723,7 @@ export function createSSE( } void drainAgentActivity(); }; - const agentActivityPoll = setInterval(onAgentActivityNudge, 2_000); + const agentActivityPoll = setInterval(onAgentActivityNudge, resolveAgentActivityPollMs()); agentActivityPoll.unref?.(); // --- Event handler definitions --- const onCreated = (task: unknown) => {