commit 6df0de3d7dcd280509c72182fadd782673685fb4
parent 203456bbdf419d85b6808015c8394576082c6dfc
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 2 Oct 2026 01:23:57 -0400
plans: slice RL — the review (H1, H2, L1–L5, N9, N10 → commits), the rollout line, FACTS, the re-gate
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
1 file changed, 47 insertions(+), 3 deletions(-)
diff --git a/plans/release-17.md b/plans/release-17.md
@@ -1638,10 +1638,54 @@ build drops the three keys on its next write, so a rollback is safe. Privacy gat
- The runner merges only `platformBackoff` from disk mid-run, as before; pace and holds written from
outside go through the live object (`mutateDownloadState`), and a disk-only write while no runner
lives is read at the runner's start.
-- At the rollout the live backoff reads `fails: 80`: unless the boot finds it lapsed for over 30 min
- (then it is pruned, as before), the first platform-level failure after the boot holds YouTube at
- once; a subtitle 429 no longer counts, and the first clean unit clears the backoff.
+- **Rollout:** the live backoff reads `fails: 80` (the subtitle 429s this slice stops counting).
+ Unless the boot finds it lapsed for over 30 min (then it is pruned, as before), the first real
+ platform-level failure after the restart holds YouTube at once. **Clear hold** on
+ `/operations/download` is the way out (it drops the hold, the backoff and the pace and says so in a
+ `clear-platform-hold` job log); a clean lane unit, or a clean manual Sync once the probe is due,
+ clears it too. The changelog bullet says the same.
- **Open question for the operator** (not probed): whether YouTube's timedtext 429 for these twelve
videos is a PO-token / player-client matter (`--extractor-args youtube:player_client=…`).
+#### Review (2026-10-01): SHIP AFTER FIXES → fixes
+
+| finding | fix |
+|---|---|
+| **H1** — under `--ignore-errors` EVERY subtitle failure exits 0 (a 403/404/5xx, a failed `live_chat` replay, an OSError writing the file) and ended `ok`, archived, with no transcript and no media, and counted as a clean lane unit | `5de4e385`: `hasNonRateLimitSubtitleFailure` (`lib/availability.ts`); a youtube primary that exited 0 with such a WARNING is a failed attempt, as before — `lastSucceeded` false, no media pass, no archive line, its error and class from the tail (a 403 → `network`, a `live_chat` 404 → `unknown`). Only a subtitle 429 takes the media path. Unit cases for a 403 and a `live_chat` failure (`subtitleRateLimit.test.ts`). FACTS' `--ignore-errors` bullet says "any subtitle failure" |
+| **H2** — a hold ended only with a lane probe; with the lane off or nothing pending it was permanent, Sync and scheduled syncs stayed refused, the page dropped the platform once the probe was overdue, and the refusal said "next probe in 1 min" for ever | `f003e29e`: `heldPlatformRefusal` refuses only while held AND before the probe time (as `fetchWindowAction` already did); `runYtdlp`'s new `onPlatformClean` (wired in `pipelineActions.ts`) and a clean metadata scan call `recordPlatformClean`, which settles the platform like a clean probe (backoff and hold clear) and logs it; `clearPlatformHold` drops hold + backoff + pace. The status view keeps a held platform whatever its probe time. `c2cc1228`: "Platforms held" says "probe overdue — the lane is off" (or "probe due — it waits for a pending video") and each row has **Clear hold**, run as a one-step `clear-platform-hold` job on queue `pacing:<pf>` whose log says what was cleared. e2e: an overdue hold with the lane off is shown, a Sync is not refused, and its clean run lifts the hold; Clear hold empties hold, backoff and pace |
+| L1 — a held probe whose media came down but whose subtitles 429'd did not lift the hold | `f003e29e`: it lifts the hold and the backoff, and does not count toward the pace's easing (`countForDecay: false`) |
+| L2 — the pace only eased on lane units | `f003e29e`: **the one time-based rule** — a raised pace eases one step per hour with no rate limit (`steppedAt`, `PACE_TIME_DECAY_MS`); readers (the args builder, the view, the doctor) apply it through `effectivePaceSeconds`, writers through `decayPaceByTime` |
+| L3 — Download missing subs ran back to back | `f003e29e`: it waits `downloadGapMs(sleepBetweenDownloadsSeconds, pace, base)` between videos |
+| L4 — the `fails: 80` rollout hazard was in the record only | the changelog bullet and the record's rollout bullet both say it, and that Clear hold is the way out |
+| L5 — a hold reached through network failures read as a rate limit | `f003e29e`: the hold carries `rateLimited`; the sentence, the list and the doctor say "failing (network errors)" for such a hold |
+| N9 — a WARNING webpage 429 beside a subtitle 429 read as subtitles-only | `5de4e385`: every 429 / too-many-requests line must be a subtitle line, and no non-429 subtitle failure may be present |
+| N10 — "YouTube's subtitles" on surfaces that match any platform | `c2cc1228`: the list heading and the video-page line say "the subtitles" |
+
+One more fix commit, `7e59c61f`: Clear hold's sentence lived inside the region it empties, so a clear
+that left nothing to list unmounted it; it now lives on the lane view (found by run 7).
+
+**Re-gate** (tip `7e59c61f`; the ruled list `rate-limit.spec video-page.spec auto-queue.spec
+lane-runner.spec`, `$T/RL-specs-fix.txt`). tsc clean before every commit. common **2638 tests, 2610
+pass, 0 fail, 28 skipped** (the 28 are `main`'s T1 mover cases; 8 new: `subtitleRateLimit` +2,
+`unitOutcome` +3 and one rewritten, `downloadBackoff` +2, `availability` +1, `autoQueueStatus` +1).
+Editor unit **109/109**. EDITOR e2e:
+- run 7 (`RL-e2e7.log`, `c2cc1228`): **53 passed, 1 failed, 4 min** — the new Clear hold test (the
+ sentence unmounted with the region), fixed in `7e59c61f`;
+- run 8 (`RL-e2e8.log`, `7e59c61f`, `rate-limit.spec` alone): **5 passed, 0 failed, 4 min** (≈3.5 in the
+ queue);
+- run 9 (`RL-e2e9.log`, `7e59c61f`, the ruled list): **54 passed, 0 failed, 2 min**.
+test:scripts, the build and the full suite were not rerun, as ruled (the fixes touch no `scripts/` or
+umtool file; the new client code is covered by tsc and the e2e above).
+
+**Left, recorded only (follow-ups).**
+- The video page's own download, the re-acquire backfill and import neither record nor clear a
+ subtitle deferral, so the page's "Left alone … until" note can be stale after a page download fetched
+ the subtitles (review item 7).
+- `pacingPlatformKey` reads `detectPlatform(url)` while the base pace reads `channelPlatform(config)`
+ (`config.platform` first); they can disagree for a channel whose `platform` differs from its URL
+ (N11). `pacing` has no `/settings` form.
+- umtool's own spawns (`check-availability.mjs`, `build-video.mjs` through `platformArgsForUrl`) run in
+ a separate process and stay at the fixed pace: "every spawn" means every spawn of the editor and the
+ CLI (N12).
+
## Rollout