diff options
| author | Adam Malczewski <[email protected]> | 2026-10-21 14:46:06 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-10-21 14:46:06 +0900 |
| commit | 0bdb04b0aa0c0500e68e2e985b1a2880730ad7e8 (patch) | |
| tree | 0768ddd1be8828738ee80770dd723236b91e32e8 /src/features/conversation-cache/cache.test.ts | |
| parent | 6a2a40d64737b3cb678740c8f85027c3be0000bc (diff) | |
| download | dispatch-web-0bdb04b0aa0c0500e68e2e985b1a2880730ad7e8.tar.gz dispatch-web-0bdb04b0aa0c0500e68e2e985b1a2880730ad7e8.zip | |
fix(review-followup-fec): reconcile epoch rollback and retain reconnect backoff
Diffstat (limited to 'src/features/conversation-cache/cache.test.ts')
| -rw-r--r-- | src/features/conversation-cache/cache.test.ts | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/features/conversation-cache/cache.test.ts b/src/features/conversation-cache/cache.test.ts index 4306d51..72b4e20 100644 --- a/src/features/conversation-cache/cache.test.ts +++ b/src/features/conversation-cache/cache.test.ts @@ -214,3 +214,38 @@ it("serializes invalidation and rejects stale epoch commits", async () => { expect(await cache.commit("c", [chunk(103)], 1)).toEqual([]); expect(await store.historyEpoch("c")).toBe(2); }); + +it("replaces a confirmed full history at a lower epoch, without trusting stale commits", async () => { + const store = createFakeStore(); + const cache = createConversationCache(store); + await cache.commit("c", [chunk(9)], 5); + expect(await cache.replace("c", [chunk(1)], 1, 5)).toBe(true); + expect(await cache.historyEpoch("c")).toBe(1); + expect(await cache.load("c")).toEqual([chunk(1)]); + expect(await cache.commit("c", [chunk(9)], 5)).toEqual([chunk(1)]); + // A delayed full response started against epoch 5 must not restore it. + expect(await cache.replace("c", [chunk(9)], 5, 5)).toBe(false); + expect(await cache.load("c")).toEqual([chunk(1)]); +}); + +it("serializes a guarded replacement behind newer invalidation", async () => { + const store = createFakeStore(); + const cache = createConversationCache(store); + await cache.commit("c", [chunk(9)], 5); + const resetting = cache.reset("c", 6); + const replacing = cache.replace("c", [chunk(1)], 1, 5); + await resetting; + expect(await replacing).toBe(false); + expect(await cache.historyEpoch("c")).toBe(6); + expect(await cache.load("c")).toEqual([]); +}); + +it("allows an empty replacement and a legacy cache only if its observed epoch still matches", async () => { + const store = createFakeStore(); + const cache = createConversationCache(store); + await store.append("c", [chunk(9)]); + expect(await cache.replace("c", [], 0, undefined)).toBe(true); + expect(await cache.sinceSeq("c")).toBe(0); + expect(await cache.historyEpoch("c")).toBe(0); + expect(await cache.replace("c", [chunk(9)], 2, undefined)).toBe(false); +}); |
