1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
import type { SurfaceSpec } from "@dispatch/ui-contract";
import { describe, expect, it, vi } from "vitest";
import { createSurfaceProtocol } from "./surface-protocol.svelte";
const spec: SurfaceSpec = { id: "s1", region: "inline", title: "Snapshot", fields: [] };
function fixture() {
let focusedId = "c1";
const surfaces = createSurfaceProtocol({
focusedConversationId: () => focusedId,
send: vi.fn(),
});
surfaces.handleServerMessage({
type: "catalog",
catalog: [{ id: "s1", region: "inline", title: "Snapshot", scope: "conversation" }],
});
return {
surfaces,
focus(id: string) {
focusedId = id;
surfaces.syncSubscriptions();
},
};
}
describe("conversation-scoped surface lookup", () => {
it("keeps retained rendering but withholds another conversation's snapshot from decisions", () => {
const { surfaces, focus } = fixture();
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
surfaces.handleServerMessage({ type: "surface", conversationId: "c1", spec });
expect(surfaces.surfaceSpecOp("s1", "c1")).toEqual(spec);
focus("c2");
expect(surfaces.surfaceSpecOp("s1")).toEqual(spec);
expect(surfaces.surfaceSpecOp("s1", "c2")).toBeNull();
surfaces.handleServerMessage({ type: "surface", conversationId: "c1", spec });
expect(surfaces.surfaceSpecOp("s1", "c2")).toBeNull();
const updated = { ...spec, title: "Current" };
surfaces.handleServerMessage({
type: "update",
update: { surfaceId: "s1", conversationId: "c2", spec: updated },
});
expect(surfaces.surfaceSpecOp("s1", "c2")).toEqual(updated);
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
});
it("does not treat an unscoped snapshot as known conversation-specific data", () => {
const { surfaces } = fixture();
surfaces.handleServerMessage({ type: "surface", spec });
expect(surfaces.surfaceSpecOp("s1")).toEqual(spec);
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
});
it("drops snapshot scope on explicit unsubscribe and catalog removal", () => {
const { surfaces } = fixture();
surfaces.handleServerMessage({ type: "surface", conversationId: "c1", spec });
surfaces.unsubscribeSurfaceOp("s1");
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
surfaces.subscribeSurfaceOp("s1");
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
surfaces.handleServerMessage({ type: "surface", conversationId: "c1", spec });
expect(surfaces.surfaceSpecOp("s1", "c1")).toEqual(spec);
surfaces.handleServerMessage({ type: "catalog", catalog: [] });
expect(surfaces.surfaceSpecOp("s1", "c1")).toBeNull();
});
});
describe("surface subscription budget", () => {
it("bounds a large catalog and releases old slots before subscribing a replacement catalog", () => {
const live = new Set<string>();
let peak = 0;
const surfaces = createSurfaceProtocol({
focusedConversationId: () => "chat",
send(message) {
if (message.type === "subscribe") live.add(message.surfaceId);
if (message.type === "unsubscribe") live.delete(message.surfaceId);
peak = Math.max(peak, live.size);
},
});
for (const prefix of ["old", "new"]) {
surfaces.handleServerMessage({
type: "catalog",
catalog: Array.from({ length: 339 }, (_, i) => ({
id: `${prefix}-${i}`,
region: "inline",
title: "Surface",
scope: "global" as const,
})),
});
expect(live.size).toBe(128);
expect([...live].every((id) => id.startsWith(prefix))).toBe(true);
}
surfaces.subscribeSurfaceOp("overflow");
expect(live.has("overflow")).toBe(false);
expect(peak).toBe(128);
});
});
|