commit 1677e2d1e7c45a32bdebcfa38e62adb877133d7a
parent 6f39ed08594451fe04fae88633c2c5b91efd3bd0
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 00:55:34 -0400
plans: release 6 Phase 4 slice 1 — record and changelog
The "Phase 4 slice 1, as shipped" record in plans/release-6.md, one
[Unreleased] bullet, and FACTS.md's PREVIEW_SHARES_ARCHIVES_NOTICE path
pointing at common/publish/build.ts.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md
@@ -4,6 +4,7 @@
- **A video the server answers with HTTP 410 Gone is recorded as removed, not as an error.** Rumble answers a taken-down video with `HTTP Error 410: Gone`; the availability check read that as a generic error (one Rekieta Law Rumble video has said "error" since 2026-08-21), and a download that hit it could stop the batch. It now reads as removed, like "Video unavailable" does, so the check says so and a download skips that one video and carries on. Existing records change the next time the video is checked.
- **umtool's report videos can fetch Rumble clips again.** The clip fetch and the source availability check in `umtool/report-to-video` ran yt-dlp without the browser fingerprint Rumble now requires, so every Rumble clip failed with 403 and every Rumble source looked missing. They now pass the same Rumble arguments as the editor, from the same single table.
- **A transcript pulled back from a remote worker is written safely.** It used to be written straight onto `transcript.json`, so a crash part-way through left a truncated transcript; it now goes through the editor's one atomic write (temp file, then rename), like every other file the editor writes.
+- **Nothing changes when you build or deploy a site; the code that does it has moved into the shared core.** The site build, the docker per-site fan-out, the R2 archive upload and the Cloudflare Pages deploy used to live inside the editor. They are now `common/publish/build.ts`, with the same log lines, exit codes and output paths, so a later command-line tool can build and deploy without the editor. The editor's Build, Deploy and Build & deploy controls and `pnpm ops build-site` / `build-deploy` / `deploy-site` call them as before. The AWS SDK packages used for the R2 upload moved with the code, from the editor's dependencies to the core's.
- **Rumble works again, and a Rumble full sweep that gets rate-limited no longer fails the sync.** Every Rumble request had started coming back 403 from Cloudflare unless yt-dlp presents a browser fingerprint (yt-dlp #17496), so Rumble downloads failed and a Rumble channel could not even be added. Every yt-dlp run for a Rumble channel — sync, download, metadata scan, availability check, the clip-window fetch and the new-channel probe — now passes `--impersonate chrome --sleep-requests 1`, from one table in the code; a channel's own extra yt-dlp arguments still come last and still win. Separately, a full sweep that hits HTTP 429 part-way through the listing used to fail the whole sync and try again on the next one, so a large channel (The Quartering on Rumble, 44 days) never synced at all. What it read is now treated as *incomplete* — not a listing, so nothing is flagged missing and the stored playlist is untouched: the job records the platform's rate-limit cooldown, says "sweep incomplete: 429 at page N of the listing, M entries" in its log, does the ordinary newest-first sync instead, and succeeds. Syncs for that platform are then refused until its cooldown ends, and the full sweep is tried again after that. Any other yt-dlp failure still fails the sync as before.
- **A site can turn off its visitors' per-video transcript downloads.** The transcript viewer on a published site has always offered three ways to take a video's text away: a **Download** menu (txt, srt, json), **Copy MD**, and **Copy download command** (a `yt-dlp` line for a marked clip). A site's settings form now has a checkbox for them, *Per-video transcript downloads*, beside the archive zips one. Unticked, the site's next build shows none of the three; **Share** and the clip marks stay. It is on by default, so a site nobody touches is unchanged, and the file stores `"transcriptDownloads": false` only when it is off (`SITE.md` has the key). The site's machine contract (`/corpus.json`, `llms.txt`, the manifests and shards the MCP server and report-to-video read) is published either way. The hub follows the same switch: the hub form on **Sites** has the same checkbox, stored as `"transcriptDownloads": false` in the hub's `homepage.json`, and it hides the three controls on the hub's Browse and Ask pages. The editor's own video pages are unaffected.
- **Channel rows no longer scroll over a group's controls on `/channels`.** Scrolled down and to the right, the pinned Slug column of every row painted over the pinned group header and its five station buttons (Sync, Download, Transcribe, Digest and the speaker lane), and took the clicks. The pinned Slug cell and the group header sat at the same stacking level, and the later rows won. The rack now has one named layer order, kept in one file: the Advanced panel, then the column header, then the group header, then the pinned checkbox and Slug cells. Nothing ties any more. The screenshot audit found four more problems, fixed as well. A group header's name and buttons now stay on screen however far the columns scroll across (they used to scroll off to the left). An Advanced panel opened near the bottom or the right edge scrolls itself into view instead of being cut off. The rule above a pinned group header moves with it instead of leaving a gap the rows showed through. On a phone, the column header no longer paints over the selection bar pinned to the bottom of the screen.
diff --git a/plans/FACTS.md b/plans/FACTS.md
@@ -5318,7 +5318,7 @@ file). On exit 0 the job log gets ONE line: `[preview] <alias> (this deployment:
namespace and the keys are `<siteId>/archives/<file>.zip` either way. Cheap in
practice (the upload skips any object R2 already holds at the same size), but a
*changed* archive replaces the one production's manifest links to.
-`PREVIEW_SHARES_ARCHIVES_NOTICE` (`editor/app/sites/lib/buildDeployCore.ts`) is
+`PREVIEW_SHARES_ARCHIVES_NOTICE` (`common/publish/build.ts`, moved from the editor in one-core Phase 4 slice 1) is
logged once at the top of every preview deploy, by both actions.
**Three surfaces, one rule.** `deployExportAction(siteId, { previewBranch })` and
diff --git a/plans/release-6.md b/plans/release-6.md
@@ -45,3 +45,56 @@ queue. Numbers: **none**. No file format changed; `availability.json` keeps its
is the same for routes this commit did not touch. The state-tree encoding may have drifted with
Next 16.2; this commit only replaced the paths, so it was not investigated.
- **Commit trailers** name `Claude Opus 5.5 (1M context)`, as in release 5.
+
+### Phase 4 slice 1, as shipped — `buildDeployCore` to the core as `common/publish/build.ts` (2026-09-25)
+
+Branch `one-core/phase-4-s1` off `main` `93dcb532`; `main` moved to `4d97049f` (the follow-ups
+slice) mid-slice and was merged before the final gates. `editor/app/sites/lib/buildDeployCore.ts`
+(578 lines) imported nothing from `editor/**`, so it moved **unchanged** to
+`common/publish/build.ts`, the path `one-core.md` Phase 4 item 1 names. Only its header comment
+and its three `yt-dlp-transcript-common/*` imports (now relative, `../jobs`, `../lib`, as the rest
+of common writes them) changed. Every export, log line, exit code and path is the same. No helper
+had to come down from the editor with it.
+
+| sha | what |
+|---|---|
+| `9cb35c37` | `git mv` to `common/publish/build.ts`. `sites/lib/buildAction.ts` and `deployAction.ts` import `yt-dlp-transcript-common/publish/build`. **No re-export is left at the old path**: no spec, script or tool imports it (`git grep buildDeployCore` finds only docs and plans). `@aws-sdk/client-s3` and `@aws-sdk/lib-storage` (`^3.1080.0`) move from `editor/package.json` to common's `dependencies`. As in the follow-ups slice, a plain `pnpm install` re-resolved unrelated peer suffixes (`supports-color`), so the lockfile change was applied by hand (the two importer entries move from `editor:` to `common:`, 12 lines) and verified with `pnpm install --frozen-lockfile`. `common/package.json` also gains `"./publish/*": "./publish/*.ts"` in `exports` (the editor resolves common through `exports`, so the new directory needs its own pattern) and `publish` in the `test` glob. `architecture.test.ts` learns the layer: `publish/` may not import `views/` or `components/`, and `lib/` and `components/` may not import `publish/`. No back-edge was found and `ALLOWED` did not grow. New `publish/build.test.ts` (3) pins `resolveOutDir`, `dockerSiteOutDir` and `dockerSiteStagingDir`. `DEPLOY_CLOUDFLARE.md`'s pointer for `ARCHIVE_CACHE_CONTROL` (it still named the pre-IA `editor/app/deploy/` path) names the new home |
+| `2a31a863` | merge `main` `4d97049f` (release 6 follow-ups). Clean: that slice's `exports` lines sit between `./components/*` and `./lib/*`, and this one sits after `./views/*`. Then `pnpm install --frozen-lockfile` to create the new umtool → common link (`--offline` failed for want of cached metadata for `@next/env`; the online frozen install changed nothing on disk in git) |
+| *(this commit)* | this record, the `[Unreleased]` bullet, `plans/FACTS.md`'s `PREVIEW_SHARES_ARCHIVES_NOTICE` path |
+
+**Gates** on the merged tree (`2a31a863`, worktree root). tsc
+(`pnpm -r --no-bail --workspace-concurrency=1 exec tsc --noEmit`) clean, and clean before
+`9cb35c37` too. common **1754/1754**: 1750 + 1 (follow-ups) + 3 (`publish/build.test.ts`); it was
+1753 before the merge. Editor unit **72/72**. test:scripts **159 pass + 1 skip** (the follow-ups
+count). mcp **219/219**. `pnpm --filter editor exec next build` ok (compiled in 18.6 s), and it
+bundles `@aws-sdk/*` from `common/node_modules` now that editor no longer depends on it.
+`pnpm --filter export exec next build` ok (7.8 s). The worktree's `export/public/archives` link
+was dangling (the primary has no `archives/` at the moment), so it was removed before the builds.
+EDITOR e2e `build deploy-page site-publish-preview sites-crud cut-release channel-build-toggle`
+(all six exist; `$T/p4-specs.txt`): **29 passed, 0 failed, 1.8 min**, with no wait in the queue.
+Numbers: `plans/tools/phase3-files-numbers.ts` over one frozen copy of the corpus
+(`FREEZE_TO`, 71 configs, 1,763 sidecars), `main` `93dcb532` against this branch (both
+before and after the merge): **diff empty** (3,858 lines each). `pnpm ops build-site` /
+`build-deploy` / `deploy-site` post to `editor/app/api/ops/*`, which call the same actions. They
+compile in the editor build and were not run, because a real build against the corpus is
+forbidden.
+
+**Left from Phase 4 item 1, by name.** The brief scoped this slice to the move. What `one-core.md`
+item 1 also lists is still to do, and most of it needs item 2's CLI first:
+- the named entry points `buildSite(id, opts)`, `deploySite`, `buildAll(mode)`, `composeHub` and
+ `composeHomepage`. The orchestration that would become them (`runManagedFunction` jobs, the
+ docker fallback, per-site queues) still lives in the editor's `"use server"`
+ `sites/lib/buildAction.ts` / `deployAction.ts`;
+- `docker/build-site.sh` and `publish-site.sh` calling the CLI;
+- export's `build` / `build:nodata` twins becoming one script with `--nodata`;
+- `build:hub` getting a CLI and an editor entry.
+
+**Found and left.**
+- **`common/package.json` `exports` was on the list of files owned by the follow-ups slice.** The
+ one-line `./publish/*` addition cannot be avoided if the spec's `common/publish/` path is kept:
+ the editor resolves common through `exports`. It was made anyway and is its own line. `git
+ merge-tree` against `one-core/r6-followups` was clean before that slice landed, and the real
+ merge was clean too.
+- `plans/STATE.md` still says Phase 4 is next and that `buildDeployCore.ts` imports nothing from
+ the editor (`:73`, `:1485`). Status is the parent's to write, so those lines were not edited.
+- **Commit trailers** name `Claude Opus 5.5 (1M context)`, as in release 5.