Archilyzer · Source

archilyzer

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

commit 607987760fea9b28cf9e94737ff76b187e1bad2b
parent e99effb6bd1d8876325d484478afb94b1ae41480
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu, 24 Sep 2026 22:38:11 -0400

plans: release 5 slice R — review fixes in the record (commit table, gates, retry cadence, umtool follow-up)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Mplans/release-5.md | 35+++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/plans/release-5.md b/plans/release-5.md @@ -144,7 +144,7 @@ STATE. umtool: rebuild only if `git diff --stat <live>..<new> -- umtool` is non- ### Slice R, as shipped — Rumble: impersonation everywhere, paced sweeps, incomplete ≠ failed (2026-09-24) -Branch `one-core/r5-rumble` off `main` `f4da04a9`, four commits, unmerged. Every Rumble request +Branch `one-core/r5-rumble` off `main` `f4da04a9`, seven commits (four, then three after review), unmerged. Every Rumble request 403s at Cloudflare without a browser TLS fingerprint (yt-dlp #17496), and the `the-quartering-rumble` full sweep 429'd at page 155 and failed the whole sync every time for 44 days. There is now one arg builder with a platform table, and a 429 part-way through a full @@ -155,7 +155,10 @@ enumeration is *incomplete*: cooldown recorded, one log line, the paged walk run | `bca929a1` | `common/ytdlp/channelArgs.ts`: `PLATFORM_ARGS` (`rumble: --impersonate chrome --sleep-requests 1`, comment names #17496 and the 2026-09-24 probe), `platformArgs(platform)`, `channelPlatform(config)` = `config.platform ?? detectPlatform(config.url)`; `channelExtraArgs` = cookies → platform args → `ytdlpExtraArgs` (override last, wins). `configArgs` (runYtdlp) delegates to it; the metadata scan's and `checkAvailability`'s inline copies call it (`checkAvailability` falls back to `cookieArgs` only when the channel has no config); `probeChannelMeta` gets `platformArgs(detectPlatform(url))` — `detectPlatform("https://rumble.com/c/…")` is `"rumble"` (host suffix). `channelArgs.test.ts` (5) | | `0a4b9999` | `EnumerationIncompleteError {platform, pagesReached, count}` + `lastListingPage(stderr)` (last `Downloading page N` — the real wording is `[RumbleChannel] TheQuartering: Downloading page 155`, job `01M3AVGZC5EZ9GCD04R9QW6NWX`). `enumeratePlaylistUrls` classifies a non-0/101 exit's buffered stderr with `classifyDownloadFailure`; `rate_limit` → the typed error (message still starts `yt-dlp exited with code N`), anything else → the plain error as before. `syncFullSweep` catches it before `acceptEnumeration`, calls `opts.onPlatformBackoff?.("rate_limit")` (= `recordDownloadBackoff(platform, paths)`, wired by `pipelineActions.ts:215`, the same helper and `nextBackoff` schedule a download's 429 uses), logs `Full sweep incomplete: 429 at page N of the listing, M entries — not a listing; next syncs are paged walks until the rumble cooldown ends.`, then `return syncPaged(opts)`. No playlist write, no missing set, no `lastFullSweepAt`. `fullSweepDue` is now exported, async, and false while `platformCooldownRemainingMs(detectPlatform(url) ?? "unknown")` > 0 — the Sync gate's key. `sweepIncomplete.test.ts` (4) | | `84788fff` | Fake yt-dlp: every `--flat-playlist --print url` records `flat-playlist:full\|paged argv=<whole argv>` in `fake-ytdlp.invocations` (no argv log existed for enumeration; the per-cwd invocations file is the fixture's existing record, so no new env var); `sweep429` sentinel — a full enumeration prints 3 pages × 5 urls with RumbleChannel page lines on stderr, then the real 429 `ERROR:` line, exit 1; a paged walk (`-I`) lists normally. New `rumble-sweep.spec.ts` | -| (this) | record, `[Unreleased]` bullet, superseded note on `plans/rumble-sweep-pacing.md` | +| `7b50cb45` | record, `[Unreleased]` bullet, superseded note on `plans/rumble-sweep-pacing.md` | +| `c145f7df` | Review fixes: the cooldown write in the incomplete branch is best-effort (try/catch as on the download path; a failure logs `Warning: could not record the <platform> cooldown …` and the paged walk still runs); the log line now reads `… M entries — not a listing. Ran the paged walk instead; syncs wait for the rumble cooldown, then the sweep is retried.` (syncs are REFUSED during the cooldown, `pipelineActions.ts:133-145`); enumeration comment back above `enumeratePlaylistUrls`, the error class has its own one-liner; `checkAvailability` adds `platformArgs(detectPlatform(url))` when the channel has no config (no unit test file exists for it) | +| `a70df836` | `classifyDownloadFailure`: `/http error 403/` joins the `network` group, so a bare `HTTP Error 403: Forbidden` backs the platform off — no new class, no `download-outcome.json` change. New `common/lib/availability.test.ts` (1). Changelog bullet reworded to match | +| (this) | record: commit table, gates, caveats | **Gates.** tsc (`pnpm -r … exec tsc --noEmit`) clean at every commit. common **1747** (1738 + 9 new), editor unit **72**, test:scripts **156 + 1 skip**, mcp **219**. `next build` editor and export both @@ -166,24 +169,40 @@ new-channel-onboarding`): **82 passed, 1 failed, 7.8 min** (after 8 min in the q failure is `pipeline.spec.ts:164`, `EEXIST: mkdir …/test-transcripts/channels` inside `resetData`'s `cp` at `helpers.ts:69` (a fixture-reset race before the test body ran, 301 ms); rerun `pipeline.spec.ts rumble-sweep.spec.ts`: **8 passed, 56 s**. `fetch-window.spec.ts`'s 429 → -cooldown test green. Numbers: none (no file format changes). +cooldown test green. **After review** (`c145f7df`, `a70df836`): tsc clean per commit; common +**1748** (+1); editor unit **72**; `next build` editor and export green; e2e `rumble-sweep +availability availability-backfill queues fetch-window pipeline`: **33 passed, 0 failed, +2.5 min** (after ~7 min in the queue). Numbers: none (no file format changes). **Found and left.** -- **403 has no classification (item 4, not done).** `DownloadFailureClass` is not cheap to widen: +- **403 has no class of its own (item 4, partly done).** `DownloadFailureClass` is not cheap to widen: it is persisted in every per-video `download-outcome.json` (`common/lib/downloadOutcome.ts:105` — a new value is a sidecar format change), and it is a decision in the auto-runner (`autoRunner.ts:1941-1944`, backoff on `rate_limit | network`), in `runYtdlp.ts` (backoff + `abortOnError`, the managed-download loop ~:1029-1051) and in `downloadOneManaged.ts:1372` - (where it is produced). Today a Cloudflare 403 reads as `network` only because yt-dlp's - traceback matches `/ssl/`, so it does back off the platform. With `--impersonate` the 403 - should stop occurring; if it recurs, a `blocked` class wants its own decision (no backoff, a - sentence on the channel), not a pattern. + (where it is produced). Before `a70df836` a Cloudflare 403 read as `network` only when the + traceback happened to contain "ssl" (the 2026-09-24 job did; a bare `HTTP Error 403: + Forbidden` did not, and read `unknown`). It is now in the `network` group, so it backs the + platform off. With `--impersonate` the 403 should stop occurring; if it recurs, a `blocked` + class wants its own decision (no backoff, a sentence on the channel), not a pattern. - **The metadata scan passes `--sleep-requests 1` twice for Rumble** (its own, then the platform table's). Harmless (same value, last wins); left so the scan's own pacing stays for every platform. - **The paged walk can also 429.** A `rate_limit` on a ranged page throws the typed error out of `syncPaged`, and the sync fails exactly as before (its message is unchanged in prefix). The fallback deliberately runs only once per sync. +- **Retry cadence after an incomplete sweep.** No last-attempt stamp is kept: once the platform + cooldown ends (`nextBackoff`: 1 min, doubling, at most 30 min — `platformBackoff.ts:22-37`) the + sweep is due again on the next sync, and any successful Rumble download clears the escalation + (`clearBackoff`, `autoRunner.ts:1957`), so it restarts at 1 min. If live sweeps keep coming back + incomplete, a `lastFullSweepAttemptAt` (retry no sooner than N hours) is the follow-up. +- **Outside the slice: umtool still spawns yt-dlp without `--impersonate`.** + `umtool/report-to-video/build-video.mjs` (`YTDLP` at :75) and `check-availability.mjs` (:32) + build their own argv, so Rumble clip fetches and availability checks there will still 403. + (The editor's clip-window fetch, `fetchWindowManaged.ts`, is covered.) +- **`pipeline.spec.ts:164` EEXIST reset race** — first sighting: `resetData`'s `cp` hit + `EEXIST: mkdir …/test-transcripts/channels` (`helpers.ts:69`) before the test body; green on + rerun and in the post-review run. Watch for a second sighting. - **Commit trailers** name `Claude Opus 5.5 (1M context)` — the model that wrote them — not the `Claude Fable 5.1` line in `plans/tools/implementer-rules.md`.