Archilyzer · Source

archilyzer

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

commit ef05a179874acdf2d101d1ffc346e56fc2d42ffb
parent f20c1af2ee3bde3ab42cf24272d32df55fed3191
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 26 Sep 2026 04:02:34 -0400

plans: release 10 slice L1 review fixes — /ask with every archive off, compose never writes through a link (proved: e2e:2origin with the links in place left the primary's eight files byte-identical), subs 404 = empty + real errors fail with Retry, networkMode always

Gates on f20c1af2:
- tsc clean.
- Unit tests: common 1,923, editor unit 79, scripts 162 + 1 skip, mcp 219.
- Builds ok: editor, export site, export hub, homepage.
- e2e: export 204, hub 24, 2origin 3 (no swap), homepage 27.
- Both new tests are red on the pre-fix source.

Also records the sw.js and compose-output worktree workarounds as retired
at merge (FACTS is left to the merger).

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

Diffstat:
Mplans/release-10.md | 127++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 123 insertions(+), 4 deletions(-)

diff --git a/plans/release-10.md b/plans/release-10.md @@ -228,7 +228,8 @@ Branch `r10/hub-lows` off `main` `5dfc9c3a`, worktree `/home/user/Projects/r10-h block #6). All five items are done. Item 4 follows the homepage: the code gave no reason to keep alphabetical (below). -1. **`retry: false` on the federated subs manifest** (`common/components/SearchDataContext.tsx`, +1. **`retry: false` on the federated subs manifest** (superseded by review fix 4 below: a 404 is an + empty manifest, and a real error is retried once) (`common/components/SearchDataContext.tsx`, the `subsQueries` of `MultiSiteDataProvider`). Readiness waits for the subs query to settle. A member with no live chat answers 404, and the client default (`retry: 1`, `QueryProvider.tsx`) held its chip at `loading` for one more second. The single-site `useSubsManifest("")` shares the @@ -319,7 +320,8 @@ alphabetical (below). and `hub-summary.json` are unchanged on disk: the order is applied in the browser. **Found and left** -- **The `/ask` composer reads ready before the hub's list loads** (pre-existing). With no archives +- **The `/ask` composer reads ready before the hub's list loads** (pre-existing; CLOSED by review + fix 1 below: an empty scope is never ready on `/ask`). With no archives listed yet, the provider has nothing in scope, so it counts as settled and `summariesReady` is true for that instant. A question sent then would ground in nothing. `ask.spec` relies on the empty-hub case being ready. The window used to end when `hub-sites.json` arrived. It now ends @@ -335,13 +337,130 @@ alphabetical (below). same order. - **FACTS is stale after merge:** "Replace `export/public/sw.js` with a copy before any export e2e in a worktree" (Release 9 facts, "Worktree e2e can write INTO the primary") no longer holds for - `sw.js`. It still holds for the compose outputs `e2e:2origin` writes. Not edited here (a shared - file). + `sw.js`. Review fix 2 below retires the compose-output swap too. Not edited here (a shared file). `[Unreleased]` bullets: `export/CHANGELOG.md` (three: order and colour, `/ask` scope, subs). `editor/CHANGELOG.md` and `homepage/CHANGELOG.md` are unchanged, because neither app changed. The item-5 harness fix is not in the public changelog. +**Review fixes** (review SHIP AFTER FIXES, `l1-review.md`; four findings, all fixed on `r10/hub-lows`). + +1. **Must-fix: `/ask` with every archive switched off** (`efe6e48f`). + - **The failure.** With L1's scope, an empty in-scope list counted as settled, so the composer + enabled and a question went out over zero records. + - **Readiness.** `MultiSiteDataProvider` now counts an empty scope as NOT ready unless it is + `progressive`. `/ask` is not progressive, so it stays disabled. That also closes the instant + before the hub's list arrives (the early-ready window from "Found and left", which no longer + applies). The progressive front page still settles on an empty scope. Its results read "No + videos match" rather than "loading index…" forever, and its chips and "Searching 0 archives" + say why. + - **The line.** `AskChat` shows one line in the composer when the hub has archives and every one + is off: `NO_ARCHIVES_IN_SCOPE`, `role="status"`, `data-testid="ask-blocked"`. It replaces the + placeholder and the key hint. The box and the Ask button are disabled. + - **The copy** is a single exported constant in `export/app/ask/hubScopeCopy.ts`, draft text "No + archives selected. Turn one on above to ask.", for the operator. **Copy note:** `/ask` shows no + chips, since they are on the hub's front page, so "above" does not match the page yet. + - **A hub with no archives at all** now reads "Loading transcripts…" on `/ask`, instead of being + ready over nothing. `ask.spec` accepts either. +2. **Should-fix: the compose scripts wrote through the worktree links** (`1203f4a6`). + - **The helpers.** `common/bin/_publicFile.ts`: `writePublicFile` and `copyPublicFile` `rm` the + path first (`fs.rm` uses lstat, so only a link is removed, never its target). `ownDir` replaces + a linked directory with an empty real one. + - **compose-hub** routes every write through them. + - **compose-site** routes through them every top-level file and the per-site subs/posts/digests + manifests, and `reconcileChannelTree` owns its tree first. The paths that already removed first + (summaries/stats `replaceDir`, archives, `sw.js`, chart-templates) are unchanged. + - **Real builds are unchanged.** Where the paths are real (the primary checkout's + `export/public`, which holds no links, and the docker per-site `/site/public` dirs), the result + is what a plain write gave. + - **Tests.** `_publicFile` (4). `compose-hub`: a worktree compose leaves all seven of the + primary's files' content and mtime as they were. This one was red on the old `compose-hub`. + `compose-site`: a linked tree is owned, and the primary's is untouched. + - **Proof:** below. +3. **Nit** (`609a7fe1`): `useHubSummary` runs with `networkMode: "always"`, so a first mount + after an `offline` event settles as "no summary" instead of pausing. +4. **Nit: the subs query** (`78e837f1`, replacing `cf5455c0`'s `retry: false`). + - **A 404** resolves to an empty manifest at once, the way posts does. It is one request. + - **Any other error** keeps one retry (explicit on this query) and then fails the archive like a + failed manifest or page: the chip reads failed with Retry, and the "N of M archives answered" + line names it. + - **Why a 404 is readable.** A member's `/subs/*` carries CORS on 404s too: checked live, + `https://jeralyzer.pages.dev/subs/<missing>.json` → `404` + `access-control-allow-origin: *`. + So a missing file reads as a 404, not as a network error. An added archive on a host that + sends no CORS header on a 404 would read as failed. + +| sha | what | +|---|---| +| `78e837f1` | `hub:` subs: a 404 is an empty manifest; a real error is retried once, then fails its archive with Retry; e2e (finding 4) | +| `efe6e48f` | `hub: /ask` with every archive off is not ready and says why (`NO_ARCHIVES_IN_SCOPE`); an empty scope is never ready when not progressive; e2e (finding 1) | +| `609a7fe1` | `hub: useHubSummary` `networkMode: "always"` (finding 3) | +| `1203f4a6` | `common:` `_publicFile.ts`; compose-hub and compose-site never write through a link; 6 unit tests (finding 2) | +| `323c878f` | `export: [Unreleased]` — the two reader-visible fixes | +| _this_ | `plans:` these review fixes | + +**Gates on `323c878f`** +- **tsc:** clean before every code commit (`l1-tsc-6..8`). `78e837f1` was staged as a subset of the + tsc-green `l1-tsc-7` tree. +- **Unit tests:** + - common **1,923** (1,917 + 6); + - editor unit **79**; + - `test:scripts` **162 + 1 skip**; + - mcp **219**. +- **Builds** (`l1-fix-gates.log`), all ok: + - editor (53 s); + - export site (43 s); + - export hub (33 s); + - homepage (20 s). +- **e2e** (`l1-fix-e2e.log`): + - export full **204 passed**, 7.1 min (after 9.0 min in the queue behind L2); + - `e2e:hub` **24 passed** (22 + the 2 new tests), 1.4 min; + - `e2e:2origin` (`TWO_ORIGIN_REBUILD=1`, links in place, **no swap**) **3 passed**, 34.0 s; + - homepage full **27 passed**, 44.8 s. +- **During development:** the three touched hub specs went 11 passed, 1 failed. The failure was the + new `/ask` test waiting for an answer the fixture member cannot produce: it serves no transcript + tree, so the chat's own search never finishes. The test now asserts the question reaches the + provider. After that, 1/1. +- **Red on the pre-fix source** (`l1-fix-e2e-red.log`, with the four `/ask` and provider files at + `a9d31063`): the two new tests fail for the reason each exists. + - The subs-500 chip read `ready` (expected `failed`). + - With every chip off, `/ask` showed no blocked line. + + The source was restored and the tree left clean. +- **Proof of finding 2:** the export and hub runs left the seven composed entries as LINKS into + the primary (`sw.js` was already the worktree's own, from item 5). + - **Before**, primary `export/public` (size, mtime, md5): + + | file | size | mtime | md5 | + |---|---|---|---| + | `sw.js` | 10,027 | 20:47:37.183119759 | `55cbf381…` | + | `hub-summary.json` | 1,441 | 20:48:07.499176932 | `7d8a101e…` | + | `hub-sites.json` | 579 | 20:47:37.173642710 | `28b9893c…` | + | `corpus.json` | 1,535 | 20:47:37.177642649 | `54b64280…` | + | `llms.txt` | 1,031 | 20:47:37.177642649 | `87255fa7…` | + | `robots.txt` | 130 | 20:47:37.178642634 | `60217070…` | + | `sitemap.xml` | 364 | 18:08:42.340736263 | `76ffaa3c…` | + | `_headers` | 459 | 20:47:37.178642634 | `a5f88f82…` | + + All mtimes are 2026-09-25 (`l1-fix-primary-before.txt`). + - `e2e:2origin` ran `build:hub` through those links. + - **After, the worktree** holds its own plain files: `hub-sites.json` 2 B (`[]`), `corpus.json` + 468 B, `llms.txt` 494 B, `robots.txt` 76 B, `_headers` 459 B, `sw.js` 11,005 B. + `hub-summary.json`'s link was removed (no index). `sitemap.xml`, which compose-hub does not + write, is still a link. + - **After, the primary's eight files** are byte-identical, with the same sizes and mtimes + (`l1-fix-primary-after-2origin.txt`, `diff` empty). They were identical again after the homepage + run (`l1-fix-primary-after.txt`). + +**Retired at merge (for FACTS; not edited here):** both worktree workarounds become unnecessary. +- "Replace `export/public/sw.js` with a copy before any export e2e in a worktree" (Release 9 facts): + `playwright.config.ts` unlinks it (item 5). +- "Swap the compose outputs for copies before `e2e:2origin` and relink after" (Brand facts, + "Worktree e2e and builds write through the `export/public` links"): compose-hub and compose-site + unlink before writing. + +The seed (per-path links from the primary) stays as it is. A worktree run now replaces a link with +its own file, and the next seed relinks it. + ## Rollout Nothing is rolled out. The live :3001 editor still runs `0213f6c8` (the pre-brand build); the five