import { test } from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import type { ChannelSnapshot } from "../../controller/channelSnapshot"; import type { OperationSnapshotEntry } from "../../lib/operations"; import { bandCoverage, buildChannelBands, buildOperationBands, sumOrNull, type OperationBand, } from "./buildBands"; // Run from this directory: // cd editor/app/components/pipelines && ../../../../node_modules/.bin/tsx --test buildBands.test.ts function snapshotOf(patch: Partial = {}): ChannelSnapshot { return { generatedAt: "2026-08-21T00:00:00.000Z", totals: { videos: 100, transcribed: 40, downloaded: 60 }, buckets: {} as ChannelSnapshot["buckets"], ...patch, } as ChannelSnapshot; } function entryOf(patch: Partial): OperationSnapshotEntry { return { missing: 0, stale: 0, partial: 0, missingInput: 0, deferred: 0, blocked: 0, ids: [], ...patch, } as OperationSnapshotEntry; } const bandOf = (bands: OperationBand[], id: string): OperationBand => { const found = bands.find((b) => b.id === id); assert.ok(found, `no band for ${id}`); return found; }; test("the four work states are kept apart and never summed", () => { // The measured shape of this corpus in miniature: diarization is dominated by // missing media and attribution-diarized by blocked work. Any code that added // them would report both lanes as busy. const bands = buildOperationBands({ snapshots: [ snapshotOf({ backfill: { diarization: entryOf({ missing: 647, missingInput: 77_276, eligible: 78_019, }), "attribution-diarized": entryOf({ missing: 94, blocked: 77_923, eligible: 78_019, }), }, }), ], operationIds: ["diarization", "attribution-diarized"], }); const dia = bandOf(bands, "diarization"); assert.equal(dia.reachable, 647); assert.equal(dia.missingInput, 77_276); assert.equal(dia.blocked, 0); const attr = bandOf(bands, "attribution-diarized"); assert.equal(attr.reachable, 94); assert.equal(attr.blocked, 77_923); assert.equal(attr.missingInput, 0); }); test("one channel that cannot report `eligible` voids the whole denominator", () => { // The partial-sum trap. A snapshot predating `eligible` contributes videos to // the corpus but nothing to the denominator, so summing what IS known gives a // denominator smaller than its own numerator. const bands = buildOperationBands({ snapshots: [ snapshotOf({ backfill: { diarization: entryOf({ missing: 1, eligible: 500 }) }, }), snapshotOf({ // No `eligible` — an older snapshot. backfill: { diarization: entryOf({ missing: 2 }) }, }), ], operationIds: ["diarization"], }); const dia = bandOf(bands, "diarization"); assert.equal(dia.reachable, 3, "work counts still sum"); assert.equal(dia.eligible, null, "the denominator does not"); assert.equal(dia.present, null); assert.equal(bandCoverage(dia), null, "and coverage renders as unknown"); }); test("coverage is null, never 0, when the denominator is unknown", () => { // A 0 here would read as "nothing digested" on a fully digested channel. assert.equal( bandCoverage({ present: null, eligible: 10 } as OperationBand), null, ); assert.equal( bandCoverage({ present: 5, eligible: null } as OperationBand), null, ); assert.equal(bandCoverage({ present: 5, eligible: 0 } as OperationBand), null); assert.equal(bandCoverage({ present: 5, eligible: 10 } as OperationBand), 0.5); }); test("digest with no registry entry is an unfilled outline, never 0 %", () => { // A channel with no `backfill.digest` must not read "all digested" — nor // "none digested". Digest is a plain registry entry here, exactly like every // other operation: no entry means no work KNOWN and coverage UNKNOWN. const bands = buildOperationBands({ snapshots: [snapshotOf({ backfill: {} })], operationIds: ["digest"], }); const digest = bandOf(bands, "digest"); assert.equal(digest.reachable, 0); // Nothing to have an opinion about, and bandCoverage refuses to divide by it: // the band draws as an empty outline rather than a filled 0 %. assert.equal(digest.eligible, 0); assert.equal(bandCoverage(digest), null); }); test("the external pipelines get bands from totals and buckets", () => { const bands = buildOperationBands({ snapshots: [ snapshotOf({ totals: { videos: 100, transcribed: 40, downloaded: 60 }, undownloadedIds: ["u1", "u2", "u3"], buckets: { downloadedNoTranscript: ["d1", "d2"], noTranscript: Array.from({ length: 60 }, (_, i) => `n${i}`), untranscribable: ["x1", "x2"], partialDownloads: ["p1"], } as unknown as ChannelSnapshot["buckets"], }), ], operationIds: [], }); const download = bandOf(bands, "download"); // Every video the playlist knows about, not just the dirs that exist. assert.equal(download.eligible, 103); assert.equal(download.present, 60); assert.equal(download.reachable, 4, "3 never fetched + 1 partial"); assert.equal(download.dispatched, false); const transcription = bandOf(bands, "transcription"); assert.equal(transcription.eligible, 98, "100 videos less 2 untranscribable"); assert.equal(transcription.present, 40); assert.equal(transcription.reachable, 2, "audio in hand"); // The rest of noTranscript is waiting on the DOWNLOAD lane — blocked on an // operation this system produces, not reachable and not missing media. assert.equal(transcription.blocked, 56); assert.equal(transcription.missingInput, 0); }); test("ids excluded from download are deferred, not reachable", () => { // A channel deliberately not fetching members-only videos is not a lane with // work to do, and the two must stay separable rather than one being netted // off the other. const bands = buildOperationBands({ snapshots: [ snapshotOf({ totals: { videos: 0, transcribed: 0, downloaded: 0 }, undownloadedIds: ["ok", "gone"], excludedFromDownload: { deleted: ["gone"] }, } as Partial), ], operationIds: [], }); const download = bandOf(bands, "download"); assert.equal(download.reachable, 1); assert.equal(download.deferred, 1); }); test("a switched-off operation gets no band at all", () => { // Absent, not zero: an empty work list because nobody enabled the feature is // not the same as being finished, and a full green bar would claim it was. const bands = buildOperationBands({ snapshots: [snapshotOf({ backfill: { diarization: entryOf({ missing: 5 }) } })], operationIds: [], }); assert.equal( bands.find((b) => b.id === "diarization"), undefined, ); }); test("sumOrNull latches null and never returns a partial total", () => { assert.equal(sumOrNull([1, 2, 3]), 6); assert.equal(sumOrNull([1, null, 3]), null); assert.equal(sumOrNull([]), 0); }); // ── THE PER-CHANNEL PROJECTION ────────────────────────────────────────────── // // The /channels strip and the channel page's station foot are the same fold as // the corpus rail, over one snapshot. These tests pin the three cases the strip // actually meets on the live corpus: every operation present, one operation the // snapshot has no entry for, and one that predates `eligible`. const CHANNEL_OPS = [ "diarization", "attribution-diarized", "attribution-text", "digest", ]; test("a channel's bands carry every operation, and the two external ones", () => { const bands = buildChannelBands( snapshotOf({ totals: { videos: 11_344, transcribed: 11_339, downloaded: 11_340 }, buckets: { downloadedNoTranscript: ["a", "b"], noTranscript: ["a", "b", "c"], untranscribable: ["c"], } as ChannelSnapshot["buckets"], undownloadedIds: ["x", "y", "z", "w"], backfill: { // The measured shape of the-quartering, in miniature: digest is all // reachable with nothing done, diarization is almost all media-gone, // and attribution-diarized is almost all blocked behind it. diarization: entryOf({ missing: 1, missingInput: 11_333, eligible: 11_338 }), "attribution-diarized": entryOf({ missing: 4, blocked: 11_334, eligible: 11_338, }), "attribution-text": entryOf({ missing: 11_337, eligible: 11_338 }), digest: entryOf({ missing: 11_329, blocked: 2, eligible: 11_340 }), }, }), CHANNEL_OPS, ); assert.deepEqual( bands.map((b) => b.id), ["download", "transcription", ...CHANNEL_OPS], ); // Digest: ALL accent, nothing done. This is the row that makes a percent bar // useless and the state band useful — "0% complete" is true of every large // channel and says nothing; "11,329 can run now" is the whole story. const digest = bandOf(bands, "digest"); assert.equal(digest.reachable, 11_329); assert.equal(digest.blocked, 2); assert.equal(digest.present, 9); assert.equal(bandCoverage(digest), 9 / 11_340); // Diarization: all hollow. 11,333 with no media left is not work, and must // never be added to the 1 video that is. const diarize = bandOf(bands, "diarization"); assert.equal(diarize.reachable, 1); assert.equal(diarize.missingInput, 11_333); // Attribution-diarized: all hatched, waiting on the lane above it. const named = bandOf(bands, "attribution-diarized"); assert.equal(named.reachable, 4); assert.equal(named.blocked, 11_334); // The external pipelines use the SAME definitions the transit line does, so a // channel figure and a corpus figure cannot disagree about "downloaded". const download = bandOf(bands, "download"); assert.equal(download.eligible, 11_344 + 4); assert.equal(download.present, 11_340); assert.equal(download.reachable, 4); }); test("an operation the snapshot has no entry for is an EMPTY band, not a missing column", () => { // A channel whose report predates a kind still gets a cell — drawn empty, // with a known denominator of 0, which bandCoverage reports as unknown rather // than as 0% done. Dropping the column instead would make the table ragged // and hide the fact that nothing has been measured yet. const bands = buildChannelBands( snapshotOf({ backfill: { diarization: entryOf({ missing: 5, eligible: 10 }) }, }), CHANNEL_OPS, ); const text = bandOf(bands, "attribution-text"); assert.equal(text.reachable, 0); assert.equal(text.blocked, 0); assert.equal(text.missingInput, 0); assert.equal(text.eligible, 0); assert.equal(bandCoverage(text), null); }); test("an entry with no `eligible` draws an outline, never 0%", () => { // UNKNOWN IS NOT ZERO, at channel scale. A snapshot written before the field // existed — or one that has lapsed — has work counts but no denominator, and // the band must say "we cannot tell you the coverage" rather than "none of it // is done", which on a fully-diarized channel would be a lie. const bands = buildChannelBands( snapshotOf({ backfill: { diarization: entryOf({ missing: 3, missingInput: 90 }), }, }), ["diarization"], ); const diarize = bandOf(bands, "diarization"); assert.equal(diarize.eligible, null); assert.equal(bandCoverage(diarize), null); // The work counts survive the unknown denominator — they are separately // known, and the cell still says how much can run now. assert.equal(diarize.reachable, 3); assert.equal(diarize.missingInput, 90); }); test("a channel with no snapshot at all is every band empty", () => { // A brand-new channel, before its first report. Every column present, every // one empty, coverage unknown — the freshness note under the table is what // explains why. const bands = buildChannelBands(null, CHANNEL_OPS); assert.equal(bands.length, 2 + CHANNEL_OPS.length); for (const band of bands) { assert.equal(band.reachable, 0); assert.equal(bandCoverage(band), null); } }); // ── THE CLIENT/SERVER SPLIT, GUARDED ──────────────────────────────────────── test("band.ts stays directive-free, so a server component can call it", () => { // band.ts carries the TYPE and every pure reading of a band. The channel // page's station foot is a SERVER component and calls bandSentence() and // bandHeadline() directly; adding "use client" here would break it at request // time with "attempted to call bandSentence() from the server". const src = readFileSync(new URL("./band.ts", import.meta.url), "utf8"); // A DIRECTIVE, not the string — this file discusses "use client" in prose. // A directive is a bare expression statement before any other code. assert.ok( !/^\s*(?:"use client"|'use client');?\s*$/m.test(src), "band.ts must not be a client module", ); // And it must import nothing but types — buildBands.ts pulls in // channelSnapshot → execa, which would put node:child_process in the browser // bundle and fail `next build`. const valueImports = [...src.matchAll(/^import\s+(?!type\b)/gm)]; assert.equal( valueImports.length, 0, "band.ts must not take a value import — see its header", ); }); test("StateBand.tsx exports only components, never callable helpers", () => { // THE BUG THIS CAUGHT, ONCE. A plain function exported from a `"use client"` // module cannot be CALLED by a server component — only rendered. bandSentence // lived here, the server-rendered station foot called it, and every channel // page 500'd at request time. // // `pnpm build` does NOT catch this: the route is force-dynamic, so nothing // prerenders it and the error only appears on a request. e2e found it and the // build did not, which is why this guard is a unit test and not a build step. // StateBand.tsx is the client half and stays in the editor — this file moved // down to common/views/ in phase 3 slice 1 and the guard came with it, so the // read reaches back across the package boundary. A textual check, not an // import: nothing in common/ may depend on editor/ at build time. const src = readFileSync( new URL("../../../editor/app/components/pipelines/StateBand.tsx", import.meta.url), "utf8", ); assert.ok( /^\s*(?:"use client"|'use client');?\s*$/m.test(src), "StateBand.tsx is the client half", ); const exported = [...src.matchAll(/^export\s+(?:function|const)\s+(\w+)/gm)].map( (m) => m[1], ); assert.ok(exported.length > 0, "found no exports to check — regex drifted"); for (const name of exported) { assert.ok( /^[A-Z]/.test(name), `${name} is exported from a client module but is not a component — a server component that calls it throws at request time. Move it to band.ts.`, ); } }); test("a download/transcription entry in the snapshot is NOT folded twice", () => { // Slice 1.5 gave the two bucket lanes a snapshot entry, and `/channels` passes // `[...EXTERNAL_BAND_IDS, ...allOperations]` as operationIds — so without the // filter in buildOperationBands the entry lands on top of addExternalBands and // a three-video channel reads "6 done of 6". backfill.spec.ts caught it in the // browser; this is the unit that pins it. // // The entries here are the ones generateChannelSnapshot writes: ids = the // lane's default bucket union, eligible = present + the work counts. const snapshot = snapshotOf({ totals: { videos: 3, transcribed: 0, downloaded: 3 }, buckets: { downloadedNoTranscript: ["vidA", "vidB", "vidC"], failedListed: [], partialDownloads: [], noTranscript: [], untranscribable: [], } as unknown as ChannelSnapshot["buckets"], undownloadedIds: [], backfill: { download: entryOf({ missing: 0, ids: [], eligible: 3 }), transcription: entryOf({ missing: 3, ids: ["vidA", "vidB", "vidC"], eligible: 3, }), }, }); const bands = buildOperationBands({ snapshots: [snapshot], operationIds: ["download", "transcription", "diarization"], }); const dl = bandOf(bands, "download"); assert.equal(dl.eligible, 3, "eligible must be the playlist, counted once"); assert.equal(dl.present, 3); assert.equal(dl.reachable, 0); const tr = bandOf(bands, "transcription"); assert.equal(tr.eligible, 3); assert.equal(tr.present, 0); assert.equal(tr.reachable, 3); // And the band is still the BUCKET definition, not the entry's: the same // numbers come back with the entries absent, which is every live snapshot. const stripped = buildOperationBands({ snapshots: [snapshotOf({ ...snapshot, backfill: {} })], operationIds: ["download", "transcription", "diarization"], }); assert.deepEqual(bandOf(stripped, "download"), dl); assert.deepEqual(bandOf(stripped, "transcription"), tr); });