import { test } from "node:test"; import assert from "node:assert/strict"; import { digestPageFileName, manifestHasDigest, newestGeneratedAt, type ChannelDigestsManifest, type VideoDigest, } from "./digests"; import { effectiveDigest, type DigestOverrides, type DigestRecord, } from "./digest"; // Run with: // pnpm --filter yt-dlp-transcript-common exec tsx --test common/lib/digests.test.ts test("digestPageFileName: zero-padded to 4, matching every other page tree", () => { assert.equal(digestPageFileName(0), "page-0000.json"); assert.equal(digestPageFileName(7), "page-0007.json"); assert.equal(digestPageFileName(1234), "page-1234.json"); }); function manifest( slugToPage: Record, ): ChannelDigestsManifest { return { version: 1, channelSlug: "alice", pageCount: 1, maxPageBytes: 1_000_000, generatedAt: "2026-07-29T00:00:00.000Z", slugToPage, }; } test("manifestHasDigest: slugToPage IS the existence check", () => { const m = manifest({ vaaa: 0, vbbb: 0 }); assert.equal(manifestHasDigest(m, "vaaa"), true); // Page 0 is a real page — a falsy page index must not read as "absent". assert.equal(manifestHasDigest(m, "vbbb"), true); assert.equal(manifestHasDigest(m, "vccc"), false); // No manifest at all (channel has zero digests) is simply "no". assert.equal(manifestHasDigest(null, "vaaa"), false); }); test("newestGeneratedAt: max across sections, tolerant of missing ones", () => { assert.equal( newestGeneratedAt({ chapters: { generatedAt: "2026-07-01T00:00:00.000Z" }, tags: { generatedAt: "2026-07-20T00:00:00.000Z" }, }), "2026-07-20T00:00:00.000Z", ); // One section only. assert.equal( newestGeneratedAt({ chapters: { generatedAt: "2026-07-01T00:00:00.000Z" } }), "2026-07-01T00:00:00.000Z", ); // Nothing to date — the cache treats "" as "always a miss", which is the safe // direction: it re-fetches rather than serving something it can't version. assert.equal(newestGeneratedAt({}), ""); }); // --- the shipped record is the COMPOSED digest, not the raw sidecar --------- // This is the property the whole build edge depends on: what reaches a page // file is effectiveDigest(machine, overrides), so a human correction ships and // a human rejection does not. function record(): DigestRecord { return { digestSchemaVersion: 1, promptVersion: 2, contextHash: "", warnings: [ { code: "out-of-range", section: "chapters", chunk: 2, value: "03:11:00" }, ], sections: { chapters: { provenance: { appId: "ollama-direct", model: "qwen2.5:7b", lane: "local-gpu", generatedAt: "2026-07-20T00:00:00.000Z", promptVersion: 2, contextHash: "", }, items: [ { id: "c300", start: 300, clock: "00:05:00", title: "Second", decidedBy: "ai" }, { id: "c0", start: 0, clock: "00:00:00", title: "Machine title", decidedBy: "ai" }, { id: "c900", start: 900, clock: "00:15:00", title: "Rejected", decidedBy: "ai" }, ], }, }, }; } // Mirror of the projection buildIndex.ts performs when it stores a record. function toVideoDigest(slug: string, id: string): VideoDigest { const eff = effectiveDigest(record(), { version: 1, // Authored as PATCHES (id + title, no start/clock) — the shape // digest-server.ts's sanitizeChapters actually emits for a hand-written // overrides file, and which it casts the same way. mergeItems is built to // spread the machine item underneath, so the snapped start survives. chapters: [ // Replaces a generated item by id (a retitle)… { id: "c0", title: "Human title", decidedBy: "human" }, // …and suppresses another without deleting it. { id: "c900", title: "", decidedBy: "human", enabled: false }, ] as DigestOverrides["chapters"], }); const provenance = { ...(eff.sections.chapters ? { chapters: eff.sections.chapters.provenance } : {}), ...(eff.sections.tags ? { tags: eff.sections.tags.provenance } : {}), }; return { slug, id, chapters: eff.chapters.map((c) => ({ id: c.id, start: c.start, clock: c.clock, title: c.title, decidedBy: c.decidedBy, })), tags: eff.tags.map((t) => ({ id: t.id, tag: t.tag, decidedBy: t.decidedBy })), generatedAt: newestGeneratedAt(provenance), provenance, ...(eff.derivedFrom ? { derivedFrom: eff.derivedFrom } : {}), }; } test("shipped digest: overrides applied, suppressed items dropped, sorted by start", () => { const d = toVideoDigest("alice/vaaa", "vaaa"); assert.deepEqual( d.chapters.map((c) => c.title), ["Human title", "Second"], ); // Sorted by start, not by the order the model emitted them. assert.deepEqual(d.chapters.map((c) => c.start), [0, 300]); // A retitled chapter keeps the machine's snapped start — an override authored // as a patch (id + title) must not blank it, or the seek target is lost. assert.equal(d.chapters[0].start, 0); assert.equal(d.chapters[0].decidedBy, "human"); assert.equal(d.chapters[1].decidedBy, "ai"); }); test("shipped digest: warnings are operator telemetry and never ship", () => { const d = toVideoDigest("alice/vaaa", "vaaa") as VideoDigest & Record; assert.equal(d.warnings, undefined); assert.equal(d.history, undefined); assert.equal(JSON.stringify(d).includes("out-of-range"), false); }); test("shipped digest: provenance and the cache version come through", () => { const d = toVideoDigest("alice/vaaa", "vaaa"); assert.equal(d.provenance.chapters?.model, "qwen2.5:7b"); assert.equal(d.provenance.chapters?.lane, "local-gpu"); assert.equal(d.generatedAt, "2026-07-20T00:00:00.000Z"); }); test("shipped digest: derivedFrom survives so a borrowed digest stays borrowed", () => { const shared: DigestRecord = { ...record(), derivedFrom: { slug: "bob/vzzz", clusterId: "cl1", sharedAt: "2026-07-21T00:00:00.000Z", offsetSeconds: 0.4, }, }; const eff = effectiveDigest(shared, null); assert.equal(eff.derivedFrom?.slug, "bob/vzzz"); assert.equal(eff.derivedFrom?.offsetSeconds, 0.4); });