@hybridlabor-api/bdb-synapse 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +173 -0
  3. package/bin/synapse +0 -0
  4. package/cmd/rubriceval/main.go +308 -0
  5. package/cmd/synapse/main.go +280 -0
  6. package/cmd/synapse/main_test.go +16 -0
  7. package/go.mod +7 -0
  8. package/go.sum +6 -0
  9. package/internal/adapter/adapter.go +1117 -0
  10. package/internal/adapter/adapter_test.go +518 -0
  11. package/internal/adapter/agy/adapter.go +193 -0
  12. package/internal/adapter/claudecode/adapter.go +415 -0
  13. package/internal/adapter/claudecode/adapter_test.go +260 -0
  14. package/internal/adapter/claudecode/agents.go +387 -0
  15. package/internal/adapter/claudecode/agents_test.go +480 -0
  16. package/internal/adapter/claudecode/summary_inputs_test.go +19 -0
  17. package/internal/adapter/codex/adapter.go +919 -0
  18. package/internal/adapter/codex/adapter_test.go +920 -0
  19. package/internal/adapter/codex/agents.go +401 -0
  20. package/internal/adapter/codex/agents_test.go +610 -0
  21. package/internal/adapter/codex/summary_inputs_test.go +20 -0
  22. package/internal/adapter/pi/adapter.go +483 -0
  23. package/internal/adapter/pi/adapter_test.go +517 -0
  24. package/internal/citymap/builder.go +1124 -0
  25. package/internal/citymap/builder_test.go +818 -0
  26. package/internal/judge/cache.go +180 -0
  27. package/internal/judge/cli.go +240 -0
  28. package/internal/judge/cli_test.go +68 -0
  29. package/internal/judge/fresh_summary_test.go +37 -0
  30. package/internal/judge/input.go +233 -0
  31. package/internal/judge/judge.go +416 -0
  32. package/internal/judge/judge_test.go +288 -0
  33. package/internal/judge/prompt.go +129 -0
  34. package/internal/judge/rubric.go +275 -0
  35. package/internal/judge/rubric_test.go +642 -0
  36. package/internal/model/agent.go +63 -0
  37. package/internal/model/agent_schema_test.go +86 -0
  38. package/internal/model/agent_test.go +64 -0
  39. package/internal/model/model.go +175 -0
  40. package/internal/model/report.go +166 -0
  41. package/internal/model/stats.go +151 -0
  42. package/internal/model/stats_test.go +89 -0
  43. package/internal/model/trace_schema_test.go +67 -0
  44. package/internal/server/analyze.go +286 -0
  45. package/internal/server/analyze_test.go +297 -0
  46. package/internal/server/codex_index_test.go +40 -0
  47. package/internal/server/hardening_test.go +147 -0
  48. package/internal/server/reportindex.go +91 -0
  49. package/internal/server/reportindex_test.go +116 -0
  50. package/internal/server/server.go +1099 -0
  51. package/internal/server/server_test.go +1389 -0
  52. package/internal/server/static/assets/fraunces-latin-ext-standard-italic-CGbN9UgK.woff2 +0 -0
  53. package/internal/server/static/assets/fraunces-latin-ext-standard-normal-CJcjJNj7.woff2 +0 -0
  54. package/internal/server/static/assets/fraunces-latin-standard-italic-lSdLDfvT.woff2 +0 -0
  55. package/internal/server/static/assets/fraunces-latin-standard-normal-DihXLNYH.woff2 +0 -0
  56. package/internal/server/static/assets/fraunces-vietnamese-standard-italic-DxWqP7Ku.woff2 +0 -0
  57. package/internal/server/static/assets/fraunces-vietnamese-standard-normal-Czevyj-6.woff2 +0 -0
  58. package/internal/server/static/assets/index-BNoY_BiB.css +1 -0
  59. package/internal/server/static/assets/index-C_adLrJr.js +3 -0
  60. package/internal/server/static/assets/react-gcHzaSmV.js +10 -0
  61. package/internal/server/static/assets/schibsted-grotesk-latin-ext-wght-normal-hsMS0n0O.woff2 +0 -0
  62. package/internal/server/static/assets/schibsted-grotesk-latin-wght-normal-Bb8VGrTG.woff2 +0 -0
  63. package/internal/server/static/assets/three-DnGjZfD1.js +4012 -0
  64. package/internal/server/static/index.html +26 -0
  65. package/internal/server/tracestore.go +173 -0
  66. package/internal/server/tracestore_test.go +51 -0
  67. package/internal/textutil/truncate.go +30 -0
  68. package/internal/textutil/truncate_test.go +39 -0
  69. package/package.json +35 -0
  70. package/web/e2e/agent-lens.spec.ts +688 -0
  71. package/web/index.html +23 -0
  72. package/web/package-lock.json +1933 -0
  73. package/web/package.json +33 -0
  74. package/web/playwright.config.ts +24 -0
  75. package/web/src/App.tsx +876 -0
  76. package/web/src/api/client.ts +74 -0
  77. package/web/src/main.tsx +12 -0
  78. package/web/src/playback/recorder.ts +160 -0
  79. package/web/src/playback/reducer.ts +91 -0
  80. package/web/src/scene/CityScene.tsx +638 -0
  81. package/web/src/scene/TreeScene.tsx +656 -0
  82. package/web/src/scene/dirLabels.ts +145 -0
  83. package/web/src/scene/sceneUtils.ts +144 -0
  84. package/web/src/scene/textures.ts +60 -0
  85. package/web/src/scene/trail.ts +79 -0
  86. package/web/src/scene/treeLayout.ts +169 -0
  87. package/web/src/state/filters.ts +40 -0
  88. package/web/src/state/store.ts +83 -0
  89. package/web/src/styles.css +2565 -0
  90. package/web/src/types.ts +315 -0
  91. package/web/src/ui/AgentsPanel.tsx +376 -0
  92. package/web/src/ui/Dock.tsx +104 -0
  93. package/web/src/ui/Hud.tsx +335 -0
  94. package/web/src/ui/Inspector.tsx +107 -0
  95. package/web/src/ui/LogoMark.tsx +38 -0
  96. package/web/src/ui/ReportPanel.tsx +491 -0
  97. package/web/src/ui/SessionRail.tsx +316 -0
  98. package/web/src/ui/Timeline.tsx +458 -0
  99. package/web/src/ui/ViewPanel.tsx +45 -0
  100. package/web/src/ui/shortcuts.ts +4 -0
  101. package/web/tsconfig.json +21 -0
  102. package/web/vite.config.ts +28 -0
@@ -0,0 +1,688 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { expect, test, type Page, type Route } from "playwright/test";
4
+
5
+ const fixtures = JSON.parse(
6
+ readFileSync(
7
+ fileURLToPath(new URL("../../testdata/agent-lens/browser-fixtures.json", import.meta.url)),
8
+ "utf8"
9
+ )
10
+ );
11
+
12
+ type TraceRoute = (agentID: string, requestCount: number, route: Route) => Promise<void>;
13
+
14
+ interface MockAppRoutes {
15
+ sessions?: (fresh: boolean, route: Route) => Promise<void>;
16
+ snapshot?: (route: Route) => Promise<void>;
17
+ graph?: (route: Route) => Promise<void>;
18
+ }
19
+
20
+ function deferred() {
21
+ let resolve!: () => void;
22
+ const promise = new Promise<void>((release) => {
23
+ resolve = release;
24
+ });
25
+ return { promise, resolve };
26
+ }
27
+
28
+ async function installHeldRecorder(page: Page) {
29
+ await page.addInitScript(() => {
30
+ const recording = window as Window & {
31
+ __finishFakeRecording?: () => void;
32
+ __fakeRecordingStopped?: boolean;
33
+ };
34
+
35
+ class FakeMediaRecorder {
36
+ static isTypeSupported() {
37
+ return true;
38
+ }
39
+
40
+ state = "inactive";
41
+ mimeType: string;
42
+ ondataavailable: ((event: { data: Blob }) => void) | null = null;
43
+ onerror: (() => void) | null = null;
44
+ onstop: (() => void) | null = null;
45
+
46
+ constructor(_stream: unknown, options?: { mimeType?: string }) {
47
+ this.mimeType = options?.mimeType ?? "video/webm";
48
+ }
49
+
50
+ start() {
51
+ this.state = "recording";
52
+ }
53
+
54
+ stop() {
55
+ this.state = "inactive";
56
+ this.ondataavailable?.({ data: new Blob(["fictional-video"], { type: this.mimeType }) });
57
+ recording.__fakeRecordingStopped = true;
58
+ recording.__finishFakeRecording = () => this.onstop?.();
59
+ }
60
+ }
61
+
62
+ Object.defineProperty(window, "MediaRecorder", { configurable: true, value: FakeMediaRecorder });
63
+ Object.defineProperty(HTMLCanvasElement.prototype, "captureStream", {
64
+ configurable: true,
65
+ value: () => ({ getTracks: () => [{ stop() {} }] })
66
+ });
67
+ HTMLAnchorElement.prototype.click = function click() {};
68
+ });
69
+ }
70
+
71
+ async function beginHeldExport(page: Page) {
72
+ await page.getByRole("button", { name: "More playback controls" }).click();
73
+ await page.getByRole("button", { name: "Export video" }).click();
74
+ await page.waitForFunction(() => {
75
+ return (window as Window & { __fakeRecordingStopped?: boolean }).__fakeRecordingStopped === true;
76
+ });
77
+ }
78
+
79
+ async function mockApp(page: Page, traceRoute?: TraceRoute, routes: MockAppRoutes = {}) {
80
+ const requests = new Map<string, number>();
81
+
82
+ await page.route("**/api/sessions**", async (route) => {
83
+ const url = new URL(route.request().url());
84
+ const path = url.pathname;
85
+
86
+ if (path === "/api/sessions") {
87
+ if (routes.sessions) {
88
+ await routes.sessions(url.searchParams.get("fresh") === "1", route);
89
+ return;
90
+ }
91
+ await route.fulfill({ json: [fixtures.session] });
92
+ return;
93
+ }
94
+ if (path === "/api/sessions/synthetic-root/snapshot") {
95
+ if (routes.snapshot) {
96
+ await routes.snapshot(route);
97
+ return;
98
+ }
99
+ await route.fulfill({ json: { trace: fixtures.traces.root, city: fixtures.city } });
100
+ return;
101
+ }
102
+ if (path === "/api/sessions/synthetic-root/agents") {
103
+ if (routes.graph) {
104
+ await routes.graph(route);
105
+ return;
106
+ }
107
+ await route.fulfill({ json: fixtures.graph });
108
+ return;
109
+ }
110
+ if (path === "/api/sessions/synthetic-root/report") {
111
+ await route.fulfill({ json: fixtures.reportStatus });
112
+ return;
113
+ }
114
+
115
+ const match = path.match(/^\/api\/sessions\/synthetic-root\/agents\/([^/]+)\/trace$/);
116
+ if (match) {
117
+ const agentID = decodeURIComponent(match[1]);
118
+ const count = (requests.get(agentID) ?? 0) + 1;
119
+ requests.set(agentID, count);
120
+ if (traceRoute) {
121
+ await traceRoute(agentID, count, route);
122
+ } else {
123
+ await fulfillAgentTrace(agentID, route);
124
+ }
125
+ return;
126
+ }
127
+
128
+ await route.fulfill({ status: 404, body: "fictional route not found" });
129
+ });
130
+ }
131
+
132
+ async function fulfillAgentTrace(agentID: string, route: Route) {
133
+ const trace = fixtures.traces[agentID];
134
+ if (trace) {
135
+ await route.fulfill({ json: trace });
136
+ } else {
137
+ await route.fulfill({ status: 409, body: "fictional trace unavailable" });
138
+ }
139
+ }
140
+
141
+ async function openFixture(page: Page) {
142
+ await page.goto("/?session=synthetic-root");
143
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
144
+ await expect(page.locator(".deck-pos-count")).toHaveText("4 / 4");
145
+ }
146
+
147
+ async function openAgents(page: Page) {
148
+ await page.locator(".dock-strip").getByRole("button", { name: /Agent lenses/ }).click();
149
+ return page.getByLabel("Agent lenses", { exact: true });
150
+ }
151
+
152
+ function row(panel: ReturnType<Page["getByLabel"]>, label: string) {
153
+ return panel.getByRole("button").filter({ hasText: label });
154
+ }
155
+
156
+ test.beforeEach(async ({ page }) => {
157
+ await page.addInitScript(() => {
158
+ localStorage.clear();
159
+ });
160
+ });
161
+
162
+ test("Agents shows truthful rows and switches lenses without letting missing rows move the scene", async ({
163
+ page
164
+ }) => {
165
+ await mockApp(page);
166
+ await openFixture(page);
167
+ const panel = await openAgents(page);
168
+
169
+ const main = row(panel, "Main");
170
+ const atlas = row(panel, "Atlas");
171
+ const missing = row(panel, "Comet");
172
+ const failed = row(panel, "Drift");
173
+
174
+ await expect(main).toHaveAttribute("aria-pressed", "true");
175
+ await expect(main.locator(".agent-row-count")).toHaveText("4 events");
176
+ await expect(atlas).toContainText("2 events");
177
+ await expect(missing).toContainText("Trace missing");
178
+ await expect(missing).toBeDisabled();
179
+ await expect(failed).toContainText("Launch failed · no trace");
180
+ await expect(failed).toBeDisabled();
181
+
182
+ await atlas.click();
183
+ await expect(page.locator(".hud-lens")).toHaveText("LensAtlas");
184
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 2");
185
+ await expect(page.getByRole("slider", { name: "Playback position" })).toHaveValue("1");
186
+
187
+ await page.getByRole("slider", { name: "Playback position" }).fill("0");
188
+ await expect(page.locator(".deck-pos-count")).toHaveText("1 / 2");
189
+ await main.click();
190
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
191
+ await expect(page.locator(".deck-pos-count")).toHaveText("4 / 4");
192
+
193
+ await atlas.click();
194
+ await expect(page.locator(".deck-pos-count")).toHaveText("1 / 2");
195
+ await expect(missing).toBeDisabled();
196
+ await expect(page.locator(".hud-lens")).toHaveText("LensAtlas");
197
+ });
198
+
199
+ test("an available zero-event child opens an empty lens and returns to Main", async ({ page }) => {
200
+ await mockApp(page);
201
+ await openFixture(page);
202
+ const panel = await openAgents(page);
203
+ const nova = row(panel, "Nova");
204
+
205
+ await expect(nova).toContainText("0 events");
206
+ await expect(nova).toBeEnabled();
207
+ await nova.click();
208
+ await expect(page.locator(".hud-lens")).toHaveText("LensNova");
209
+ await expect(page.locator(".deck-pos-count")).toHaveText("0 / 0");
210
+ await expect(page.locator(".readout-summary")).toHaveText("No recorded activity for this agent.");
211
+
212
+ await row(panel, "Main").click();
213
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
214
+ await expect(page.locator(".deck-pos-count")).toHaveText("4 / 4");
215
+ });
216
+
217
+ test("HUD entry points open compact two-line Agent rows with accessible details", async ({ page }) => {
218
+ await page.setViewportSize({ width: 1440, height: 900 });
219
+ const graph = structuredClone(fixtures.graph);
220
+ const longInstruction = "g".repeat(240);
221
+ graph.agents.find((agent: { id: string }) => agent.id === "child-a").instructionPreview =
222
+ longInstruction;
223
+ await mockApp(page, undefined, {
224
+ graph: async (route) => {
225
+ await route.fulfill({ json: graph });
226
+ }
227
+ });
228
+ await openFixture(page);
229
+
230
+ await page.getByRole("button", { name: "Open Agent lenses, current Main" }).click();
231
+ const panel = page.getByLabel("Agent lenses", { exact: true });
232
+ await expect(panel).toBeVisible();
233
+ await panel.getByRole("button", { name: "Close agents" }).click();
234
+
235
+ await page.getByRole("button", { name: "Open 1 subagent in Agent lenses" }).click();
236
+ await expect(panel).toBeVisible();
237
+
238
+ const atlas = row(panel, "Atlas");
239
+ await expect(atlas.locator(".agent-row-primary")).toBeVisible();
240
+ await expect(atlas.locator(".agent-row-secondary")).toBeVisible();
241
+ await expect(atlas.locator(".agent-row-count")).toHaveText("2 events");
242
+ await atlas.focus();
243
+ const detail = page.locator("body > .agent-detail-popover.preview");
244
+ await expect(detail).toBeVisible();
245
+ await expect(detail).toContainText(longInstruction);
246
+
247
+ const dockPanel = page.locator(".dock-panel");
248
+ const overflow = await dockPanel.evaluate((element) => ({
249
+ clientWidth: element.clientWidth,
250
+ scrollWidth: element.scrollWidth
251
+ }));
252
+ expect(overflow.scrollWidth).toBe(overflow.clientWidth);
253
+
254
+ const detailBox = await detail.boundingBox();
255
+ expect(detailBox!.x).toBeGreaterThanOrEqual(12);
256
+ expect(detailBox!.x + detailBox!.width).toBeLessThanOrEqual(1440 - 12);
257
+ await expect
258
+ .poll(async () => {
259
+ const [currentPanelBox, currentDetailBox] = await Promise.all([
260
+ dockPanel.boundingBox(),
261
+ detail.boundingBox()
262
+ ]);
263
+ return currentPanelBox!.x - (currentDetailBox!.x + currentDetailBox!.width);
264
+ })
265
+ .toBeGreaterThanOrEqual(0);
266
+ });
267
+
268
+ test("pinned Agent details scroll without switching lenses and dismiss cleanly", async ({
269
+ page
270
+ }) => {
271
+ await page.setViewportSize({ width: 1280, height: 720 });
272
+ const graph = structuredClone(fixtures.graph);
273
+ graph.agents.find((agent: { id: string }) => agent.id === "child-a").instructionPreview =
274
+ "p".repeat(4000);
275
+ await mockApp(page, undefined, {
276
+ graph: async (route) => {
277
+ await route.fulfill({ json: graph });
278
+ }
279
+ });
280
+ await openFixture(page);
281
+ const panel = await openAgents(page);
282
+
283
+ await panel.getByRole("button", { name: "Pin details for Atlas" }).click();
284
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
285
+
286
+ const pinned = page.locator("body > .agent-detail-popover.pinned");
287
+ await expect(pinned).toBeVisible();
288
+ const metrics = await pinned.evaluate((element) => ({
289
+ clientHeight: element.clientHeight,
290
+ scrollHeight: element.scrollHeight,
291
+ overflowY: getComputedStyle(element).overflowY
292
+ }));
293
+ expect(metrics.scrollHeight).toBeGreaterThan(metrics.clientHeight);
294
+ expect(metrics.overflowY).toBe("auto");
295
+
296
+ await page.keyboard.press("Escape");
297
+ await expect(pinned).toBeHidden();
298
+
299
+ await panel.getByRole("button", { name: "Pin details for Atlas" }).click();
300
+ await page.getByRole("button", { name: "Close details" }).click();
301
+ await expect(pinned).toBeHidden();
302
+
303
+ await panel.getByRole("button", { name: "Pin details for Atlas" }).click();
304
+ await page.mouse.click(20, 20);
305
+ await expect(pinned).toBeHidden();
306
+ });
307
+
308
+ test("top child failure keeps its error and Retry row-local in a 12-row panel", async ({ page }) => {
309
+ await page.setViewportSize({ width: 1280, height: 720 });
310
+ const graph = structuredClone(fixtures.graph);
311
+ for (let i = 0; i < 7; i++) {
312
+ graph.agents.push({
313
+ id: `extra-${i}`,
314
+ parentId: "main",
315
+ depth: 1,
316
+ kind: "subagent",
317
+ label: `Extra ${i + 1}`,
318
+ role: "observer",
319
+ instructionPreview: `Observe fictional branch ${i + 1}`,
320
+ launchSeq: 10 + i,
321
+ launchCallId: `fictional-extra-${i}`,
322
+ status: "launched",
323
+ traceAvailability: "available",
324
+ traceSessionKey: `synthetic-extra-${i}`,
325
+ traceEventCount: 1,
326
+ linkQuality: "derived",
327
+ linkMethod: "parent-thread-id"
328
+ });
329
+ }
330
+
331
+ await mockApp(
332
+ page,
333
+ async (agentID, _count, route) => {
334
+ if (agentID === "child-a") {
335
+ await route.fulfill({ status: 503, body: "fictional top-row timeout" });
336
+ return;
337
+ }
338
+ await fulfillAgentTrace(agentID, route);
339
+ },
340
+ { graph: async (route) => route.fulfill({ json: graph }) }
341
+ );
342
+ await openFixture(page);
343
+ const panel = await openAgents(page);
344
+ const atlas = row(panel, "Atlas");
345
+ await atlas.click();
346
+
347
+ const alert = panel.getByRole("alert");
348
+ await expect(alert).toContainText("fictional top-row timeout");
349
+ await expect(alert.getByRole("button", { name: "Retry" })).toBeVisible();
350
+ await expect(
351
+ atlas.locator("xpath=ancestor::*[contains(@class, 'agent-row')]/following-sibling::*[1]")
352
+ ).toHaveAttribute("role", "alert");
353
+ expect(await panel.evaluate((element) => element.scrollTop)).toBe(0);
354
+ const box = await alert.boundingBox();
355
+ expect(box?.y).toBeLessThan(720);
356
+ });
357
+
358
+ test("no session keeps the start-walk empty state", async ({ page }) => {
359
+ await mockApp(page, undefined, {
360
+ sessions: async (_fresh, route) => route.fulfill({ json: [] })
361
+ });
362
+ await page.goto("/");
363
+ await expect(page.locator(".readout-summary")).toHaveText("Select a session to start the walk.");
364
+ });
365
+
366
+ test("subagent marks open Agents only and report evidence restores Main", async ({ page }) => {
367
+ await mockApp(page);
368
+ await openFixture(page);
369
+
370
+ await page.getByRole("button", { name: /Jump to fictional helper launch/ }).click();
371
+ const agents = page.getByLabel("Agent lenses", { exact: true });
372
+ await expect(agents).toBeVisible();
373
+ await expect(row(agents, "Main")).toHaveAttribute("aria-pressed", "true");
374
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
375
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 4");
376
+
377
+ await row(agents, "Borealis").click();
378
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
379
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 3");
380
+
381
+ await page.getByRole("button", { name: "Evaluation ready", exact: true }).click();
382
+ await page.getByRole("button", { name: "The fictional garden was verified." }).click();
383
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
384
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 4");
385
+ });
386
+
387
+ test("export locks evaluation navigation without changing the child lens or playhead", async ({ page }) => {
388
+ await installHeldRecorder(page);
389
+
390
+ await mockApp(page);
391
+ await openFixture(page);
392
+ const panel = await openAgents(page);
393
+ await row(panel, "Borealis").click();
394
+ await page.getByRole("slider", { name: "Playback position" }).fill("1");
395
+ await page.getByRole("button", { name: "Evaluation ready", exact: true }).click();
396
+
397
+ await beginHeldExport(page);
398
+
399
+ const evidence = page.getByRole("button", { name: "The fictional garden was verified." });
400
+ const moment = page.getByRole("button", { name: /A fictional checkpoint was recorded/ });
401
+ await expect(evidence).toBeDisabled();
402
+ await expect(moment).toBeDisabled();
403
+
404
+ for (const control of [evidence, moment]) {
405
+ await control.evaluate((button) => {
406
+ button.removeAttribute("disabled");
407
+ button.click();
408
+ });
409
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
410
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 3");
411
+ }
412
+
413
+ await page.evaluate(() => {
414
+ (window as Window & { __finishFakeRecording?: () => void }).__finishFakeRecording?.();
415
+ });
416
+ await expect(page.getByRole("button", { name: "More playback controls" })).toBeEnabled();
417
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
418
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 3");
419
+ });
420
+
421
+ test("export locks Inspector history and guards forced history jumps", async ({ page }) => {
422
+ await installHeldRecorder(page);
423
+ await mockApp(page);
424
+ await openFixture(page);
425
+
426
+ await page.getByRole("button", { name: "Evaluation ready", exact: true }).click();
427
+ await page.getByRole("button", { name: "The fictional garden was verified." }).click();
428
+ await page.getByRole("slider", { name: "Playback position" }).fill("3");
429
+ await page.getByRole("button", { name: "Inspect the selected file" }).click();
430
+ const visit = page.locator(".history-row").filter({ hasText: "#3" });
431
+
432
+ await beginHeldExport(page);
433
+ await expect(visit).toBeDisabled();
434
+
435
+ await visit.evaluate((button) => {
436
+ button.removeAttribute("disabled");
437
+ button.click();
438
+ });
439
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
440
+ await expect(page.locator(".deck-pos-count")).toHaveText("4 / 4");
441
+ });
442
+
443
+ test("export locks Rescan and guards forced refresh requests", async ({ page }) => {
444
+ await installHeldRecorder(page);
445
+ const sessionRequests: string[] = [];
446
+ page.on("request", (request) => {
447
+ const url = new URL(request.url());
448
+ if (url.pathname === "/api/sessions" || url.pathname.endsWith("/snapshot")) {
449
+ sessionRequests.push(`${url.pathname}${url.search}`);
450
+ }
451
+ });
452
+ await mockApp(page);
453
+ await openFixture(page);
454
+ const panel = await openAgents(page);
455
+ await row(panel, "Borealis").click();
456
+ await page.getByRole("slider", { name: "Playback position" }).fill("1");
457
+
458
+ await beginHeldExport(page);
459
+ const rescan = page.getByRole("button", { name: "Rescan sessions" });
460
+ await expect(rescan).toBeDisabled();
461
+ const before = sessionRequests.length;
462
+
463
+ await rescan.evaluate((button) => {
464
+ button.removeAttribute("disabled");
465
+ button.click();
466
+ });
467
+ await page.evaluate(
468
+ () => new Promise<void>((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())))
469
+ );
470
+
471
+ expect(sessionRequests).toHaveLength(before);
472
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
473
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 3");
474
+ });
475
+
476
+ test("rescan invalidates child projections and preserves the actor playhead", async ({ page }) => {
477
+ let refreshed = false;
478
+ const refreshedGraph = structuredClone(fixtures.graph);
479
+ refreshedGraph.agents.find((agent: { id: string }) => agent.id === "child-a").traceEventCount = 3;
480
+
481
+ const refreshedCity = structuredClone(fixtures.city);
482
+ refreshedCity.files.push({
483
+ id: 3,
484
+ path: "src/orbit.ts",
485
+ dir: "src",
486
+ lines: 10,
487
+ bytes: 200,
488
+ lang: "TypeScript",
489
+ rect: { x: 4, z: 0, w: 1, d: 1 },
490
+ ghost: false
491
+ });
492
+
493
+ const refreshedChild = structuredClone(fixtures.traces["child-a"]);
494
+ refreshedChild.session.eventCount = 3;
495
+ refreshedChild.events.push({
496
+ seq: 2,
497
+ tool: "Read",
498
+ action: "read",
499
+ targets: [{ path: "src/orbit.ts", fileId: 3, touch: "read" }],
500
+ resultBytes: 7,
501
+ isError: false,
502
+ summary: "Read the refreshed fictional orbit module"
503
+ });
504
+ refreshedChild.stats.filesInRepo = 3;
505
+ refreshedChild.stats.fovea = 2;
506
+ refreshedChild.stats.actions.read += 1;
507
+
508
+ await mockApp(
509
+ page,
510
+ async (agentID, requestCount, route) => {
511
+ if (agentID === "child-a") {
512
+ await route.fulfill({ json: requestCount === 1 ? fixtures.traces["child-a"] : refreshedChild });
513
+ return;
514
+ }
515
+ await fulfillAgentTrace(agentID, route);
516
+ },
517
+ {
518
+ sessions: async (fresh, route) => {
519
+ if (fresh) refreshed = true;
520
+ await route.fulfill({ json: [fixtures.session] });
521
+ },
522
+ snapshot: async (route) => {
523
+ await route.fulfill({
524
+ json: { trace: fixtures.traces.root, city: refreshed ? refreshedCity : fixtures.city }
525
+ });
526
+ },
527
+ graph: async (route) => {
528
+ await route.fulfill({ json: refreshed ? refreshedGraph : fixtures.graph });
529
+ }
530
+ }
531
+ );
532
+
533
+ await openFixture(page);
534
+ const panel = await openAgents(page);
535
+ await row(panel, "Atlas").click();
536
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 2");
537
+
538
+ await page.getByRole("button", { name: "Rescan sessions" }).click();
539
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
540
+ await expect(row(panel, "Atlas")).toContainText("3 events");
541
+
542
+ await row(panel, "Atlas").click();
543
+ await expect(page.locator(".hud-lens")).toHaveText("LensAtlas");
544
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 3");
545
+ await expect(page.locator(".hud-commit")).toContainText("3 files");
546
+ });
547
+
548
+ test("rescan preserves the Main actor playhead", async ({ page }) => {
549
+ await mockApp(page);
550
+ await openFixture(page);
551
+ await page.getByRole("slider", { name: "Playback position" }).fill("1");
552
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 4");
553
+
554
+ await page.getByRole("button", { name: "Rescan sessions" }).click();
555
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
556
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 4");
557
+ });
558
+
559
+ test("a rapid delayed Atlas to Borealis switch cannot let Atlas overwrite Borealis", async ({ page }) => {
560
+ const atlasRelease = deferred();
561
+ const atlasFulfilled = deferred();
562
+ await mockApp(page, async (agentID, _count, route) => {
563
+ if (agentID === "child-a") await atlasRelease.promise;
564
+ await fulfillAgentTrace(agentID, route);
565
+ if (agentID === "child-a") atlasFulfilled.resolve();
566
+ });
567
+ await openFixture(page);
568
+ const panel = await openAgents(page);
569
+
570
+ await row(panel, "Atlas").click();
571
+ await expect(panel).toContainText("Loading trace…");
572
+ await row(panel, "Borealis").click();
573
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
574
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 3");
575
+
576
+ atlasRelease.resolve();
577
+ await atlasFulfilled.promise;
578
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
579
+ await expect(row(panel, "Borealis")).toHaveAttribute("aria-pressed", "true");
580
+ });
581
+
582
+ test("a failed child load keeps Main visible and Retry starts a fresh request", async ({ page }) => {
583
+ await mockApp(page, async (agentID, count, route) => {
584
+ if (agentID === "child-a" && count === 1) {
585
+ await route.fulfill({ status: 503, body: "fictional child timeout" });
586
+ return;
587
+ }
588
+ await fulfillAgentTrace(agentID, route);
589
+ });
590
+ await openFixture(page);
591
+ const panel = await openAgents(page);
592
+
593
+ await row(panel, "Atlas").click();
594
+ await expect(panel.getByRole("alert")).toContainText("fictional child timeout");
595
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
596
+ await expect(page.locator(".deck-pos-count")).toHaveText("4 / 4");
597
+
598
+ await panel.getByRole("button", { name: "Retry" }).click();
599
+ await expect(page.locator(".hud-lens")).toHaveText("LensAtlas");
600
+ await expect(page.locator(".deck-pos-count")).toHaveText("2 / 2");
601
+ });
602
+
603
+ test("export locks lens controls, discards delayed child data, and allows a fresh request afterward", async ({
604
+ page
605
+ }) => {
606
+ const borealisRelease = deferred();
607
+ const borealisFulfilled = deferred();
608
+ await page.addInitScript(() => {
609
+ class FakeMediaRecorder {
610
+ static isTypeSupported() {
611
+ return true;
612
+ }
613
+
614
+ state = "inactive";
615
+ mimeType: string;
616
+ ondataavailable: ((event: { data: Blob }) => void) | null = null;
617
+ onerror: (() => void) | null = null;
618
+ onstop: (() => void) | null = null;
619
+
620
+ constructor(_stream: unknown, options?: { mimeType?: string }) {
621
+ this.mimeType = options?.mimeType ?? "video/webm";
622
+ }
623
+
624
+ start() {
625
+ this.state = "recording";
626
+ }
627
+
628
+ stop() {
629
+ this.state = "inactive";
630
+ this.ondataavailable?.({ data: new Blob(["fictional-video"], { type: this.mimeType }) });
631
+ setTimeout(() => this.onstop?.(), 0);
632
+ }
633
+ }
634
+
635
+ Object.defineProperty(window, "MediaRecorder", { configurable: true, value: FakeMediaRecorder });
636
+ Object.defineProperty(HTMLCanvasElement.prototype, "captureStream", {
637
+ configurable: true,
638
+ value: () => ({ getTracks: () => [{ stop() {} }] })
639
+ });
640
+ HTMLAnchorElement.prototype.click = function click() {};
641
+ });
642
+
643
+ await mockApp(page, async (agentID, count, route) => {
644
+ if (agentID === "child-a" && count === 1) {
645
+ await route.fulfill({ status: 503, body: "fictional retry setup" });
646
+ return;
647
+ }
648
+ if (agentID === "child-b" && count === 1) {
649
+ await borealisRelease.promise;
650
+ }
651
+ await fulfillAgentTrace(agentID, route);
652
+ if (agentID === "child-b" && count === 1) borealisFulfilled.resolve();
653
+ });
654
+ await openFixture(page);
655
+ const panel = await openAgents(page);
656
+
657
+ await row(panel, "Atlas").click();
658
+ const retry = panel.getByRole("button", { name: "Retry" });
659
+ await expect(retry).toBeVisible();
660
+
661
+ await page.getByRole("button", { name: "More playback controls" }).click();
662
+ await page.getByRole("button", { name: "Export video" }).click();
663
+ await expect(retry).toBeDisabled();
664
+ await expect(row(panel, "Atlas")).toBeDisabled();
665
+ await expect(page.getByRole("button", { name: /Jump to fictional helper launch/ })).toBeDisabled();
666
+ await expect(page.getByRole("slider", { name: "Playback position" })).toBeDisabled();
667
+ await expect(page.getByRole("button", { name: "More playback controls" })).toBeEnabled({ timeout: 3_000 });
668
+
669
+ await retry.click();
670
+ await expect(page.locator(".hud-lens")).toHaveText("LensAtlas");
671
+ await row(panel, "Main").click();
672
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
673
+
674
+ await row(panel, "Borealis").click();
675
+ await expect(panel).toContainText("Loading trace…");
676
+ await page.getByRole("button", { name: "More playback controls" }).click();
677
+ await page.getByRole("button", { name: "Export video" }).click();
678
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
679
+ borealisRelease.resolve();
680
+ await borealisFulfilled.promise;
681
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
682
+ await expect(page.getByRole("button", { name: "More playback controls" })).toBeEnabled({ timeout: 3_000 });
683
+ await expect(page.locator(".hud-lens")).toHaveText("LensMain");
684
+
685
+ await row(panel, "Borealis").click();
686
+ await expect(page.locator(".hud-lens")).toHaveText("LensBorealis");
687
+ await expect(page.locator(".deck-pos-count")).toHaveText("3 / 3");
688
+ });