Archilyzer · Source

archilyzer

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

commit 4153f62ed4e01c0b3bd52b09c8a9e9ccacc58262
parent 6b7a36a1050a92daf10552158971bb357f7dc2e6
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue,  6 Oct 2026 09:30:25 -0400

Merge r18/docker-publish (slice S5: the image runs Node 22 in the build stage and every runtime — the pinned wrangler's floor)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
MDockerfile | 14+++++++++++---
MRUNNING_IN_DOCKER.md | 2+-
Mcommon/publish/buildImage.test.ts | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mdocker-compose.vulkan.yml | 8++++----
Mplans/release-18.md | 12+++++++++++-
5 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/Dockerfile b/Dockerfile @@ -39,10 +39,18 @@ # bookworm is 2.36, trixie 2.41, ubuntu 24.04 2.39 — so building on bookworm and # running on any of them is safe, and moving NODE_IMAGE to trixie would silently # break the CUDA target. If you bump one of these, check that direction first. -ARG NODE_IMAGE=node:20-bookworm-slim +# +# NODE'S MAJOR IS THE SECOND RULE, and it must be the same everywhere: the +# native modules are compiled against the build stage's Node ABI, so every +# runtime (NODE_IMAGE, RUNTIME_IMAGE here and in docker-compose.vulkan.yml, +# NODE_MAJOR in runtime-cuda) carries the same major. 22, not 20: the wrangler +# pinned in common/package.json refuses to start on anything older (its +# engines floor), and every deploy runs it from this image. +# common/publish/buildImage.test.ts holds all four to one major and that floor. +ARG NODE_IMAGE=node:22-bookworm-slim # The runtime base, overridable per target: docker-compose.vulkan.yml builds with # trixie because the Vulkan stack needs it (see the parakeet stage below). -ARG RUNTIME_IMAGE=node:20-bookworm-slim +ARG RUNTIME_IMAGE=node:22-bookworm-slim # ubuntu24.04, not 22.04: 22.04 is glibc 2.35, OLDER than the bookworm the # workspace is built on, and the native modules would not load. ARG CUDA_DEVEL_IMAGE=nvidia/cuda:12.6.3-devel-ubuntu24.04 @@ -456,7 +464,7 @@ ENV ARCHILYZER_COMMIT=${ARCHILYZER_COMMIT} \ # --------------------------------------------------------------------------- FROM ${CUDA_RUNTIME_IMAGE} AS runtime-cuda -ARG NODE_MAJOR=20 +ARG NODE_MAJOR=22 # The same python + pipx + git-filter-repo as runtime-base (read its comments). RUN apt-get update \ && apt-get install -y --no-install-recommends \ diff --git a/RUNNING_IN_DOCKER.md b/RUNNING_IN_DOCKER.md @@ -657,7 +657,7 @@ docker compose down -v # stop AND DELETE the corp ## What is in the image, and what is not -**Baked in:** node + the installed workspace, the built editor / umtool / homepage, +**Baked in:** Node 22 (the pinned wrangler needs it) + the installed workspace, the built editor / umtool / homepage, `yt-dlp`, a JavaScript runtime for it (`deno` — without one yt-dlp warns and silently loses formats), `ffmpeg`/`ffprobe`, `whisper-cli` (statically linked), `zip`/`tar`/`xz`/`gzip`, `rsync`, `git`, `curl`, `ps`; `python3` with yt-dlp's diff --git a/common/publish/buildImage.test.ts b/common/publish/buildImage.test.ts @@ -126,3 +126,50 @@ test("every runtime target names its own yt-dlp and links the from-source wrappe assert.equal(links.length, 2); assert.ok(existsSync(path.join(REPO, "docker", "yt-dlp-from-source.sh"))); }); + +// Node's major, everywhere the image is built or run: the build stage +// (NODE_IMAGE), the default runtime (RUNTIME_IMAGE), the Vulkan overlay's +// runtime and runtime-cuda's nodesource major. The native modules are compiled +// once against the build stage's ABI, so all of them must agree. +function imageNodeMajors(): Record<string, number> { + const dockerfile = readFileSync(path.join(REPO, "Dockerfile"), "utf8"); + const vulkan = readFileSync(path.join(REPO, "docker-compose.vulkan.yml"), "utf8"); + const one = (re: RegExp, text: string, what: string) => { + const m = re.exec(text); + assert.ok(m, `${what} not found`); + return Number(m[1]); + }; + const out: Record<string, number> = { + NODE_IMAGE: one(/^ARG NODE_IMAGE=node:(\d+)-/m, dockerfile, "ARG NODE_IMAGE=node:<major>-…"), + RUNTIME_IMAGE: one(/^ARG RUNTIME_IMAGE=node:(\d+)-/m, dockerfile, "ARG RUNTIME_IMAGE=node:<major>-…"), + NODE_MAJOR: one(/^ARG NODE_MAJOR=(\d+)$/m, dockerfile, "ARG NODE_MAJOR=<major> (runtime-cuda)"), + }; + const vk = [...vulkan.matchAll(/RUNTIME_IMAGE: node:(\d+)-/g)].map((m) => Number(m[1])); + assert.ok(vk.length > 0, "docker-compose.vulkan.yml names a RUNTIME_IMAGE"); + vk.forEach((v, i) => (out[`vulkan RUNTIME_IMAGE #${i + 1}`] = v)); + return out; +} + +test("every image target runs the Node major the build stage compiled the native modules for", () => { + const majors = imageNodeMajors(); + assert.equal(new Set(Object.values(majors)).size, 1, `one Node major everywhere, found ${JSON.stringify(majors)}`); +}); + +// Every deploy runs the wrangler pinned in common's devDependencies from this +// image, and wrangler refuses to start below its engines floor (4.x: >=22). +// Skipped where wrangler is not installed. +test("the image's Node major meets the pinned wrangler's engines floor", (t) => { + const pkg = path.join(REPO, "common", "node_modules", "wrangler", "package.json"); + if (!existsSync(pkg)) { + t.skip("wrangler is not installed in common/node_modules"); + return; + } + const engines = (JSON.parse(readFileSync(pkg, "utf8")) as { engines?: { node?: string } }).engines?.node ?? ""; + const floor = /(\d+)/.exec(engines); + assert.ok(floor, `wrangler's engines.node (${JSON.stringify(engines)}) names a major`); + const major = imageNodeMajors().NODE_IMAGE; + assert.ok( + major >= Number(floor[1]), + `the image runs Node ${major}, and wrangler needs ${engines} — every deploy from the container would exit 1`, + ); +}); diff --git a/docker-compose.vulkan.yml b/docker-compose.vulkan.yml @@ -38,7 +38,7 @@ services: # The Vulkan stack needs a newer Debian than the default image runs on; # the Dockerfile explains why, and why the workspace is still BUILT on # the older one. - RUNTIME_IMAGE: node:20-trixie-slim + RUNTIME_IMAGE: node:22-trixie-slim image: archilyzer:${ARCHILYZER_TAG:-local}-vulkan devices: # The render node. This is the whole GPU passthrough — no toolkit, no @@ -59,17 +59,17 @@ services: build: target: runtime-vulkan args: - RUNTIME_IMAGE: node:20-trixie-slim + RUNTIME_IMAGE: node:22-trixie-slim image: archilyzer:${ARCHILYZER_TAG:-local}-vulkan homepage: build: target: runtime-vulkan args: - RUNTIME_IMAGE: node:20-trixie-slim + RUNTIME_IMAGE: node:22-trixie-slim image: archilyzer:${ARCHILYZER_TAG:-local}-vulkan umtool: build: target: runtime-vulkan args: - RUNTIME_IMAGE: node:20-trixie-slim + RUNTIME_IMAGE: node:22-trixie-slim image: archilyzer:${ARCHILYZER_TAG:-local}-vulkan diff --git a/plans/release-18.md b/plans/release-18.md @@ -515,11 +515,21 @@ merged, so the doctor's `wrangler`, `publish-lock` and `index-stamp` checks, the | `ba83cbff` | `docker-compose.source.yml`: long bind syntax, `create_host_path: false` — a missing host `.git` now fails `up` ("bind source path does not exist: …", verified) instead of becoming an empty root-owned dir | | `fb1a1f24` | `YTDLP_AUTO_UPDATE`: the doctor reads it with the entrypoint's exact-match rule (`1`, `true`, `yes`, `on` as written; `TRUE` is off in both), +1 test loop; RUNNING_IN_DOCKER.md states the rule | | `07bc2395` | RUNNING_IN_DOCKER.md: no gitleaks or stagit in the image — the container's source publish skips the secret scan (with its warning) and the history pages; pinned gitleaks a follow-up | -| this one | the record: only `--target runtime` was built (vulkan and cuda unverified, left for the rollout); the second half's added items; found and left | +| `e9fe6bdd` | the record: only `--target runtime` was built (vulkan and cuda unverified, left for the rollout); the second half's added items; found and left | +| `908c7c4a` | **Node 22** (S2's review: the pinned wrangler 4.147.0 has `engines.node >=22.0.0`, so every deploy from a Node 20 image would exit 1): `NODE_IMAGE` and `RUNTIME_IMAGE` `node:22-bookworm-slim` (glibc 2.36, unchanged — the glibc rule holds), the Vulkan overlay `node:22-trixie-slim`, runtime-cuda `NODE_MAJOR=22` on ubuntu 24.04. Two drift tests in `buildImage.test.ts`: one Node major across all of them (the native modules are built once, against the build stage's ABI; proven red with `NODE_MAJOR=20`), and that major ≥ wrangler's `engines.node` floor (skipped here — wrangler is S2's devDependency; S2's worktree has 4.147.0, `>=22.0.0`) | +| this one | RUNNING_IN_DOCKER.md names Node 22 in the image's contents; this table | Re-run after the fixes at `07bc2395`: tsc (all workspaces) clean; `doctor`, `buildImage`, `source` and `envVars` tests **61/61** (`$T/s5-fix-tests.log`). +Node 22, at `908c7c4a`: `buildImage.test.ts` 5 passed, 1 skipped (the wrangler floor); common tsc clean. +`--target runtime` rebuilt in the capped builder, exit 0, 349 s; the image is 1.79 GB. Smoke (`-p r18smoke`, +the same fixture, `down -v` after): `node --version` in the container is **v22.23.3**; the boot log's +`yt-dlp: /usr/local/bin/yt-dlp 2026.08.19 (image)`; `/api/pulse` 200; the build stage's native modules +load in the runtime — `lmdb` opens, writes and reads (`process.versions.modules` 127), `msgpackr-extract`'s +binding loads; `archilyzer doctor` reports `node v22.23.3` ok and every S5 check, exit 1 only for the +model the smoke skips. vulkan and cuda still unbuilt (above). + ## Rollout (Steps 1–7 above; "### As it went" is written as the rollout runs.)