fix(web): omit plan transcript rows
This commit is contained in:
@@ -109,6 +109,121 @@ describe("structured connection: data flow", () => {
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("keeps snapshot plan rows out of the transcript while rendering the plan rail", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
ws.open();
|
||||
ws.emit({
|
||||
type: "transcript_snapshot",
|
||||
snapshot: {
|
||||
cursor: 3,
|
||||
rows: [
|
||||
row("user:1", "user", { content: { type: "text", text: "before plan" } }),
|
||||
row("plan", "plan", { entries: [{ content: "ship it", status: "pending" }] }),
|
||||
row("agent:1", "agent_text", { content: { type: "text", text: "after plan" } }),
|
||||
],
|
||||
},
|
||||
});
|
||||
ws.emit({
|
||||
type: "reduced_state",
|
||||
state: {
|
||||
...idleState,
|
||||
plan: { entries: [{ content: "ship it", priority: "high", status: "pending" }] },
|
||||
},
|
||||
});
|
||||
|
||||
const transcript = conn.el.querySelector(".structured-rows")!;
|
||||
expect(transcript.querySelectorAll(".st-row")).toHaveLength(2);
|
||||
expect(transcript.querySelector('[data-row-id="plan"]')).toBeNull();
|
||||
expect(transcript.textContent).toContain("before plan");
|
||||
expect(transcript.textContent).toContain("after plan");
|
||||
expect(transcript.textContent).not.toContain("[plan]");
|
||||
expect(conn.el.querySelector(".structured-rail")!.textContent).toContain("ship it");
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("applies plan append, patch, and remove without disturbing surrounding rows", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
ws.open();
|
||||
ws.emit({
|
||||
type: "transcript_snapshot",
|
||||
snapshot: {
|
||||
cursor: 1,
|
||||
rows: [row("user:1", "user", { content: { type: "text", text: "keep me" } })],
|
||||
},
|
||||
});
|
||||
ws.emit({ type: "reduced_state", state: idleState });
|
||||
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: {
|
||||
type: "append",
|
||||
row: row("plan", "plan", { entries: [{ content: "first", status: "pending" }] }),
|
||||
},
|
||||
state: {
|
||||
...idleState,
|
||||
plan: { entries: [{ content: "first", priority: "high", status: "pending" }] },
|
||||
},
|
||||
});
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: {
|
||||
type: "append",
|
||||
row: row("agent:1", "agent_text", { content: { type: "text", text: "still here" } }),
|
||||
},
|
||||
state: {
|
||||
...idleState,
|
||||
plan: { entries: [{ content: "first", priority: "high", status: "pending" }] },
|
||||
},
|
||||
});
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: {
|
||||
type: "patch",
|
||||
row: row("plan", "plan", { entries: [{ content: "updated", status: "completed" }] }),
|
||||
},
|
||||
state: {
|
||||
...idleState,
|
||||
plan: { entries: [{ content: "updated", priority: "high", status: "completed" }] },
|
||||
},
|
||||
});
|
||||
|
||||
const transcript = conn.el.querySelector(".structured-rows")!;
|
||||
expect([...transcript.querySelectorAll<HTMLElement>(".st-row")].map((el) => el.dataset.rowId)).toEqual([
|
||||
"user:1",
|
||||
"agent:1",
|
||||
]);
|
||||
expect(conn.el.querySelector(".structured-rail")!.textContent).toContain("updated");
|
||||
expect(conn.el.querySelector(".structured-rail")!.textContent).not.toContain("first");
|
||||
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: { type: "remove", id: "plan" },
|
||||
state: idleState,
|
||||
});
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: {
|
||||
type: "patch",
|
||||
row: row("agent:1", "agent_text", { content: { type: "text", text: "patched neighbor" } }),
|
||||
},
|
||||
state: idleState,
|
||||
});
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: { type: "remove", id: "user:1" },
|
||||
state: idleState,
|
||||
});
|
||||
|
||||
expect(conn.el.querySelector(".structured-rail .st-plan")).toBeNull();
|
||||
expect([...transcript.querySelectorAll<HTMLElement>(".st-row")].map((el) => el.dataset.rowId)).toEqual([
|
||||
"agent:1",
|
||||
]);
|
||||
expect(transcript.textContent).toContain("patched neighbor");
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("appends and patches rows via projection_update without duplicating them", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
@@ -551,6 +666,47 @@ describe("structured connection: reconnection/error/loading", () => {
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("does not mount plan rows from a reconnect snapshot", () => {
|
||||
const first = new FakeSocket();
|
||||
const second = new FakeSocket();
|
||||
const conn = mount({ sockets: [first, second], shouldReconnect: () => true });
|
||||
first.open();
|
||||
first.emit({
|
||||
type: "transcript_snapshot",
|
||||
snapshot: {
|
||||
cursor: 1,
|
||||
rows: [row("agent:old", "agent_text", { content: { type: "text", text: "old" } })],
|
||||
},
|
||||
});
|
||||
|
||||
first.drop();
|
||||
vi.advanceTimersByTime(1000);
|
||||
second.open();
|
||||
second.emit({
|
||||
type: "transcript_snapshot",
|
||||
snapshot: {
|
||||
cursor: 4,
|
||||
rows: [
|
||||
row("user:new", "user", { content: { type: "text", text: "new" } }),
|
||||
row("plan", "plan", { entries: [{ content: "reconnected", status: "in_progress" }] }),
|
||||
],
|
||||
},
|
||||
});
|
||||
second.emit({
|
||||
type: "reduced_state",
|
||||
state: {
|
||||
...idleState,
|
||||
plan: { entries: [{ content: "reconnected", priority: "high", status: "in_progress" }] },
|
||||
},
|
||||
});
|
||||
|
||||
const transcript = conn.el.querySelector(".structured-rows")!;
|
||||
expect(transcript.textContent).toBe("Younew");
|
||||
expect(transcript.querySelector('[data-row-id="plan"]')).toBeNull();
|
||||
expect(conn.el.querySelector(".structured-rail")!.textContent).toContain("reconnected");
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("keeps surviving expanded rows open across a reconnect snapshot and leaves fresh rows collapsed", () => {
|
||||
const first = new FakeSocket();
|
||||
const second = new FakeSocket();
|
||||
|
||||
Reference in New Issue
Block a user