Archilyzer · Source

archilyzer

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

commit a826ba0c86cac9bc046e8e4c418fc655ad715807
parent 8c576dbf23b74da43352f45ad4e9416364877362
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue, 29 Sep 2026 23:36:45 -0400

editor: review L1, L3 — the channel page's statfs of the drive goes through the watchdog; the comments name the detectors as they are

- L1: the Storage stage's free space for a relocated channel is read through
  `onDrive(media.target, …)` and shows "—" when refused or given up on.
- L3: /channels, /storage's page shell and its Refresh action no longer say a
  child stat is what asks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Meditor/app/channels/[slug]/components/stages/StorageStage.tsx | 5+++--
Meditor/app/channels/[slug]/page.tsx | 18+++++++++++++++++-
Meditor/app/channels/page.tsx | 3++-
Meditor/app/storage/actions.ts | 10++++++----
Meditor/app/storage/buildStorage.ts | 5+++--
5 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/editor/app/channels/[slug]/components/stages/StorageStage.tsx b/editor/app/channels/[slug]/components/stages/StorageStage.tsx @@ -93,7 +93,8 @@ type Props = { clipsBytes: number | null; // Free space on the volume the media is on RIGHT NOW — the platter for a // relocated channel, the corpus disk otherwise. - freeBytes: number; + // Null when the drive did not answer the statfs ("—"). + freeBytes: number | null; volumeDir: string; // Why both buttons are off, or null when they are live. Running/queued jobs // for this channel, or a relocation marker left by an interrupted move. @@ -151,7 +152,7 @@ export function StorageStage({ </dd> <dt className="text-muted-foreground">Free on that volume</dt> <dd aria-label="free on media volume"> - {formatBytes(freeBytes)}{" "} + {freeBytes === null ? "—" : formatBytes(freeBytes)}{" "} <span className="text-xs text-muted-foreground font-mono"> ({volumeDir}) </span> diff --git a/editor/app/channels/[slug]/page.tsx b/editor/app/channels/[slug]/page.tsx @@ -45,6 +45,10 @@ import { inspectChannelMedia, } from "yt-dlp-transcript-common/lib/channelMedia"; import { MediaNotAnswering } from "./components/MediaNotAnswering"; +import { + isDriveNotAnswering, + onDrive, +} from "yt-dlp-transcript-common/lib/storageHealth"; import { getFreeBytes } from "yt-dlp-transcript-common/lib/diskSpace"; import { platformQueueKey, @@ -612,7 +616,19 @@ export default async function ChannelDetailPage({ // marker — reading the file again here was a second read of the same // bytes that could disagree with the status rendered beside it. const marker = media.marker ?? null; - const freeBytes = await getFreeBytes(volumeDir); + // A statfs of the channel's drive goes through the watchdog + // (lib/storageHealth.ts): refused on a stalled location, given up on + // after 3 s, and read "—" either way. + let freeBytes: number | null; + try { + freeBytes = + volumeDir === media.target && media.target + ? await onDrive(media.target, () => getFreeBytes(volumeDir)) + : await getFreeBytes(volumeDir); + } catch (err) { + if (!isDriveNotAnswering(err)) throw err; + freeBytes = null; + } // The SAME two conditions storageActions.ts refuses on, stated here as // prose so the button is off with a reason rather than off and silent — // and stated in the action too, because a disabled button is a courtesy diff --git a/editor/app/channels/page.tsx b/editor/app/channels/page.tsx @@ -225,7 +225,8 @@ export default async function ChannelsPage({ // 71 rows on every auto-refresh and the rule is that tables never shell out. const freeByVolume = await volumeFreeBytes({ paths, locations }); // A DRIVE THAT IS NOT ANSWERING, said on its chip. From memory — the health - // probe (a child `stat` every 15 s) is what asked; the table asks nothing. + // pass (the block device's counters every 15 s) or the watchdog on a read is + // what found it (lib/storageHealth.ts); the table asks nothing. const notAnsweringByVolume: Record<string, string | undefined> = {}; for (const loc of locations) { const stall = stalledLocation(loc); diff --git a/editor/app/storage/actions.ts b/editor/app/storage/actions.ts @@ -250,10 +250,12 @@ export async function refreshStorageLocationAction( const settings = getSettings(); const location = settings.storage.locations.find((l) => l.id === id); if (!location) return { ok: false, error: `There is no storage location "${id}".` }; - // IS IT ANSWERING, asked first and out of process (a child `stat` against a - // 3 s timer): the probe below runs in-process, and on a stalled drive it is - // not asked at all. The channels' remembered answers go too — the operator - // has just done something about the drive. + // IS IT ANSWERING, asked first and without touching the drive (the block + // device's counters in /sys, or a child `stat` raced against 3 s where no + // device can be named): the probe below runs in-process, and on a stalled + // drive it is not asked at all. The counters give no answer within 10 s of + // the pass's last sample. The channels' remembered answers go too — the + // operator has just done something about the drive. await refreshLocationHealth(location); forgetChannelMedia(); const health = locationHealth(location.id); diff --git a/editor/app/storage/buildStorage.ts b/editor/app/storage/buildStorage.ts @@ -87,8 +87,9 @@ export async function buildStorage(): Promise<StorageRowsPayload> { // situation the operator opened the page to understand. The store's SIZE is // the only thing cached; its location, status and marker are read fresh every // render, because those are the safety facts. - // THE DRIVES THAT ARE NOT ANSWERING, in words. From memory: the health probe - // (a child `stat`, every 15 s) is what asked. + // THE DRIVES THAT ARE NOT ANSWERING, in words. From memory: the health pass + // (the block device's counters every 15 s) or the watchdog on a page's read + // is what found it (lib/storageHealth.ts). const now = Date.now(); const notAnswering: Record<string, string> = {}; for (const loc of locations) {