commit 980196abe0efa9b4fc2e07524bedeee3b483ca87
parent d0370b7552020c11088b9e38200d50d2b4cc67c0
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 28 Sep 2026 04:24:19 -0400
plans: slice O6 checkpoint B as shipped — the E2E_ prefix cleanup, declared in the playwright configs, the harnesses on ports.mjs; the editor and homepage [Unreleased] bullets
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md
@@ -7,6 +7,7 @@
- **A bucket's retry keeps its log when it empties the bucket.** On a channel's Download stage, "Download with cookies", the partial-download resume and the missing-transcript retry could lose their run log part-way: the video they fetched left the bucket, the page refreshed, and the card disappeared with the log in it. The card now stays, with its log and its button disabled, until the page is reloaded. The Transcribe stage's "Fetch audio" button does the same. (A Diagnostics card still disappears, log and all, when its retry empties it.)
- **A release cut whose commit fails still refreshes the pages.** When the changelog's new heading was written but the commit after it failed, the Cut release form and `pnpm ops cut-release` answered as if nothing had happened and no page showed the new heading until a reload. Both now refresh the changelog pages, and `pnpm ops cut-release` says the file was written. Every refused cut's answer says whether anything was written (`untouched`), and a cut of both changelogs that stopped half-way names the one already cut as well as the failure.
- **`archilyzer` checks the machine, runs one operation offline, starts the MCP server, and is one command from the repo root.** `pnpm archilyzer <command>` is the short form (`pnpm archilyzer --help` lists them all). `pnpm archilyzer doctor` is a read-only report: Node, the checkout, the corpus and whether each channel's media is reachable, `settings.json`, every tool the paths name plus each enabled worker's engine and model, umtool's report-pipeline tools, and this checkout's ports; it exits 1 only for something the machine is set up to do and cannot. `pnpm archilyzer run <operation> <channel> [ids…]` runs diarization, either attribution pass or digest over one channel as the editor's job does (a job record and log under `.jobs/`, the same summary line, the same refusal for an unmounted drive); sync, the metadata scan, downloads and transcription are refused with the reason, because they run on the editor's paced download queue and worker pool. `pnpm archilyzer mcp` starts the MCP server, so it can be registered as `-- pnpm -C "$PWD" archilyzer mcp`. Every other script in `common/bin/` is a subcommand too (`duplicates`, `posts fetch`, `digest plan`, `verify transcripts`, …), and export's `detect:duplicates` script is now `archilyzer duplicates`. Every environment variable is listed, by audience, in the new `ENVIRONMENT.md`, and `DEPLOY_CLOUDFLARE.md` and `DEPLOY_DOCKER.md` are now one `PUBLISH.md`. Settings and `/sites` no longer call the Docker build mode a follow-up, and say what it is: a label. **Build all sites** builds in containers whenever a container engine answers, whichever mode is set.
+- **Settings' build mode says it is a label, and the test-only environment variables start with `E2E_`.** The Build mode choices now read *Basic (a label for now)* and *Docker (a label for now)*, and the **Build all sites** section and the per-site panel on `/sites` say the same: Build all builds every site in parallel in containers whenever a container engine answers, whatever the mode, and single-site builds run one at a time. For whoever runs the test suites: every variable only a test harness reads is renamed with an `E2E_` prefix and listed in its package's `playwright.config.ts` (and in `ENVIRONMENT.md`); `SHARDS=N pnpm e2e:sharded` is now `E2E_SHARDS=N`.
- **In high-contrast mode the sidebar's Archilyzer mark keeps its edge.** In Windows' high-contrast mode (forced colours) the reader's own background replaces the page on every ground and can be as dark as the mark's slate tile, whose thin ring is only drawn on Dark. In that mode the tile now gets a 1-pixel outline in the reader's text colour, on every ground, following its rounded corners. Nothing changes outside that mode.
## [0.9.4] - 2026-09-28
diff --git a/homepage/CHANGELOG.md b/homepage/CHANGELOG.md
@@ -2,6 +2,7 @@
## [Unreleased]
+- **The docs' *Building several sites at once* page says what Build all does.** It called the container pipeline opt-in, turned on in the settings. Build all sites builds every site in parallel in containers whenever a container engine is available, whichever build mode is set (that choice is only a label for now), and one after another when none is.
- **A single-colour social icon shows on every ground.** The footer's social icons are the operator's (`homepage.json`'s, else `settings.socialLinks`), normalized when they are saved (`normalizeSocialSvg`, release 11 slice O1). An icon drawn in one colour now takes the footer's colour throughout; before, a part that carried its own colour kept it, so X's official logo, which is white, was invisible on the Light ground. An icon of two or more colours, such as YouTube's red mark with its white triangle, keeps its colours as pasted. "No fill", gradients, masks, clip paths and animation timing are never changed, and a clip path's own colour does not count, so a one-colour icon exported from Figma follows the footer too. It applies when the settings are next saved, then needs a rebuild and deploy of the homepage.
- **In high-contrast mode the header mark's tile keeps its edge.** In Windows' high-contrast mode (forced colours) the reader's own background replaces the page on every ground and can be as dark as the slate tile, whose ring is only drawn on Dark. In that mode the tile gets a 1-pixel outline in the reader's text colour, on every ground, following its rounded corners. Nothing changes outside that mode.
- **A sixth official instance has a chart colour of its own.** The growth chart, its legend and `/stats` had five validated colours, so a sixth site fell to a pink within a degree of the fifth's magenta. There is now a sixth, a rust (`--chart-6`: `#823c10` on Light and Sepia, `#a54a08` on Dark), which is Vermilion's hue family, so Jasolyzer's card and its layer will share a hue once it is published. It clears every pair with the other five on all three grounds for colour-blind readers (the dataviz validator, all pairs; worst CVD ΔE 9.1, normal 16.3). Any six sites now wear the six validated colours; `/stats`' sixth channel gets the rust too.
@@ -33,7 +34,7 @@
Violet → violet, Green → green, Sakura → magenta), since the accents themselves fail as a
chart palette. No two sites share a colour. The `/stats` By-site leaderboard keeps each
site's colour instead of colouring by rank. The e2e reads a copy of the summary with fixture
- accents (`HOMEPAGE_SUMMARY_FILE`, `e2e/fixture-accents.ts`).
+ accents (`E2E_HOMEPAGE_SUMMARY_FILE`, `e2e/fixture-accents.ts`).
## 2026-08-12
diff --git a/plans/release-11.md b/plans/release-11.md
@@ -1375,6 +1375,115 @@ small round on the same branch and worktree. `main` merged first (a fast-forward
attribute` during `stats.spec`'s Customize test (ranked / small multiples). It is in O2's runs too,
so it predates O2b.
+### Slice O6, as shipped — checkpoint B: the `E2E_` prefix cleanup (2026-09-28)
+
+After checkpoint A merged (`cb9d02b2`), the branch fast-forwarded to `main` `15d5d646` and then
+`59d2f877` (O2b in). No merge commit was needed. The plan was written first
+(`$T/o6-b-plan.md`): every variable, every reader, old → new, and which stay unprefixed and why.
+
+**The rule.** A variable only a harness reads gets the `E2E_` prefix and is declared in its
+package's playwright config. "A harness" means a playwright config, an e2e helper, a fixture, a
+fake binary, a stub server, the sharded runner, or a test-mode branch of app code. The config
+either sets the variable (webServer `env`) or lists it with where it is read. Two new
+`envVars.test.ts` tests hold the rule:
+- the `test` audience is `E2E_`-prefixed (`PLAYWRIGHT_BASE_URL` and `QUEUE_LOCK_HELD` are
+ excepted, with the reason);
+- each test-audience variable is named in a playwright config (the queue's own variables in
+ `queue-lock.mjs`).
+
+**Renamed**, every reader and writer:
+
+| old | new |
+|---|---|
+| `EDITOR_TEST_ROUTES` | `E2E_TEST_ROUTES` |
+| the five `AUDIO_CHECK_*_OVERRIDE` | `E2E_AUDIO_CHECK_*` (suffix dropped) |
+| `AUDIO_CHECK_DEBUG_PAUSE_MS` | `E2E_AUDIO_CHECK_DEBUG_PAUSE_MS` |
+| `FAKE_YTDLP_*` ×7, `FAKE_GALLERY_DL_AUTH_FAIL` | `E2E_FAKE_*` |
+| `FIXTURE_MAX_LIFETIME_MS`, `OLLAMA_STUB_MODEL`, `RACK_SHOTS`, `TWO_ORIGIN_REBUILD`, `HOMEPAGE_SUMMARY_FILE` | `E2E_…` |
+| `SHARDS`, `IMAGE`, `SKIP_BUILD` (sharded runner) | `E2E_SHARDS`, `E2E_IMAGE`, `E2E_SKIP_BUILD` |
+| umtool: `EDITOR_STUB_LOG`, `UMTOOL_CUT_DELAY_MS`, `UMTOOL_EXTRA_KINDS` | `E2E_…` |
+
+- **The editor's test-server values moved.** `E2E_TEST_ROUTES` and the audio-check knobs moved
+ from `dev:test` / `start:test` into `editor/playwright.config.ts`'s `E2E_SERVER_ENV` (the
+ webServer's env). A hand-started `dev:test` could already not be reused under the queue's port
+ check, so nothing depended on it carrying them.
+- **Newly declared:** `E2E_RETRIES` (read dynamically, so the scan had missed it), and two runtime
+ knobs the scan had also missed because they are read through helpers:
+ `AUDIO_CHECK_RESUME_DURING_PROBE` and `AUDIO_CHECK_BACKOFF_FACTOR`. The scan now knows
+ `env(Int|Float|Bool)Override` and `parseIntArg`.
+- **umtool's three** are declared in `umtool/playwright.config.ts`, not in `envVars.ts` (umtool is
+ outside the list until Phase 5).
+
+**Unchanged, by design:**
+- the queue lock and port check: `E2E_QUEUE`, `E2E_PORT_CHECK`, `E2E_QUEUE_TIMEOUT`,
+ `E2E_PORT_GRACE_MS`, `E2E_QUEUE_LOCK_FILE`, `QUEUE_LOCK_HELD`, and the lock file;
+- the port names (`ports.mjs`, the worktree injector, queue-lock's `--ports` lists);
+- `PLAYWRIGHT_BASE_URL`, `CI`, and the real overrides a harness points at fixtures;
+- the docker `ARCHILYZER_*` set;
+- two unit-test knobs, `KEEP_TAG_PREVIEW_FIXTURE` and `CUES_TEST_DIR`, which are read by node unit
+ tests, not an e2e harness.
+
+**Ports.** Everything that used to spell a fallback now reads `common/lib/ports.mjs`
+(`portFor` / `PORT_BASES`), so `ports.test.ts` finds only the package.json shell defaults and
+the `--ports` lists, which cannot import a module:
+- the configs: editor, export, hub, 2origin, homepage, umtool;
+- the editor's `baseUrl.ts`, the two export specs, and the ollama stub;
+- the umtool editor stub and the 2origin spec.
+
+The umtool stub's port is now `EDITOR_STUB_PORT`'s base whatever `UMTOOL_E2E_PORT` is, which is
+what queue-lock's preflight already checked.
+
+**Folded in (the parent's asks):**
+- The Settings Build mode options read "Basic (a label for now)" / "Docker (a label for now)".
+- The per-site panel's note shows whatever the mode is (its `serial` prop is gone).
+- `/sites`' Build all sentence no longer says "(Docker mode)".
+- The public homepage's "Building several sites at once" page and its `/docs` blurb say Build all
+ uses containers whenever an engine is available, and that the mode is a label; the homepage
+ changelog has a bullet.
+- `E2E_SHARDS` is in CONTRIBUTING.md and SETUP.md.
+- One editor `[Unreleased]` bullet.
+
+| sha | what |
+|---|---|
+| `f4367aca` | `e2e:` the renames, the declarations, `E2E_SERVER_ENV`, the two guard tests, the harnesses on ports.mjs, ENVIRONMENT.md regenerated |
+| `43b2572b` | `editor:` the build-mode options, the per-site panel note, /sites' Build all sentence |
+| `b3f2ee86` | `docs:` `E2E_SHARDS`; the homepage's Docker page and blurb |
+| _this_ | `plans:` this section; the editor and homepage `[Unreleased]` bullets |
+
+**Gate B**, on `59d2f877` + these commits, from the worktree root. The logs are `o6-gateB*.log`
+and `o6-gB-*.log`.
+- tsc clean (66 s, then 31 s).
+- **common 2,112/2,112**, **editor unit 85/85**, **`test:scripts` 185 + 1 skip**, **mcp
+ 269/269**, homepage unit 2/2.
+- `docs env --check`, `settings example --check` and `docs files --check`: all exit 0.
+- Every touched playwright config loads (`playwright test --list`): editor 665, export 206, hub
+ 33, homepage 31, umtool 222.
+- **Editor subset** (`o6-specsB.txt`: ops-api, worker-unit, audio-check-classifier,
+ audio-check-scenarios, social-channel, digest, export-search, export-player-platform-cache,
+ deploy-page, settings, channels-rack-audit), with `E2E_RACK_SHOTS=1` so the audit actually runs
+ (its shots landed in `editor/test-results/rack-shots/`): **115 passed, 0 failed, 5.3 min**.
+- **Export full:** **206 passed, 0 failed, 6.7 min**.
+- **`e2e:hub`:** **33 passed, 1.2 min**.
+- **Homepage full**, with the primary's `homepage/public` data copied: **31 passed, 0 skipped, 45 s**.
+- **umtool full** (`SONG_DIR=~/reports/quartering-uh-song/data`): **175 passed, 2 failed, 45
+ skipped, 4.1 min**. That is exactly O5's recorded baseline. The two failures are the known
+ order-dependent pair, `mix.spec.ts:166` and `:201`; the skips are the song-data capabilities.
+ **`mix.spec.ts` alone: 12 passed** (22 s). The renamed umtool knobs are exercised in that run:
+ deliver's Stop test passed (18.3 s, `E2E_UMTOOL_CUT_DELAY_MS`), and so did the
+ unregistered-kind test in projects.spec (`E2E_UMTOOL_EXTRA_KINDS`).
+- **They bite** (`o6-bite.log`, "checkpoint B"):
+ - a test-only var without the prefix fails 4, including the prefix test;
+ - removing a name from the editor config's declaration fails the declared-in-a-config test (1);
+ - an old name read again in a fixture fails "every variable the code reads is declared" (1);
+ - a drifting port fallback in `baseUrl.ts` fails `ports.test` (1).
+
+**Found and left (checkpoint B):**
+- `e2e:2origin` was not run. Its config's ports and declaration changed, and its setup renames
+ `E2E_TWO_ORIGIN_REBUILD`. But a rebuild runs `pnpm run build:hub`, whose compose writes into
+ `export/public`, and in a worktree that is symlinks into the primary checkout (the release-7
+ lesson). Run it from the primary, or with `export/public` de-linked first.
+- Old names survive only in `plans/` and released changelog text.
+
## Rollout
Nothing is rolled out tonight. The morning runbook lists what is owed: the :3001 editor restart,