Archilyzer · Source

archilyzer

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

commit 9b0f8b17988c60dc0fe05d822d856789f8d3922b
parent 72ac50ae460720f6d3851696ef81c6f92453461a
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  1 Oct 2026 20:59:33 -0400

common, editor(e2e): a unit test pins the yield; the e2e budget is capped at 15 s (D0 review L5)

snapshotYield.test.ts: a setImmediate probe queued during the first chunk runs
before the second chunk's first unit (fails with the yield removed). The spec's
idle-floored budget stops at 15 s, and its header says what it pins.

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

Diffstat:
Mcommon/controller/channelSnapshot.ts | 5+++--
Acommon/controller/snapshotYield.test.ts | 39+++++++++++++++++++++++++++++++++++++++
Meditor/e2e/dashboard-answers.spec.ts | 14++++++++++++--
3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/common/controller/channelSnapshot.ts b/common/controller/channelSnapshot.ts @@ -694,8 +694,9 @@ const SNAPSHOT_VIDEO_CONCURRENCY = 16; const SNAPSHOT_YIELD_EVERY = 2 * SNAPSHOT_VIDEO_CONCURRENCY; // `fn` over `items` in chunks of `size`, in order, one setImmediate between -// chunks. The concurrency inside a chunk is whatever `fn` imposes. -async function mapInYieldingChunks<T, R>( +// chunks. The concurrency inside a chunk is whatever `fn` imposes. Exported for +// snapshotYield.test.ts, which pins the yield. +export async function mapInYieldingChunks<T, R>( items: readonly T[], size: number, fn: (item: T) => Promise<R>, diff --git a/common/controller/snapshotYield.test.ts b/common/controller/snapshotYield.test.ts @@ -0,0 +1,39 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { mapInYieldingChunks } from "./channelSnapshot"; + +// Run with: +// pnpm --filter yt-dlp-transcript-common exec tsx --test controller/snapshotYield.test.ts +// +// THE WALK YIELDS BETWEEN CHUNKS (release 17 slice D0). A macrotask queued +// while the first chunk runs — a request's I/O callback, here a setImmediate +// probe — runs before the second chunk's first unit starts. Without the yield +// every unit below would finish in microtasks before the probe ever ran. + +test("a macrotask queued during chunk 1 runs before chunk 2 starts", async () => { + const events: string[] = []; + const items = Array.from({ length: 64 }, (_, i) => i); + const out = await mapInYieldingChunks(items, 32, async (i) => { + if (i === 0) setImmediate(() => events.push("probe")); + events.push(`unit ${i}`); + await Promise.resolve(); + return i * 2; + }); + assert.deepEqual(out, items.map((i) => i * 2), "results in order"); + const probe = events.indexOf("probe"); + assert.ok(probe > events.indexOf("unit 31"), "after the first chunk"); + assert.ok(probe < events.indexOf("unit 32"), "before the second chunk"); +}); + +test("one chunk, no yield; an empty list, no call", async () => { + let calls = 0; + assert.deepEqual( + await mapInYieldingChunks([1, 2, 3], 32, async (i) => { + calls++; + return i; + }), + [1, 2, 3], + ); + assert.equal(calls, 3); + assert.deepEqual(await mapInYieldingChunks([], 32, async (i: number) => i), []); +}); diff --git a/editor/e2e/dashboard-answers.spec.ts b/editor/e2e/dashboard-answers.spec.ts @@ -29,7 +29,14 @@ import { // renders in 0.3 s on a quiet machine takes 2–4 s with nothing regenerating at // all. What this pins is that the regeneration does not starve the pages, not // how fast the machine is — so the idle measurement taken a moment before sets -// the floor, and on a quiet machine the budget is simply 5 s. +// the floor, and on a quiet machine the budget is simply 5 s. CAPPED AT 15 s: +// on a machine so loaded that idle pages take over 5 s, the floor stops +// growing, and the case fails rather than stretching to hide starvation. +// +// What the case pins, honestly: the serial queue (read from the jobs' own +// records) and starvation at the scale of seconds. The yield between chunks is +// pinned by a unit test (common/controller/snapshotYield.test.ts): on a dev +// server under load `main`'s walk answered inside such a budget too. const OPS_AUTH = { authorization: "Bearer test-worker-token" }; @@ -131,7 +138,10 @@ test("/ and /jobs answer while two large reports regenerate, one after the other for (let i = 0; i < 3; i++) { for (const path of ["/", "/jobs"]) idle.push(await timedGet(request, path)); } - const budgetMs = Math.max(5_000, 3 * Math.max(...idle.map((s) => s.ms))); + const budgetMs = Math.min( + Math.max(5_000, 3 * Math.max(...idle.map((s) => s.ms))), + 15_000, + ); // "Update all reports", through the ops API: a refresh-report job per // channel on the serial queue. The call answers when both have finished, so