Archilyzer · Source

archilyzer

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

commit 3f7b09b9d5972169ac64a9a91cc33d9ffc401d4c
parent 9f315744f6b5f6658fad5cf6256338ea9f3aeb53
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Fri, 17 Jul 2026 20:22:35 -0400

Audio-check: e2e coverage for the adaptive probe interval

Drive the AIMD backoff end-to-end: a fake source that serves corruption on its
first two download attempts (new `corruptRuns` sidecar knob, generalizing
recoverOnResume) then behaves. Each malformed checkpoint halves the live probe
interval (300->150->75ms), and the ensuing clean run steps it back up — asserted
from the job log ("Audio-check interval backoff:" / "recovering:").

Enable the adaptive cadence in the test server env (dev:test / start:test):
a 50ms floor plus recovery step/threshold overrides give the 300ms test
interval room to shrink. The change is inert for non-corrupting downloads, so
the rest of the audio-check suite is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Diffstat:
Meditor/e2e/audio-check-scenarios.spec.ts | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Meditor/e2e/fixtures/bin/fake-ytdlp.mjs | 11+++++++++++
Meditor/package.json | 4++--
3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/editor/e2e/audio-check-scenarios.spec.ts b/editor/e2e/audio-check-scenarios.spec.ts @@ -14,6 +14,10 @@ const VIDEO_ID = "abc123"; type FakeSidecar = { mode: "happy" | "corrupt-after" | "corrupt-final" | "corrupt-from-start"; recoverOnResume?: boolean; + // Serve corruption on the first N audio-check invocations, then behave. + // Generalizes recoverOnResume (= corruptRuns:1) to drive several successive + // rollbacks (e.g. to watch the adaptive probe interval shrink). + corruptRuns?: number; deterministicCorrupt?: boolean; totalChunks?: number; chunkDelayMs?: number; @@ -191,6 +195,55 @@ test.describe("audio-checked download scenarios", () => { expect(await pathExists(`${CHANNEL_ROOT}/data/${VIDEO_ID}/audio.mp3`)).toBe(true); }); + test("adaptive interval: repeated corruption halves the probe cadence, then it recovers", async ({ + page, + }) => { + // The source serves corruption on its first two download attempts (each + // caught mid-stream and rolled back to the .good baseline), then behaves. + // With the test server's adaptive-cadence env (300ms interval, 50ms floor, + // ×0.5 backoff, +100ms recovery after 2 clean probes), each malformed + // checkpoint halves the live interval (300→150→75), and the ensuing clean + // run steps it back up — proving the AIMD backoff end-to-end, not just in + // the unit test (common/ytdlp/audioCheckCadence.test.ts). + await resetData("audio-check-channel"); + await writeFakeConfig({ + mode: "corrupt-after", + corruptAfterChunk: 3, + corruptRuns: 2, + totalChunks: 10, + chunkDelayMs: 150, + }); + await triggerDownload(page); + + const log = page.getByLabel("Download videos output"); + // Two successive malformed checkpoints, each halving the live interval. The + // reduced cadence persists across the yt-dlp relaunch between them. + await expect(log).toContainText( + "Audio-check interval backoff: 300ms -> 150ms", + { timeout: 30_000 }, + ); + await expect(log).toContainText( + "Audio-check interval backoff: 150ms -> 75ms", + { timeout: 30_000 }, + ); + // Once the source stabilises, a run of clean checkpoints relaxes it back up. + await expect(log).toContainText("Audio-check interval recovering:", { + timeout: 30_000, + }); + + const outcome = await waitForOutcome( + (o) => o.status === "ok-audio-checked", + "adaptive-interval recovery outcome", + ); + // Two corruption episodes → at least two rollback/restart decisions; the + // download then finalizes cleanly. + expect( + (outcome.attempts[0].audioCheck?.rollbacks ?? 0) + + (outcome.attempts[0].audioCheck?.restarts ?? 0), + ).toBeGreaterThanOrEqual(2); + expect(await pathExists(`${CHANNEL_ROOT}/data/${VIDEO_ID}/audio.mp3`)).toBe(true); + }); + test("final-extraction probe failure triggers rollback and retry", async ({ page }) => { await resetData("audio-check-channel"); await writeFakeConfig({ diff --git a/editor/e2e/fixtures/bin/fake-ytdlp.mjs b/editor/e2e/fixtures/bin/fake-ytdlp.mjs @@ -247,6 +247,16 @@ async function modeAudioCheckOneUrl(url) { const recoverOnResume = sidecar.recoverOnResume === true || process.env.FAKE_YTDLP_RECOVER_ON_RESUME === "1"; + // Generalizes recoverOnResume (= corruptRuns:1): serve corruption on the + // first N audio-check invocations, then behave. Lets a test drive several + // successive mid-stream rollbacks (e.g. to observe the adaptive probe + // interval shrinking) before the source recovers. null = unset. + const corruptRuns = + sidecar.corruptRuns != null + ? Number.parseInt(String(sidecar.corruptRuns), 10) + : process.env.FAKE_YTDLP_CORRUPT_RUNS != null + ? Number.parseInt(process.env.FAKE_YTDLP_CORRUPT_RUNS, 10) + : null; const deterministicCorrupt = sidecar.deterministicCorrupt === true || process.env.FAKE_YTDLP_DETERMINISTIC_CORRUPT === "1"; @@ -299,6 +309,7 @@ async function modeAudioCheckOneUrl(url) { const shouldEmitMarker = (() => { if (mode === "happy") return false; if (deterministicCorrupt) return true; + if (corruptRuns != null) return priorAudioCheckRuns < corruptRuns; if (recoverOnResume && priorAudioCheckRuns > 0) return false; return true; })(); diff --git a/editor/package.json b/editor/package.json @@ -5,8 +5,8 @@ "type": "module", "scripts": { "dev": "next dev --port ${EDITOR_PORT:-3001}", - "dev:test": "WORKER_TOKEN=test-worker-token TRANSCRIPTS_DIR=$(pwd)/test-transcripts EXPORT_PUBLIC_DIR=$(pwd)/test-transcripts/.export-public SETTINGS_FILE=$(pwd)/test-settings.json YTDLP_BIN=$(pwd)/e2e/fixtures/bin/fake-ytdlp.mjs WHISPER_BIN=$(pwd)/e2e/fixtures/bin/fake-whisper.mjs WHISPER_MODEL=/dev/null CHOUGH_BIN=$(pwd)/e2e/fixtures/bin/fake-chough.mjs CHOUGH_MODEL=/dev/null PARAKEET_STITCH_BIN=$(pwd)/e2e/fixtures/bin/fake-parakeet-stitch.mjs PARAKEET_CLI=/dev/null PARAKEET_MODEL=/dev/null FFMPEG_BIN=$(pwd)/e2e/fixtures/bin/fake-ffmpeg.mjs FFPROBE_BIN=$(pwd)/e2e/fixtures/bin/fake-ffprobe.mjs AUDIO_CHECK_INTERVAL_MS_OVERRIDE=300 AUDIO_CHECK_SIZE_GATE_OVERRIDE=4096 next dev --port ${PORT:-3011}", - "start:test": "WORKER_TOKEN=test-worker-token TRANSCRIPTS_DIR=$(pwd)/test-transcripts EXPORT_PUBLIC_DIR=$(pwd)/test-transcripts/.export-public SETTINGS_FILE=$(pwd)/test-settings.json YTDLP_BIN=$(pwd)/e2e/fixtures/bin/fake-ytdlp.mjs WHISPER_BIN=$(pwd)/e2e/fixtures/bin/fake-whisper.mjs WHISPER_MODEL=/dev/null CHOUGH_BIN=$(pwd)/e2e/fixtures/bin/fake-chough.mjs CHOUGH_MODEL=/dev/null PARAKEET_STITCH_BIN=$(pwd)/e2e/fixtures/bin/fake-parakeet-stitch.mjs PARAKEET_CLI=/dev/null PARAKEET_MODEL=/dev/null FFMPEG_BIN=$(pwd)/e2e/fixtures/bin/fake-ffmpeg.mjs FFPROBE_BIN=$(pwd)/e2e/fixtures/bin/fake-ffprobe.mjs AUDIO_CHECK_INTERVAL_MS_OVERRIDE=300 AUDIO_CHECK_SIZE_GATE_OVERRIDE=4096 next start --port ${PORT:-3011}", + "dev:test": "WORKER_TOKEN=test-worker-token TRANSCRIPTS_DIR=$(pwd)/test-transcripts EXPORT_PUBLIC_DIR=$(pwd)/test-transcripts/.export-public SETTINGS_FILE=$(pwd)/test-settings.json YTDLP_BIN=$(pwd)/e2e/fixtures/bin/fake-ytdlp.mjs WHISPER_BIN=$(pwd)/e2e/fixtures/bin/fake-whisper.mjs WHISPER_MODEL=/dev/null CHOUGH_BIN=$(pwd)/e2e/fixtures/bin/fake-chough.mjs CHOUGH_MODEL=/dev/null PARAKEET_STITCH_BIN=$(pwd)/e2e/fixtures/bin/fake-parakeet-stitch.mjs PARAKEET_CLI=/dev/null PARAKEET_MODEL=/dev/null FFMPEG_BIN=$(pwd)/e2e/fixtures/bin/fake-ffmpeg.mjs FFPROBE_BIN=$(pwd)/e2e/fixtures/bin/fake-ffprobe.mjs AUDIO_CHECK_INTERVAL_MS_OVERRIDE=300 AUDIO_CHECK_SIZE_GATE_OVERRIDE=4096 AUDIO_CHECK_INTERVAL_FLOOR_MS_OVERRIDE=50 AUDIO_CHECK_RECOVER_STEP_MS_OVERRIDE=100 AUDIO_CHECK_RECOVER_AFTER_OVERRIDE=2 next dev --port ${PORT:-3011}", + "start:test": "WORKER_TOKEN=test-worker-token TRANSCRIPTS_DIR=$(pwd)/test-transcripts EXPORT_PUBLIC_DIR=$(pwd)/test-transcripts/.export-public SETTINGS_FILE=$(pwd)/test-settings.json YTDLP_BIN=$(pwd)/e2e/fixtures/bin/fake-ytdlp.mjs WHISPER_BIN=$(pwd)/e2e/fixtures/bin/fake-whisper.mjs WHISPER_MODEL=/dev/null CHOUGH_BIN=$(pwd)/e2e/fixtures/bin/fake-chough.mjs CHOUGH_MODEL=/dev/null PARAKEET_STITCH_BIN=$(pwd)/e2e/fixtures/bin/fake-parakeet-stitch.mjs PARAKEET_CLI=/dev/null PARAKEET_MODEL=/dev/null FFMPEG_BIN=$(pwd)/e2e/fixtures/bin/fake-ffmpeg.mjs FFPROBE_BIN=$(pwd)/e2e/fixtures/bin/fake-ffprobe.mjs AUDIO_CHECK_INTERVAL_MS_OVERRIDE=300 AUDIO_CHECK_SIZE_GATE_OVERRIDE=4096 AUDIO_CHECK_INTERVAL_FLOOR_MS_OVERRIDE=50 AUDIO_CHECK_RECOVER_STEP_MS_OVERRIDE=100 AUDIO_CHECK_RECOVER_AFTER_OVERRIDE=2 next start --port ${PORT:-3011}", "build": "next build", "start": "next start --port ${EDITOR_PORT:-3001}", "lint": "eslint",