authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-18 01:30:38-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-02-18 21:59:17-08:00
log6aea858ed85fc3e8e4b41d6164b428a80895dcc7
tree5b874cdb67a5f7bb0aabdb7f5a996115d94126b0
parentf07b6ac8e6d17efde13fe3135bb52159962b5bdc

Scope checkpoint diff cache keys to avoid collisions

- Include `cacheScope` in checkpoint diff query keys - Pass turn/conversation-specific scopes from `ChatView` and `DiffPanel` - Add tests for key separation and API argument forwarding

4 files changed, 64 insertions(+), 0 deletions(-)

apps/web/src/components/ChatView.tsx+1
......@@ -529,6 +529,7 @@ export default function ChatView() {
529529 threadRuntimeId: activeThreadRuntimeId,
530530 fromTurnCount: target.fromTurnCount,
531531 toTurnCount: target.toTurnCount,
532 cacheScope: `turn:${target.turnId}`,
532533 }),
533534 ),
534535 });
apps/web/src/components/DiffPanel.tsx+8
......@@ -138,12 +138,19 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) {
138138 const activeCheckpointRange = selectedTurn
139139 ? selectedCheckpointRange
140140 : conversationCheckpointRange;
141 const conversationCacheScope = useMemo(() => {
142 if (selectedTurn || turnDiffSummaries.length === 0) {
143 return null;
144 }
145 return `conversation:${turnDiffSummaries.map((summary) => summary.turnId).join(",")}`;
146 }, [selectedTurn, turnDiffSummaries]);
141147 const activeCheckpointDiffQuery = useQuery(
142148 checkpointDiffQueryOptions(api, {
143149 sessionId: activeSessionId,
144150 threadRuntimeId: activeThreadRuntimeId,
145151 fromTurnCount: activeCheckpointRange?.fromTurnCount ?? null,
146152 toTurnCount: activeCheckpointRange?.toTurnCount ?? null,
153 cacheScope: selectedTurn ? `turn:${selectedTurn.turnId}` : conversationCacheScope,
147154 }),
148155 );
149156 const selectedTurnCheckpointDiff = selectedTurn
......@@ -184,6 +191,7 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) {
184191 threadRuntimeId: activeThreadRuntimeId,
185192 fromTurnCount: Math.max(0, checkpointTurnCount - 1),
186193 toTurnCount: checkpointTurnCount,
194 cacheScope: `turn:${summary.turnId}`,
187195 }),
188196 )?.diff;
189197 if (checkpointPatch) {
apps/web/src/lib/providerReactQuery.test.ts created+53
......@@ -0,0 +1,53 @@
1import type { NativeApi } from "@t3tools/contracts";
2import { describe, expect, it, vi } from "vitest";
3import { checkpointDiffQueryOptions, providerQueryKeys } from "./providerReactQuery";
4
5describe("providerQueryKeys.checkpointDiff", () => {
6 it("includes cacheScope so reused turn counts do not collide", () => {
7 const baseInput = {
8 sessionId: "session-id",
9 threadRuntimeId: "thread-id",
10 fromTurnCount: 1,
11 toTurnCount: 2,
12 } as const;
13
14 expect(
15 providerQueryKeys.checkpointDiff({
16 ...baseInput,
17 cacheScope: "turn:old-turn",
18 }),
19 ).not.toEqual(
20 providerQueryKeys.checkpointDiff({
21 ...baseInput,
22 cacheScope: "turn:new-turn",
23 }),
24 );
25 });
26});
27
28describe("checkpointDiffQueryOptions", () => {
29 it("forwards checkpoint range to the provider API", async () => {
30 const getCheckpointDiff = vi.fn().mockResolvedValue({ diff: "patch" });
31 const api = {
32 providers: {
33 getCheckpointDiff,
34 },
35 } as unknown as NativeApi;
36
37 const options = checkpointDiffQueryOptions(api, {
38 sessionId: "session-id",
39 threadRuntimeId: "thread-id",
40 fromTurnCount: 3,
41 toTurnCount: 4,
42 cacheScope: "turn:abc",
43 });
44
45 await options.queryFn();
46
47 expect(getCheckpointDiff).toHaveBeenCalledWith({
48 sessionId: "session-id",
49 fromTurnCount: 3,
50 toTurnCount: 4,
51 });
52 });
53});
apps/web/src/lib/providerReactQuery.ts+2
......@@ -6,6 +6,7 @@ export interface CheckpointDiffQueryInput {
66 threadRuntimeId: string | null;
77 fromTurnCount: number | null;
88 toTurnCount: number | null;
9 cacheScope?: string | null;
910}
1011
1112export const providerQueryKeys = {
......@@ -18,6 +19,7 @@ export const providerQueryKeys = {
1819 input.threadRuntimeId,
1920 input.fromTurnCount,
2021 input.toTurnCount,
22 input.cacheScope ?? null,
2123 ] as const,
2224};
2325