# Release 16 — what a search reads `main` at `9a259787` (releases 14 and 15 merged and rolled out). No plan file of its own: each slice's prompt carries its ruling, and this record carries what was built. Rules: `plans/tools/implementer-rules.md`, with the commit trailer this release's prompts give. **The standing choices** (not re-opened): - **A search reads transcripts and posts unless the visitor says otherwise; live chat is read only when asked.** On `main` before this release a plain query read the transcript cues only: posts only through a query-builder leaf whose scope is "Posts", live chat only through one whose scope is "Live chat". A plain query now reads transcripts and posts by default; the three become one row of toggles. (Corrected after slice CK found the first wording, "a plain query already reads … the posts corpus", untrue of the code.) - **The toggles say what a query reads, not which records list.** "Type: Videos, Livestreams" keeps saying which records are shown; an empty query with Transcripts off still lists videos. - **A slice that needs another slice's file stops and says so**; it does not edit it. - **Nothing is edited in the primary checkout**; each slice has its own worktree, and the parent merges with `git merge --no-ff` only on a clean tree. ## The slices | Slice | Branch | What | Owns | |---|---|---|---| | CK | `r16/search-in` | A "Search in" row — Transcripts, Posts, Live chat — on the export and hub search, Transcripts and Posts on by default | `common/components/{FiltersPanel,SearchSessionContext,SearchResults,SearchBar,exportFilterStorage}.tsx/.ts`, `common/lib/searchQuery.ts` and `common/lib/search/*` as its prompt names, `export/e2e/search-in.spec.ts` (new) and the specs its prompt names, `export/e2e/helpers.ts`; records: `plans/FACTS.md` | | DX | `r16/research-setup` | The research-only setup (source → `pnpm install` → `claude mcp add archilyzer` → `/ask`) in one place, the homepage's AI and MCP doc; the sites' and the hub's Use-with-AI page removed and its links pointed at the doc; `README.md` §1/§4 and `mcp/README.md` their own copies (as amended) | `homepage/content/docs/ai-and-mcp.md`, `export/app/use-with-ai/` (removed), the Use with AI links (`export/app/components/{Header,MobileMenu,Footer}.tsx`, `export/app/(workspace)/ask/page.tsx`), `common/lib/{project,corpus}.ts` + `common/bin/compose-site.ts` (what named the page), `mcp/README.md`, `README.md` §1/§4 (wording only), `homepage/e2e/docs.spec.ts`, `export/e2e{,-hub}/use-with-ai-link.spec.ts` and the specs that visited the page | | FK | `r16/forms-keep-input` | Every editor form keeps what was typed when its action fails: actions return the submitted values with the error, the shared field helpers seed from them | new `editor/app/lib/formState.ts` + test; `editor/app/components/forms/Field.tsx` and the local `Field`s in `SiteForm.tsx`, `ChannelForm.tsx`; every action that returns `{ok:false,error}`/`{error}` (sites, settings, operations/settingsActions, scheduler, storage, homepageActions, cutReleaseAction, channels, videoActions); the 15 forms the ruling lists; e2e `forms-keep-input.spec.ts` (new) + the existing `sites-crud`, `settings`, `channels` specs; records: `plans/FACTS.md`. As shipped, also `editor/app/components/forms/Controlled.tsx` (new) and one tag swap each in `DurationField`, `SocialLinksField`, `SiteMembershipsSection`, `WorkersField` ("Slice FK, as shipped") | | RM | `r16/move-holds-writers` | A media move holds the channel's writers and mirrors its copy, so a transcription or download during the move cannot fail it | `common/controller/relocateChannelMedia.ts` (+ the saved-video mover if it shares the code) + tests; the lane runners' per-channel skip (`common/controller/autoRunner.ts`, the backfill/digest/normalize/clip-fetch entry points, `common/lib/channelMediaHold.ts`); `common/jobs/jobKinds.ts` (`needsMedia`); the channel page's Storage panel and the rack's reason text; `editor/e2e/relocate*.spec.ts`; records: `plans/FACTS.md`. As shipped, also `common/controller/{channelWriters,relocateDir}.ts` (+ tests), `common/jobs/streamCommand.ts`, `common/views/channelRow.ts`, `editor/app/channels/lib/{mediaBusy,relocationJob}.ts`, `editor/app/storage/lib/{storeBusy,savedVideosJob}.ts`, `editor/app/api/test/stuck-job/route.ts`; the relocate spec is `editor/e2e/channel-storage.spec.ts` ("Slice RM, as shipped") | | XL | `r16/x-login` | Connecting an X account works: the Connect window is the operator's own browser without automation signals, and the fetchers can use the operator's browser login directly (`cookiesFromBrowser`) with no window at all | `common/social/{xSessionBroker,xGalleryDlFetcher,fetchers,playwrightRuntime}.ts` + tests; `common/lib/settingsSchema.ts` (one key) + `SETTINGS.md`; `editor/app/settings/{xSessionActions.ts,components/XSessionSection.tsx}`; `editor/e2e/settings*.spec.ts`; records: `plans/FACTS.md`, `ENVIRONMENT.md` if an env var is added. As shipped, also `common/social/{xBrowser,xCookieSource,xBrowserLogin,nodeSqlite}.ts` and `__fixtures__/firefoxCookieStore.ts` (new), `xPlaywrightFetcher.ts`, `common/controller/fetchPosts.ts` (the source per channel), `common/lib/{settingsDocs,envVars}.ts`, `editor/app/settings/page.tsx`, and `editor/e2e/x-session.spec.ts` — the spec that covers the section ("Slice XL, as shipped") | ## Slice CK — the ruling (2026-09-30) - One row, **"Search in"**, beside the Type row of the Filters panel: **Transcripts** (on), **Posts** (on; the Posts box moves here from the Type row, same storage key `nop`, same accessible name), **Live chat** (off; offered only when the site's subs manifest reports live chat, as Posts is offered only when the site ships posts). - The row governs every query leaf whose scope is "transcripts" (the default leaf): it reads the cues of the kinds ticked. A leaf whose scope is "Live chat" or "Posts" was asked for by name and is not changed by the row. - With all three off the Search button does nothing and the panel says which row to fix; the visitor cannot commit a query that reads nothing. - A live-chat hit inside a video's row wears the "live chat" track badge whenever the visitor could also be seeing transcript hits — the suppression at `SearchResults.tsx` for that one track ends. - Stored like the other toggles (the working snapshot and the profiles, `ytdlp-tb:export-filters`), only when off the default. Share links do not carry the row this release (they do not carry `nop` either); a `qt=` link a visitor opens reads with the visitor's own row. - The hub's search gets the row through the shared components; nothing hub-specific. ## Slice DX — the ruling (2026-09-30, amended by the operator the same evening) - **The setup lives in ONE place: the homepage's AI and MCP doc** (`/docs/ai-and-mcp/`). It tells a visitor who only wants to run Claude Code against a public instance, in one block: get the source (the mirror clone or the tarball on `/downloads/`), `pnpm install`, register the MCP server **as `archilyzer`** against the instance of their choice (`TRANSCRIPT_SITE_URL`; `TRANSCRIPT_HUB_URL` to federate), start `claude`, try `/ask`. Windows → WSL2, one line. The optional editor lines for `fetch_clip`, one sentence. The reason for the name (the shipped `/ask` and `/sweep` call `mcp__archilyzer__…`) sits beside it. What that page already says about the published contract (`/corpus.json`, `/llms.txt`), the MCP server and the honesty features stays. - **The sites' `/use-with-ai` page is removed** (export and hub). Its footer entry, its header entry and the link on Ask AI point at the homepage doc instead (`PROJECT_URL` + `/docs/ai-and-mcp/`, same tab), keeping the label **Use with AI**. Nothing a site said there is lost: the contract lines are on the homepage doc, and a site's own `/llms.txt` still describes the site. Specs that used the page as "another page" (`first-search`, `restore-no-refire`, `responsive`) use `/changelog/` instead. - **The READMEs are their own copies**: `README.md` §1/§4 and `mcp/README.md` say the same steps in the same order and register `archilyzer`; the record notes that the homepage doc and the READMEs are two places to change together (there is no shared source between markdown in `homepage/content` and the repo's READMEs this release). - No code path other than the removed page and its links changes. ## Slice FK — the ruling (2026-10-01) - **A form that fails keeps what was typed.** React resets a `