From 46ea5a051b17bd2458b949ee459b622763b2348f Mon Sep 17 00:00:00 2001 From: Abdulrahman Alfozan Date: Sun, 7 Jun 2026 21:58:50 -0700 Subject: [PATCH 1/2] Fix transcript cache mtime writes - Include fileMtime when writing transcript cache entries - Add real cache-store regression coverage for local file transcripts --- src/cache.ts | 13 +++++-------- tests/cache.store.test.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/cache.ts b/src/cache.ts index b1fa4b1c..250cd71b 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -362,20 +362,17 @@ export async function createCacheStore({ typeof transcriptNamespace === "string" && transcriptNamespace.trim().length > 0 ? transcriptNamespace.trim() : null; - const getTranscriptKey = (url: string): string => + const getTranscriptKey = (url: string, fileMtime?: number | null): string => buildTranscriptCacheKey({ url, namespace: normalizedTranscriptNamespace, + fileMtime, }); const transcriptCache: TranscriptCache = { get: async ({ url, fileMtime }) => { const now = Date.now(); - const key = buildTranscriptCacheKey({ - url, - namespace: normalizedTranscriptNamespace, - fileMtime, - }); + const key = getTranscriptKey(url, fileMtime); const row = readEntry("transcript", key, now); if (!row) return null; const expired = typeof row.expires_at === "number" && row.expires_at <= now; @@ -400,8 +397,8 @@ export async function createCacheStore({ metadata: (payload?.metadata as Record | null | undefined) ?? null, }; }, - set: async ({ url, content, source, ttlMs, metadata, service, resourceKey }) => { - const key = getTranscriptKey(url); + set: async ({ url, content, source, ttlMs, metadata, service, resourceKey, fileMtime }) => { + const key = getTranscriptKey(url, fileMtime); setJson( "transcript", key, diff --git a/tests/cache.store.test.ts b/tests/cache.store.test.ts index 6af51d8d..c9a6a07e 100644 --- a/tests/cache.store.test.ts +++ b/tests/cache.store.test.ts @@ -182,6 +182,34 @@ describe("cache store", () => { otherStore.close(); }); + it("keys local transcript cache writes by file mtime", async () => { + const root = mkdtempSync(join(tmpdir(), "summarize-cache-")); + const path = join(root, "cache.sqlite"); + const store = await createCacheStore({ path, maxBytes: 1024 * 1024 }); + const url = "file:///tmp/audio.opus"; + + await store.transcriptCache.set({ + url, + service: "generic", + resourceKey: null, + ttlMs: 1000, + content: "cached transcript", + source: "yt-dlp", + metadata: null, + fileMtime: 1234, + }); + + const hit = await store.transcriptCache.get({ url, fileMtime: 1234 }); + const staleFile = await store.transcriptCache.get({ url, fileMtime: 5678 }); + const noMtime = await store.transcriptCache.get({ url }); + + expect(hit?.content).toBe("cached transcript"); + expect(staleFile).toBeNull(); + expect(noMtime).toBeNull(); + + store.close(); + }); + it("transcript cache normalizes unknown sources and handles bad payloads", async () => { const root = mkdtempSync(join(tmpdir(), "summarize-cache-")); const path = join(root, "cache.sqlite"); From 5c550efc071960d0b6a1e3ab843003f0688e0e1e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 11 Jun 2026 00:10:06 +0100 Subject: [PATCH 2/2] docs: credit transcript cache fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b1484ce..3f910114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Fixes +- CLI cache: include local media `fileMtime` when writing transcript cache entries so repeated unchanged audio/video extraction can hit cache (#240, #241, thanks @alfozan). - CLI: pass Codex image attachments to `codex exec` so local image summaries no longer fail before starting (#242, #243, thanks @alfozan). - Chrome extension: abort stale side-panel summary streams on tab changes so delayed output from a closed or replaced tab cannot render under the new page title. - Core: extract video IDs from YouTube `/live/` URLs so live and premiere links no longer abort summarization (#232, thanks @devYRPauli).