Archilyzer · Source

archilyzer

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

commit 974fa4e5dd1cc68677bc91f731e9e909e68c6b09
parent 1c92a17816b8a5e883e47936b3c68fb6d11493fb
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 10 Oct 2026 03:10:44 -0400

Merge r20/whisper-fix (Clear failure list keeps its log after the list empties) into r20/integration

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

Diffstat:
Meditor/CHANGELOG.md | 1+
Meditor/app/channels/[slug]/components/stages/TranscribeStage.tsx | 18+++++++++++++-----
Mplans/release-20.md | 12++++++++++++
3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- **"Clear failure list" keeps its log on screen.** On a channel's Transcribe stage, clearing the failed-transcriptions list hid the controls the moment the list emptied, its output ("Cleared N entries") with them. They now stay until the page is reloaded, the button disabled at (0). - **archive.org imports take many items, or a search.** `pnpm ops import-archive-org` now takes `"items"` (identifiers, or `{item, files | match}`) or `"query"` (an archive.org search, its first `"limit"` items) as one job, paced between files and between items. Records already held — on disk or in the saved-video store — are skipped; a dry run lists every file as held, RESTRICTED (archive.org will not hand it out) or would-get; three items in a row refused by archive.org stop the job and back the platform off. - **What an Odysee or BitChute channel lists that it does not hold.** `pnpm ops get remote-listing <slug>` reads the channel's listing once, on the platform's own queue at its pace, and prints the videos listed but not held and the ones held but no longer listed. Nothing is written. - **Cues without an index build.** `pnpm ops build-cues` writes `transcript.cues.json` for a channel (or chosen ids); `pnpm ops get transcript <id>` reads one video's cues off disk; the MCP's `get_transcript` reads a video the archive has not published yet through the editor, marked as such. diff --git a/editor/app/channels/[slug]/components/stages/TranscribeStage.tsx b/editor/app/channels/[slug]/components/stages/TranscribeStage.tsx @@ -395,6 +395,13 @@ function FailedTranscriptionsSection({ const [clearQueue, setClearQueue] = useState(defaultQueueKey); const [confirmText, setConfirmText] = useState(""); const armed = confirmText === "clear"; + // A CLEAR EMPTIES ITS OWN LIST, and the controls must outlive that + // (plans/FACTS.md, "A run log lives in the panel's React state"). The run's + // refresh re-renders this section with no ids; gating the block on + // `ids.length` alone unmounted the StreamActionLog and its "Cleared N + // entries" with it. `ran` keeps the block for the rest of this page's life, + // its button disabled at (0); a reload drops it as before. + const [ran, setRan] = useState(false); return ( <div aria-label="failed transcriptions section" @@ -418,7 +425,7 @@ function FailedTranscriptionsSection({ emptyMessage="No failed transcriptions." itemAriaLabel={(id) => `failed transcription ${id}`} /> - {ids.length > 0 ? ( + {ids.length > 0 || ran ? ( <div className="flex flex-col gap-2"> <label className="flex items-center gap-2 text-xs text-muted-foreground"> Type @@ -433,14 +440,15 @@ function FailedTranscriptionsSection({ /> </label> <StreamActionLog - trigger={() => - clearFailedTranscriptionsAction(slug, clearQueue) - } + trigger={() => { + setRan(true); + return clearFailedTranscriptionsAction(slug, clearQueue); + }} cancelAction={cancelJobAction} buttonLabel={`Clear failure list (${ids.length})`} runningLabel="Clearing…" label="Clear failed transcriptions" - disabled={!armed} + disabled={!armed || ids.length === 0} extraControls={ <QueueControl value={clearQueue} diff --git a/plans/release-20.md b/plans/release-20.md @@ -128,4 +128,16 @@ after the upload dropped; a changed rule re-derives once, a removed one drops th (release 21 D2's tests included), and after the revert the touched index, normalize, caption-track and architecture tests 54/54, tsc clean; editor unit 228/228; export unit 118/118; mcp 293/293; `archilyzer docs files --check` and `docs env --check` clean. E2E, one run in the foreground (start of the queue after the heavy slot freed): `transcript-source.spec.ts` (D3's index spec, 4) and `ops-api.spec.ts` (13, the channel-config round trip among them) — 17 passed, 1.5 min. Release end per the plan: the full editor suite once, the orchestrator's. +## As it went + +**The whisper red: "Clear failure list" unmounted its own log** (`r20/whisper-fix`). `whisper.spec.ts:184` +failed 3/3 as a whole file on `r20/integration` in start mode (it passed alone with `-g`, and in release 19's dev +runs). Not a release 20/21 regression and not the harness: `FailedTranscriptionsSection` (TranscribeStage.tsx) +rendered the clear controls — the `StreamActionLog` among them — only while `ids.length > 0`, so the refresh +`StreamActionLog` fires at the end of its own run re-rendered the section with an empty list and dropped the log +with "Cleared 2 entries" in it, the case plans/FACTS.md's "A run log lives in the panel's React state" rules out. +Under `next dev` the slow refresh left the text up long enough for the assertion; `next start`'s fast one did not. +The fix is DiagnosticsStage's: a `ran` flag set on click keeps the block mounted for the page's life, its button +disabled at (0). Whole file 10/10 three runs in start mode; tsc clean; editor unit 237/237. + ## Rollout