refactor: stop creating jsonl compaction successors

This commit is contained in:
Peter Steinberger
2026-05-08 13:32:17 +01:00
parent ac0b29e9a4
commit f04fae4c6a
2 changed files with 35 additions and 21 deletions

View File

@@ -281,6 +281,25 @@ describe("rotateTranscriptAfterCompaction", () => {
expect(result.reason).toBe("no compaction entry");
});
it("does not create legacy jsonl successor files for unmigrated transcripts", async () => {
const dir = await createTmpDir();
const { manager } = createCompactedSession(dir);
const result = await rotateTranscriptAfterCompaction({
sessionManager: manager,
sessionFile: path.join(dir, "legacy-session.jsonl"),
now: () => new Date("2026-04-27T12:15:00.000Z"),
});
expect(result).toMatchObject({
rotated: false,
reason: "transcript not in SQLite",
});
await expect(
fs.stat(path.join(dir, "2026-04-27T12-15-00-000Z_legacy-session.jsonl")),
).rejects.toMatchObject({ code: "ENOENT" });
});
it("uses a refreshed manager after manual boundary hardening", async () => {
const dir = await createTmpDir();
const manager = SessionManager.create(dir);

View File

@@ -1,5 +1,4 @@
import { randomUUID } from "node:crypto";
import path from "node:path";
import {
createSqliteSessionTranscriptLocator,
isSqliteSessionTranscriptLocator,
@@ -52,6 +51,9 @@ export async function rotateTranscriptAfterCompaction(params: {
if (!sessionFile) {
return { rotated: false, reason: "missing session file" };
}
if (!isSqliteSessionTranscriptLocator(sessionFile)) {
return { rotated: false, reason: "transcript not in SQLite" };
}
const branch = params.sessionManager.getBranch();
const latestCompactionIndex = findLatestCompactionIndex(branch);
@@ -62,10 +64,14 @@ export async function rotateTranscriptAfterCompaction(params: {
const compaction = branch[latestCompactionIndex] as CompactionEntry;
const timestamp = (params.now?.() ?? new Date()).toISOString();
const sessionId = randomUUID();
const sourceScope = resolveSourceTranscriptScope({
agentId: params.agentId,
transcriptPath: sessionFile,
});
const successorTranscriptPath = resolveSuccessorTranscriptPath({
transcriptPath: sessionFile,
sessionId,
timestamp,
agentId: sourceScope.agentId,
});
const successorEntries = buildSuccessorEntries({
allEntries: params.sessionManager.getEntries(),
@@ -83,10 +89,6 @@ export async function rotateTranscriptAfterCompaction(params: {
cwd: params.sessionManager.getCwd(),
parentSession: sessionFile,
});
const sourceScope = resolveSourceTranscriptScope({
agentId: params.agentId,
transcriptPath: sessionFile,
});
replaceSqliteSessionTranscriptEvents({
agentId: sourceScope.agentId,
sessionId,
@@ -360,20 +362,13 @@ function buildSuccessorHeader(params: {
function resolveSuccessorTranscriptPath(params: {
transcriptPath: string;
sessionId: string;
timestamp: string;
agentId: string;
}): string {
if (isSqliteSessionTranscriptLocator(params.transcriptPath)) {
const existing = resolveSqliteSessionTranscriptScopeForPath({
transcriptPath: params.transcriptPath,
});
return createSqliteSessionTranscriptLocator({
agentId: existing?.agentId,
sessionId: params.sessionId,
});
}
const fileTimestamp = params.timestamp.replace(/[:.]/g, "-");
return path.join(
path.dirname(params.transcriptPath),
`${fileTimestamp}_${params.sessionId}.jsonl`,
);
const existing = resolveSqliteSessionTranscriptScopeForPath({
transcriptPath: params.transcriptPath,
});
return createSqliteSessionTranscriptLocator({
agentId: params.agentId || existing?.agentId || DEFAULT_AGENT_ID,
sessionId: params.sessionId,
});
}