// The per-video "Exclude from truncated check" toggle writes an // exclude-truncated-check.json marker that suppresses the incomplete/short // detection everywhere it surfaces: the snapshot's incompleteTranscript bucket // AND the video panel's "looks truncated" banner (which computes independently // of the snapshot). For videos that legitimately have little speech. See // common/lib/excludeTruncatedCheck*.ts + common/controller/channelSnapshot.ts. import { mkdir, writeFile } from "node:fs/promises"; import { test, expect } from "@playwright/test"; import { pathExists, readJson, resetData, resolvePath, generateReport } from "./helpers"; import { baseUrl } from "./baseUrl"; const CHANNEL = "test-transcribe"; const DATA = `test-transcripts/channels/${CHANNEL}/data`; const SNAPSHOT_REL = `test-transcripts/channels/${CHANNEL}/snapshot.json`; const MARKER_REL = `${DATA}/vidTrunc/exclude-truncated-check.json`; const WHISPER = JSON.stringify({ transcription: [{ text: "hello" }] }); async function writeFlaggedVideo(id: string): Promise { const dir = resolvePath(`${DATA}/${id}`); await mkdir(dir, { recursive: true }); await writeFile(`${dir}/transcript.json`, WHISPER); await writeFile(`${dir}/audio.m4a`, "fake-audio"); // 2h22m video, transcript stops at ~6:52 → 4.8% coverage → flagged. await writeFile( `${dir}/transcript.cues.json`, JSON.stringify({ version: 1, source: "whisper", duration: 8541, isLivestream: false, cues: [{ start: 0, end: 412, text: "hello" }], }), ); } test("excluding a video from the truncated check clears the banner and the snapshot bucket", async ({ page, }) => { await resetData("one-transcribe-channel"); await writeFlaggedVideo("vidTrunc"); await fetch(`${baseUrl}/api/test/invalidate-cache`).catch(() => {}); // Snapshot flags it. await generateReport(page, CHANNEL); await page.goto(`/channels/${CHANNEL}`); { const snap = await readJson<{ buckets: { incompleteTranscript?: string[] }; }>(SNAPSHOT_REL); expect(snap.buckets.incompleteTranscript).toContain("vidTrunc"); } // The video panel shows the "looks truncated" banner. await page.goto(`/channels/${CHANNEL}/videos/vidTrunc`); await expect(page.getByLabel("incomplete transcript")).toBeVisible(); // Exclude it from the check (the toggle lives in a collapsed stage card). await page .getByLabel("Truncated check stage summary") .click(); await page .getByRole("button", { name: "exclude video vidTrunc from truncated check", }) .click(); // Banner clears (the panel recomputes after revalidation). await expect(page.getByLabel("incomplete transcript")).toBeHidden(); expect(await pathExists(MARKER_REL)).toBe(true); // Snapshot regen drops it from the bucket. The regen is debounced (~1s) after // the mutation, so poll the on-disk snapshot rather than reading it once. await generateReport(page, CHANNEL); await page.goto(`/channels/${CHANNEL}`); await expect .poll( async () => { const snap = await readJson<{ buckets: { incompleteTranscript?: string[] }; }>(SNAPSHOT_REL); return snap.buckets.incompleteTranscript ?? []; }, { timeout: 15_000 }, ) .not.toContain("vidTrunc"); // Re-enabling the check restores the flag. await page.goto(`/channels/${CHANNEL}/videos/vidTrunc`); await page .getByLabel("Truncated check stage summary") .click(); await page .getByRole("button", { name: "include video vidTrunc in truncated check", }) .click(); await expect(page.getByLabel("incomplete transcript")).toBeVisible(); expect(await pathExists(MARKER_REL)).toBe(false); });