Archilyzer · Source

archilyzer

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

commit cd038193aa42f2030b25774975f457d2426949f0
parent ceadca718377344e68d77a87011000faccbed55f
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 02:44:12 -0400

plans: slice O1 as shipped — the built-ins flag, /ask waits for the hub's list, the three DRAFT copy lines (NO_ARCHIVES_ON_HUB, LIVE_CHAT_MISSING, ASK_SCOPE_LINE), the live-chat Retry that keeps its archive ready, normalizeSocialSvg themes child fills, mcp README env lines; gates, bites, found and left

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

Diffstat:
Mplans/release-11.md | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+), 0 deletions(-)

diff --git a/plans/release-11.md b/plans/release-11.md @@ -187,6 +187,163 @@ waits on the :3001 restart. After it: 2. **Deploy homepage**, or `pnpm ops deploy-homepage --wait`. The job's log ends with `[deployed] https://<hash>.archilyzer.pages.dev`. +### Slice O1, as shipped — hub lows and the DRAFT copy (2026-09-28) + +Release 10's hub lows (`release-10.md`, "Slice L1, as shipped", both "Found and left" lists) and +STATE's x.com icon low, with the three lines that need words shipped as DRAFT constants for a +morning ruling. Branch `r11/hub-lows` off `main` `2162db92`, merged up to `baaa4b47` (O4) before +the first commit; worktree `/home/user/Projects/r11-hub-lows` (port block #4). One Opus +implementer. Scratch files `o1-*` in the job's `tmp/overnight`. + +**What shipped.** +1. **A "built-ins loaded" flag** (`common/components/siteRegistry.ts`). `builtinsLoaded` turns true + once `/hub-sites.json` has been answered — a list, `[]`, a 404, a 500, a network error, bad JSON + or a non-list. It is set in the same update that adds the built-ins (one `emit`), so no reader + sees "loaded" over a list that lacks them. `useRegistry()` returns it, and `getBuiltinsLoaded()` + reads it outside React. `loadBuiltins` is exported, and so are the store's `getRegisteredSites` / + `subscribeRegistry`. The one-shot guard is now its own `builtinsRequested`: before, a flag named + `builtinsLoaded` was set at the START of the fetch. The file is still never retried. +2. **`/ask` counts as ready only once the hub's list is in.** `useHubSites()` returns + `listed = builtinsLoaded && summary settled`, and `useFederatedSites()` passes it through. + `MultiSiteDataProvider` takes a `listed` prop (default `true`), and + `allSettled = listed && …`. `federation` carries `listed`. `AskHub` passes it; the front page + does not, so it is unchanged. The archives a browser added are read from storage at once, and + `/hub-sites.json`'s arrive a moment later. Before this, a question sent in between grounded in + the added archives alone. Their fetches still start at once; only readiness waits. +3. **Three DRAFT copy lines** (`export/app/ask/hubScopeCopy.ts`), each marked + `// DRAFT (release 11, 2026-09-28) — awaiting the operator's ruling`: + - **`NO_ARCHIVES_ON_HUB`** (`:16`). On `/ask`, once the list is in and it is empty (a hub whose + `hub-sites.json` is `[]` or failed, with none added here), the composer shows it in + `data-testid="ask-blocked"` (`role="status"`), the box and Ask disabled. It replaces + "Loading transcripts…" forever. Its [bracketed] words link to `/`, where the add form is. + - **`LIVE_CHAT_MISSING`** (`:24`). The note on a scope chip (`data-testid="hub-scope-live-chat"`) + for a READY archive whose subs manifest settled in error. Beside it is a Retry, accessible name + `Retry live chat from <title>`: `federation.retryLiveChat(origin)` refetches + `["subs-manifest", origin]` exactly, and nothing else. The Retry is disabled while it runs. + - **`ASK_SCOPE_LINE`** (`:33`). A function of `(inScope, total)` so the plural and the words are + one editable constant. `AskScope` renders it (`data-testid="ask-scope"`) between `/ask`'s + header and the chat, once the list is in, whenever at least one archive is in scope. Returning + `null` hides it: e.g. `inScope === total ? null : …` shows it only when some archives are off. + Its [bracketed] words link to `/`. + `NO_ARCHIVES_IN_SCOPE` (L1's draft, still unruled) also waits for the list now, so it no longer + flashes while the built-ins arrive. `LinkedCopy` (`export/app/ask/LinkedCopy.tsx`) is the one + renderer of a copy line with its link. It replaces AskChat's inline split. +4. **The archive stays ready through a live-chat Retry.** TanStack puts an errored query that has + no data back to `pending` while it refetches (`fetchState`, query-core 5.100.5). So + `isError && !isFetching`, L1's rule, would have taken the archive and its videos out of the + search for the length of the Retry. The subs rule now keys on `errorUpdateCount > 0` with no + data: the count moves only once the query's own retry is spent, and it survives a refetch. + `FederatedSiteState.liveChatMissing = {retrying, error?}` rides in `statusKey`. +5. **`normalizeSocialSvg` themes every fill colour** (`common/lib/settingsSchema.ts`). + - **What changes.** Every `fill` attribute, and every `fill:` in a `style`, becomes + `currentColor`: the root's (a root colour too, not only an absent one) and every child tag's. + The exceptions are `none`, `transparent`, `currentColor`, `inherit` and `url(…)` paint (with or + without a fallback). + - **What is kept.** The tags inside a `<mask>` (white and black there are coverage, not colour), + `fill-rule` / `fill-opacity`, strokes and gradient stops. + - **The operator's icons.** x.com: the root's `fill="none"` stays, and the path's `white` becomes + `currentColor`. Kiwi Farms: the gradient drop and its stops are unchanged, and the `#414042` + dot follows the footer's colour. + - The function is idempotent. +6. **`mcp/README.md`.** The `claude mcp add` and `mcp.json` examples carry + `ARCHILYZER_EDITOR_URL=http://localhost:3001` and `WORKER_TOKEN=…`, marked optional for + `fetch_clip` in AGENTS.md's words (the URL's default and the no-editor answer added). mcp has no + changelog. + +| sha | what | +|---|---| +| `0a2ba7b9` | `common:` siteRegistry `builtinsLoaded` (+ `getBuiltinsLoaded`, exported `loadBuiltins`), set in the same update as the built-ins; +8 unit tests | +| `615563d1` | `common: normalizeSocialSvg` themes every fill colour, children's too; `none` / `url()` / mask fills kept; +8 unit tests | +| `2f9b5ab9` | `hub:` `listed` through `useHubSites` → `MultiSiteDataProvider` → `federation`; `liveChatMissing` + `retryLiveChat` (the `errorUpdateCount` rule); the three DRAFT constants; `AskScope`, `LinkedCopy`; the chip note; e2e `ask.spec` (+3), `federated-search.spec` (+2, and the scope line in the chips test) | +| `2ef9e745` | `mcp:` README — the two `fetch_clip` env lines in both examples | +| `db555285` | `export: [Unreleased]` above `[0.9.4]` (five bullets) | +| _this_ | `plans:` this record | + +**Gates** (logs `o1-*.log`): +- **tsc:** clean (`o1-tsc-2.log`, 34 s, on the committed tree). `0a2ba7b9` and `615563d1` are + additive subsets of it, with no type dependency on the rest. +- **Unit and script tests** (`o1-units-1.log`): + - common **2,057/2,057** (2,041 + 16); + - editor unit **85/85**; + - `test:scripts` **175 + 1 skipped**; + - mcp **269/269**. +- **Builds** (`o1-run-1.log`), with `export/public` seeded per path (17 links, none dangling): + - export site ok (24 s), `data-accent="signal"`; + - export hub ok (24 s), `dark data-base="dark"`, `out/ask/index.html` present. + - Editor and homepage builds were not run: neither app changed. The editor's two save paths call + `normalizeSocialSvg`, and its output for their e2e inputs is byte-identical (unit test 4). +- **e2e** on `db555285` (`o1-run-1.log`; no wait in the queue): + - `e2e:hub` in full: **31 passed** (26 + 5 new), 1.3 min; + - export `site-branding` + `ask-chat` + `ask-workspace`: **36 passed**, 1.9 min. The footer's + social row is `site-branding`'s. No export spec reads the icons' colour, and the fixture's icon + is already `currentColor`. + - `e2e:2origin` (`TWO_ORIGIN_REBUILD=1`, the links in place, no swap): **3 passed**, 36.7 s. +- **The primary's `export/public`:** all **380 files**' path, size, mtime and md5 were identical + before and after the three runs (`o1-primary-before-1.txt` vs `-after-1.txt`, `diff` empty). + After 2origin the worktree held its own `hub-sites.json`, `sw.js`, `robots.txt`, `_headers`, + `corpus.json` and `llms.txt`. The seed relinked them. +- **Screens** (`o1-shots/`, from a temporary spec, deleted after): the chip note and its Retry, the + scope line under `/ask`'s header, and the zero-archive line under the composer. +- **Numbers tool:** none. No `settings.json`, `site.json` or `config.json` key changed. + +**They bite:** +- **Unit, against `baaa4b47`'s source** (a scratch copy of the old `common/`, `o1-bite-units.log`): + - `siteRegistry.test.ts` fails to load (no `getBuiltinsLoaded`). + - `normalizeSocialSvg.test.ts` **4 of 8 fail**: x.com, Kiwi Farms, the colour spellings and the + mask. + - The other four pin behaviour the old code already had: unchanged icons, the bare icon's exact + output, idempotency and the refusals. They are guards and pass on it by design. +- **Mutations of the new code:** + - the flag set at the start of `loadBuiltins`: 7 of 8 fail; + - the flag set only when the file listed something (the old early returns): 6 of 8; + - the flag announced in its own update before the built-ins join: 7 of 8; + - `none` themed too: the x.com and "unchanged" tests fail; + - masks not skipped: the mask test fails. +- **e2e, against `baaa4b47`'s seven source files,** with the new specs and `hubScopeCopy.ts` kept + (`o1-bite-e2e.log`, restored by a trap, tree clean after): **6 failed, 10 passed.** The six are + every new-behaviour test: + - the three zero-archive tests: no `ask-blocked` line; + - the chips test: no `ask-scope` line; + - the listed test: `Loading transcripts…` gone, because the chat was ready over the added archive + alone; + - the live-chat test: no note. + +**Found and left** +- **The icon fix applies on save.** `normalizeSocialSvg` runs when a link is saved, not when the + footer renders. The stored x.com icon in `settings.json` keeps `fill="white"` until the Settings + form is saved once. Any save re-normalizes every link, with no re-paste. Then every site and the + hub need a rebuild. A render-side pass (as `sizeSocialSvg` does for sizes) would fix stored + icons with no save, but `Footer.tsx` and `sizeSocialSvg` are outside this slice. +- **The Kiwi Farms dot changes colour.** It was a fixed `#414042`, barely visible on Dark, and now + follows the footer's colour. The green gradient drop is unchanged. +- **Strokes are not themed.** An icon drawn with `stroke="white"` would still vanish. Neither of the + operator's icons is stroked. +- **A failed `/hub-sites.json` reads as "no archives yet"**, the same as an empty one, and the + registry still never retries: a reload asks again. +- **The front page does not wait for the list.** It is progressive and does not take `listed`, so + it still settles for the instant before `hub-sites.json` arrives. This is pre-existing, and its + chips show the loading. +- **A live-chat Retry that fails again brings the note back,** with its Retry enabled + (`errorUpdateCount` moves, `isFetching` clears). No e2e covers that second failure. TanStack + clears `error` during the refetch, so the Retry's title says only "Try again" while it runs. The + button is disabled then. +- **FACTS is stale after merge** (release 10 facts, "L1 — hub lows"): "nothing says so (a new low)" + (the subs rule) and "A hub with zero archives therefore reads 'Loading transcripts…' forever" + are both closed here, and the subs rule's anchor now keys on `errorUpdateCount`. Not edited here + (a shared file). + +`[Unreleased]` bullets: `export/CHANGELOG.md` (five: `/ask` with no archives, its wait for the +hub's list, its scope line, the chip's missing live chat, the social icon). `editor/CHANGELOG.md` +and `homepage/CHANGELOG.md` are unchanged, because neither app changed. + +**DRAFT copy for the morning ruling** (`export/app/ask/hubScopeCopy.ts`): +- `:16` `NO_ARCHIVES_ON_HUB` = "This hub has no archives yet. Add one on the [hub's front page] to ask." +- `:24` `LIVE_CHAT_MISSING` = "live chat didn't load" +- `:33` `ASK_SCOPE_LINE(n, m)` = "Searching {n} of {m} archive(s) — [change on the front page]." (shown + whenever at least one archive is in scope, all included) +- Still owed from release 10: `:7` `NO_ARCHIVES_IN_SCOPE` = "No archives selected. Choose some on the + [hub's front page] to ask." + ## Rollout Nothing is rolled out tonight. The morning runbook lists what is owed: the :3001 editor restart,