Archilyzer · Source

archilyzer

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

commit eaf0cfaef447c1f95890edf14d984c1d36d31ca8
parent fa3a3517cf4c01ca1f86ce15c0f236ef7dc569d6
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue,  8 Sep 2026 08:20:40 -0400

editor: the e2e fixture's video id matches its directory, and a reset quiesces before it mutates

`video-page.spec.ts` "Delete directory wrong-id confirmation" reddened once in a
full run, asserting a directory that was never deleted was gone. It had been
RENAMED. Snapshot generation calls reconcileVideoDirs, which moves
`data/<name>` to `data/<extractVideoId(webpage_url)>` when the two differ, and
`one-youtube-channel-with-data` was the only fixture in the tree whose canonical
id was not its directory name. The preceding test's delete-file action armed the
debounced regen; resetData copied the fixture back in and only then invalidated,
so the regen fired into the fresh copy and renamed it. The page still rendered
because the video page swallows the readdir failure.

Two changes, neither to the product. The fixture's `id` and `webpage_url` now
carry `20240101_test1234567`, so the canonical id equals the directory name and
reconcile has nothing to do; the directory is NOT renamed to `test1234567`
because video-page.spec.ts:148 creates a different video by that id in the same
channel. `regional-vtt-fallback.spec.ts` looks a record up by the index id,
which is `metadata.info.json`'s `id`, so its VIDEO_ID follows the fixture.
And resetData now calls `/api/test/invalidate-cache` before the `rm` as well as
after it: that route's `resetSnapshotScheduler()` cancels exactly the pending
regen that did the damage. Quiesce, then mutate. `fileExists` re-throws anything
that is not ENOENT rather than reporting a transient errno as "gone".

Measured from a worktree at this tree, one worker, behind the e2e queue:
`playwright test video-page.spec.ts --repeat-each 10` — **200 passed, 0 failed,
5.0 min**, the whole file each round so :196 always precedes :216. (`pnpm e2e --`
inserts a literal `--` that Playwright reads as end-of-flags, so `--repeat-each`
became a filename filter and the run was a single pass of 20; the stress was run
through `node ../scripts/queue-lock.mjs --ports PORT:3011,EXPORT_PORT:3010,OLLAMA_STUB_PORT:11435
-- pnpm exec playwright test …`, the same lock and ports the script takes.)

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

Diffstat:
Meditor/e2e/fixtures/test-transcripts/one-youtube-channel-with-data/channels/test-youtube/data/20240101_test1234567/metadata.info.json | 4++--
Meditor/e2e/helpers.ts | 32+++++++++++++++++++++-----------
Meditor/e2e/regional-vtt-fallback.spec.ts | 5++++-
3 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/editor/e2e/fixtures/test-transcripts/one-youtube-channel-with-data/channels/test-youtube/data/20240101_test1234567/metadata.info.json b/editor/e2e/fixtures/test-transcripts/one-youtube-channel-with-data/channels/test-youtube/data/20240101_test1234567/metadata.info.json @@ -1,5 +1,5 @@ { - "id": "test1234567", + "id": "20240101_test1234567", "title": "Synthetic Test Video", "channel": "Test YouTube Channel", "channel_id": "UCtestchannelid", @@ -13,5 +13,5 @@ "live_status": "not_live", "age_limit": 0, "extractor_key": "Youtube", - "webpage_url": "https://www.youtube.com/watch?v=test1234567" + "webpage_url": "https://www.youtube.com/watch?v=20240101_test1234567" } diff --git a/editor/e2e/helpers.ts b/editor/e2e/helpers.ts @@ -26,22 +26,32 @@ async function fileExists(p: string): Promise<boolean> { try { await stat(p); return true; - } catch { + } catch (err) { + // Only "it is not there" means false. Any other errno (EACCES, EIO, a + // transient ELOOP over a symlinked fixture) is a real fault and must not + // be laundered into a confident "gone" that a caller then acts on. + if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err; return false; } } export async function resetData(fixtureName: string | null = null) { - // maxRetries is load-bearing, not defensive padding. A job left running by the - // PREVIOUS spec (the registry/runner singletons live in the one Next server, - // and are only cleared by the invalidate-cache call at the end of this - // function) can write a file back into this tree while the recursive walk is - // deleting it — the walk then empties a directory, the runner re-creates a - // file in it, and the rmdir fails with ENOTEMPTY. Node retries the whole - // operation with linear backoff on exactly that errno set (also EBUSY/EPERM), - // which is enough for a runner that is about to notice its job is gone. - // Observed as two unrelated-looking full-suite failures at - // channel-work.spec and pipeline.spec:106; both pass in isolation. + // Quiesce the server BEFORE touching the tree, not only after. The + // registry/runner singletons live in the one Next server and outlive a spec: + // a debounced snapshot regen armed by the previous test's action fires while + // this function is copying the fixture back in, and snapshot generation calls + // reconcileVideoDirs, which RENAMES a data dir whose name differs from its + // canonical video id. Freshly copied fixture, renamed out from under the + // spec that just asked for it. Invalidating first cancels that work; the + // second call at the end of this function clears caches over the new tree. + // + // The same quiescing is why the rm below can usually complete, but maxRetries + // stays: a runner mid-write can still re-create a file inside a directory the + // recursive walk has just emptied, and the rmdir then fails with ENOTEMPTY. + // Node retries the whole operation with linear backoff on exactly that errno + // set (also EBUSY/EPERM). Observed as two unrelated-looking full-suite + // failures at channel-work.spec and pipeline.spec:106; both pass in isolation. + await fetch(`${baseUrl}/api/test/invalidate-cache`).catch(() => {}); await rm(testTranscriptsDir, { recursive: true, force: true, diff --git a/editor/e2e/regional-vtt-fallback.spec.ts b/editor/e2e/regional-vtt-fallback.spec.ts @@ -10,7 +10,10 @@ import { const CHANNEL = "test-youtube"; const VIDEO_DIR = "20240101_test1234567"; -const VIDEO_ID = "test1234567"; +// The index keys a record by metadata.info.json's `id`, which the fixture now +// keeps equal to its directory name (see that file — a mismatch made snapshot +// generation rename the directory mid-spec). +const VIDEO_ID = VIDEO_DIR; const DATA = `test-transcripts/channels/${CHANNEL}/data/${VIDEO_DIR}`; const TRANSCRIPTS_PAGE = `test-transcripts/.export-index/shared/transcripts/${CHANNEL}/page-0000.json`; // parseVtt only emits cues from lines carrying YouTube's inline word-timing