// SPEC: PJ2026-01060505 Workbench Performance draft-2026-06-17-p0 // Exercises the browser-side Workbench performance probe without sending network traffic. import assert from "node:assert/strict"; import test from "node:test"; import type { ChatMessage, TraceEvent } from "../src/types/index.ts"; import { acknowledgeWorkbenchVisible, drainWorkbenchPerformanceEventsForTest, finishWorkbenchOpenFullLoad, finishWorkbenchSessionSwitchFullLoad, markWorkbenchSubmitApiAccepted, markWorkbenchTraceEventsReceived, markWorkbenchTraceProjected, resetWorkbenchPerformanceForTest, startWorkbenchOpenJourney, startWorkbenchSessionSwitch, startWorkbenchSubmitJourney } from "../src/utils/workbench-performance.ts"; test("Workbench performance probe records journeys and strips high-cardinality identifiers", () => { resetWorkbenchPerformanceForTest(); startWorkbenchOpenJourney({ route: "/workbench/sessions/cnv_secret", cache: "cold", authState: "warm" }); acknowledgeWorkbenchVisible({ messages: [], activeConversationId: "cnv_secret", detailLoading: false }); finishWorkbenchOpenFullLoad("ok"); startWorkbenchSessionSwitch({ conversationId: "cnv_secret", source: "rail", targetState: "running", cache: "warm" }); acknowledgeWorkbenchVisible({ messages: [userMessage("cnv_secret")], activeConversationId: "cnv_secret", detailLoading: false }); finishWorkbenchSessionSwitchFullLoad("cnv_secret", "ok"); const wallBase = Date.now(); const createdAt = new Date(wallBase - 300).toISOString(); const appendedAt = new Date(wallBase - 220).toISOString(); const serverSentAt = new Date(wallBase - 120).toISOString(); startWorkbenchSubmitJourney({ traceId: "trc_secret", conversationId: "cnv_secret", entry: "existing", backend: "codex", transport: "sse" }); markWorkbenchSubmitApiAccepted("trc_secret"); markWorkbenchTraceEventsReceived({ traceId: "trc_secret", transport: "sse", serverSentAt, traceSeq: 42, events: [{ type: "assistant_message", eventType: "assistant", backend: "agentrun-v01/codex", createdAt, appendedAt, ts: createdAt, sourceSeq: 42 } as TraceEvent] }); markWorkbenchTraceProjected("trc_secret"); acknowledgeWorkbenchVisible({ messages: [agentMessage("cnv_secret", "trc_secret")], activeConversationId: "cnv_secret", detailLoading: false }); const events = drainWorkbenchPerformanceEventsForTest(); const payload = JSON.stringify(events); assert.ok(events.some((event) => event.kind === "workbench_journey" && event.journey === "workbench_open_first_visible")); assert.ok(events.some((event) => event.kind === "workbench_journey" && event.journey === "session_switch_first_visible")); assert.ok(events.some((event) => event.kind === "workbench_journey" && event.journey === "submit_to_first_visible" && event.backend === "agentrun-v01/codex")); assert.ok(events.some((event) => event.kind === "workbench_event_phase" && event.phase === "created_to_append" && event.eventType === "assistant")); assert.ok(events.some((event) => event.kind === "workbench_event_phase" && event.phase === "append_to_sse" && event.eventType === "assistant")); assert.ok(events.some((event) => event.kind === "workbench_event_phase" && event.phase === "sse_to_receive" && event.eventType === "assistant")); assert.ok(events.some((event) => event.kind === "workbench_event_phase" && event.phase === "receive_to_project" && event.eventType === "assistant")); assert.ok(events.some((event) => event.kind === "workbench_event_phase" && event.phase === "project_to_paint" && event.eventType === "assistant")); assert.ok(events.some((event) => event.kind === "workbench_backend_event_visible" && event.eventType === "assistant")); assert.doesNotMatch(payload, /trc_secret|cnv_secret|sessionId|conversationId|runId|commandId/u); }); function userMessage(conversationId: string): ChatMessage { return { id: "msg_user", role: "user", title: "User", text: "hello", status: "sent", createdAt: new Date().toISOString(), conversationId }; } function agentMessage(conversationId: string, traceId: string): ChatMessage { return { id: "msg_agent", role: "agent", title: "Code Agent", text: "visible", status: "running", createdAt: new Date().toISOString(), conversationId, traceId, runnerTrace: { traceId, eventCount: 1, events: [{ type: "assistant_message" }] } }; }