Archilyzer · Source

archilyzer

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

commit 08ae4c72167a60944a87b1bad345d05feb696511
parent 1413de3744febdae605ef2ccd9ea73474e3a5d64
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 21 Sep 2026 02:15:15 -0400

storage: show what the clip windows are costing

The bytes now exist (previous commit); these are the two surfaces that read
them. `LocationRollup` and `StorageRow` gain `clipsBytes` — the "of which" of
the Media figure, rendered UNDER it and never beside it as a second total,
because a window lives inside `data/<id>/` and is already in the number above.

Zero is not rendered. "0 B in clip windows" on every drive that has never been
walked by a report is noise on the one page where a byte figure is supposed to
mean something.

No `unknownClipsBytes`: it would be exactly the set of channels `unknownBytes`
already counts — the two fields are written by one snapshot pass — and a second
copy of one number is a second thing to keep in step.

On the video page the total is free: every window `listClipWindows` returns
already carries its own `bytes`. It goes in the card SUMMARY as well as the
body, and the body says the part that matters — nothing prunes a window on its
own (the retention sweep is pointer-driven and never sees one), and the only
thing that removes one evicts BY AGE.

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

Diffstat:
Mcommon/controller/storageLocations.ts | 17+++++++++++++++++
Mcommon/views/review.test.ts | 8++++----
Mcommon/views/storage.test.ts | 42+++++++++++++++++++++++++++++++++++++++++-
Mcommon/views/storage.ts | 27+++++++++++++++++++++++++++
Meditor/app/channels/[slug]/videos/[id]/components/VideoPanel.tsx | 19++++++++++++++++++-
Meditor/app/storage/buildStorage.ts | 10+++++++++-
Meditor/app/storage/components/StorageLocationsTable.tsx | 16+++++++++++++++-
Meditor/e2e/review.spec.ts | 8++++----
8 files changed, 135 insertions(+), 12 deletions(-)

diff --git a/common/controller/storageLocations.ts b/common/controller/storageLocations.ts @@ -95,6 +95,16 @@ export type LocationRollup = { // surface renders "+ n unknown" beside the total. bytes: number; unknownBytes: number; + // THE `clips/` SHARE OF `bytes`, not a sibling of it. Fetched clip windows + // live under `data/<id>/clips/` and are counted into `totalMediaBytes` like + // everything else there — this is the "of which", because clips are the one + // part of a location's bytes that is a CACHE nothing prunes, and an operator + // looking at a full drive wants to know how much of it is that. + // + // No `unknownClipsBytes`: it would be the same set of channels + // `unknownBytes` already counts (the two fields are written by one snapshot + // pass), and a second copy of one number is a second thing to keep in step. + clipsBytes: number; // `inspectChannelMedia` status, bucketed into the three numbers the page // shows. `unreachable` DELIBERATELY ABSORBS `inconsistent`: both mean "this // channel's media is not readable through its link right now", which is the @@ -114,6 +124,7 @@ function emptyRollup(locationId: string): LocationRollup { total: 0, bytes: 0, unknownBytes: 0, + clipsBytes: 0, ok: 0, unreachable: 0, moving: 0, @@ -158,6 +169,10 @@ export async function channelsOnLocation(opts: { // file in one render. A slug that is absent (or maps to undefined) counts // towards `unknownBytes`, never towards `bytes`. mediaBytes?: Readonly<Record<string, number | undefined>>; + // `snapshot.totalClipsBytes` per slug — the `clips/` share of the above. + // Absent for a snapshot written before the field existed, which is the same + // set `mediaBytes` is absent for. + clipsBytes?: Readonly<Record<string, number | undefined>>; // The in-place row (see INTERNAL_LOCATION_ID). When true, every channel with // NO `dataDir` is rolled up under that id alongside the configured ones. includeInternal?: boolean; @@ -191,6 +206,8 @@ export async function channelsOnLocation(opts: { const bytes = opts.mediaBytes?.[slug]; if (typeof bytes === "number") roll.bytes += bytes; else roll.unknownBytes += 1; + const clips = opts.clipsBytes?.[slug]; + if (typeof clips === "number") roll.clipsBytes += clips; const media = await inspectChannelMedia(opts.paths, slug, config); if (media.status === "ok" || media.status === "in-place") roll.ok += 1; else if (media.status === "in-transition") roll.moving += 1; diff --git a/common/views/review.test.ts b/common/views/review.test.ts @@ -17,7 +17,7 @@ test("only auto-paused channels are rows, and they carry where Resume puts them autoPaused: { reason: "storage", since: "2026-09-19T04:05:06.000Z", - previousTier: "high", + previousTier: "low", }, }, // Paused BY A PERSON. It must not appear: /review is for decisions the @@ -31,14 +31,14 @@ test("only auto-paused channels are rows, and they carry where Resume puts them rows.map((r) => r.slug), ["zeta"], ); - assert.equal(rows[0].previousTier, "high"); + assert.equal(rows[0].previousTier, "low"); assert.equal(rows[0].reason, "storage"); assert.match(rows[0].detail, /drive that is not there/); assert.match(rows[0].detail, /2026-09-19/); }); test("the order is the slug order, so an auto-refresh cannot reshuffle the list", () => { - const entry = (previousTier: "normal" | "high") => ({ + const entry = (previousTier: "normal" | "low") => ({ tier: "paused" as const, autoPaused: { reason: "storage" as const, @@ -47,7 +47,7 @@ test("the order is the slug order, so an auto-refresh cannot reshuffle the list" }, }); const rows = autoPausedRows( - model({ zeta: entry("high"), alpha: entry("normal"), mid: entry("normal") }), + model({ zeta: entry("low"), alpha: entry("normal"), mid: entry("normal") }), ); assert.deepEqual( rows.map((r) => r.slug), diff --git a/common/views/storage.test.ts b/common/views/storage.test.ts @@ -3,7 +3,12 @@ import assert from "node:assert/strict"; import type { StorageLocation } from "../lib/storageLocations"; import type { LocationRollup, MemoizedProbe } from "../controller/storageLocations"; import type { RegistryReader } from "./inputs"; -import { buildStorageRows, type StorageActionKind, type StorageRow } from "./storage"; +import { + buildStorageRows, + storageClipsText, + type StorageActionKind, + type StorageRow, +} from "./storage"; // Run with: // pnpm --filter yt-dlp-transcript-common exec tsx --test views/storage.test.ts @@ -25,6 +30,7 @@ function rollup(partial: Partial<LocationRollup>): LocationRollup { total: partial.total ?? 0, bytes: partial.bytes ?? 0, unknownBytes: partial.unknownBytes ?? 0, + clipsBytes: partial.clipsBytes ?? 0, ok: partial.ok ?? 0, unreachable: partial.unreachable ?? 0, moving: partial.moving ?? 0, @@ -359,3 +365,37 @@ test("no internal input means no internal row (a caller that wants only the loca ); assert.equal(bytesInPlace, 0); }); + +test("the clip-window line is rendered only when there are windows", () => { + // Zero is not rendered: "0 B in clip windows" on every drive that has never + // been walked by a report is noise on the one page where a byte figure is + // supposed to mean something. + assert.equal(storageClipsText(0), ""); + assert.equal(storageClipsText(-1), ""); + assert.match(storageClipsText(5 * 1024 ** 3), /5\.00 GB of it is fetched/); +}); + +test("a location row carries the clips share of its bytes", () => { + const payload = buildStorageRows({ + locations: [loc("cold", "/mnt/cold")], + defaultLocationId: "", + probes: {}, + rollups: { + cold: rollup({ + locationId: "cold", + total: 2, + bytes: 10_000_000_000, + clipsBytes: 2_000_000_000, + ok: 2, + }), + }, + registry: NO_JOBS, + udisksctlAvailable: false, + now: 0, + }); + const row = payload.rows.find((r) => r.id === "cold"); + assert.equal(row?.clipsBytes, 2_000_000_000); + assert.match(String(row?.clipsText), /fetched clip windows/); + // A SUBSET, not a sibling: the clips are already inside `bytes`. + assert.equal(row?.bytes, 10_000_000_000); +}); diff --git a/common/views/storage.ts b/common/views/storage.ts @@ -88,6 +88,15 @@ export type StorageRow = { // ONE wording, and never a bare "0 B" for a location whose channels have // simply never had a report — that reads as an empty drive. bytesText: string; + // The `clips/` share of `bytes` — fetched clip windows, the one part of a + // location's media that is a cache nothing prunes. 0 is a real answer here + // (no windows have been fetched onto this drive), unlike `bytes`, which is + // why it needs no "unknown" companion: the channels that could not measure + // clips are exactly the ones `unknownBytes` already counts. + clipsBytes: number; + // "· 4.21 GB in clip windows", or "" when there are none. Built here so the + // row and any future poll cannot word it differently. + clipsText: string; // Absent when the location is not available, and ALSO when it is available // but unmeasurable (getFreeBytes fails open to Infinity, which the probe // drops rather than carry). Render "—" for both. @@ -259,6 +268,18 @@ export function storageBytesText(bytes: number, unknown: number): string { return bytesLabel(bytes); } +// THE CLIP-WINDOW LINE, or nothing at all. +// +// Zero is not rendered: a row saying "0 B in clip windows" on every drive that +// has never been walked by a report is noise on the only page where a byte +// figure is supposed to mean something. The phrasing names EVICTION rather than +// size, because the number is only actionable if you know there is a control +// for it. +export function storageClipsText(clipsBytes: number): string { + if (clipsBytes <= 0) return ""; + return `${bytesLabel(clipsBytes)} of it is fetched clip windows`; +} + // The one running re-point, or null. Reported for the whole page rather than // per row because the job record carries no location id: it is enqueued on the // shared `relocate` queue key, which the registry caps at concurrency 1, so @@ -331,6 +352,7 @@ export function buildStorageRows(i: StorageRowsInputs): StorageRowsPayload { const roll = i.rollups[loc.id]; const bytes = roll?.bytes ?? 0; const unknownBytes = roll?.unknownBytes ?? 0; + const clipsBytes = roll?.clipsBytes ?? 0; bytesOnLocation[loc.id] = bytes; return { id: loc.id, @@ -348,6 +370,8 @@ export function buildStorageRows(i: StorageRowsInputs): StorageRowsPayload { bytes, unknownBytes, bytesText: storageBytesText(bytes, unknownBytes), + clipsBytes, + clipsText: storageClipsText(clipsBytes), ...(probe?.freeBytes !== undefined ? { freeBytes: probe.freeBytes } : {}), lastProbeAgeMs: probe ? Math.max(0, i.now - probe.probedAt) : 0, ...(probe?.warning ? { warning: probe.warning } : {}), @@ -431,6 +455,7 @@ function internalRow( const counts = countsOf(roll); const bytes = roll?.bytes ?? 0; const unknownBytes = roll?.unknownBytes ?? 0; + const clipsBytes = roll?.clipsBytes ?? 0; bytesOnLocation[INTERNAL_ROW_ID] = bytes; const withheld = "The corpus volume is where media lives when it has not been moved " + @@ -452,6 +477,8 @@ function internalRow( bytes, unknownBytes, bytesText: storageBytesText(bytes, unknownBytes), + clipsBytes, + clipsText: storageClipsText(clipsBytes), ...(internal.freeBytes !== undefined ? { freeBytes: internal.freeBytes } : {}), lastProbeAgeMs: 0, busy: null, diff --git a/editor/app/channels/[slug]/videos/[id]/components/VideoPanel.tsx b/editor/app/channels/[slug]/videos/[id]/components/VideoPanel.tsx @@ -433,9 +433,16 @@ export function VideoPanel({ <PipelineStageCard id="fetched-windows" title="Fetched windows" + // THE BYTES ARE IN THE SUMMARY, not only inside the card. A window is + // seconds of media, but nothing prunes one — the retention sweep is + // pointer-driven and never sees a `clips/` file — so a video walked + // by many reports accumulates them silently. The total is free here: + // every window in the list already carries its own `bytes`. summary={`${clipWindows.length} window${ clipWindows.length === 1 ? "" : "s" - } of this video's source media, fetched for another tool.`} + } (${formatBytes( + clipWindows.reduce((n, w) => n + w.bytes, 0), + )}) of this video's source media, fetched for another tool.`} defaultOpen={false} tone="neutral" > @@ -1221,6 +1228,16 @@ function FetchedWindows({ windows }: { windows: FetchedWindow[] }) { metadata, so the video&apos;s pipeline state and its place in the index are unchanged. </p> + {/* WHAT THEY COST, AND THAT NOTHING RECLAIMS IT. The retention sweep is + pointer-driven and never sees a window; the cleanup lanes are about + `audio.*`. The only thing that removes one is Evict fetched windows on + /storage, and it evicts BY AGE — which surfaces have to say, because a + window a report still cites looks identical to one nothing wants. */} + <p aria-label="clip windows total" className="text-xs text-muted-foreground"> + {formatBytes(windows.reduce((n, w) => n + w.bytes, 0))} in total, + counted in this channel&apos;s media size. Nothing prunes a window on + its own — Storage evicts them by age. + </p> </div> ); } diff --git a/editor/app/storage/buildStorage.ts b/editor/app/storage/buildStorage.ts @@ -43,7 +43,14 @@ export async function buildStorage(): Promise<StorageRowsPayload> { // row says so rather than under-reporting. const briefs = await listChannelBriefs(paths); const mediaBytes: Record<string, number | undefined> = {}; - for (const b of briefs) mediaBytes[b.slug] = b.snapshot?.totalMediaBytes; + // The `clips/` share, off the same snapshot. Absent for a report written + // before the field existed — the same set `mediaBytes` is absent for, which + // is why the rollup needs no second "unknown" counter. + const clipsBytes: Record<string, number | undefined> = {}; + for (const b of briefs) { + mediaBytes[b.slug] = b.snapshot?.totalMediaBytes; + clipsBytes[b.slug] = b.snapshot?.totalClipsBytes; + } const configs = briefs.map((b) => ({ slug: b.slug, config: b.config })); const [probes, rollups, udisksctl, freeOnCorpus] = await Promise.all([ probeAllLocations(locations, paths), @@ -52,6 +59,7 @@ export async function buildStorage(): Promise<StorageRowsPayload> { locations, configs, mediaBytes, + clipsBytes, includeInternal: true, }), // Memoised per binary path inside storageVolumes, so this is one diff --git a/editor/app/storage/components/StorageLocationsTable.tsx b/editor/app/storage/components/StorageLocationsTable.tsx @@ -220,7 +220,21 @@ function LocationCard({ </> )} <dt className="text-muted-foreground">Media</dt> - <dd aria-label="location media bytes">{row.bytesText}</dd> + <dd aria-label="location media bytes"> + {row.bytesText} + {/* THE CLIPS SHARE, inside the Media figure and never beside it as a + second total. A fetched window lives under `data/<id>/clips/`, so + it is already in the number above; what this adds is that some of + it is a CACHE nothing prunes. Absent when there are none. */} + {row.clipsText && ( + <span + aria-label="location clip bytes" + className="block text-xs text-muted-foreground" + > + {row.clipsText} + </span> + )} + </dd> <dt className="text-muted-foreground">Free</dt> <dd aria-label="location free space"> {row.freeBytes === undefined ? "—" : formatBytes(row.freeBytes)} diff --git a/editor/e2e/review.spec.ts b/editor/e2e/review.spec.ts @@ -53,7 +53,7 @@ test("an auto-paused channel is listed with its reason", async ({ page }) => { autoPaused: { reason: "storage", since: "2026-09-19T04:05:06.000Z", - previousTier: "high", + previousTier: "low", }, }, }, @@ -74,10 +74,10 @@ test("an auto-paused channel is listed with its reason", async ({ page }) => { page.getByLabel("auto-paused reason for test-youtube"), ).toContainText("drive that is not there"); // It offers to put the channel back where it WAS, not at "normal" — the - // previous tier is the whole content of the record, and resuming a `high` + // previous tier is the whole content of the record, and resuming a `low` // channel as `normal` would silently demote it. const resume = page.getByLabel("resume test-youtube"); - await expect(resume).toHaveText("Resume as high"); + await expect(resume).toHaveText("Resume as low"); // And the fix for the actual problem is one link away. await expect(section.getByRole("link", { name: "Storage" })).toHaveAttribute( @@ -102,7 +102,7 @@ test("an auto-paused channel is listed with its reason", async ({ page }) => { }, { timeout: 20_000 }, ) - .toMatchObject({ tier: "high" }); + .toMatchObject({ tier: "low" }); const after = await readJson<{ channelPriority?: { channels: Record<string, { autoPaused?: unknown }>;