Archilyzer · Source

archilyzer

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

commit 58569da848f69b3b3ba75c0c6b4a0239d687f3b8
parent 92cc9d6d94a6ff1c069d9109091b6b7e8a6e1750
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 26 Sep 2026 14:23:45 -0400

plans: release 10 integration (S4 + L1 + L2) as merged — the combined tree's gates (tsc; common 1,954, editor unit 85, scripts 173 + 1, mcp 219; five builds with the icon checks; e2e export 204, hub 24, 2origin 3 with the export/public links in place and the primary byte-identical, homepage 27, umtool 175 + the known mix.spec pair, editor 634 + 6 load flakes, 18/18 alone), the Jeralyzer early deploy, STATE's "Merged to main, NOT rolled out" block, the Rollout re-cut and the optional umtool step

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

Diffstat:
Mplans/STATE.md | 169++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mplans/brand-and-themes.md | 4++++
Mplans/release-10.md | 249+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 322 insertions(+), 100 deletions(-)

diff --git a/plans/STATE.md b/plans/STATE.md @@ -3,90 +3,109 @@ The working memory for the local-AI derived-corpus work. Rewritten at the end of every session, before context is cleared. See [`README.md`](README.md) for the protocol. -**Now (2026-09-26, just after midnight): the brand is merged to `main` and NOT rolled out.** `main` = -`85cf6e81` + the S3 review-fix `plans:` record (review: SHIP AFTER FIXES, the fixes were in the -runbook). It is release 10's first content, the Found-line mark and base × accent reader themes: S0 -`7c9e3bdf`, S1 `575ae1d4`, S2 `b9772e53`, then S3 (integrate: review carry-overs, a coherence pass, the -full gates, the records, the runbook) fast-forwarded. Record: -[`release-10.md`](release-10.md); the plan and the per-slice records: -[`brand-and-themes.md`](brand-and-themes.md). -- **The live :3001 editor still runs the pre-brand build**, `0213f6c8` / `BUILD_ID` - `P0VMdKX7gbdsaiS5GvorF` (umtool `a9YAe_dwhuM6DiCPzIwMD`, untouched; the brand does not touch - umtool). The five sites, the hub and the homepage still serve pre-brand builds (below). -- **Next action: the operator's rollout, per `~/reports/release-10/RUNBOOK.html`** (`make-runbook.py` - beside it; the rollout scripts in `scripts/`). In order: cut the export `[Unreleased]` notes (they - are public on every site's `/changelog`); restart :3001 on the new `main` (one editor restart, md5 - before / pre-restart / after-boot, smoke); set each site's accent + wordmark lead in the site form; - preview Anilyzer (`https://brand.anilyzer.pages.dev`) and check it on a phone; then the five sites - by name, the hub, the homepage. -- **Archilyzer Media (the YouTube channel) awaits the operator's picks** on the canvas - (https://claude.ai/artifact/UsUxwgRkP5a3m4jZXucAvG): mark M1 bone / **M2 Signal**, lockup inline / - **imprint** (recommended in bold). Then slice S4 (`brand-and-themes.md` "Proposed"); it needs - `ttf-ibm-plex` and Archivo installed as system fonts. -- Worktrees: `brand-mark` and `brand-themes` are merged and can go; `brand-found-line` once `main` - carries its tip. Removing any of them re-sorts the port blocks (`diet-series` moves up). - -**Parked for after the brand rollout (2026-09-26, all Opus-reviewed to SHIP; none merged):** -- **Brand S4 (Archilyzer Media)**, `brand/media` @ `333d2826`, worktree `../brand-media`: - - `common/lib/brandMedia.ts` builds the lockup with its text as glyph outlines; - - `common/bin/brand-media.ts` writes the YouTube assets. They are already generated in - `~/reports/archilyzer-media/brand/` and can be uploaded now; see `INDEX.html` there - (Customization → Profile); - - the opt-in umtool report-to-video preset `render.brand: "archilyzer-media"`, with its fonts - vendored (OFL) under `umtool/report-to-video/fonts/`. Manifests that don't opt in render - byte-identical (334 files checked). -- **L1, hub lows**, `r10/hub-lows` @ `b6b47ec1`, worktree `../r10-hub-lows`: - - subs 404 = an empty manifest, with one retry that never fails the archive; - - `/ask` honours the scope chips; - - the official-instance accent fallback, and one card order (the homepage's); - - the playwright config and `compose-hub`/`compose-site` never write through `export/public` - links (`common/bin/_publicFile.ts`). -- **L2, runner lows**, `r10/runner-lows` @ `14e96739`, worktree `../r10-runner-lows`: - - YouTube's "try again later" soft block reads as `rate_limit` and backs off: download batch, - runner, scan, and a prefetch early exit; - - the availability check stops on it, and `verifyBeforeClean` marks every unprobed suspect - `unverified`; - - the boot pass waits at most 60 s for the storage pass; - - `/jobs` shows `cancelReason`; - - the safeRevalidate warning is counted. -- **Merge plan.** Merge in the order S4 → L2 → L1. The code merges clean. `plans/release-10.md` - conflicts on the record sections only: keep every section. At that merge: - - update FACTS to retire the `sw.js`-copy and compose-output-swap workarounds; the per-path - seed of the `export/public` links stays; - - L1 adds public `export/CHANGELOG.md` `[Unreleased]` bullets, so cut before the next site - deploy; - - the live umtool needs a rebuild and restart before its new-project form offers the brand. -- **Copy rulings owed by the operator:** - - `NO_ARCHIVES_IN_SCOPE` (`export/app/ask/hubScopeCopy.ts`, draft "No archives selected. - Choose some on the [hub's front page] to ask."); - - whether `/ask` shows a "Searching N of M archives" scope line. -- **New lows:** - - `/ask` waits forever on a hub with zero archives; +**Now (2026-09-26, afternoon): release 10 is merged to `main` in full and NOT rolled out.** It is +the brand (S0–S3: the Found-line mark and base × accent reader themes; its own final commit +`bb6f378f`, then cut as editor + export 0.9.0 at 01:37, `0e0d8f59` + `31798769`), plus brand S4 and +the lows L1 + L2. Those three merged 2026-09-26 12:52 on the operator's word, before the rollout, +and the integration pass gated them together. Record: [`release-10.md`](release-10.md) (the L2 +and L1 records, then "Integration (S4 + L1 + L2), as merged"); the brand's plan and per-slice +records, S4's included: [`brand-and-themes.md`](brand-and-themes.md). + +**Merged to main (2026-09-26), NOT rolled out:** +- **The merges**, in the planned order: S4 `dcb04f61` (`brand/media` @ `333d2826`) → L2 `41ddc382` + (`r10/runner-lows` @ `14e96739`) → L1 `5c0a6ef9` (`r10/hub-lows` @ `b6b47ec1`). The code merged + clean; the conflicts were `plans/release-10.md` (the record sections, all kept) and one + `editor/CHANGELOG.md` `[Unreleased]` join (S4's bullet and L2's four in one section above + `[0.9.0]`). +- **Integration tip:** `brand/found-line` = `main` `4ac32a2e` + the integration `plans:` commits + (FACTS `9e3047e3`, then this STATE and the record). `4ac32a2e` is `5c0a6ef9` plus the plans-only + `plans/mcp-fetch-clip.md`, committed to `main` during the pass; the integration commits were + rebased onto it. No code changed at integration. The parent fast-forwards `main` to the tip, and + the runbook's `FINAL` is that tip. +- **What is in it:** + - **S4, Archilyzer Media:** `common/lib/brandMedia.ts` (the lockup with its letters as glyph + outlines); `common/bin/brand-media.ts` (the YouTube assets, already generated in + `~/reports/archilyzer-media/brand/`, with `INDEX.html` there; upload any time); umtool + report-to-video's opt-in `render.brand: "archilyzer-media"` with vendored OFL fonts (a manifest + without it renders byte-identical, 334 files checked); and the brand choice in umtool's + new-project form. + - **L1, hub:** subs 404 = an empty manifest, one retry, never fails an archive; `/ask` honours + the scope chips (none in scope: disabled + one line); the official instances in the homepage's + order and colours; the playwright config and the compose scripts never write through + `export/public` links (`common/bin/_publicFile.ts`; the FACTS workarounds are retired). + - **L2, runner:** YouTube's "try again later" soft block backs off (batch, runner, scan, a + prefetch early exit; the availability check stops); `verifyBeforeClean` never judges an + unprobed suspect; the boot pass waits at most 60 s for the storage pass; `/jobs` shows + `cancelReason`; the safeRevalidate warning is counted. +- **Gates on the merged tree** (`5c0a6ef9`; every number in the record): + - tsc clean; + - common 1,954, editor unit 85, `test:scripts` 173 + 1 skip (the report-to-video tests + included), mcp 219; + - editor, export site + hub, homepage and umtool builds ok, the icon checks green; + - e2e: export 204, `e2e:hub` 24, `e2e:2origin` 3 (the `export/public` links left in place: the + primary's `export/public` and a `sw.js` sentinel byte-identical throughout), homepage 27; + - umtool 175 + 2 failed + 45 skipped (the known order-dependent `mix.spec` pair; alone 6/6); + - editor full 634 + 6 failed + 12 skipped in 54.6 min, under the live editor's load. All six are + flakes (fixture EEXIST, the pulse timing tripwire, two sync-deep stamp races, a 7 s task timer, + the diarization snapshot poll); alone ×3: 18/18. No integration regression. +- **Next action: the operator re-cuts the editor + export `[Unreleased]` notes, then the rollout + per `~/reports/release-10/RUNBOOK.html`** (`make-runbook.py` beside it; the scripts in + `scripts/`). Both changelogs have a new `[Unreleased]` above the 0.9.0 cut. Export's (L1's three + hub bullets) is public on every site's `/changelog` from the next site build; the editor's holds + S4's and L2's. Cut on `/sites` → Release notes with "Commit changelog" unticked whenever the + primary's tree is dirty (it refuses one; at the 0.9.0 cut an untracked + `settings.json.pre-priority-*` made it so, and the tree was clean at this pass), then commit both + files by hand. + Then, per the runbook: + 1. restart :3001 on the new `main` (one editor restart; md5 before / pre-restart / after-boot; + smoke); + 2. optionally, rebuild and restart umtool on :3050 with `r10-umtool.sh`, for the form's brand + choice; + 3. set each site's accent and wordmark lead; + 4. preview Anilyzer; + 5. deploy the five sites by name, then the hub, then the homepage. +- **Jeralyzer already serves the brand, in Signal.** A build-deploy on the live editor built + Jeralyzer from `main` @ `386ac995` and deployed it to production (job `01M3F36N7SCKGC5JV27EBDFYPN`, + 2026-09-26 10:51–11:06, no agent recorded). That tree was the brand plus the 0.9.0 notes, before + S4/L1/L2. Its accent is unset, so it wears Signal until the runbook's step 4 (every site by name) rebuilds + it in Brass. + The same build left the primary's `export/public` as a Jeralyzer site compose (no hub `sw.js`, + `hub-sites.json` or `hub-summary.json`). +- **umtool is no longer untouched.** Its report-to-video scripts changed on disk, and the live :3050 + already spawns them (it still runs release 8's build, `a9YAe_dwhuM6DiCPzIwMD`). That is safe: a + render that does not opt in is byte-identical. Its app changed only for the new-project form's + brand choice, which appears after the optional `r10-umtool.sh` rebuild and restart. +- **Copy rulings still owed by the operator:** + - `NO_ARCHIVES_IN_SCOPE` (`export/app/ask/hubScopeCopy.ts`). The draft is "No archives selected. + Choose some on the [hub's front page] to ask.", with the bracketed words a link to `/`. It + ships as drafted unless changed. + - Whether `/ask` shows a "Searching N of M archives" scope line. +- **New lows (not started):** + - `/ask` waits forever ("Loading transcripts…") on a hub with zero archives; - the chip doesn't show a member's missing live chat (it needs a subs-only Retry); - `resolveMaybeMissingState` reads an `error` probe newer than the scan as `available` - (display only); - - umtool's rail, ledger and chart are still on Fira Sans, and a bold Plex Mono is not vendored. + (display only: the published presence badge); + - umtool's rail, ledger and chart text stays Fira Sans under the brand; + - no bold IBM Plex Mono is vendored (the HyperFrames band's `fontBold`). +- **Worktrees that can go:** `brand-mark`, `brand-themes`, `brand-media`, `r10-hub-lows` and + `r10-runner-lows` are all merged. `brand-found-line` can go once `main` carries its tip. Removing + any of them re-sorts the port blocks (`diet-series` moves up). **Live on :3001 — unchanged since 2026-09-25, 19:40:** `0213f6c8` (release 9 slice F + hub C1), -`BUILD_ID` `P0VMdKX7gbdsaiS5GvorF`; umtool untouched (`a9YAe_dwhuM6DiCPzIwMD`). Live sites: +`BUILD_ID` `P0VMdKX7gbdsaiS5GvorF`; umtool's build untouched (`a9YAe_dwhuM6DiCPzIwMD`; its +report-to-video scripts on disk are `main`'s, above). Live sites: - https://archilyzer-hub.pages.dev — C1 + C1b + C2 (archilyzer theme, "Official Instances" with the homepage's figures, scope chips, per-archive state, "N of M archives answered", archive named on every card, bare Ko-fi footer link), deploy `6ef7f472` (20:50); - https://archilyzer.pages.dev — the refresh with the copy rulings and the hub link ON (C3), deploy `e09900af` (20:51); -- the five official sites at release 8's slices Z + E (17:45 / 18:10 deploys); they carry no Ko-fi. - -**Release 10 candidates (found 2026-09-25 evening, none started; any may join release 10 before its -rollout):** `retry: false` on the hub's subs query (a member with no subs corpus is ready ~1 s late); -`/ask` on the hub honours the scope chips (`useHubScope().isOn` in `AskHub`); official-site accents -on the hub (shared `seriesColor` fallback for result stripes + chip dots, needs `hub-summary.json` — -setting the accents at rollout already fixes the cards' stripes); the hub orders its cards -alphabetically, the homepage by transcripts; `export/playwright.config.ts` must unlink -`public/sw.js` before copying (a worktree run overwrites the primary's hub SW); YouTube's soft block -"try again later" classifies `deleted`/per_video so it never backs off; the boot pass's wait on the -storage pass has no timeout; `/jobs` does not show `cancelReason`; the safeRevalidate warning is once -per bundle. Then Phase 4 slice 3 (`plans/one-core.md`), the LM chat-only tier config, the -`Dockerfile.build` image refresh. +- https://jeralyzer.pages.dev — **the brand, in Signal**, deploy `35593886` (2026-09-26 11:06, above); +- the other four official sites at release 8's slices Z + E (17:45 / 18:10 deploys); they carry no + Ko-fi. + +**The release 10 candidates of 2026-09-25 evening are all done** (L1 and L2 above). Next after +release 10's rollout: Phase 4 slice 3 (`plans/one-core.md`), the LM chat-only tier config, the +`Dockerfile.build` image refresh, and the new lows above. **The 2026-09-25 evening plan is complete** (steps A–C: release 9 F + C1 live on :3001; C1b, C2, C3 on the hub and the homepage). The operator's rulings (C2's federated search as proposed; a bare Ko-fi diff --git a/plans/brand-and-themes.md b/plans/brand-and-themes.md @@ -1549,3 +1549,7 @@ rail/ledger/chart on Fira, no bold Plex Mono yet — stand). different**. The branded fixture rebuilt (same 3,631,785-byte cut). The real assets were regenerated: every PNG and SVG byte-identical to the first run, only `INDEX.html` changed. No e2e: the one umtool app line is a `neededBy` label no spec reads. + +**Merged** to `main` 2026-09-26 as `dcb04f61` (S4, then L2, then L1), and gated with L1 and L2 on the +merged tree: [`release-10.md`](release-10.md), "Integration (S4 + L1 + L2), as merged". Its rollout step +is the optional umtool rebuild (`~/reports/release-10/scripts/r10-umtool.sh`). diff --git a/plans/release-10.md b/plans/release-10.md @@ -9,11 +9,10 @@ families retire. The plan, the design decisions and the per-slice records are [`brand-and-themes.md`](brand-and-themes.md); this file records the release as a whole. Rules: `plans/tools/implementer-rules.md`. -**The release-10 "lows" in `STATE.md` are still unstarted** (`retry: false` on the hub's subs -query, `/ask` honouring the hub's scope chips, the shared `shelfAccent` fallback, the hub's card -order, `playwright.config.ts` unlinking `public/sw.js` before its copy, the YouTube soft-block -classification, the boot pass's storage wait, `cancelReason` on `/jobs`, the safeRevalidate -warning). Any of them may join this release before it is rolled out. +**The release-10 "lows" joined the release** (2026-09-26): they shipped as slices L1 (hub) and L2 +(runner), and merged to `main` with brand S4 before the rollout, on the operator's word. Their +records and the integration pass that gated the three together are below ("Slice L2", "Slice L1", +"Integration (S4 + L1 + L2), as merged"). ## Record @@ -222,7 +221,11 @@ safeRevalidate helper. - **L2:** the editor `next build`, and the editor e2e specs for `/jobs`, boot and downloads (the full editor suite runs at integration). Unit tests for the classification (6) and the timeout (7). -**S4 — Archilyzer Media** (the YouTube channel's assets and umtool's opt-in `render.brand` preset) merges after the release-10 cut, from `brand/media`, and is **not part of the site rollout**: it touches only `common/lib` + `common/bin` and umtool; see `brand-and-themes.md`, "Slice S4, as shipped". +**S4 — Archilyzer Media** (the YouTube channel's assets and umtool's opt-in `render.brand` preset) +merges after the release-10 cut, from `brand/media`, and is **not part of the site rollout**: it +touches only `common/lib` + `common/bin` and umtool; see `brand-and-themes.md`, "Slice S4, as +shipped". (Merged 2026-09-26 as `dcb04f61`; its one rollout step is the optional umtool rebuild, +"Rollout" 2b.) ### Slice L2, as shipped — runner lows (2026-09-26) @@ -761,27 +764,215 @@ its own file, and the next seed relinks it. `ready` with no sign that its live chat is missing. A chip note with a subs-only Retry would show it. +### Integration (S4 + L1 + L2), as merged (2026-09-26) + +The operator asked for S4, L1 and L2 on `main` now, before the brand rollout, and will re-cut the +editor and export release notes before deploying. Each slice was reviewed to SHIP on its own branch; +they had never run together. The parent merged them in the planned order, and this pass gated the +combined tree, wrote the records and updated the runbook. Worktree `/home/user/Projects/brand-found-line`, +branch `brand/found-line` fast-forwarded to `main` `5c0a6ef9`, port block #1. **No code changed at +integration**: every gate below ran on `5c0a6ef9`, and the commits after it are `plans:` only. During +the pass `main` gained `4ac32a2e` (`plans/mcp-fetch-clip.md`, plans-only), and the integration commits +were rebased onto it so `main` can fast-forward. + +| merge | branch → tip | review | on `main` | +|---|---|---|---| +| **S4** Archilyzer Media | `brand/media` → `333d2826` | SHIP AFTER FIXES → re-read SHIP | `dcb04f61` | +| **L2** runner lows | `r10/runner-lows` → `14e96739` | SHIP AFTER FIXES → re-read fix `52bb00ef` | `41ddc382` | +| **L1** hub lows | `r10/hub-lows` → `b6b47ec1` | SHIP AFTER FIXES, twice (re-read `d0fa13ae`, `0fc63ed7`) | `5c0a6ef9` | + +**Conflicts resolved at merge** (`git show --remerge-diff`): `plans/release-10.md` in all three (the +record sections; every section kept, S4's line, then L2's record, then L1's), and one +`editor/CHANGELOG.md` `[Unreleased]` join in L2's merge (S4's bullet and L2's four in the one new +section). No code file conflicted. + +**Changelogs, checked as one set.** `editor/CHANGELOG.md` and `export/CHANGELOG.md` each have exactly +one `[Unreleased]`, and everything from `[0.9.0]` down is byte-identical to the 0.9.0 cut +(`31798769`; md5 of the released part `aeb7fd45…` editor, `ae97cb39…` export). The editor's five +bullets (S4's umtool brand; L2's soft block, boot wait, `cancelReason`, safeRevalidate count) and +export's three (L1's order and colour, `/ask` scope, subs) neither repeat nor contradict each other +or the code as merged (the subs bullet states the final rule: a failure after its one retry leaves +the archive searched without its live chat). No rewrite was needed. `homepage/CHANGELOG.md` is +unchanged by all three. + +**Gates**, all from the worktree root on `5c0a6ef9` (`$T/i10-gates.log`, `$T/i10-e2e.log`). +- **tsc** (`pnpm -r --no-bail --workspace-concurrency=1 exec tsc --noEmit`): clean, 0 errors, 80 s. +- **Unit and script tests:** + - common **1,954/1,954** (1,913 + S4's 10 + L1's 10 + L2's 21), 59 s; the glyph-parity test ran, + not skipped (fontTools 4.65.0 installed); + - editor unit **85/85** (79 + L2's 6); + - `test:scripts` **173 passed + 1 skip of 174** (162 + S4's 11 `brand.test.mjs`; the report-to-video + tests are in this script; the skip is the `LIVE=1` network test); + - mcp **219/219**; + - `file-schemas-docs.ts --check` clean. +- **Builds**, all ok, `export/public` seeded per path from the primary (links, no copies), `homepage/public` + copied (60 MB): + - editor 64 s (`BUILD_ID` `OjVWgLuZA1ucPntDKDx8C`); + - export site 41 s: `<html … data-accent="signal">`, theme-color `#f3f6f7` / `#0c0a08`; + - export hub 44 s: `… dark" data-base="dark" data-accent="signal"`, `out/ask/index.html` present; + - homepage 20 s: `dark data-base="dark" data-accent="signal"`; + - umtool 29 s (`pnpm --filter umtool run build`, `BUILD_ID` `BktSP58PkTab_aLIBJ1Vc`). + - Every export/homepage build: `out/icons` = the seven files; PNG magic `89504e470d0a1a0a` and IHDR + 180/192/32/512/512 (apple-touch, 192, 32, 512, maskable-512); `favicon.ico` `00 00 01 00 03 00` + (1,804 B site, 1,832 B hub/homepage); the site's `icon.svg` lit Signal `#5fa8a0` on `#0c0a08`, the + hub's and homepage's the parent mark `#151b20 #3f4c56 #e7edf1`. +- **e2e**, one detached sequence (13:04 → 14:19), every run through the machine-wide queue: + + | suite | passed | failed | skipped | time | + |---|---|---|---|---| + | export full | **204** | 0 | 0 | 9.7 min | + | `e2e:hub` | **24** | 0 | 0 | 1.1 min | + | `e2e:2origin` (`TWO_ORIGIN_REBUILD=1`, links in place, no swap) | **3** | 0 | 0 | 1.4 min (2.2 min with `build:hub`) | + | homepage full | **27** | 0 | 0 | 49.7 s | + | umtool full (`SONG_DIR=~/reports/quartering-uh-song/data`) | **175** | 2 | 45 | 5.8 min | + | **editor full** (`pnpm e2e`, 652 tests) | **634** | 6 | 12 | 54.6 min | + + The 45 umtool skips are the song-data capabilities this machine lacks (FACTS "The umtool suite skips + instead of going red…"); S4's full run had the same 175 / 2 / 45. +- **Failures, classified** (each re-run alone ×3: umtool `$T/i10-rerun.log`, editor `$T/i10-rerun2.log`): + - **umtool `mix.spec.ts:166` and `:201`: known flake, not the integration.** The pair FACTS records + as failing in every full umtool run on `main` (`FACTS.md:5013`, "`mix.spec.ts` IS + ORDER-DEPENDENT"): an earlier spec leaves a clip window in the fixture's + `channels/testchan/data/vid1/clips/`, and the row links to it (`…/clips/0.00-14.00.mp4`) instead of + `/out/clips-raw/vid1_0.00-9.00.mp4`. S4's full run failed on exactly this pair. Alone, + `--repeat-each 3`: **6 passed**, 24.4 s; the whole `mix.spec.ts` alone: **12 passed**, 23.0 s. + None of the three slices touches `umtool/app/mix`, `umtool/lib/projects/report.mjs`, `mix.spec.ts` or the fixture: in umtool's app + and lib, S4 changed only `bin/umtool.mjs` (`--brand`), `components/NewProjectMenu.tsx`, + `lib/projects/{kinds,scaffold}.mjs`, `scaffold.ts` and `lib/tools.mjs`'s doctor label (`git diff + --stat 386ac995 5c0a6ef9 -- umtool/app umtool/lib umtool/components umtool/bin`). + - **Editor: six failures, all flakes under machine load; none is the integration.** Each alone, + `--repeat-each 3`, straight after the suite (`$T/i10-e2e-editor-x3.log`): **18 passed, 0 failed, + 1.8 min**. The suite ran while the live :3001 editor was busy with its own auto-queue work (load + average 10–13 on 8 cores; 7.4 during the re-runs), and took 54.6 min against S3's 38.2. The six: + - `queues.spec.ts:144` (281 ms): `EEXIST: file already exists, mkdir + '…/test-transcripts/channels/slow-b'` in the fixture setup, before the test touched the page. + This is the fixture-reset race S3 met in `pipeline.spec.ts:164` and L2 in `channel-work.spec.ts:208`. + - `pulse.spec.ts:18` (3.6 s): the idle `/api/pulse` averaged 499.2 ms a call against its 250 ms + tripwire. The spec calls that budget "a tripwire … not a benchmark, and it runs on a shared + machine". The idle path (in-memory state plus two `stat`s) is untouched by all three slices; the + one `listJobs` change adds a field only to cancelled metas, and pulse does not list jobs. + - `sync-deep.spec.ts:256` (ENOENT reading `viddeleted1/availability.json`) and `:442` + (`lastFullSweepAt` undefined). Both read something the sync writes AFTER the `lastSyncedAt` + stamp their `runSync` helper waits on: `runYtdlp.ts:1853` `touchLastSync`, then `:1858` + `touchLastFullSweep` and `:1859` `safeBackfillAvailability`. That is a pre-existing race in the + spec's wait, which load widened. The merges change `runYtdlp.ts` by one comment (`:904-909`) and + `backfillAvailability.ts` not at all. + - `jobs-batch-tasks-drain.spec.ts:54` (24.6 s): the task row's elapsed timer read `0:06` and did + not pass it within 10 s. The fake whisper's slow task lives 7 s (`fake-whisper.mjs`, ten 700 ms + lines), so a bar that renders late under load leaves about a second before the task ends. L2's + `JobRow.tsx` change draws only on `cancelled` rows (`cancelReasonOf`), and the running task's + timer (`JobProgressBars.tsx`) is unchanged. + - `diarization.spec.ts:185` (1.3 min): the channel snapshot's `transcribedWithAudio` bucket read + `[]` for the whole 60 s poll (expected `["vidA"]`). The same poll failed in an earlier full run + (the storage-locations slice 4 worktree, job `4cc6ed24`: `["vidC"]`, left by the previous test's + batch) and passed on its re-run. `channelSnapshot.ts` is untouched by the merges, and the file's + other four tests passed, including the backfill test that drives the same cleanup. +- **The `export/public` links stayed in place, and the primary was never written.** The rules' per-path + seed (`$T/i10-seed-public.sh`): every gitignored entry of the primary's `export/public` linked into + the worktree, and no `sw.js` or compose-output copies (the workarounds L1 retired, FACTS updated). + - The primary's `export/public` had changed since L1's proof: the live editor's Jeralyzer + build-deploy (below) re-composed it at 11:03 as a SITE, so it holds `site.json` and no hub `sw.js`, + `hub-sites.json` or `hub-summary.json`. Of L1's eight files, five exist, plus + `site.json`. The worktree's stale links to the three absent ones were dropped before the seed, so + none dangled (the rules' check before every export build). + - With no primary `sw.js` to link, the worktree's `sw.js` was linked to a sentinel in the job's + scratch (`$T/i10-sentinel/sw.js`), so a write-through by the export config would change it. + - The snapshot (`$T/i10-snap.sh`): every entry of the primary's `export/public` (614 entries, 543 + files, 2.9 GB) by type, size and mtime, and the md5 of every file, plus the sentinel's md5. It was + taken before the gates, after them, before the e2e, after the export run, after `e2e:hub`, after + `e2e:2origin`, and after the editor suite: **identical every time** (tree md5 `2f7f3bb9be9d`, + content md5 `e3661fb98468`, sentinel `fc1bd566…`), and the primary still had no `sw.js`, + `hub-sites.json` or `hub-summary.json`. The five named files throughout: + + | file | size | mtime (2026-09-26) | md5 | + |---|---|---|---| + | `corpus.json` | 13,702 | 11:03:23.547761504 | `f89e603b…` | + | `llms.txt` | 4,245 | 11:03:23.574761030 | `5b6be721…` | + | `robots.txt` | 125 | 11:03:23.574761030 | `17b7cc13…` | + | `sitemap.xml` | 352 | 11:03:23.575761012 | `4bd0cd6b…` | + | `_headers` | 736 | 11:03:23.513762100 | `302b4216…` | + | `site.json` | 5,858 | 11:03:23.541761609 | `9394b81b…` | + | `sw.js`, `hub-sites.json`, `hub-summary.json` | absent | | | + + - **What the runs did in the worktree:** the export suite replaced the `sw.js` LINK with a plain + 11,172 B file whose md5 equals `service-worker/site-sw.js` (`15b4689b…`), and the sentinel kept its + md5 — `playwright.config.ts:54`'s `rmSync` removed the link. `e2e:2origin`'s `build:hub` replaced + the `corpus.json`, `llms.txt`, `robots.txt` and `_headers` LINKS with the worktree's own plain + files (468 / 494 / 76 / 459 B), wrote a plain `hub-sites.json` (2 B, `[]`) where none existed, + removed the `site.json` link and left `sitemap.xml` (which it does not write) a link. The next + seed relinked them for the homepage and later suites. +- **The live processes were never touched:** :3001 still serves `BUILD_ID` `P0VMdKX7gbdsaiS5GvorF` and + :3050 `a9YAe_dwhuM6DiCPzIwMD`; nothing was deployed, pushed, restarted or written under + `transcripts/`. +- Numbers tools: none. + +**Found during the pass.** +- **Jeralyzer is already on the brand, in Signal.** Job `01M3F36N7SCKGC5JV27EBDFYPN` (`build-deploy`, + queue `deploy`, no agent recorded) ran on the live :3001 editor 2026-09-26 10:51–11:06. It built + Jeralyzer from the primary's working tree, then `main` @ `386ac995` (the brand plus the 0.9.0 cut, + before S4/L1/L2), and deployed it to production (`https://35593886.jeralyzer.pages.dev`). The old + editor runs the on-disk build scripts, so the site got the brand, but its `site.json` has no + `accent` (the pre-brand editor cannot set one), so it wears Signal. `jeralyzer.pages.dev` serves + `data-accent="signal"`; the other four sites, the hub and the homepage are pre-brand. The runbook + now says so. The sites step (the runbook's 4, "Rollout" 5 below) rebuilds Jeralyzer in Brass, + and its readers' stored themes have already migrated. +- **umtool is not "untouched" any more.** The live :3050 already spawns `main`'s report-to-video + scripts from disk. That is safe (a render that does not opt in is byte-identical), and the form's + brand choice needs a rebuild. The runbook adds an optional step for it (`r10-umtool.sh`). + +**Runbook** (`~/reports/release-10/make-runbook.py`, regenerated `RUNBOOK.html`): +- `FINAL` is this pass's tip, and every script's ancestor guard checks it. +- It says what the rollout contains: the brand, then S4, L1 and L2, in plain words. +- Step 0 is a **re-cut**: both `[Unreleased]` sections are shown, since export's is public. The editor + cut, the hand commit of both files and the untracked-file caveat are unchanged. +- The new **step 1b** is an OPTIONAL `r10-umtool.sh`: fail-stop, with the ancestor guard, and it + refuses while a umtool job runs. It builds into the live `umtool/.next` and never restarts after a + failed build. Then one restart on :3050 and a smoke: `/` and `/api/jobs` 200, the form offers + "Archilyzer Media", no `⨯` in the start log. `r10-rollback-umtool.sh` is its rollback twin. +- It adds what readers and the operator will notice. +- The YouTube assets point to `~/reports/archilyzer-media/brand/INDEX.html`. +- It adds these gates and the link-safety proof. +- The copy rulings and new lows are listed. +- `bash -n` and `sh -n` pass on all nine scripts. No script was run. + +| sha | what | +|---|---| +| `9e3047e3` | `plans:` FACTS: the two worktree workarounds superseded (L1), and the release 10 facts for S4, L1 and L2 | +| _this_ | `plans:` this record, STATE ("Merged to main (2026-09-26), NOT rolled out"), the Rollout steps | + ## Rollout -Nothing is rolled out. The live :3001 editor still runs `0213f6c8` (the pre-brand build); the five -official sites are at release 8's Z + E; the hub and homepage at release 9's C1b/C2/C3. The -operator's runbook is `~/reports/release-10/RUNBOOK.html` (generated by `make-runbook.py` beside it, -with the rollout scripts in `scripts/`). The steps: - -0. **Check the primary contains the brand's final commit** (this release's `plans:` review-fix - commit): `git -C /home/user/Projects/yt-dlp-transcript-browser merge-base --is-ancestor <final> - HEAD`. The runbook names the sha, and every rollout script refuses to run without it. -1. **Cut the export release notes first.** `export/CHANGELOG.md`'s `[Unreleased]` is rendered on - every site's public `/changelog` until it is cut: `/sites` → Release notes → Cut release (the - form suggests `0.8.8`). With "Commit changelog" ticked the form refuses a dirty tree, and the - primary has an untracked `settings.json.pre-priority-*`, so untick it and commit the changelog by - hand. The - editor's own notes (`/changelog`) can be cut the same way; they are not public. +Nothing is rolled out, except that **Jeralyzer is already on the brand, in Signal** (a build-deploy +on the live editor, 2026-09-26 10:51–11:06; "Integration (S4 + L1 + L2), as merged", above). The +live :3001 editor still runs `0213f6c8` (the pre-brand build); the other four official sites are at +release 8's Z + E; the hub and homepage at release 9's C1b/C2/C3. The operator's runbook is +`~/reports/release-10/RUNBOOK.html` (generated by `make-runbook.py` beside it, with the rollout +scripts in `scripts/`). The steps: + +0. **Check the primary contains release 10's final commit** (the integration pass's `plans:` + record, on top of the brand, S4, L2 and L1; it was the brand's S3 review-fix commit before): + `git -C /home/user/Projects/yt-dlp-transcript-browser merge-base --is-ancestor <final> HEAD`. The + runbook names the sha, and every rollout script refuses to run without it. +1. **Re-cut the release notes first.** Editor and export 0.9.0 were cut for the brand (2026-09-26 + 01:37); S4, L1 and L2 then added a new `[Unreleased]` to both (export: L1's three hub bullets; + editor: S4's and L2's). `export/CHANGELOG.md`'s `[Unreleased]` is rendered on every site's public + `/changelog` until it is cut: `/sites` → Release notes → Cut release (the form suggests + `0.9.1`). With "Commit changelog" ticked the form refuses a dirty tree; the primary had an + untracked `settings.json.pre-priority-*` at the 0.9.0 cut (its tree was clean at the integration + pass), so untick it whenever the tree is dirty and commit the changelog by hand. The + editor's own notes (`/changelog`) can be cut the same way; they are not public. Commit both files + in one commit. 2. **Restart the live :3001 editor on the new `main`** (release 9's procedure): check `/jobs` for an - operator-started job; md5 `before`; the editor build into the live `.next` (umtool untouched, not - rebuilt or restarted); md5 `pre-restart`; ONE editor restart; md5 `after-boot` — the three must - match; the smoke (`SMOKE_FAIL=0`, or every flag explained). The editor itself changes look: the - parent mark and a favicon, Archivo/Plex, and the operator's stored theme migrates once. + operator-started job; md5 `before`; the editor build into the live `.next` (umtool is not + rebuilt or restarted in this step; see 2b); md5 `pre-restart`; ONE editor restart; md5 + `after-boot` — the three must match; the smoke (`SMOKE_FAIL=0`, or every flag explained). The + editor itself changes look: the parent mark and a favicon, Archivo/Plex, and the operator's + stored theme migrates once. + - **2b. Optional: rebuild and restart umtool on :3050** (`r10-umtool.sh`). Only for the + new-project form's brand choice (S4). The live :3050 already spawns `main`'s report-to-video + scripts from disk, which is safe because a render that does not opt in is byte-identical. The + script refuses while a umtool job runs, never restarts after a failed build, restarts once, and + checks that `/` offers "Archilyzer Media". 3. **Set each site's accent and wordmark lead** in the site form (`/sites/<id>`, the one writer; never hand-edit `transcripts/`): @@ -814,4 +1005,12 @@ with the rollout scripts in `scripts/`). The steps: **What readers will notice:** a stored theme migrates once (light stays light, Archive light becomes Sepia, dark stays dark, system stays system; the family is dropped). After the service-worker update an installed app opens offline only after one more online visit (`shell-v2` drops the old shell); -offline channel downloads are kept. +offline channel downloads are kept. From L1 (on the hub): the official instances are listed in +the homepage's order, each in one colour everywhere; `/ask` follows the scope chips and, with every +archive off, is disabled with one line saying why; an archive whose live chat fails is still searched +(without its live chat, its chip ready). + +**What the operator will notice:** a YouTube soft block ("…isn't available, try again later") now +pauses the platform like a 429 (the batch stops, the runner defers the video 6 h, a scan stops, +the availability check stops) instead of excluding the video as deleted; cleanup keeps the audio of +every video its confirmation check did not reach; `/jobs` says why a job was cancelled at boot.