Archilyzer · Source

archilyzer

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

commit 53d1d4a75ab642a5e62897ac13b23fa48a8353f2
parent c7d6311ec4fa8a6b81017e15d6ec7e3bf5a81105
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  1 Oct 2026 23:03:45 -0400

plans: slice XP — the review, its fixes, the rollout steps (the hub rebuild, old Pages deployments) and the gates after it

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

Diffstat:
Mplans/FACTS.md | 6++++++
Mplans/release-17.md | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/plans/FACTS.md b/plans/FACTS.md @@ -8265,6 +8265,12 @@ phase deletes from the destination. (`resolveHubUrl`), its `corpus.json` says `site.audience: "private"`, and every deploy path refuses it or its bundle before any upload (`lib/builtExport.ts` `deployAudienceProblem`; the bulk deploys skip it). Build & deploy all still BUILDS it. +- **The hub carries no site's data** (release 17 XP review): `public/` is shared, so a hub built after + a site's compose used to ship that site's data trees. `compose-hub` now removes every per-site entry + first (`SITE_ONLY_PUBLIC_ENTRIES`) and writes the global `search-aliases.json`; `builtHubProblem` + refuses a hub bundle carrying a data tree. **compose-site's own stages (summaries, stats, + duplicates) are trusted from its cache only when `public/site.json` names the site**; the + per-channel trees keep their signatures across sites. - **gallery-dl 1.32.9** takes `--cookies-from-browser BROWSER[/DOMAIN][+KEYRING][:PROFILE][::CONTAINER]` (yt-dlp's syntax plus `/DOMAIN`) and reads every browser it supports, Chromium's encrypted store included, on each run. The spec is passed verbatim (`galleryDlCookieChoice`). diff --git a/plans/release-17.md b/plans/release-17.md @@ -435,8 +435,14 @@ loop (`buildIndex.ts` ~1943 and the fingerprint), a different hunk from T1's `sc pnpm archilyzer index # or any editor build: the index build writes the per-site manifests BUILD_ARCHIVES=0 EXPORT_PUBLIC_DIR="$HOME/archives/<private-id>" \ EXPORT_INDEX_DIR="$PWD/export/.export-index" pnpm archilyzer compose site <private-id> - claude mcp add archilyzer -- pnpm --silent -C "$PWD" archilyzer mcp --local "$HOME/archives/<private-id>" + claude mcp remove archilyzer -s local # the name must be free; use the scope it was added in + claude mcp add archilyzer \ + --env ARCHILYZER_EDITOR_URL=http://localhost:3001 \ + --env WORKER_TOKEN=… \ + -- pnpm --silent -C "$PWD" archilyzer mcp --local "$HOME/archives/<private-id>" ``` + The two `--env` lines are what `fetch_clip` needs (the editor's own `WORKER_TOKEN`, from + `editor/.env`); the name stays `archilyzer` for `/ask` and `/sweep` (AGENTS.md). (`EXPORT_PUBLIC_DIR` must be absolute — the command runs in `common/`; the compose cache lands beside it, in `$HOME/archives/.compose-cache/`.) The site's editor **Build** works too: it composes into `export/public` and builds into `export/out`. **The current registration, `--local @@ -457,7 +463,11 @@ loop (`buildIndex.ts` ~1943 and the fingerprint), a different hunk from T1's `sc | `75ccbef3` | `editor(e2e), export(e2e):` `x-session` and `sites-crud` cases; `export/e2e/x-posts-private.spec.ts` | | `30c14aa0` | `common:` compose never ships a posts tree the index withheld; the cache trusted only over the site's own last compose | | `63002de3` | `common:` the per-channel trees keep their signatures across sites | -| this commit | `plans:` this section, the ruling, the slices row; FACTS; the editor changelog | +| `4ed7d410` | `plans:` this section, the ruling, the slices row; FACTS; the editor changelog | +| `6466a68e` | `common:` the hub carries no site's data; `builtHubProblem` refuses one that does (review HIGH 1) | +| `385e4eb1` | `common:` a compose over a stale index lists no withheld channel; the comments (LOW 3, NIT 7) | +| `8e448fde` | `editor:` the changelog (LOW 5) | +| this commit | `plans:` the review, its record, the rollout steps and the gates after it | #### Gates (logs `$T/XP-*.log`) @@ -502,6 +512,20 @@ loop (`buildIndex.ts` ~1943 and the fingerprint), a different hunk from T1's `sc content. The posts tree, the posts manifest, the channel list and `corpus.json` follow the index build and do not carry it. - The `/sites` list does not mark a private site; its form and every deploy refusal do. +- **The posts reconcile ships only the channels the site's posts manifest lists, on every build**: a + social channel with 0 posts no longer gets a posts folder. Nothing advertised that folder (no posts + manifest entry, no `corpus.json` posts link), so nothing reads the difference. +- **A private site changes the homepage's and the hub's totals.** A private site is unlisted, and + `channelsOnlyOnUnlistedSites` keeps a channel only unlisted sites expose out of every public total. A + private site holding every channel turns every pool-only channel (on no public site) into "only on + unlisted sites", so the homepage's and the hub's instance-wide totals drop by those channels at the + next homepage and hub build. Channels a public site also has are unaffected. +- **Cloudflare Pages keeps old builds reachable.** A production redeploy replaces what the production + URL serves, nothing else: every earlier deployment stays live at its own + `<hash>.<project>.pages.dev`, and a preview alias (`<branch>.<project>.pages.dev`) keeps its last + build. The review found `tags-exclude.anilyzer.pages.dev/posts/manifest.json` still listing an X + channel. So after the rollout, X posts are gone from the production URLs only; whether to delete + the old deployments is the operator's call (rollout step 5). - `queue-lock.test.mjs`'s two timing cases failed under the machine's load (below); not this slice's file. #### Decisions the operator could overturn @@ -513,5 +537,63 @@ loop (`buildIndex.ts` ~1943 and the fingerprint), a different hunk from T1's `sc | A bundle whose `corpus.json` says private is refused even when the site is public now | Trust the site's current audience only (a stale private build could ship) | | `docker/publish-site.sh` refuses a private site (the `site` service is the host's public face) | Let it publish locally behind Caddy | | `social.x.visibility` lives in `xCookieSource.ts` with the rest of the social block | A module of its own | +| The hub's `search-aliases.json` is the global dictionary (it was whichever site composed last) | Ship none: hub-wide search in a reader (`reader-hub.ts`) would have no aliases | + +#### Rollout for this slice (the parent's, through the editor's own writers) + +1. Rebuild and restart the editor (the setting, the Audience field, the deploy refusals, the compose + and hub fixes). +2. Create the private site (Sites → New, **Audience: Private**, every channel), then set **Where X posts + appear: Private** on `/settings`. +3. Rebuild and deploy every public site that has an X channel (each by name; Build & deploy all skips the + private site's deploy and says why). +4. **Rebuild and deploy the hub** — the live hub serves the last-built site's data, X posts included, + until it is rebuilt from this branch (the review's HIGH 1). Then the homepage, for the totals. +5. **Old deployments** (the operator decides): every earlier production deployment and every preview + alias of a site that had X posts still serves them. To remove them: the Cloudflare dashboard → + Workers & Pages → the project → Deployments → a deployment's ⋯ menu → Delete deployment (a preview + alias's branch deployments are listed there too); or `pnpm dlx wrangler pages deployment list + --project-name <project>` then `pnpm dlx wrangler pages deployment delete <deployment-id> + --project-name <project>` (check `--help` for the force flag an aliased deployment needs). The + current production deployment cannot be deleted, and needs none. +6. Build the private site (its **Build**, or the compose-to-a-directory commands above) and point the + MCP at it. + +#### Review + +**Verdict: SHIP AFTER FIXES** (`XP-review.md` in the job's scratch): two Highs, four Lows, three nits. + +| Finding | Where | +|---|---| +| HIGH 1: the hub bundle carried the last-composed site's data trees (the live hub serves jeralyzer's posts manifest, two X channels), through no gate | `6466a68e`: `compose-hub` removes every per-site entry from `public/` first (`SITE_ONLY_PUBLIC_ENTRIES`: summaries, transcripts, subs, posts, digests, stats, archives, `site.json`, `tags.json`, `duplicates.json`, `search-aliases.json`, `chart-templates.json`, `sitemap.xml`; a worktree link by the link only) and writes the global alias dictionary as the hub's; `builtHubProblem` refuses a hub bundle that still carries a data tree, so Deploy hub refuses one. Tests: `compose-hub.test.ts` +1, `builtExport.test.ts` extended. Rollout step 4 | +| HIGH 2: Pages preview aliases and old deployments keep serving X posts | Record: "Found and left" and rollout step 5 (the operator decides; the dashboard and wrangler paths) | +| LOW 3: a compose over an index built before the flip listed the X channel's name and count | `385e4eb1`: the served posts manifest and summaries manifest are narrowed to the published members (`site.json`, `corpus.json` follow); a narrowed summaries copy is not trusted by the next compose. Test: "a compose over an index built before the setting flipped lists no X channel anywhere" | +| LOW 4: the MCP line lost `fetch_clip`'s env, and `add` fails over a registered name | This commit: `claude mcp remove archilyzer -s local` first, the two `--env` lines kept (`WORKER_TOKEN=…`) | +| LOW 5: the changelog missed the compose-cache fix and the restart notes | `8e448fde`: a bullet for the compose-cache fix, one for the hub, and the restart/redeploy notes | +| LOW 6: a private site holding every channel moves the homepage's and hub's totals | Record: "Found and left" | +| NIT 7: the deploy-all comment said the bundle check runs first | `385e4eb1`: the comment says the audience check runs first and what that means for a private wrong-site bundle | +| NIT 8: the posts reconcile drops a 0-post social channel's folder | Record: "Found and left" | +| NIT 9: `/sites` does not mark a private site | Already listed as left | + +#### Gates after the review + +- **tsc** (all workspaces) clean at `385e4eb1`'s tree (`XP-tsc6.log`). +- **common:** 2,500 passed, 1 failed of 2,501 (`XP-common4.log`; +2 since the first gates: the hub + clearing and the stale-index compose). The one failure is `relocateChannelMedia.test.ts`'s "reconcile: + an extra and a changed file on the destination are settled" (its diff listing counted `./` as + changed — a directory mtime); 3/3 alone, and the file is not this slice's. **Export unit:** 98/98. + **Homepage unit:** 23/23. **Editor unit:** 109/109. +- **No rebuild:** the fixes touch two bins (`compose-hub`, `compose-site`), `builtExport.ts` and + comments in `publish/build.ts`; no Next app bundles a changed module beyond `builtExport` (the + editor's hub action reads `builtHubProblem`, a pure function, tsc-checked). + + | Run | At | Specs | Result | + |---|---|---|---| + | 3 (editor) | `8e448fde` | the run-1 list | **62 passed**, 0 failed, 3.0 min (after 45 min in the queue) | + | 4 (export) | `8e448fde` | the run-2 list | **20 passed**, 0 failed, 1.1 min (after 50 min in the queue) | + | 5 (hub) | `8e448fde` | `e2e:hub`, the whole suite | **39 passed**, 0 failed, 1.6 min (after 12 min in the queue) | + + The hub suite runs `next dev` in hub mode over `export/public` and never composes, so it shows the + hub app is unchanged; the clearing itself is pinned by `compose-hub.test.ts`. ## Rollout