Archilyzer · Source

archilyzer

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

commit c80cd066474b267503fd2a2c8cb640b4e4dd2885
parent 3caac3c614b6d18a13acb0abd41d5cb5d3fb6f7c
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue, 29 Sep 2026 21:16:37 -0400

common(test): review M1 — case (i): the drive is lost mid-walk (after the scan's first metadata stat); the second look holds the channel, 0 removed, records and pages unchanged (without that look, 3 of 4 removed)

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

Diffstat:
Mcommon/controller/buildIndex.test.ts | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+), 0 deletions(-)

diff --git a/common/controller/buildIndex.test.ts b/common/controller/buildIndex.test.ts @@ -77,6 +77,7 @@ const COMMON = fileURLToPath(new URL("..", import.meta.url)); // sync and callback, synced into the named ESM imports the code under test // holds. The last case reads it. const writes: string[] = []; +let afterStat: ((p: string) => void) | null = null; { const req = createRequire(import.meta.url); const fsCjs = req("node:fs") as Record<string, unknown>; @@ -111,6 +112,15 @@ const writes: string[] = []; wrap(fsCjs, "open", "open"); wrap(fsCjs, "openSync", "open"); wrap(fsCjs, "createWriteStream", "write"); + // Case (i)'s hook: the drive is lost DURING the scan's walk. node:fs/promises + // `stat` calls `afterStat` with each path it has just answered for. + const stat = fspCjs.stat as (...a: unknown[]) => Promise<unknown>; + fspCjs.stat = async function (this: unknown, ...args: unknown[]) { + const result = await stat.apply(this, args); + const p = asPath(args[0]); + if (p !== null) afterStat?.(path.resolve(p)); + return result; + }; syncBuiltinESMExports(); } @@ -584,6 +594,47 @@ test("(h) a curated-tag change while a channel is held reaches its pages when th assert.equal(pagesPending(), false); }); +test("(i) the drive lost MID-WALK: the second look holds the channel instead of dropping the rest of it", async () => { + resetCorpus(); + seedVideo("local"); + seedDriveChannel(); + for (const id of ["d3", "d4"]) seedVideo(id, DRIVE_CHANNEL); + const drive = [...DRIVE_VIDEOS, `${DRIVE_CHANNEL}/d3`, `${DRIVE_CHANNEL}/d4`]; + await runIndex(); + assert.deepEqual(indexed(), [...drive, `${CHANNEL}/local`]); + const pagesBefore = sharedTranscripts(); + const subsBefore = sharedSubs(); + + // The first look before the walk finds the drive, and readdir lists all four + // videos. Then the drive goes, right after the walk's first metadata stat: + // every later stat in the channel is ENOENT, which on its own reads as "no + // metadata yet" and would drop the rest of the channel as gone. + let lost = false; + afterStat = (p) => { + if (lost || !p.endsWith(`${path.sep}metadata.info.json`)) return; + if (!p.includes(`${path.sep}${DRIVE_CHANNEL}${path.sep}data${path.sep}`)) return; + lost = true; + unmount(); + }; + seedVideo("local2"); // so the build is not a no-op + const { res, log } = await runIndex().finally(() => { + afterStat = null; + }); + assert.ok(lost, "the drive went away inside the walk"); + assert.deepEqual(res.heldChannels, [DRIVE_CHANNEL]); + assert.equal(res.removed, 0, log.join("\n")); + assert.equal(res.added, 1); + assert.deepEqual(indexed(), [...drive, `${CHANNEL}/local`, `${CHANNEL}/local2`]); + assert.deepEqual(sharedTranscripts(), pagesBefore); + assert.deepEqual(sharedSubs(), subsBefore); + assert.ok( + log.some((l) => + l.startsWith(`Channel ${DRIVE_CHANNEL}: its media is not reachable (drive not mounted?), on location "USB drive"; its 4 indexed video(s) are kept`), + ), + log.join("\n"), + ); +}); + 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);