commit 316b8c43933406205651ab53810f75c71310c6e7
parent 90c3dfd775aceae85b87ac0fcea8fc343e86de89
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 28 Sep 2026 02:46:35 -0400
common: `archilyzer transcribe` goes; `run`'s exit codes match its header (review Q2, L6, L1)
- Q2: `common/bin/transform.ts` and its `transcribe` row are deleted
together. It ran a whisper batch with this process's own worker pool —
what `run transcription` refuses — and nothing referenced it;
`runWhisperBatch` stays in use by the editor.
- L6: a usage error (unknown operation or channel, a stray flag) exits 2,
a refusal exits 1 — an external operation now exits 1, not 2. A list of
ids none of which has a data dir is refused (exit 1) instead of starting
an empty job (+1 test).
- L1: the header and the usage line say `run` does not see the editor's
lanes, so not beside one on the same channel (the same videos twice:
wasted work, not damage).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
4 files changed, 30 insertions(+), 33 deletions(-)
diff --git a/common/bin/archilyzer.ts b/common/bin/archilyzer.ts
@@ -196,7 +196,7 @@ export const COMMANDS: Command[] = [
{
path: ["run"],
usage:
- "<operation> <channel> [ids…] [--lane local|remote] run one catalogued operation over a channel offline, as the editor's job does (sync, downloads and transcription are refused: they run in the editor)",
+ "<operation> <channel> [ids…] [--lane local|remote] run one catalogued operation over a channel offline, as the editor's job does (sync, downloads and transcription are refused: they run in the editor; it does not see the editor's lanes, so not beside one on the same channel)",
flags: { lane: "string" },
maxPositionals: Number.MAX_SAFE_INTEGER,
run: async ({ positionals, flags }) => {
@@ -235,8 +235,6 @@ export const COMMANDS: Command[] = [
"[--channel <slug>] [--dry-run] [--verbose] rename video dirs to the canonical id layout"),
script(["verify", "transcripts"], "verify-transcripts.ts",
"--channel <slug> list duplicate and missing transcripts"),
- script(["transcribe"], "transform.ts",
- "--channel <slug> whisper over a channel's downloaded audio with THIS process's own worker pool — never beside a running editor"),
script(["migrate", "channel-priority"], "migrate-channel-priority.ts",
"[--dry-run] the one-shot channel-priority migration (plans/channel-priority.md, S5)"),
{
diff --git a/common/bin/run-operation.test.ts b/common/bin/run-operation.test.ts
@@ -99,11 +99,11 @@ test("an unknown operation is refused with the list", async () => {
test("sync, the scan, downloads and transcription are refused with a sentence, not half-run", async () => {
for (const id of ["sync", "metadata-scan", "download"]) {
const { o, out } = capture();
- assert.equal(await runOperation({ operation: id, channel: "x", ids: [] }, { out }), 2, id);
+ assert.equal(await runOperation({ operation: id, channel: "x", ids: [] }, { out }), 1, id);
assert.match(o.stderr, /download queue inside the editor/, id);
}
const { o, out } = capture();
- assert.equal(await runOperation({ operation: "transcription", channel: "x", ids: [] }, { out }), 2);
+ assert.equal(await runOperation({ operation: "transcription", channel: "x", ids: [] }, { out }), 1);
assert.match(o.stderr, /worker pool/);
// Every catalogued operation has an answer, and exactly the registry's run.
const runs = operationCatalog().filter((op) => offlineRefusal(op) === null).map((op) => op.id);
@@ -190,3 +190,14 @@ test("ids scope the run, and ids with no data dir are named", { timeout: 60_000
assert.match(o.stderr, /1 of 2 id\(s\) have no data\/<id>\/ on disk and are skipped: gone/);
assert.match(o.stdout, /Backfill scoped: 0 done, 0 already current, 0 failed; 1 still need their media re-acquired/);
});
+
+test("ids none of which is on disk are refused, and no job is started", { timeout: 60_000 }, async () => {
+ settings();
+ await seed("empty-ids", ["v1"]);
+ const before = jobRecords();
+ const { o, out } = capture();
+ const code = await runOperation({ operation: "diarization", channel: "empty-ids", ids: ["gone", "also-gone"] }, { out });
+ assert.equal(code, 1);
+ assert.match(o.stderr, /none of the 2 id\(s\) has a data\/<id>\/ on disk/);
+ assert.deepEqual(jobRecords(), before);
+});
diff --git a/common/bin/run-operation.ts b/common/bin/run-operation.ts
@@ -24,8 +24,15 @@
// - a paused lane is REFUSED up front rather than held: the batch would
// idle-wait for a resume that only the editor can give.
//
-// Ctrl-C cancels the job the way the editor's Cancel does. Exit: 0 done,
-// 1 failed or refused, 2 usage, 130 cancelled.
+// - it does not see the editor's lanes either: a `run` over a channel the
+// editor's lane is working on at the same moment does the same videos
+// twice (the writes are atomic, so it is wasted work, not damage). Run it
+// when that lane is paused or elsewhere.
+//
+// Ctrl-C cancels the job the way the editor's Cancel does. Exit: 0 done;
+// 1 failed or refused (an operation this process will not run, one switched
+// off, a paused lane, unreachable media, no given id on disk); 2 usage (an
+// unknown operation or channel, a stray flag); 130 cancelled.
import { existsSync } from "node:fs";
import path from "node:path";
@@ -91,7 +98,7 @@ export async function runOperation(
const refusal = offlineRefusal(op);
if (refusal) {
out.error(`run: ${refusal}`);
- return 2;
+ return 1;
}
if (args.lane && op.id !== DIGEST_OPERATION_ID) {
out.error(`run: --lane is the digest engine lane; ${op.label} has none`);
@@ -129,6 +136,12 @@ export async function runOperation(
const ids = [...new Set(args.ids.map((s) => s.trim()).filter(Boolean))];
if (ids.length > 0) {
const absent = ids.filter((id) => !existsSync(path.join(channelDir, "data", id)));
+ if (absent.length === ids.length) {
+ out.error(
+ `run: none of the ${ids.length} id(s) has a data/<id>/ on disk (${absent.join(", ")}) — nothing to run`,
+ );
+ return 1;
+ }
if (absent.length > 0) {
out.error(
`run: ${absent.length} of ${ids.length} id(s) have no data/<id>/ on disk and are skipped: ${absent.join(", ")}`,
diff --git a/common/bin/transform.ts b/common/bin/transform.ts
@@ -1,25 +0,0 @@
-#!/usr/bin/env tsx
-import { getPaths } from "../lib/paths";
-import { runWhisperBatch } from "../controller/whisperBatch";
-import { parseFlags } from "./_parseFlags";
-
-const flags = parseFlags(process.argv.slice(2));
-const channelSlug = flags.channel;
-if (!channelSlug) {
- console.error("Usage: transform.ts --channel <slug>");
- process.exit(2);
-}
-
-runWhisperBatch({
- channelSlug,
- paths: getPaths(),
-})
- .then((result) => {
- console.log(
- `Done: ${result.succeeded} succeeded, ${result.failed} failed, ${result.skipped} skipped, ${result.attempted} attempted.`,
- );
- })
- .catch((err) => {
- console.error(err);
- process.exit(1);
- });