From ae9bcfec3adaae454d8405478b8a4ad552a303e4 Mon Sep 17 00:00:00 2001 From: biosias Date: Tue, 22 Sep 2026 16:02:31 +0200 Subject: [PATCH] Fix IndexedDB cache being defeated when mtime is unparseable (AI) resolveStub() required a non-null mtime to reuse a cached hydrated entry, so any listing without a parseable mtime (HTML-autoindex fallback edge cases) rebuilt every stub from scratch on every crawl. Comparing mtime directly (including null === null) trusts the cache when there's no evidence either way, same as before this changed. Co-Authored-By: Claude Sonnet 5 --- js/discovery.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/js/discovery.js b/js/discovery.js index 69f37c9..e879fbe 100644 --- a/js/discovery.js +++ b/js/discovery.js @@ -217,11 +217,18 @@ function normalizeMtime(mtime) { // string. `cacheSnapshot` is the whole cache read once up front (see // runCrawl) — an in-memory lookup here instead of a separate IndexedDB read // per file, which mattered when this also had to guard a listing fetch; -// kept anyway since it's still the same one cheap lookup. +// kept anyway since it's still the same one cheap lookup. `mtime` is a +// change-detection signal, not a required key: `cached.mtime === mtime` +// already matches when both are `null` (a server whose listing never +// yields a parseable mtime — see parseHtmlDirectoryListing), which is the +// right call — there's no evidence the file changed, as opposed to a +// mismatch, which is evidence that it did. Treating "unknown" as "assume +// changed" would defeat the cache on every single crawl instead of just +// when a file actually needs re-hydrating. function resolveStub(author, fileName, mtime, authorRoot, cacheSnapshot) { const path = `${authorRoot}${encodeURIComponent(fileName)}`; const cached = cacheSnapshot.get(path); - if (cached && mtime != null && cached.mtime === mtime && cached.article?.hydrated) return cached.article; + if (cached && cached.mtime === mtime && cached.article?.hydrated) return cached.article; return buildStub(author, fileName, mtime, authorRoot); }