Skip to content

Commit 23b6b42

Browse files
committed
fix(session): git-rm prompt.jsonl after identical write
extraCommitPaths stripped vendor roots from the remove list because base.commit() git.adds files that still exist. It never git.removes missing ones, so a committed-then-identical prompt snapshot stayed in HEAD.
1 parent 4ebf366 commit 23b6b42

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

‎src/session/optimized-context-store.test.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,4 +1061,61 @@ describe("createOptimizedContextStore prompt dedupe (CL-9026)", () => {
10611061
expect(await gitLsTree(dir)).not.toContain(PROMPT_FILE);
10621062
expect(turnTexts((await store.load()).turns)).toEqual(["a", "b"]);
10631063
});
1064+
1065+
test("committed then identical writePrompt drops prompt.jsonl from HEAD", async () => {
1066+
const dir = tempDir();
1067+
const store = await createOptimizedContextStore(dir);
1068+
const live = [turn("a"), turn("b")];
1069+
await store.writeTurns([...live]);
1070+
await store.writePrompt([turn("a")]);
1071+
await store.writeMetadata(EMPTY_CHECKPOINT_METADATA);
1072+
await store.commit({ message: "differing prompt" });
1073+
expect(await gitLsTree(dir)).toContain(PROMPT_FILE);
1074+
1075+
await store.writePrompt(cloneTurns(live));
1076+
await store.writeMetadata(EMPTY_CHECKPOINT_METADATA);
1077+
const afterIdentical = await store.commit({ message: "identical prompt" });
1078+
expect(await gitLsTree(dir)).not.toContain(PROMPT_FILE);
1079+
expect(turnTexts((await store.load()).turns)).toEqual(["a", "b"]);
1080+
1081+
await store.writeMetadata(EMPTY_CHECKPOINT_METADATA);
1082+
const empty = await store.commit({ message: "empty checkpoint" });
1083+
expect(empty.hash).toBe(afterIdentical.hash);
1084+
});
1085+
1086+
test("identical writePrompt after multi-segment differing prompt drops all prompt files from HEAD", async () => {
1087+
const dir = tempDir();
1088+
const store = await createOptimizedContextStore(dir);
1089+
const live: ConversationTurn[] = [];
1090+
const big = "x".repeat(20_000);
1091+
for (let i = 0; i < 18; i++) {
1092+
live.push(turn(`${i}-${big}`));
1093+
}
1094+
await store.writeTurns([...live]);
1095+
1096+
const differing: ConversationTurn[] = [];
1097+
for (let i = 0; i < 18; i++) {
1098+
differing.push(turn(`p-${i}-${big}`));
1099+
}
1100+
await store.writePrompt(differing);
1101+
const extraPrompt = segmentFileName(PROMPT_FILE, 1);
1102+
expect(fs.existsSync(path.join(dir, PROMPT_FILE))).toBe(true);
1103+
expect(fs.existsSync(path.join(dir, extraPrompt))).toBe(true);
1104+
1105+
await store.writeMetadata(EMPTY_CHECKPOINT_METADATA);
1106+
await store.commit({ message: "multi-segment prompt" });
1107+
const treeAfterDiffering = await gitLsTree(dir);
1108+
expect(treeAfterDiffering).toContain(PROMPT_FILE);
1109+
expect(treeAfterDiffering).toContain(extraPrompt);
1110+
1111+
await store.writePrompt(cloneTurns(live));
1112+
await store.writeMetadata(EMPTY_CHECKPOINT_METADATA);
1113+
await store.commit({ message: "identical drops prompt segments" });
1114+
const tree = await gitLsTree(dir);
1115+
expect(tree).not.toContain(PROMPT_FILE);
1116+
expect(tree).not.toContain(extraPrompt);
1117+
expect(turnTexts((await store.load()).turns)).toEqual(
1118+
live.map((t) => (t.content[0] as { text: string }).text),
1119+
);
1120+
});
10641121
});

‎src/session/optimized-context-store.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -864,9 +864,10 @@ export async function createSessionStores(
864864
}
865865

866866
const add = extraCommitPaths([...new Set(toAdd)]);
867-
const remove = extraCommitPaths([...new Set(toRemove)]).filter(
868-
(p) => !add.includes(p),
869-
);
867+
// extraCommitPaths strips vendor roots because base.commit() git.adds
868+
// those that still exist. It does not git.remove missing ones, so an
869+
// unlinked prompt.jsonl must stay in `remove`.
870+
const remove = [...new Set(toRemove)].filter((p) => !add.includes(p));
870871
extraPaths = [...new Set([...add, ...remove])];
871872

872873
for (const filepath of add) {

0 commit comments

Comments
 (0)