Archilyzer · Source

archilyzer

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

commit edb870090027d8bb9da3f7352281768e37117ce5
parent 0a6ca1ddf93fc94fef4a059d9d7e593b8f428331
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 15:13:32 -0400

Merge r12/source-mirror (release 12 records) — the rollout checklist, STATE and FACTS for the source mirror, and AGENTS.md's section on it; merged, not deployed

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

Diffstat:
MAGENTS.md | 20++++++++++++++++++++
Mplans/FACTS.md | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mplans/STATE.md | 37+++++++++++++++++++++++++++++++++++++
Mplans/release-12.md | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 353 insertions(+), 0 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md @@ -339,6 +339,26 @@ The editor's `instrumentation.ts` arms the runners on boot, which resumes long-r sweeps against production data. To exercise `common/` controllers over the real corpus, run them offline with `tsx` instead of starting a server. +# The source mirror + +`archilyzer source publish` (`common/publish/source.ts`), which `archilyzer build homepage` and +the `/sites` Homepage jobs run, puts this repo on the project site read-only: +- a fresh clone of `main`, scrubbed by git-filter-repo; +- audited against a denylist, every object and every file; +- published as a dumb-HTTP mirror at `/source/archilyzer.git/`, a raw tree and a tarball. + +**A refusal withdraws the previous publish** from `public/` and `out/`, and `deploy homepage` +refuses a source it cannot vouch for. +- **The operator's two files live OUTSIDE the repo** (`~/.config/archilyzer/source-scrub.txt`, + `source-denylist.txt`). **Never print, cat, quote, log or commit them** — they hold the private + strings the gate keeps off the site. Code reads them; you may count lines or check a mode. +- **Never bypass the gate.** No denylist or scrub file of your own, no hand-edited + `homepage/.source-publish.json`. A refusal is fixed by an operator scrub rule, or by removing the + text from history. +- **Never publish a path segment named `.git`:** wrangler's upload drops it silently. + +Everything else is in [PUBLISH.md](PUBLISH.md), "The source mirror (homepage)". + # Roadmap Long-running work on the local-AI derived corpus is tracked in [PLAN.md](PLAN.md). diff --git a/plans/FACTS.md b/plans/FACTS.md @@ -153,6 +153,11 @@ THROWS at declaration — module load — on a name `SUB_FILE_RE` matches; Never name the curated field `tags`. Never assume a `tags.json` is the keyword list: `transcripts/tags.json` and `sites/<id>/tags.json` are curated tags. +**Never publish a path segment named `.git`.** wrangler's Pages upload drops `**/.git` (and +`**/node_modules`) SILENTLY, and Cloudflare's managed rules block `/.git/` requests. The source +mirror is `/source/archilyzer.git/` for that reason (release 12, below). A mirror named `.git` would +deploy "successfully" and 404. + --- ## Reusable helpers (do not rewrite these) @@ -7168,3 +7173,147 @@ out. O3's facts are the section just above ("O3 — runner lows"). Anchors are a byte-identical after every run): the export suite replaces the `sw.js` link with its own file; `e2e:2origin` (`compose hub`, twice) replaces `sw.js`, `hub-sites.json`, `corpus.json`, `llms.txt`, `robots.txt` and `_headers`. `e2e:hub` writes none. Re-seed before the next export run. + +## Release 12 — the source mirror (verified 2026-09-28, `main` @ `ffdeb2cd`) + +Slices Q (`4855f70b`) and R (`ffdeb2cd`): [`release-12.md`](release-12.md), the plan +[`source-mirror.md`](source-mirror.md), the operator-facing doc `PUBLISH.md` "The source mirror +(homepage)". Anchors are at `ffdeb2cd`. + +### The step (`common/publish/source.ts`) + +- **`publishSource`** (`:611`) → `publish` (`:647`) runs these steps in order: + 1. The git COMMON dir's `refs/heads/main`: a worktree build mirrors the primary's main. No + repository at all (`commonDir` `:543`) says `NO_REPOSITORY` (`:510`). + 2. The operator files (`loadSourceRules` `:216`). + 3. The tools: `resolveFilterRepo` `:321` and `gitleaksIdentity` `:483`. + 4. The skip. + 5. A `--no-local --bare --single-branch --no-tags` clone into + `mkdtemp(ARCHILYZER_SOURCE_SCRATCH/archilyzer-source-)`. The scratch root is refused inside the + checkout or the public dir (`scratchRootProblem` `:582`). + 6. filter-repo, then `repack -a -d --max-pack-size=20m`, `prune-packed`, `pack-refs`, + `update-server-info`. + 7. The object audit. + 8. The tree and the tarball. + 9. The allowlisted stage. + 10. The file audit. + 11. The limits: 15,000 files, 24 MiB a file. + 12. The link-safe install: the manifest removed first and written LAST. + + `buildHomepage` (`build.ts:991`) runs it between compose and `next build`, with `noRepository: + "empty"`. So `archilyzer build homepage`, `/sites` Build homepage and `pnpm ops build-homepage` + all do. +- **A refusal withdraws the source.** + - Once the rules are loaded, any non-zero outcome runs `removePublishedSource` (`:520`). `--check` + writes nothing, this included. + - `buildHomepage` then removes `out/source` and the two download files (`withdrawBuiltSource`, + `build.ts:1026`). `out/source/index.html`, the `/source` PAGE, goes with them. +- **The deploy key.** `homepage/.source-publish.json` sits beside `public/`, NEVER inside it (a + published rules hash would confirm a guess at the denylist). It holds `sourceCommit`, + `mirrorHead`, `rulesHash`, `filterRepo`, `gitleaks` and `contentDigest`: + - `rulesHash` is `rulesHashOf(scrub lines, literals, SOURCE_STEP_VERSION)` (`:243`). + **`SOURCE_STEP_VERSION` (`:86`, now 3) must be bumped whenever the scrub or the audit + changes**, so an unchanged main is re-published and an old `out/` refuses to deploy. + - `gitleaks` is the version line plus the sha256 of the binary. This machine's gitleaks prints + `version is set by build process` for every release. + - `contentDigest` is `sourceDigest` (`:447`): the sorted path, size and streamed sha256 of every + published file — `source/archilyzer.git/**`, `source/tree/**`, `source/manifest.json`, the + tarball, `snapshot.json`. It takes about 0.5 s over 2,459 files. +- **`publishedSourceProblem`** (`:985`), asked by `deployHomepage` (`build.ts:1079`) before every + deploy, preview included: + - no `/source` page in `out/` refuses: a refused build, or one from before release 12; + - the page with no artefacts beside it is a `--no-source` build, and deploys; + - otherwise it binds: a valid manifest, a complete state, `rulesHash` = today's, `mirrorHead` = + `out`'s, main = the state's and the manifest's, the tarball's sha256, the gitleaks identity, and + the content digest. + + A hand-written state file is the only way past it, and the file is the operator's own record. +- **The report never prints a literal or an object's bytes.** + - A literal is `denylist line N (len L)`, `scrub line N lhs (len L)` or `built-in home rule (len + L)`. + - A hit is its kind, object id, the blob's path in history, the byte offset and a commit/tag + field (`objectField`, `sourceAudit.ts:229`). + - Every refusal message, and every path it prints, goes through `maskLiterals` + (`sourceAudit.ts:144`). + - A literal spanning path components (`a/b`) is invisible to the object walk, which reads tree + entry names one at a time. The staged-path sweep catches it. +- **The operator files** are `${ARCHILYZER_CONFIG_DIR:-~/.config/archilyzer}/source-{scrub,denylist}.txt`, + read through `getPaths()` (`sourceScrubFile`, `sourceDenylistFile`). The two readers are + `operatorLines` (`sourceAudit.ts:72`) and `parseScrubRules` (`source.ts:161`): + - they drop a BOM and CRLF; + - the home dir loses a trailing `/`; + - an empty left side refuses; + - every literal left side is denied too — its exact bytes; a new spelling is caught only by the + denylist. + +### git-filter-repo (2.47.0, pipx `~/.local/bin`) + +- **`--replace-text` has no comments.** `get_replace_text` treats a `#` line as a literal to replace + with `***REMOVED***`. The step writes `replace.txt` without comments or blank lines. + `--replace-message` reads the same syntax. Lines split at the LAST `==>`, then + `regex:`/`glob:`/`literal:`. +- **`git filter-repo --version` prints a hash (`a40bce548d2c`), not `2.47.0`.** + `commit-map`/`ref-map` under `<repo>/filter-repo/` hold the PRIVATE ids, and are deleted before + staging. The default `--replace-refs` is `update-no-add`; the step passes `delete-no-add`. +- **A blob with a NUL in its first 8 KiB is never scrubbed** (`_tweak_blob`): a binary is audited, + never scrubbed. Compressed content (a zip member, PNG text chunks, a PDF stream) is opaque to the + byte search. At release 12 every such blob in history was decompressed by the reviewer: 0 hits. +- **Deterministic:** the same main, rules and filter-repo gave the same `mirrorHead` on every run + (`20c367613f75` for main `e56101fdee5d`). Pack BYTES differ run to run, which is why the digest is + taken per publish. + +### git's dumb HTTP, and Cloudflare Pages + +- **The published file set** is `HEAD`, `packed-refs`, a LOOSE `refs/heads/main`, `info/refs`, + `objects/info/packs` and `objects/pack/pack-*.{pack,idx}`, from an allowlist: never `config` + (the clone's origin path), `hooks/`, `description`, `logs/`, `filter-repo/`, `*.rev` (git 2.55 + writes them by default) or `*.bitmap`. +- **The loose ref is load-bearing.** git treats a directory as a repository only if it has a + `refs/` directory, so a `file://` clone or `source audit` of the published dir fails without it. + An empty `refs/` would not survive a deploy. +- **The `?service=git-upload-pack` probe falls back to dumb** when the server returns plain + `info/refs`. Verified against `python3 -m http.server`. The live Pages proof is the rollout's + preview. +- **`_headers`** (wrangler 4.88 `attachHeaders`, re-read in 4.142 by the review): + - EVERY matching rule applies, in file order. A header a LATER rule sets again is **APPENDED** + (`text/plain; charset=utf-8, text/html; charset=utf-8`), so an override must detach it first + with `! Content-Type`. + - A splat is `(?<splat>.*)` matched against the ENCODED pathname. A rule with two `*` compiles to + duplicate group names and is dropped silently; wrangler's parser also refuses it. + - The limits are 100 rules and 2,000 characters a line. Only the ROOT `_headers` is read. + - `homepage/app/lib/headers.test.ts` holds a replica and pins the source-tree rules. +- **Pages answers a missing path with the NEAREST `404.html`**, walking up, with the REQUEST path's + headers. So a tracked `404.html` in the raw tree would run as HTML on the origin, and the tree + step refuses one (`sourceTree.ts:142`), as it refuses a tracked `index.html` or a symlink. +- **A Pages PREVIEW is a public publication, and every deployment stays reachable at + `<hash>.<project>.pages.dev` until that deployment is DELETED.** A newer deploy does not remove + an older one. A preview branch name is guessable (`source`, named in the mirrored plans). +- **`next dev` serves `public/` but not a directory's `index.html` at `/<dir>/`,** and ignores + `_headers`. A static export always writes the `/source` page into `out/source/index.html`, so + `out/source` exists in every build, `--no-source` included. + +### Tailwind, tsc, eslint and docker must not read the mirror + +- `/homepage/public/source` and `homepage/.source-publish.json` are gitignored, because Tailwind v4 + scans every file `.gitignore` does not exclude, and a binary pack yields "class names" that break + the stylesheet. +- `homepage/tsconfig.json` excludes **`public` AND `out`**. `next build` copies `public/` into + `out/`, and the SECOND build with a mirror failed its type check on + `out/source/tree/common/jobs/registry.ts`: a duplicate `declare global var __yttJobRegistry__`. +- `homepage/eslint.config.mjs` ignores `public/source/**`, and `.dockerignore` excludes both paths. + +### Measured (2026-09-28, the real repo) + +- **`main` `e56101fdee5d` publishes:** + - 1,703 commits and 21,447 objects; + - 2,459 staged files, 69–71 MB; + - 2 packs (about 21 and 16 MB); + - 2,035 tree files in 412 directories; + - a tarball of about 7.2 MB. +- **`homepage/out`:** 2,640 files, about 78 MB. The largest file is 19.99 MiB, against the step's + 24 MiB limit and Pages' 25 MiB. +- **Time:** the step adds about 19 s to `build homepage` (filter-repo about 5 s, gitleaks about 7 s). + An unchanged main, rules, tools and files skip it. The deploy check takes 0.6–0.8 s. +- **The live :3001 editor runs its BUILT bundle.** Until it is rebuilt on a tree with release 12, + its `/sites` Homepage jobs have no source step, no withdrawal and no deploy check. + diff --git a/plans/STATE.md b/plans/STATE.md @@ -3,6 +3,43 @@ 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-28, evening): release 12 — the source mirror — is merged to `main` and NOT rolled +out.** [`release-12.md`](release-12.md) holds Q's and R's records, their reviews, "Merged" and +"Rollout". The operator's runbook is `~/reports/release-12/RUNBOOK.html`, with its scripts in +`~/reports/release-12/scripts/`. The plan is [`source-mirror.md`](source-mirror.md). +- **What merged:** + - **Q** (`4855f70b`, and the changelog fix `e6c5d2e3`) fixes the hardcoded umtool paths. + - **R** (`ffdeb2cd`) adds `archilyzer source publish`: + - a fresh bare clone of `main` is rewritten by git-filter-repo with the operator's scrub rules, + then repacked for git's dumb HTTP; + - an audit gate refuses a denied literal anywhere; + - the raw tree at `/source/tree/` and the tarball are published beside the mirror, and the + `/source/` page shows them; + - a refusal withdraws the source from `public/` and `out/`; + - `deployHomepage` refuses any `out/` it cannot vouch for. +- **The operator's side is prepared:** + - `~/.config/archilyzer/` holds a scrub file (3 rules) and a denylist (3 literals: the user name, + the host name, an email address). NEVER print them; + - `git-filter-repo` 2.47.0 is installed with pipx; + - `source publish --check` exits 0. With `main` at `ffdeb2cd` it would publish `8188e02a7d04`: + 2,473 files, 69.8 MB. The parent's first check, on `e56101fdee5d`, gave `20c367613f75`. +- **Owed, in order** (release-12.md "Rollout"): + 0. The operator completes the denylist (real name, handles), then runs `source publish --check`. + **No deploy of any kind before this: a Pages preview is public and permanent until it is + deleted.** + 1. The song link, before any umtool restart. + 2. Rebuild and restart :3001 with `~/.local/bin` on PATH. It runs 0.10.0 (`BUILD_ID` + `vWCJb87ktCy5akih_pM9X`), which has no source step, no withdrawal and no deploy check. + 3. A FRESH `archilyzer build homepage` in the primary. The current `out/` predates `/source`, so + the deploy check refuses it. + 4. The preview `--preview source` and its live checks. + 5. Production. + 6–7. What to do if the edge refuses the clone, and if anything private ever ships: delete that + deployment. + 8. The cut (`release cut editor …`: 2 bullets; export has none) and the worktrees. +- **Baselines now:** common **2,149**, homepage unit **7**, homepage e2e **36**; editor unit 85, + `test:scripts` 185 + 1 and mcp 269 are unchanged. + **Now (2026-09-28, afternoon): release 11 is LIVE as 0.10.0, and Jasolyzer is launched.** The rollout ran 12:11–14:05 ([`release-11.md`](release-11.md), "Rollout, as done", every deploy and job id): the cut (editor `24c8352e`, export `bf6904e8`), ONE :3001 restart (`BUILD_ID` diff --git a/plans/release-12.md b/plans/release-12.md @@ -775,3 +775,150 @@ accepted as built, and that the four new Lows be closed before the merge: - Nothing was deployed. `main` had not moved. ## Rollout + +**Merged** (by the parent, in the primary, `git merge --no-ff` on a clean tree): +- **Slice Q** merged as `4855f70b`, then the changelog fix `e6c5d2e3`. The 0.10.0 cut landed between + Q's branch point and its merge. A clean textual merge filed Q's bullet inside the released + `[0.10.0]` section, and `e6c5d2e3` moved it back under `[Unreleased]`. +- **Slice R** merged as `ffdeb2cd`. The tree is identical to R's tip `484952ed`. +- **The parent then prepared the operator's side:** + - it created `~/.config/archilyzer/` (mode 700) with the two files (mode 600): the scrub file + holds **3 rules**, the denylist **3 literals** — the Unix user name, the host name and one email + address. The contents are never printed; + - it installed `git-filter-repo` 2.47.0 with pipx (`~/.local/bin`); + - it ran `pnpm archilyzer source publish --check`: **exit 0**, it would publish main + `e56101fdee5d` as `20c367613f75`, with 2,459 files, 69.3 MB, 2 packs, 412 tree dirs and a + 6.9 MB tarball. + - The runbook's `r12-check.sh`, run in the primary while this record was written with `main` at + `ffdeb2cd`, also exits **0**. It would publish `ffdeb2cd770e` as `8188e02a7d04`, with 2,473 + files, 69.8 MB, 2 packs, 413 tree dirs and a 7.0 MB tarball; its log holds 0 user-name and 0 + host-name occurrences. +- **Nothing is rolled out.** Nothing was deployed. The live :3001 editor runs 0.10.0 (`BUILD_ID` + `vWCJb87ktCy5akih_pM9X`, built on `e6c5d2e3`): it has no source step, no withdrawal and no deploy + check. The primary's `homepage/out` predates release 12 (it has no `/source` page), so the deploy + check refuses it until it is rebuilt. +- **A side effect of the scrub, cosmetic and in the mirror only:** the bare user name is scrubbed to + `user`. The `plans/` text in the mirror (the grep gates, one risk sentence) therefore reads + differently from the private repository. + +**What is OWED, in order.** The operator's runbook is `~/reports/release-12/RUNBOOK.html`, rendered +by `~/reports/release-12/make-runbook.py`. Its scripts are in `~/reports/release-12/scripts/` and +log to `~/reports/release-12/tmp/`. Every script refuses unless the primary's `HEAD` contains +`ffdeb2cd`. + +**Before ANY deploy, a preview included, the denylist must hold everything private.** A Pages +preview is public, and every deployment stays reachable at its own `<hash>.archilyzer.pages.dev` +until it is deleted. + +0. **The operator completes the denylist**, then runs the check. Add your real name, other handles + and anything else that must never appear to `~/.config/archilyzer/source-denylist.txt`: one per + line, `i:` for any case. Then: + ``` + cd ~/Projects/yt-dlp-transcript-browser && pnpm archilyzer source publish --check + ``` + (or `sh ~/reports/release-12/scripts/r12-check.sh`, which also counts user-name occurrences in its + log: expect 0). + - **Expect:** `[source] audit clean: …` and `[source] check passed — would publish main <12 hex> + as <12 hex>: 2459 files …; nothing written`. + - **If it refuses:** the report names the source only by position (`denylist line N (len L)`) and + each hit only by object, field and byte offset. Add a scrub rule to + `~/.config/archilyzer/source-scrub.txt` (`<text>==>user`), or drop the file from history. Then + re-run. +1. **The song link, before any umtool restart** (slice Q's operator step, with the review's I1 + correction): + ``` + mkdir -p ~/.local/share/archilyzer && ln -s ~/.claude/jobs/efbe67a7/tmp/song ~/.local/share/archilyzer/song + ``` + - The target holds only umtool's rebuildable `.cache/umtool`. The song project's bulk data is in + `~/reports/quartering-uh-song/data`; pointing the link there instead is a separate choice. + - `~/.local/share/archilyzer` did not exist on 2026-09-28. If a restarted :3050 created + `…/song/.cache` as a real directory first, remove that directory before linking, or the link + lands inside it. +2. **Rebuild and restart the live editor, with `~/.local/bin` on its PATH.** The precedent is + release 11's `r11-build.sh` + `r11-restart.sh` in `~/reports/overnight-2026-09-28/scripts/`. + Release 12's copies are `r12-build.sh` and `r12-restart.sh`: + - `r12-build.sh` builds into the live `.next`. Run the restart right after it. + - `r12-restart.sh` refuses while `BUILD_ID` is still `vWCJb87ktCy5akih_pM9X`. It starts the + editor with `PATH=$HOME/.local/bin:$PATH` and checks that the new server's environment has it. + Without it, `/sites` Build homepage falls back to `pipx run`, which needs the network. + - Run the md5 sweep around the restart, and the smoke after it. `r12-md5.sh` and `r12-smoke.sh` + wrap `plans/tools/rollout/md5.sh` and `smoke.sh` with `CLAUDE_JOB_DIR=~/reports/release-12 + REL=r12`: + ``` + sh ~/reports/release-12/scripts/r12-md5.sh before + sh ~/reports/release-12/scripts/r12-build.sh + sh ~/reports/release-12/scripts/r12-md5.sh pre-restart + sh ~/reports/release-12/scripts/r12-restart.sh + sh ~/reports/release-12/scripts/r12-md5.sh after-boot + sh ~/reports/release-12/scripts/r12-smoke.sh + cd ~/Projects/yt-dlp-transcript-browser && pnpm archilyzer doctor + ``` + - **Expect:** `BUILD_OK`, then `RESTART_DONE editor / 200`, `/sites` carries release 12's + sentence ("also publishes the source mirror") and the editor's PATH has `.local/bin`. `r12-md5.sh after-boot` ends `MD5_SAME`, and + the smoke ends `SMOKE_FAIL=0`. A `PAIR_DIFF` on a pair that moves live (auto-queue status) is + drift, as it was at release 11. + - **Doctor** has a **source publish** block: + - `filter-repo git filter-repo a40bce548d2c`; + - `gitleaks` ok; + - `scrub rules … (3 rules, mode 600)` and `denylist … (N literals, mode 600)`; + - `published` says nothing is published in the primary yet. +3. **A FRESH homepage build in the primary.** The deploy check refuses any `out/` built before + release 12, because it has no `/source` page. + ``` + sh ~/reports/release-12/scripts/r12-home-build.sh + ``` + - It runs `pnpm archilyzer build homepage`, then checks + `homepage/out/source/archilyzer.git/info/refs`, the file count and the deploy check, read-only. + - **Expect:** `[source] published main … as …: 2459 files` (about 19 s for the step), `out: ~2,640 + files`, `info/refs: <40 hex>\trefs/heads/main`, and `deploy check: ok (would deploy)`. + - **If the build refuses:** it has already WITHDRAWN the source from `public/` and `out/`. Fix the + rule (step 0) and rebuild. +4. **The preview** (`source.archilyzer.pages.dev`; public): + ``` + sh ~/reports/release-12/scripts/r12-preview.sh + sh ~/reports/release-12/scripts/r12-live-check.sh https://source.archilyzer.pages.dev + ``` + - The first script runs `pnpm archilyzer deploy homepage --preview source`, which asks the deploy + check first. Its log ends `[preview] https://source.archilyzer.pages.dev (this deployment: + https://<hash>.archilyzer.pages.dev)`. + - The live check is `source-mirror.md` Rollout step 2, as commands. Each line prints OK or FAIL: + - `git clone https://source.archilyzer.pages.dev/source/archilyzer.git` works; + - the clone's HEAD = `manifest.json`'s `mirrorHead`; + - `…/source/tree/common/lib/paths.ts` is `content-type: text/plain; charset=utf-8`, ONE value, + with `x-content-type-options: nosniff`; + - `…/source/tree/common/` is `text/html; charset=utf-8`, ONE value. The appended form + `text/plain…, text/html…` is the bug `f218ed86` fixed; + - `…/source/tree/umtool/report-to-video/fonts/Archivo%5Bwdth%2Cwght%5D.ttf` is 200 `font/ttf`; + - `…/source/tree/homepage/app/docs/%5Bslug%5D/page.tsx` is 200 `text/plain; charset=utf-8`; + - the tarball's sha256 = `snapshot.json` = `manifest.json` = the one on `/source/`; + - `pnpm archilyzer source audit <clone>/.git` is clean; + - user-name and host-name counts in the clone's history are 0. +5. **Production:** + ``` + sh ~/reports/release-12/scripts/r12-prod.sh + sh ~/reports/release-12/scripts/r12-live-check.sh https://archilyzer.pages.dev + ``` + - The first script runs `pnpm archilyzer deploy homepage`: branch `main`, the log ends + `[deployed] https://<hash>.archilyzer.pages.dev`. + - Or use the editor's path, which also proves the step inside its job: `pnpm ops build-homepage + --json '{"deploy":true}' --wait` with `WORKER_TOKEN` from `editor/.env`. + - The same checks must pass on `archilyzer.pages.dev`. +6. **If the edge refuses the dumb clone** (`source-mirror.md` Rollout step 4): the tree and the + tarball still stand. The mirror would need another host (R2 behind a custom domain, out of scope). + Record it, do not improvise. +7. **If something private ever ships:** + - DELETE THAT DEPLOYMENT in the Cloudflare dashboard (Workers & Pages → `archilyzer` → + Deployments). A newer deploy does not remove it; for a preview, delete every deployment on + that branch. + - Then add the literal (and a scrub rule) and run `pnpm archilyzer build homepage`, which refuses + and withdraws. Rebuild clean, and deploy again. +8. **Housekeeping:** + - `pnpm archilyzer release show` has 2 editor bullets pending; export has none, so `all` would + refuse. When the operator chooses: `pnpm archilyzer release cut editor next --commit` (0.10.1) + or `next-minor` (0.11.0). + - Remove the worktrees when done: `pnpm wt rm r12-paths-fix` and `pnpm wt rm r12-source-mirror`, + from the primary. Removing them re-sorts the index-based port blocks, so do it only when no + dev server or e2e runs in any worktree; the parallel session's `r13-*` worktrees are active. + The seven `r11-*` wait on these. + - Optional: `git branch -d r12/paths-fix r12/source-mirror`. +