export type Mode = "sort" | "salvage" | "verify" | "keeps"; export const MODES: Mode[] = ["sort", "salvage", "verify", "keeps"]; export function isMode(v: string): v is Mode { return (MODES as string[]).includes(v); } /** A candidate as mined into cand2/*.json. Times are ABSOLUTE episode seconds. */ export type Candidate = { video: string; token?: string; start: number; end: number; dur?: number; f0?: number; spreadCents?: number; rms?: number; peak?: number; marginBefore?: number; marginAfter?: number; gapPrev?: string; gapNext?: string; noTrim?: boolean; salvagedFrom?: string; sortedFrom?: string; }; /** * One ASR token. `conf` is OPTIONAL because this type dropped it, not because * the data lacks it -- every word in asr/ carries a parakeet confidence, 70% of * them at 0.9 or better and only 1.1% below 0.4. Consumers must read an absent * conf as UNKNOWN and never as 1.0: a missing reading is not a perfect one. */ export type AsrWord = { start: number; end: number; w: string; conf?: number }; /** What the deck needs to render a queue. No wav is opened to build one. */ export type ClipStub = { key: string; video: string; title: string; date: string; /** The ASR token. Often wrong -- that is what the word selector is for. */ token: string; candStart: number; candEnd: number; f0: number; /** Why find-risky.mjs flagged it (verify mode). */ risk: string; /** Previously recorded human label, if this clip has been through the tool. */ word?: string; /** keeps mode: the side already recorded, if any. */ side?: number; /** wav48/