commit d41d745959f3dc2cd76a0222afe089cf7ed5f5c8
parent 6f2d48322fbb80c12c42cdd03040f6784a49d62c
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 24 Sep 2026 19:22:57 -0400
plans: visitor exports off on the published sites — inventory and slice, scheduled after release 4
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 51 insertions(+), 0 deletions(-)
diff --git a/plans/site-exports-off.md b/plans/site-exports-off.md
@@ -0,0 +1,51 @@
+# Plan — visitor exports off on the published sites, kept as an option for the OSS release
+
+**Asked 2026-09-24** (operator, mid release 4): turn off "exports" on every existing published
+site to strengthen the legal footing of the operator's own instances, while keeping the
+capability as a per-site option so anyone running the OSS release can leave it on. Scheduled as
+the release AFTER one-core Phase 3 release 4 (it needs a rebuild + deploy of the five published
+sites, and Phase 3's slices are already cut). Inventory below was taken on `4130aca1`
+(2026-09-24, one Explore pass); re-verify the path:line anchors before cutting the slice.
+
+## What a visitor can export from a published site today
+
+| Surface | Where | Switch today |
+|---|---|---|
+| Downloads page: whole-channel `.zip` of transcripts + live chat, its nav and footer links | `export/app/downloads/page.tsx`, `export/app/components/Header.tsx:39,49`, `Footer.tsx:38,44-50`; zips built by `common/bin/build-archives.ts` | `site.archives` (`common/lib/siteSchema.ts:86`, SITE.md), absent = **on** |
+| Offline / PWA whole-channel cache in the browser | `export/app/components/OfflineManager.tsx`, `export/app/offline/page.tsx` | `site.pwa`, default **off** |
+| Duplicates page (bulk cluster listing) | `export/app/duplicates/**` | `site.duplicates`, absent = on |
+| Per-video **Download** menu (txt / srt / json), **Copy MD**, **Copy download command** (a `yt-dlp --download-sections` string; the site never serves media) | `common/components/TranscriptModal.tsx:405-500`, impl `common/components/PlayerProvider.tsx:480-572` — client-side from cues already in the browser | **none** — unconditional on every build |
+| Machine contract: `/corpus.json`, `/llms.txt`, tree manifests, `page-<NNNN>.json` shards, `robots.txt`, `sitemap.xml` | written by `common/bin/compose-site.ts:158-185`; URL contract `common/lib/archive/contract.ts` | none, and must **stay unconditional**: the MCP server (`common/lib/archive/reader.ts` `RemoteSource`, `mcp/src/sourceRegistry.ts`) and `umtool/report-to-video/cues.mjs` walk it over HTTP — it is the "no local corpus" research mode `AGENTS.md` promises |
+
+None of the six `transcripts/sites/*/site.json` files sets `archives`, `pwa` or `duplicates`
+today, so every published site ships the zip Downloads page and the in-modal buttons.
+
+## The slice
+
+1. **One new `site.json` key**, `transcriptDownloads` (name to settle at planning; boolean,
+ absent = **on**, so the OSS default is unchanged and the operator opts out per site), declared
+ in `common/lib/siteSchema.ts` beside `archives` and regenerated into `SITE.md`
+ (`file-schemas-docs.ts --check` stays green). It gates the three in-modal actions (Download
+ menu, Copy MD, Copy download command) on the export site only. `TranscriptModal` is shared with
+ the editor, so the gate is a prop the export site derives from `currentSite()`
+ (`export/app/lib/site.ts`); the editor keeps every button.
+2. **`archives: false`** on the operator's sites — the existing switch; no code.
+3. Nothing changes for `/corpus.json`, `llms.txt`, manifests or shards. The `llms.txt` prose and
+ `use-with-ai` page (`export/app/use-with-ai/page.tsx:128-136`) already hide the Downloads link
+ when archives are off; check the prose does not still promise zips.
+4. **Site form + `pnpm ops`**: the two new/used keys are set through `writeSite` (the site's
+ Publish tab or `pnpm ops site-config`), never by editing `site.json` by hand.
+5. **Rollout**: for each of the five published sites (jeralyzer, rekietalyzer, hasanalyzer,
+ anilyzer, bonnellyzer; jasolyzer has no `siteUrl`), set `archives: false` +
+ `transcriptDownloads: false`, then `build-site` + `deploy-site` — five independent runs; the
+ archives volume can be pruned afterwards. Verify per site: no `/downloads` link, no Download menu
+ in a transcript modal, `/corpus.json` and one `page-0001.json` still 200.
+6. **Tests**: export e2e for the gated modal (buttons present with the key absent, absent with it
+ false), the existing archives-off coverage, a schema round-trip in `phase3-files-numbers.ts`
+ (unknown-key check must not flag the new key on either side).
+
+Out of scope, stated: gating the machine contract (breaks the MCP and report-to-video), removing
+"Copy share link" (not an export), umtool's clip fetching (operator tooling, not visitor-facing).
+
+Open for the operator: whether the Duplicates page counts as an export (it lists, it does not
+serve data) and whether the hub (`_homepage`) needs the same key.