commit 4d89abf91a8ae8ee3aa488d51d0e3d21ed2d3001
parent 00f8b1b8c6417689c1391862508f0f1091bbc35f
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 11:06:05 -0400
common: an identical scan error refreshes its `at` once a cooldown old
upsertMetadataScan skipped an error identical in class + message, so `at`
never moved and metadataScanWanted re-queued the id at every runner start
(142 members-only legal-mindset videos, cookie-authed, each start). It now
also rewrites when now - prev.at >= METADATA_SCAN_ERROR_COOLDOWN_MS.
metadataScanStore.test +2 (25 h later rewrites; 1 h later leaves the file).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/common/controller/metadataScanStore.test.ts b/common/controller/metadataScanStore.test.ts
@@ -132,6 +132,43 @@ test("an unchanged upsert skips the write entirely", async () => {
});
});
+test("an identical error a cooldown old refreshes its `at` (25 h later rewrites)", async () => {
+ await withPaths(async (paths) => {
+ const err = { class: "members_only", message: "join", at: T1 };
+ await upsertMetadataScan(paths, SLUG, { errors: { a: err } }, T1);
+ const later = new Date(Date.parse(T1) + 25 * 3_600_000).toISOString();
+ await upsertMetadataScan(
+ paths,
+ SLUG,
+ { errors: { a: { ...err, at: later } } },
+ later,
+ );
+ const scan = await loadMetadataScan(paths, SLUG);
+ assert.equal(scan.errors.a.at, later);
+ assert.equal(scan.updatedAt, later);
+ });
+});
+
+test("an identical error inside the cooldown leaves the file alone (1 h later)", async () => {
+ await withPaths(async (paths) => {
+ const err = { class: "members_only", message: "join", at: T1 };
+ await upsertMetadataScan(paths, SLUG, { errors: { a: err } }, T1);
+ const file = metadataScanPath(paths, SLUG);
+ const before = (await stat(file)).mtimeMs;
+ const later = new Date(Date.parse(T1) + 3_600_000).toISOString();
+ await upsertMetadataScan(
+ paths,
+ SLUG,
+ { errors: { a: { ...err, at: later } } },
+ later,
+ );
+ assert.equal((await stat(file)).mtimeMs, before);
+ const scan = await loadMetadataScan(paths, SLUG);
+ assert.equal(scan.errors.a.at, T1);
+ assert.equal(scan.updatedAt, T1);
+ });
+});
+
test("normalize-on-read drops unknown fields and malformed records", async () => {
await withPaths(async (paths) => {
await writeFile(
diff --git a/common/controller/metadataScanStore.ts b/common/controller/metadataScanStore.ts
@@ -247,7 +247,16 @@ export async function upsertMetadataScan(
// a later pass must not un-scan it.
if (scan.entries[id]) continue;
const prev = scan.errors[id];
- if (!prev || prev.class !== err.class || prev.message !== err.message) {
+ // An IDENTICAL error still rewrites once its `at` is a cooldown old: `at`
+ // is what metadataScanWanted reads, so leaving it stale re-queues the id
+ // at every runner start forever (142 members-only videos re-scanned,
+ // cookie-authed, at each start). Refreshed, the id rests for another day.
+ if (
+ !prev ||
+ prev.class !== err.class ||
+ prev.message !== err.message ||
+ Date.parse(now) - Date.parse(prev.at) >= METADATA_SCAN_ERROR_COOLDOWN_MS
+ ) {
scan.errors[id] = err;
changed = true;
}