summaryrefslogtreecommitdiffhomepage
path: root/src/adapters/ws
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-10-21 02:31:38 +0900
committerAdam Malczewski <[email protected]>2026-10-21 02:31:38 +0900
commit2686cf6bcd247d17528922e36aa380a521c964e0 (patch)
treed49a0a59e0025e6b3dad9dc40d691a7a4a728c04 /src/adapters/ws
parentde421a9720bc00334c2cac2913067079a410f8b4 (diff)
downloaddispatch-web-2686cf6bcd247d17528922e36aa380a521c964e0.tar.gz
dispatch-web-2686cf6bcd247d17528922e36aa380a521c964e0.zip
fix(review-3.6): invalidate history caches by epoch and coalesce syncs
Diffstat (limited to 'src/adapters/ws')
-rw-r--r--src/adapters/ws/logic.test.ts15
-rw-r--r--src/adapters/ws/logic.ts3
2 files changed, 18 insertions, 0 deletions
diff --git a/src/adapters/ws/logic.test.ts b/src/adapters/ws/logic.test.ts
index 2179ad0..4be2cd6 100644
--- a/src/adapters/ws/logic.test.ts
+++ b/src/adapters/ws/logic.test.ts
@@ -562,3 +562,18 @@ describe("parseServerMessage — subagent tab groups", () => {
).toBeNull();
});
});
+
+it("preserves a compaction epoch and rejects absent or invalid epochs", () => {
+ const msg = {
+ type: "conversation.compacted",
+ conversationId: "c",
+ newConversationId: "archive",
+ messagesSummarized: 2,
+ messagesKept: 1,
+ historyEpoch: 7,
+ };
+ expect(parseServerMessage(JSON.stringify(msg))).toEqual(msg);
+ for (const historyEpoch of [undefined, -1, 1.5, "7"]) {
+ expect(parseServerMessage(JSON.stringify({ ...msg, historyEpoch }))).toBeNull();
+ }
+});
diff --git a/src/adapters/ws/logic.ts b/src/adapters/ws/logic.ts
index cecc66c..858deaa 100644
--- a/src/adapters/ws/logic.ts
+++ b/src/adapters/ws/logic.ts
@@ -180,7 +180,10 @@ export function parseServerMessage(data: string): WsServerMessage | null {
if (typeof parsed.newConversationId !== "string") return null;
if (typeof parsed.messagesSummarized !== "number") return null;
if (typeof parsed.messagesKept !== "number") return null;
+ if (!Number.isSafeInteger(parsed.historyEpoch) || (parsed.historyEpoch as number) < 0)
+ return null;
const msg: ConversationCompactedMessage = {
+ historyEpoch: parsed.historyEpoch as number,
type: "conversation.compacted",
conversationId: parsed.conversationId,
newConversationId: parsed.newConversationId,