ask the events table which key a transcript belongs to, instead of a live map
The id-space fix worked only for conversations younger than the process. The caller resolves a session key from an in-memory map filled as sessions announce themselves, so anything created before the last restart resolves to null and the key list arrives empty — which is exactly what the first live test did. Everything else cascaded; the events stayed, silently, for the one reason the code could not report. The answer was already in the rows. Every event carries `claudeSessionId` in its payload: durable, restart-proof, and the one place the two id spaces are written down beside each other. One event carrying that id resolves the key for all of that session's rows — including the majority that carry no id of their own. `sessionKeys` stays as a fast path for a live session and is now a hint rather than the answer. A cleanup that only works for conversations younger than the process is not a cleanup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { inArray } from 'drizzle-orm';
|
||||
import { inArray, sql } from 'drizzle-orm';
|
||||
import { db } from './db';
|
||||
import { chatSessionEvents } from './chat-events/schema';
|
||||
import { chatNotificationPrefs } from './chat-notification-prefs/schema';
|
||||
@@ -66,7 +66,27 @@ export async function forgetChatSessions({ transcriptIds, sessionKeys = [] }: Fo
|
||||
await db.delete(chatSessionModels).where(inArray(chatSessionModels.sessionId, transcriptIds));
|
||||
await db.delete(chatNotificationPrefs).where(inArray(chatNotificationPrefs.sessionId, transcriptIds));
|
||||
}
|
||||
if (sessionKeys.length) {
|
||||
/*
|
||||
Events, resolved from the table's OWN data rather than from the caller's key.
|
||||
|
||||
`sessionKeys` is a fast path and not a reliable one: the caller gets it from an in-memory map that is
|
||||
empty for any session created before the last restart, so the first real test of this deleted everything
|
||||
except the events — the key came back null and the list was empty. A cleanup that only works for
|
||||
conversations younger than the process is not a cleanup.
|
||||
|
||||
So ask the rows. Every event carries `claudeSessionId` in its payload, which is durable, survives any
|
||||
restart, and is the one place the two id spaces are written down together. One id inside the JSON is
|
||||
enough to resolve the key for all of that session's rows, including the events that carry no id of their
|
||||
own — which is most of them.
|
||||
*/
|
||||
if (transcriptIds.length) {
|
||||
const keysFromEvents = await db
|
||||
.selectDistinct({ sessionId: chatSessionEvents.sessionId })
|
||||
.from(chatSessionEvents)
|
||||
.where(inArray(sql`${chatSessionEvents.event}->>'claudeSessionId'`, transcriptIds));
|
||||
const keys = [...new Set([...sessionKeys, ...keysFromEvents.map((r) => r.sessionId)])];
|
||||
if (keys.length) await db.delete(chatSessionEvents).where(inArray(chatSessionEvents.sessionId, keys));
|
||||
} else if (sessionKeys.length) {
|
||||
await db.delete(chatSessionEvents).where(inArray(chatSessionEvents.sessionId, sessionKeys));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user