Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit cd1c5dbea3a0baa6c23f762bad774bdbc17ee207
parent 0a2639b3dc1794f75c2ca458ef225da1e4f792ea
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  1 Oct 2026 22:10:35 -0400

common: the index probes the media drive through the watchdog and reads a tiered raw live chat directly; a track neither read nor kept is retried (re-review R1)

One stat under the watchdog's budget, then the read outside it, so a large
replay on a slow platter is neither refused nor marks the location stalled;
when nothing was read or kept the record stores subsMs null and the next
build retries. Case (l), mutation-checked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mcommon/controller/buildIndex.test.ts | 32++++++++++++++++++++++++++++++++
Mcommon/controller/buildIndex.ts | 21+++++++++++++++------
2 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/common/controller/buildIndex.test.ts b/common/controller/buildIndex.test.ts @@ -769,6 +769,38 @@ test("(k) release 17: a STALLED media drive with a tiered live chat holds neithe } }); +test("(l) release 17: a tiered raw live chat that cannot be read, with no cues to keep, is retried by the next build", async () => { + resetCorpus(); + seedVideo("local"); + seedDriveChannel(); + const chat = + JSON.stringify({ replayChatItemAction: { actions: [{ addChatItemAction: { item: { liveChatTextMessageRenderer: { message: { runs: [{ text: "hi" }] }, authorName: { simpleText: "a" }, timestampUsec: "1000000" } } } }], videoOffsetTimeMsec: "1000" } }) + "\n"; + mkdirSync(path.join(DRIVE_MEDIA(), "d2"), { recursive: true }); + writeFileSync(path.join(DRIVE_MEDIA(), "d2", "transcript.live_chat.json"), chat); + symlinkSync("../../media/d2/transcript.live_chat.json", path.join(videoDir("d2", DRIVE_CHANNEL), "transcript.live_chat.json")); + const tracksOfD2 = () => + withIndex((db) => + [...db("subs").getRange()] + .filter(({ key }) => (key as unknown as string[])[2] === "d2") + .flatMap(({ value }) => (value as { track: string }[]).map((t) => t.track)), + ); + // The media drive is away for the first build: nothing to read, nothing kept. + unmountMedia(); + try { + const away = await runIndex(); + assert.deepEqual(away.res.heldChannels, []); + assert.equal(tracksOfD2().includes("live_chat"), false); + } finally { + remountMedia(); + } + // Back: nothing on disk moved, yet the record is retried and the chat read. + const back = await runIndex(); + assert.equal(back.res.changed, 1, "d2 is retried"); + assert.ok(tracksOfD2().includes("live_chat")); + // And then it settles. + assert.equal((await runIndex()).res.changed, 0); +}); + test("(z) no write this file caused landed outside its temp root", () => { // LMDB writes natively, past the spy: its file must be under the root too. assert.ok(paths.lmdbPath.startsWith(ROOT + path.sep), paths.lmdbPath); diff --git a/common/controller/buildIndex.ts b/common/controller/buildIndex.ts @@ -896,6 +896,9 @@ export async function buildIndex({ else cues.remove(indexKey); const parsedSubs: StoredSubs = []; + // A tiered track that could be neither read nor kept: `subsMs` is + // stored null so the next build's scan sees a change and retries. + let retrySubs = false; for (const t of s.subTracks) { try { let trackCues: Cue[] | null = null; @@ -912,9 +915,14 @@ export async function buildIndex({ const rawPath = path.join(path.dirname(s.metaPath), t.filename); // THE RAW REPLAY IS MEDIA (release 17). Tiered — a link into // channels/<slug>/media — it is read only while the channel's - // media is reachable, through the watchdog; otherwise (or when - // the drive does not answer) the cues the last build held are - // kept, and the track is re-read on a later build. + // media is reachable: the drive is PROBED through the watchdog + // (one stat, which is what its budget is sized for), then the + // file is read directly — a raw replay of hundreds of MB on a + // slow platter would outlast the budget, be refused, and, where + // the disk's counters are unknown, mark the location stalled. + // Not read (unreachable, not answering, unreadable): the cues + // the last build held are kept; with none to keep, the record + // is written with no sub-track time, so the next build retries. const tiered = t.track === "live_chat" && (await lstat(rawPath).then((l) => l.isSymbolicLink(), () => false)); @@ -923,8 +931,8 @@ export async function buildIndex({ let raw: string | null = null; if (access?.readable) { try { - const read = () => readFile(rawPath, "utf8"); - raw = await (access.drive ? onDrive(access.drive, read) : read()); + if (access.drive) await onDrive(access.drive, () => stat(rawPath)); + raw = await readFile(rawPath, "utf8"); } catch { raw = null; } @@ -932,6 +940,7 @@ export async function buildIndex({ if (raw === null) { const kept = prevSubs?.find((x) => x.track === t.track); if (kept) parsedSubs.push(kept); + else retrySubs = true; continue; } trackCues = parseLiveChat(raw); @@ -1041,7 +1050,7 @@ export async function buildIndex({ mtimes.put(pk, { metaMs: s.metaMs, transcriptMs: s.transcriptMs, - subsMs: s.subsMs, + subsMs: retrySubs ? null : s.subsMs, availabilityMs: s.availabilityMs, digestMs: s.digestMs, ...(availability ? { availability } : {}),