Archilyzer · Source

archilyzer

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

commit f92e6ff93ac98827463f17d9acfc338289d09c2c
parent aaf4258a99b76432ffc6624a203336d6347c61fc
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 02:42:17 -0400

editor, common: the build-mode copy says the mode is a label (review S2)

No build path reads `buildPipeline.mode`: Build all / Build & deploy all
fan out in containers whenever `docker version` answers and build serially
on the host otherwise, and a single site always builds in export/ on one
queue. Copy only, no behaviour change (the parent's ruling); whether Build
all should honour the mode is a question for the operator.

- /sites: the toggle's note ("Docker builds are a follow-up — runs the
  basic build for now", docker mode only) is now shown in both modes and
  says the mode is a label; Build all's paragraph and lane subtitle no
  longer claim "Docker mode is off — serial host fallback" (the
  `dockerMode` prop that only picked that copy is gone); the per-site
  panel's note says these run one at a time whichever mode is set.
- Settings → Build pipeline hint and the Max parallel builds hint; the
  schema's buildPipeline description, `mode` and `maxParallelBuilds` docs
  and the BuildMode comment (SETTINGS.md regenerated).
- deploy-page.spec.ts: the two asserted sentences, in step.

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

Diffstat:
MSETTINGS.md | 6+++---
Mcommon/lib/settingsSchema.ts | 20+++++++++++---------
Meditor/app/settings/components/SettingsForm.tsx | 14+++++++-------
Meditor/app/sites/components/BuildAllSitesButton.tsx | 22++++++++++++----------
Meditor/app/sites/components/BuildModeToggle.tsx | 17++++++++++-------
Meditor/app/sites/components/BuildSitesPanel.tsx | 11++++++-----
Meditor/app/sites/page.tsx | 2+-
Meditor/e2e/deploy-page.spec.ts | 6+++---
8 files changed, 53 insertions(+), 45 deletions(-)

diff --git a/SETTINGS.md b/SETTINGS.md @@ -556,14 +556,14 @@ Default: ## `buildPipeline` -How the static export is built: "basic" reuses the single export/ tree and serializes builds on one queue (the long-standing behavior); "docker" builds every site at once, each in its own container (Dockerfile.build), then deploys them serially, and falls back to the basic build when no container engine answers — see PUBLISH.md. This block persists the chosen mode plus the image and concurrency knobs that pipeline reads. +The build pipeline's settings. A single site builds in the shared export/ tree, serialized on one queue. Build all sites (and Build & deploy all) builds every site at once, each in its own container (Dockerfile.build, the image and maxParallelBuilds below), then deploys them serially, whenever a container engine answers, and serially on the host when none does — see PUBLISH.md. `mode` is persisted and shown on /sites, but no build path reads it today: it is a label, not a switch. #### `buildPipeline` | Key | Default | Description | |---|---|---| -| `mode` | `"basic"` | "basic" — `pnpm run build` in export/, serialized on the build queue (shared output tree, no safe parallelism). "docker" — isolated per-site container builds, parallel up to `maxParallelBuilds`. | -| `maxParallelBuilds` | `2` | Cap on concurrent per-site container builds in docker mode. Ignored in basic mode (which is always serial). Clamped to [1, BUILD_MAX_PARALLEL_MAX]. | +| `mode` | `"basic"` | "basic" or "docker". Persisted and shown on /sites, but no build path reads it today — a label, not a switch: Build all sites uses containers whenever a container engine answers, and builds serially on the host when none does, in either mode. | +| `maxParallelBuilds` | `2` | Cap on concurrent per-site container builds when Build all sites runs in containers (whenever a container engine answers, whatever `mode` says). Clamped to [1, BUILD_MAX_PARALLEL_MAX]. | | `dockerImage` | `"yt-dlp-transcript-browser-build"` | Tag of the reusable build image (built once, reused for every site). | | `dockerfile` | `"Dockerfile.build"` | Dockerfile path relative to the monorepo root, used to (re)build the image. | diff --git a/common/lib/settingsSchema.ts b/common/lib/settingsSchema.ts @@ -414,11 +414,12 @@ export const DIGEST_SETTINGS_FIELD_DOCS: FieldDocs<DigestSettings> = { "fresh. Empty = default.", }; -// "basic" — `pnpm run build` in export/, serialized on the build queue (shared -// output tree → no safe parallelism). -// "docker" — isolated per-site container builds (publish/build.ts, -// runDockerBuildAllPhase): real parallel multi-site builds capped by -// maxParallelBuilds. +// "basic" | "docker" — persisted and shown on /sites, but A LABEL TODAY: no +// build path reads it. Build all / Build & deploy all (editor buildAction.ts) +// fan out in containers (publish/build.ts, runDockerBuildAllPhase, capped by +// maxParallelBuilds) whenever `docker version` answers, and build serially on +// the host otherwise, whichever mode is set. Whether they should honour it is +// an open question for the operator (plans/release-11.md, slice O6). export type BuildMode = "basic" | "docker"; // Each field is documented in BUILD_PIPELINE_SETTINGS_FIELD_DOCS below (rendered into SETTINGS.md). @@ -431,10 +432,11 @@ export type BuildPipelineSettings = { export const BUILD_PIPELINE_SETTINGS_FIELD_DOCS: FieldDocs<BuildPipelineSettings> = { mode: - "\"basic\" — `pnpm run build` in export/, serialized on the build queue (shared output tree, no safe parallelism). \"docker\" — isolated per-site container builds, parallel up to `maxParallelBuilds`.", + "\"basic\" or \"docker\". Persisted and shown on /sites, but no build path reads it today — a label, not a switch: Build all sites uses containers whenever a container engine answers, and builds serially on the host when none does, in either mode.", maxParallelBuilds: - "Cap on concurrent per-site container builds in docker mode. Ignored in" + - " basic mode (which is always serial). Clamped to [1, " + + "Cap on concurrent per-site container builds when Build all sites runs in" + + " containers (whenever a container engine answers, whatever `mode` says)." + + " Clamped to [1, " + "BUILD_MAX_PARALLEL_MAX].", dockerImage: "Tag of the reusable build image (built once, reused for every site).", @@ -1525,7 +1527,7 @@ export const siteSettingsSchema = z.object({ "Where a channel's downloaded media goes when it is relocated off the corpus disk. A DEFAULT ONLY: the relocate controller never reads it and always takes an explicit root, so this is the value the per-channel Storage panel prefills and the /channels bulk move falls back to. Blank = no default. See StorageSettings.", ), buildPipeline: settingsField((v): BuildPipelineSettings => sanitizeBuildPipeline(v)).describe( - "How the static export is built: \"basic\" reuses the single export/ tree and serializes builds on one queue (the long-standing behavior); \"docker\" builds every site at once, each in its own container (Dockerfile.build), then deploys them serially, and falls back to the basic build when no container engine answers — see PUBLISH.md. This block persists the chosen mode plus the image and concurrency knobs that pipeline reads.", + "The build pipeline's settings. A single site builds in the shared export/ tree, serialized on one queue. Build all sites (and Build & deploy all) builds every site at once, each in its own container (Dockerfile.build, the image and maxParallelBuilds below), then deploys them serially, whenever a container engine answers, and serially on the host when none does — see PUBLISH.md. `mode` is persisted and shown on /sites, but no build path reads it today: it is a label, not a switch.", ), digest: settingsField((v): DigestSettings => sanitizeDigest(v)).describe( "AI digest generation (chapters + topic tags over the existing transcripts). Local-first: the metered lane is off by default. See DigestSettings.", diff --git a/editor/app/settings/components/SettingsForm.tsx b/editor/app/settings/components/SettingsForm.tsx @@ -298,12 +298,12 @@ export function SettingsForm({ initial }: Props) { <fieldset className="flex flex-col gap-3 border border-border rounded p-3"> <legend className="px-1 text-sm font-medium">Build pipeline</legend> <p className="text-xs text-muted-foreground"> - How the static export is built. <strong>Basic</strong> runs the build - in <code>export/</code> and serializes builds on one queue.{" "} - <strong>Docker</strong> builds every site at once, each in its own - container (capped by Max parallel builds), then deploys them one by - one; with no container engine it falls back to the basic build. See - PUBLISH.md. The mode can also be toggled on the{" "} + A single site builds in <code>export/</code>, one at a time on one + queue. <strong>Build all sites</strong> builds every site at once, each + in its own container (capped by Max parallel builds), then deploys them + one by one, whenever a container engine answers, and serially on the + host when none does. The mode below is a label for now: no build reads + it. See PUBLISH.md. It can also be toggled on the{" "} <a href="/sites" className="underline"> Sites </a>{" "} @@ -325,7 +325,7 @@ export function SettingsForm({ initial }: Props) { name="maxParallelBuilds" defaultValue={String(initial.buildPipeline.maxParallelBuilds)} type="number" - hint="Cap on concurrent per-site container builds in Docker mode (1–16). Ignored in Basic mode, which is always serial." + hint="Cap on concurrent per-site container builds (1–16) when Build all sites runs in containers — whenever a container engine answers, whichever mode is set." /> <Field label="Docker image tag" diff --git a/editor/app/sites/components/BuildAllSitesButton.tsx b/editor/app/sites/components/BuildAllSitesButton.tsx @@ -10,12 +10,13 @@ import { JobLane } from "./JobLane"; type Lane = { deploy: boolean; skipArchives: boolean; key: number }; // One-click orchestrated pipeline over EVERY site as a SINGLE managed job (one -// log, one Cancel): in Docker mode it runs the shared data phase + archive warm -// once, fans the per-site builds out in parallel (capped by maxParallelBuilds), -// then deploys the built sites serially. Without a container engine it falls back -// to a serial host build+deploy. Distinct from the per-site panel below, which -// launches one separate job per selected site. -export function BuildAllSitesButton({ dockerMode }: { dockerMode: boolean }) { +// log, one Cancel): whenever a container engine answers — whatever +// buildPipeline.mode says, which nothing reads — it runs the shared data phase + +// archive warm once, fans the per-site builds out in parallel (capped by +// maxParallelBuilds), then deploys the built sites serially. Without one it falls +// back to a serial host build+deploy. Distinct from the per-site panel below, +// which launches one separate job per selected site. +export function BuildAllSitesButton() { const [deploy, setDeploy] = useState(true); const [skipArchives, setSkipArchives] = useState(false); const [lane, setLane] = useState<Lane | null>(null); @@ -55,16 +56,17 @@ export function BuildAllSitesButton({ dockerMode }: { dockerMode: boolean }) { </label> </div> <p className="text-xs text-muted-foreground"> - {dockerMode - ? "Docker pipeline: shared data phase runs once, per-site builds run in parallel, then deploys run serially." - : "Docker mode is off — this runs a serial host build+deploy fallback (one site at a time)."} + When a container engine answers (whichever build mode is set): the shared + data phase runs once, per-site builds run in parallel in containers, then + deploys run serially. With none, a serial host build and deploy, one site + at a time. </p> {lane && ( <JobLane key={lane.key} title={lane.deploy ? "Build & deploy all sites" : "Build all sites"} subtitle={ - dockerMode ? "Docker pipeline · parallel builds" : "Serial host fallback" + "Containers when an engine answers, else serial on the host" } trigger={() => lane.deploy diff --git a/editor/app/sites/components/BuildModeToggle.tsx b/editor/app/sites/components/BuildModeToggle.tsx @@ -4,8 +4,11 @@ import { useState, useTransition } from "react"; import type { BuildMode } from "yt-dlp-transcript-common/lib/settings"; import { setBuildModeAction } from "../lib/buildModeAction"; -// Segmented Basic | Docker control. Persists the choice as the global build-mode -// default (setBuildModeAction → settings.json) so every subsequent build uses it. +// Segmented Basic | Docker control. Persists the choice (setBuildModeAction → +// settings.json `buildPipeline.mode`). TODAY IT IS A LABEL: no build path reads +// it — Build all / Build & deploy all use containers whenever `docker version` +// answers (buildAction.ts, dockerAvailable) — and the note below says so rather +// than promising a switch. export function BuildModeToggle({ mode: initialMode }: { mode: BuildMode }) { const [mode, setMode] = useState<BuildMode>(initialMode); const [pending, startTransition] = useTransition(); @@ -53,11 +56,11 @@ export function BuildModeToggle({ mode: initialMode }: { mode: BuildMode }) { ); })} </div> - {mode === "docker" && ( - <span className="text-xs text-warning"> - Docker builds are a follow-up — runs the basic build for now. - </span> - )} + <span className="text-xs text-muted-foreground"> + The mode is a label for now: Build all sites uses containers whenever a + container engine answers, and builds serially on the host when none + does, in either mode. + </span> </div> ); } diff --git a/editor/app/sites/components/BuildSitesPanel.tsx b/editor/app/sites/components/BuildSitesPanel.tsx @@ -13,9 +13,9 @@ export type SiteOption = { type Lane = { siteId: string; title: string; deploy: boolean; key: string }; // Batch build (and optionally deploy) several sites at once. Each selected site -// launches its own managed job, rendered as its own live JobLane. In Basic mode -// the jobs share the build/deploy queue and run one at a time (the export/ tree -// is shared); Docker mode (a follow-up) unlocks true parallelism. +// launches its own managed job, rendered as its own live JobLane. The jobs share +// the build/deploy queue and run one at a time (the export/ tree is shared), +// whichever build mode is set; "Build all sites" is the parallel path. export function BuildSitesPanel({ sites, serial, @@ -127,8 +127,9 @@ export function BuildSitesPanel({ )} {serial && ( <p className="text-xs text-muted-foreground"> - Basic mode runs these one at a time (the build output tree is shared). - Use “Build all sites” above in Docker mode for true parallel builds. + These run one at a time (the build output tree is shared). “Build + all sites” above builds every site in parallel, in containers, whenever + a container engine answers. </p> )} diff --git a/editor/app/sites/page.tsx b/editor/app/sites/page.tsx @@ -171,7 +171,7 @@ export default async function SitesPage() { </p> </div> <BuildModeToggle mode={buildMode} /> - <BuildAllSitesButton dockerMode={buildMode === "docker"} /> + <BuildAllSitesButton /> <div className="mt-4"> <h3 className="font-semibold">Or pick specific sites</h3> diff --git a/editor/e2e/deploy-page.spec.ts b/editor/e2e/deploy-page.spec.ts @@ -68,7 +68,7 @@ test("Build & deploy is enabled only when the active site has a Cloudflare proje ).toBeVisible(); }); -test("build-mode toggle persists the choice and shows the Docker follow-up note", async ({ +test("build-mode toggle persists the choice and says the mode is a label", async ({ page, }) => { await writeSite("testsite", { cloudflareProject: "proj" }); @@ -93,7 +93,7 @@ test("build-mode toggle persists the choice and shows the Docker follow-up note" timeout: 1_000, }); }).toPass({ timeout: 15_000 }); - await expect(page.getByText(/Docker builds are a follow-up/i)).toBeVisible(); + await expect(page.getByText(/The mode is a label for now/i)).toBeVisible(); // Wait for the choice to actually reach settings.json before reloading. // BuildModeToggle updates its own state OPTIMISTICALLY — setMode(next) flips @@ -150,5 +150,5 @@ test("batch panel: selecting sites enables the launch button and reflects deploy ).toBeVisible(); // Basic mode (the default) notes that the batch runs serially. - await expect(page.getByText(/Basic mode runs these one at a time/i)).toBeVisible(); + await expect(page.getByText(/These run one at a time/i)).toBeVisible(); });