Archilyzer · Source

archilyzer

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

commit 3ca9da34bfc7f485ecce18f7008a42b7468746b6
parent 9c59d06c0e3aa7942f00ce6610bcc4f1483c8b69
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed, 30 Sep 2026 21:17:24 -0400

deck S4: buildSteps' chromeOnly → --chrome-only, "re-render on-screen"

The driver maps options.chromeOnly to the build's --chrome-only flag with the
step label "re-render on-screen". It skips the availability preflight and the
dry resolve (no source is touched) but keeps the build's own timeout and the
verify step: it re-renders the deck and re-concats the whole cut.

POST /api/report/build accepts options.chromeOnly, refuses it beside
chaptersOnly or preview, and does not apply the overwrite guard to it — like
chaptersOnly it rewrites the deliverable in place because it was asked to.

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

Diffstat:
Mumtool/app/api/report/build/route.ts | 21+++++++++++++++++----
Mumtool/lib/report/driver.mjs | 21++++++++++++++++-----
Aumtool/lib/report/driver.test.mjs | 26++++++++++++++++++++++++++
3 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/umtool/app/api/report/build/route.ts b/umtool/app/api/report/build/route.ts @@ -76,7 +76,13 @@ export async function POST(request: Request) { // ---- the options the pipeline has and the driver used to hide ---------- const raw = (body.options ?? {}) as Record<string, unknown>; - const options: { variant?: string; xfade?: boolean; chaptersOnly?: boolean; preview?: { at: number; dur: number } | null } = {}; + const options: { + variant?: string; + xfade?: boolean; + chaptersOnly?: boolean; + chromeOnly?: boolean; + preview?: { at: number; dur: number } | null; + } = {}; if (raw.variant !== undefined && raw.variant !== "") { const v = String(raw.variant); if (!(VARIANTS as string[]).includes(v)) { @@ -86,6 +92,10 @@ export async function POST(request: Request) { } if (raw.xfade === false) options.xfade = false; if (raw.chaptersOnly) options.chaptersOnly = true; + // Re-render the on-screen deck over the segments on disk ("Re-render + // on-screen"). Like chaptersOnly it rewrites the deliverable in place because + // somebody asked it to, so the overwrite guard below does not apply. + if (raw.chromeOnly) options.chromeOnly = true; if (raw.preview && typeof raw.preview === "object") { const pv = raw.preview as Record<string, unknown>; const at = Number(pv.at); @@ -95,8 +105,11 @@ export async function POST(request: Request) { } options.preview = { at, dur }; } - if (options.chaptersOnly && options.preview) { - return Response.json({ error: "chaptersOnly and preview are different runs — pick one" }, { status: 400 }); + if ([options.chaptersOnly, options.chromeOnly, options.preview].filter(Boolean).length > 1) { + return Response.json( + { error: "chaptersOnly, chromeOnly and preview are different runs — pick one" }, + { status: 400 }, + ); } const project = await projectRef(projectId); @@ -137,7 +150,7 @@ export async function POST(request: Request) { // the same file in place by design, and a preview writes a different one, so // neither is guarded. const finalPath = variantPaths(path.join(project.dir, "out"), manifest.slug, options.variant ?? DEFAULT_VARIANT).final; - if (!only && !options.chaptersOnly && !options.preview) { + if (!only && !options.chaptersOnly && !options.chromeOnly && !options.preview) { const [fin, man] = await Promise.all([ stat(finalPath).catch(() => null), stat(path.join(project.dir, "video.manifest.json")).catch(() => null), diff --git a/umtool/lib/report/driver.mjs b/umtool/lib/report/driver.mjs @@ -53,11 +53,15 @@ export const buildTimeoutMs = (clipCount, xfade) => * chaptersOnly `--chapters-only` -- retitle the chapters from the segments * already on disk; no fetch, no encode * preview `--preview <at> <dur>` -- the rail alone over a window + * chromeOnly `--chrome-only` -- re-render the on-screen deck over the + * segments already on disk and re-concat; no segment rebuilt * - * chaptersOnly and preview SKIP the preflight and the dry resolve: neither - * touches a source, and both are seconds of work under a five-minute cap. + * chaptersOnly, preview and chromeOnly SKIP the preflight and the dry resolve: + * none of them touches a source. The first two are seconds of work under a + * five-minute cap; a deck re-render is a render plus a concat of the whole + * cut, so it keeps the build's own timeout. * - * @typedef {{ variant?: string, xfade?: boolean, chaptersOnly?: boolean, preview?: { at: number, dur: number } | null }} BuildOptions + * @typedef {{ variant?: string, xfade?: boolean, chaptersOnly?: boolean, chromeOnly?: boolean, preview?: { at: number, dur: number } | null }} BuildOptions */ /** The step-1 preflight alone, reused by the check-sources job. */ @@ -84,7 +88,7 @@ export function buildSteps(project, { preset = "fast", only = null, skipFetch = const base = { cwd: PIPELINE_DIR, env }; const quick = !!(options.chaptersOnly || options.preview); - const steps = quick + const steps = quick || options.chromeOnly ? [] : [ { @@ -117,11 +121,18 @@ export function buildSteps(project, { preset = "fast", only = null, skipFetch = if (skipFetch) buildArgv.push("--skip-fetch"); if (p.only && only) buildArgv.push("--only", only); if (options.chaptersOnly) buildArgv.push("--chapters-only"); + if (options.chromeOnly) buildArgv.push("--chrome-only"); if (options.preview) buildArgv.push("--preview", String(options.preview.at), String(options.preview.dur)); steps.push({ ...base, - label: options.chaptersOnly ? "retitle the chapters (no encode)" : options.preview ? `rail preview at ${options.preview.at}s` : p.label, + label: options.chaptersOnly + ? "retitle the chapters (no encode)" + : options.chromeOnly + ? "re-render on-screen" + : options.preview + ? `rail preview at ${options.preview.at}s` + : p.label, argv: buildArgv, ndjson: true, timeoutMs: quick ? 5 * 60_000 : buildTimeoutMs(clipCount, p.xfade), diff --git a/umtool/lib/report/driver.test.mjs b/umtool/lib/report/driver.test.mjs @@ -0,0 +1,26 @@ +// buildSteps' `chromeOnly`: the deck re-rendered over the segments on disk. +// +// Run with: pnpm test:scripts +import assert from "node:assert/strict"; +import test from "node:test"; + +import { buildSteps } from "./driver.mjs"; + +const project = { id: "p", dir: "/r/p" }; + +test("chromeOnly: no preflight, --chrome-only on the build, labelled, then the verify", () => { + const steps = buildSteps(project, { preset: "final", options: { chromeOnly: true, variant: "full" } }); + assert.deepEqual(steps.map((s) => s.label), ["re-render on-screen", "verify the file that came out"]); + const argv = steps[0].argv; + assert.ok(argv.includes("--chrome-only")); + assert.deepEqual(argv.slice(argv.indexOf("--variant"), argv.indexOf("--variant") + 2), ["--variant", "full"]); + assert.ok(!argv.includes("--chapters-only")); + // A render plus a concat of the whole cut: the build's timeout, not the quick cap. + assert.ok(steps[0].timeoutMs > 5 * 60_000); +}); + +test("without chromeOnly nothing changes: the preflight leads and no --chrome-only", () => { + const steps = buildSteps(project, { preset: "final" }); + assert.equal(steps[0].label, "check every source is still fetchable"); + assert.ok(steps.every((s) => !s.argv.includes("--chrome-only"))); +});