Archilyzer · Source

archilyzer

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

commit 62a1de45c519ad207b8c56ecb3c4d9570d412174
parent d4436ad75f04d63a0e797f9662e1bf4b3c0dc7f0
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon,  7 Sep 2026 17:11:09 -0400

plans: one-core Phase 0 is shipped, and the record says what it cost

STATE.md gets the dated entry, FACTS.md the anchors, and one-core.md a
"Phase 0, as shipped" section. Three things the survey had wrong or could not
know are recorded rather than left to be rediscovered:

- report-to-video had EIGHT import sites in umtool, not four.
- `page-${n}.json` existed SIX times, not three — lib/stats.ts, lib/posts.ts
  and lib/digests.ts each had their own copy.
- An exports map with a fallback array (`["./x.tsx", "./x.ts"]`) type-checks
  and does NOT build: Turbopack takes the first entry and stops. `tsc` is not
  the test for an exports change; `next build` is.

And one blocker that is not ours: `editor/content` is an untracked symlink to
/home/user/Projects/recipe-content, Tailwind's source detection follows it out
of the project, and Turbopack panics compiling editor/app/globals.css
("leaves the filesystem root"). The editor dev server 500s, so `pnpm e2e` dies
before the first spec. Reproduced on main @ 42576a3 — environmental, not a
Phase 0 regression. The suite is green from a worktree: 511 passed, 0 failed,
23.8 min.

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

Diffstat:
Mplans/FACTS.md | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mplans/STATE.md | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mplans/one-core.md | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 219 insertions(+), 1 deletion(-)

diff --git a/plans/FACTS.md b/plans/FACTS.md @@ -3184,3 +3184,105 @@ around `:251-290`) while this change deleted four entries lower in the same file `/duplicates` to `nav.ts` where main's `nav.test.ts` pins eleven, and still carries files main deleted (`build/page.tsx` with its own `BUILD_KINDS`, `actionable/page.tsx`). Their merge — recorded so nobody is surprised. + +--- + +## one-core Phase 0 (verified 2026-09-07, branch `one-core/phase-0`) + +### The exports-map trap: a fallback array type-checks and does not build + +`common/package.json` now has an `exports` map. `"./components/*": +["./components/*.tsx", "./components/*.ts"]` passes `tsc --noEmit` in all six packages and +**fails `next build`**: Turbopack resolves the first entry of a fallback array and stops, so +`components/statsCache`, `components/summariesCache` and `components/virtualizer` (all `.ts`) +died with module-not-found. The map lists the **25** `.ts` modules under `components/` +explicitly — an exact key beats a pattern — and keeps `"./components/*": "./components/*.tsx"` +for the 30 `.tsx` ones. **A new `.ts` file under `components/` needs a new line in that map.** +Corollary for any future exports work: an `exports` change is a RUNTIME resolution change, so +`tsc` is not the test. `pnpm --filter editor exec next build` is. + +### `styles/tokens.css` is imported by relative path, not as a subpath + +`editor/app/globals.css:2`, `export/app/globals.css:2`, `homepage/app/globals.css:2` all do +`@import "../../common/styles/tokens.css"`. Only `styles/fonts` is a package subpath +(`editor/app/layout.tsx:10` and the two siblings). The exports map maps `"./styles/*.css"` +anyway, but nothing uses it today. + +### `common/`'s back-edges: 12 remain, and the test is the ledger + +`common/architecture.test.ts:41-99` — the allow-list, one entry per edge with the phase that +removes it. Rules: `lib/` ✗ `controller/` `jobs/`; `jobs/` ✗ `controller/`; `components/` ✗ +`controller/` `jobs/` `ytdlp/`. It fails on a NEW edge **and** on a stale entry, so the list +can only shrink. The heaviest cluster is `lib/operations.ts` → four controllers (plus three in +its test): the registry's `run()` closures call the engines, which inverts in phase 1 step 4. + +`common/lib/autoQueueTypes.ts` is new and holds the persisted auto-queue shape +(`AutoQueueMode/MatchType/Order/Reach/Match/Leaf/Group/Node/Policy/Settings`, `isGroup`, +`AutoQueueKind`). `jobs/autoQueuePolicy.ts:2-20` and `jobs/autoQueueState.ts:23-25` re-export +every name, so `from "../jobs/autoQueuePolicy"` still resolves everywhere. + +### `page-${n}.json` existed six times, not three + +`common/lib/manifest.ts` had three identical copies (the survey's count) — **and** so did +`lib/stats.ts:23`, `lib/posts.ts:164` and `lib/digests.ts:38`. All six are now +`manifest.ts`'s single `pageFileName`; `statsPageFileName`, `postsPageFileName` and +`digestPageFileName` are aliases of it, and `transcriptPageFileName` / `subsPageFileName` are +**deleted** (12 call sites rewritten). A seventh copy at +`common/components/searchIndex.worker.ts:39` is deliberate and stays: it is a bundled web +worker whose only import is its sibling protocol module. + +### `CONTRACT` owns the published version numbers + +`common/lib/corpus.ts` — `CONTRACT` holds `corpusSpec 3`, `siteDescriptor 1`, `manifest 3`, +`transcriptsManifest 1`, `subsManifest 4`, `subsChannelManifest 1`, `summariesPageSize 1000`, +`pagePad 4`, and `layers ["transcripts","subs","posts","digests","summaries"]`. The seven +existing named exports re-export its fields. Import direction is `corpus.ts` → +`{manifest,siteDescriptor}.ts`; `corpus.ts` imports `siteDescriptor` **type-only**, so there +is no runtime cycle, and `project.ts` (its only value import) imports nothing. + +### How to compose a fixture site offline, and what a clean diff looks like + +There is no existing harness for this — export's e2e route-mocks and the 2origin setup +hand-writes its shards. What works: + +```sh +# a corpus root + a one-channel site +cp -r editor/e2e/fixtures/test-transcripts/one-youtube-channel-with-data/channels $F/ +mkdir -p $F/sites/testsite && cat > $F/sites/testsite/site.json # siteId/groups/channels +cd common && env TRANSCRIPTS_DIR=$F SITES_DIR=$F/sites \ + EXPORT_PUBLIC_DIR=$O/public EXPORT_INDEX_DIR=$O/index \ + SETTINGS_FILE=$F/settings.json SITE_ID=testsite \ + pnpm exec tsx bin/build-index.ts && ... bin/compose-site.ts +``` + +Output: **16 files** under `public/`, **7** under `index/`. Two runs differ ONLY in +`generatedAt` — in `corpus.json`, `site.json`, the subs/posts/digests/summaries/transcripts +manifests, and (pretty-printed, so normalize `"generatedAt": "…"` with a space too) the +archive zip's `channel.json`. The zip's own bytes differ because entry mtimes do; its +CONTENTS diff clean. Anything else differing is a real change to the wire. + +### `editor/content` is a symlink out of the repo and it panics Turbopack in dev + +`editor/content -> /home/user/Projects/recipe-content` (untracked, made 2026-08-31). +Tailwind's automatic source detection follows it out of the project and Turbopack panics +compiling `editor/app/globals.css`: `FileSystemPath("editor").join("../../recipe-content") +leaves the filesystem root`. The dev server reports `Ready` and then FATALs on the first +request, so **`pnpm e2e` in the primary checkout dies before the first spec**. Verified +2026-09-07 on `one-core/phase-0` AND on `main` @ `5ffb0e1` — environmental, not a code +regression. `next build` is unaffected. A `git worktree` of the same commit has no such +symlink and runs the suite normally — **511 passed / 0 failed in 23.8 min** on `1691c4f`, +one worker. A worktree needs one extra step first: its `export/public` holds only the tracked +static assets, so the export webServer 500s and Playwright dies with "Timed out waiting +120000ms from config.webServer". Copy a composed fixture site into it (16 files) and it +serves 200. + +### The bake-off harnesses do not take `--help` + +`plans/tools/{digest-bakeoff,attribution-bakeoff,attribution-pilot}.ts` (moved here from +`common/bin/`) ignore unknown flags and **start a real run against the corpus** — the first +opens the LMDB index and writes `plans/bakeoff/round.partial.json`. Run them under +`cd common && pnpm exec tsx ../plans/tools/<name>.ts` only when you mean to. They needed +`common/bin/_lmdb.ts` (a re-export of `open`) because `plans/` is not a workspace package: a +bare `import "lmdb"` resolves from the importing file upward and the repo root's +`node_modules` holds only `tsx`. + diff --git a/plans/STATE.md b/plans/STATE.md @@ -3,7 +3,67 @@ 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. -**Last updated:** 2026-08-31 — **the transcode operation is removed** (`904f1a9` → `f717a36`): it never fired in production. The census over 68 channels found the `untranscoded` bucket empty in every one, both `failed-transcodings` files 0 bytes, and only four channels even passing the stage's gate — and `resolveAudioFile` falls back to any real audio file anyway, so transcription never needed it. Gone: four controllers, four job kinds, the channel stage and station, the catalog entry and with it `appliesTo`/`operationApplies` (catalog 8 → 7). Kept: `transcodeAudio` and the download path, the per-file *Transcode …* rows, both wrong-format sweeps — whose bucket is `wrongFormatAudio` now. The slice-5 leftovers rode first (`measure-nav.mjs`, `BUILD_KINDS`, `EditorAliasesClient`). Plan: [`editor-transcode-removed.md`](editor-transcode-removed.md). +**Last updated:** 2026-09-07 — **one-core Phase 0 shipped** on branch `one-core/phase-0` +(`df5eb48` → `1691c4f`, six commits, not merged): **guardrails and dead weight.** The umbrella +plan is [`one-core.md`](one-core.md); its "Phase 0, as shipped" section is the detail and +[`FACTS.md`](FACTS.md#one-core-phase-0-verified-2026-09-07) the anchors. Every item is a +deletion, a move or a guard. **Nothing on disk in a corpus changed and nothing on the wire +changed** — proved, not asserted: a fixture corpus composed through `build-index` + +`compose-site` before and after item 5 gives 16 public files and 7 index files that are +**identical apart from `generatedAt`** (and the archive zip's entry mtimes; its contents diff +clean). + +- **`scripts/report-to-video` → `umtool/report-to-video`**, package `umtool-report-to-video`. + A rename only. The survey undercounted: **eight** import sites, not four. +- **`common/architecture.test.ts`** is the layering. Back-edges **17 lines / 16 edges → 13 / + 12**. The four burned down were type-only and now live in `common/lib/autoQueueTypes.ts`, + re-exported by `jobs/autoQueue{Policy,State}.ts` so no import site outside `common/lib` + changed. The allow-list fails on a NEW edge *and* on a stale entry, so it can only shrink; + each of the 12 names the slice that removes it. **Nine wait on phase 1** — + `lib/operations.ts` → four controllers is the registry's `run()` closures, THE structural + back-edge, and it inverts at phase 1 step 4. +- **`common/package.json` has an `exports` map**; `mcp/package.json` finally declares + `yt-dlp-transcript-common` (it had been resolving by hoisting). One trap paid for: + `"./components/*": ["./components/*.tsx", "./components/*.ts"]` **type-checks and does not + build** — Turbopack takes the first entry of a fallback array and stops. The 25 `.ts` + modules under `components/` are listed explicitly; a new one needs a new line. +- **Deleted**: root `sites/`, `common/bin/migrate-to-sites.ts` (the *controller* stays — the + Sites page's Migrate button calls it), `create-archives.sh`'s commented tail, + `export/.compose-cache/`, and `PARALLEL_TRANSCRIBE_LIMIT` from three doc tables. + `export/.r2-staging/` (2.5 GB) deliberately untouched. **Moved**: the three bake-off + harnesses (3,828 lines, 58% of `common/bin/`) to `plans/tools/`. +- **One `pageFileName`, one `CONTRACT`.** The page-shard name existed **six** times, not + three. `CONTRACT` in `lib/corpus.ts` owns eight values plus the layer names; the seven + existing constants re-export its fields. + +**Decision taken here:** the bake-off move needed one new file, `common/bin/_lmdb.ts`, because +`plans/` is not a workspace package and a bare `import "lmdb"` resolves upward from the +importing file. Making `plans/tools` an eighth workspace member was rejected — it would add a +`Dockerfile` COPY and a package to a workspace this plan exists to shrink. + +**BLOCKER FOR ANY EDITOR e2e IN THE PRIMARY CHECKOUT, and it is not ours.** +`editor/content` is an untracked **symlink to `/home/user/Projects/recipe-content`** (made +2026-08-31, after the last recorded e2e on 2026-08-30). Tailwind's automatic source detection +follows it and Turbopack **panics** compiling `editor/app/globals.css`: +`FileSystemPath("editor").join("../../recipe-content") leaves the filesystem root`. The dev +server never serves a page, so `pnpm e2e` dies before the first spec. **Reproduced on `main` +at `5ffb0e1` with the same panic**, so it is environmental, not a Phase 0 regression — and +`pnpm --filter editor exec next build` is unaffected (production builds do not run the dev +source scan). The operator should remove or move that symlink. + +**The suite itself is green.** Run from a detached `git worktree` of `1691c4f` (no such +symlink there): **511 passed, 0 failed, 23.8 min**, one worker, serial behind the queue lock. +Nothing to compare against FACTS.md's known-failing list — that list was superseded +2026-07-30 and the run had no reds at all. One extra step a worktree needs: its +`export/public` holds only the tracked static assets, so the export webServer 500s and +Playwright times out after 120 s. Seed it with a composed fixture site (the same one used for +the wire diff) and it serves 200. + +**Next:** phase 1 (dispatch: one scheduler), 4–5 slices, starting with persisting the arbiter. +Read `common/architecture.test.ts`'s allow-list first — it is the shortest accurate statement +of what is still tangled. + +**Previously:** 2026-08-31 — **the transcode operation is removed** (`904f1a9` → `f717a36`): it never fired in production. The census over 68 channels found the `untranscoded` bucket empty in every one, both `failed-transcodings` files 0 bytes, and only four channels even passing the stage's gate — and `resolveAudioFile` falls back to any real audio file anyway, so transcription never needed it. Gone: four controllers, four job kinds, the channel stage and station, the catalog entry and with it `appliesTo`/`operationApplies` (catalog 8 → 7). Kept: `transcodeAudio` and the download path, the per-file *Transcode …* rows, both wrong-format sweeps — whose bucket is `wrongFormatAudio` now. The slice-5 leftovers rode first (`measure-nav.mjs`, `BUILD_KINDS`, `EditorAliasesClient`). Plan: [`editor-transcode-removed.md`](editor-transcode-removed.md). **Previously:** 2026-08-30 — **editor IA slice 5 shipped** (`140212a` → `df9b839`): **a site has tabs, and the family has one page.** Charts, Search aliases, Deploy, Build and diff --git a/plans/one-core.md b/plans/one-core.md @@ -382,3 +382,59 @@ umbrella), each slice committed with its measurements in the commit body, `STATE updated before context is cleared. The first concrete slice to write is **Phase 0** — it is one session, deletes only dead weight, and its architecture test is what makes every later deletion cheap to verify. + +## Phase 0, as shipped + +Branch `one-core/phase-0`, 2026-09-07, six commits (`df5eb48` → `1691c4f`). Every item is a +deletion, a move or a guard; nothing on disk in a corpus changed and nothing on the wire +changed. + +**report-to-video is under umtool.** `umtool/report-to-video/`, package +`umtool-report-to-video`. Behaviour, bins and exports are untouched — `cues.mjs`'s `REPO_ROOT` +is still two levels up, so `DEFAULT_CHANNELS_DIR` is unchanged. The survey undercounted the +import sites: there were **eight**, not four (add `components/projects/ClaimBench{,Page}.tsx`, +`lib/report/manifest.mjs`) plus three path references and `Dockerfile`'s manifest COPY. + +**The layering is a test.** `common/architecture.test.ts`. Back-edges went **17 import lines / +16 distinct edges → 13 / 12**; the four burned down were all type-only and moved into a new +`common/lib/autoQueueTypes.ts` (the persisted auto-queue shape, plus `AutoQueueKind`), which +`jobs/autoQueuePolicy.ts` and `jobs/autoQueueState.ts` re-export so no import site outside +`common/lib` changed. The allow-list can only shrink: a stale entry fails the suite too. Twelve +remain, each with its reason in the file — nine of them wait on phase 1 (the registry's `run()` +closures are THE structural back-edge), one on phase 3 slice 4 (the auto-queue sanitizers are +settings-schema code), one on phase 3 slice 1 (`StreamActionResult` becomes a view-model). + +**The surface is declared.** `common/package.json` has an `exports` map; `mcp/package.json` +declares `yt-dlp-transcript-common` (it had been resolving by hoisting). One trap paid for +here: `"./components/*": ["./components/*.tsx", "./components/*.ts"]` **type-checks and does +not build** — Turbopack takes the first entry of a fallback array and stops. The 25 `.ts` +modules under `components/` are listed explicitly instead, and a new one needs a new line. + +**Deleted**: root `sites/`, `common/bin/migrate-to-sites.ts` (the controller stays — the Sites +page's Migrate button calls it), `create-archives.sh`'s commented tail, `export/.compose-cache/` +(`.r2-staging/` deliberately kept), and `PARALLEL_TRANSCRIBE_LIMIT` from three doc tables. +**Moved**: the three bake-off harnesses (3,828 lines, 58% of `common/bin/`) to `plans/tools/`. +That needed one new file — `common/bin/_lmdb.ts` — because `plans/` is not a workspace package +and a bare `import "lmdb"` resolves from the importing file upward. + +**One `pageFileName`, one `CONTRACT`.** The page-shard name existed **six** times, not three: +`lib/manifest.ts` ×3 plus `stats.ts`, `posts.ts`, `digests.ts` (a seventh copy in +`components/searchIndex.worker.ts` is left alone — a bundled worker). `CONTRACT` in +`lib/corpus.ts` owns eight values and the layer names; the seven existing constants are +re-exports of its fields. Proved on the wire by composing a fixture site before and after: +16 public files and 7 index files, **identical apart from `generatedAt`** (and the archive +zip's entry mtimes; its contents diff clean). + +**What phase 1 should read first**: the allow-list in `common/architecture.test.ts`. It is now +the shortest accurate statement of what is still tangled, and every entry names the slice that +untangles it. + +**Verification, in full**: `tsc --noEmit` clean in common, editor, export, mcp, homepage and +umtool after every item; `pnpm --filter yt-dlp-transcript-common test` **876/876** (874 + the +2 new architecture tests), `pnpm --filter yt-dlp-transcript-mcp test` **205/205**, +`pnpm test:scripts` **71 passed / 1 skipped**; a real `pnpm --filter editor exec next build` +(the only test an `exports` map has); the compose byte-diff above; and the editor e2e +**511 passed / 0 failed in 23.8 min**. The e2e had to run from a `git worktree` — the primary +checkout's untracked `editor/content` symlink panics Turbopack in dev, on `main` as well as +here. See `plans/STATE.md`. +