import { STATION_DOT, STATION_TEXT, formatCount, } from "./pipeline/tone"; // A lane's state, and the one derivation every surface reads it from. // // THE POINT OF THIS TYPE IS THAT A LANE HAS TWO SWITCHES, NOT ONE. There is the // RUNNER — is anything dispatching at all — and the GATE — the pause that // decides whether the lane may consume what it picks. They are independent, and // the state nobody had a word for is the combination "runner up, gate shut": // the lane is not stopped and it is not working. That is `holding`, and it is // the whole reason this is four states rather than a boolean. // // Every lane's gate reaches the wire as `held`, computed once by isGateHeld // (common/lib/pauseGates.ts); no reader inverts. // // THE `feedRunning` AXIS RETIRED WITH THE SWEEPS in slice 1.3. It meant "a // corpus-wide sweep is armed", which was a fact only two of the four lanes had; // all four are dispatched by a runner now, so a caller with no work in flight is // `idle` on the same terms auto-transcribe always was. export type LaneState = "running" | "holding" | "idle" | "unavailable"; export function deriveLaneState({ available = true, gateHeld, activeCount = 0, }: { // The lane exists at all. `false` is not "idle": with no operation registered // there is nothing to hold, and an idle-looking lane would read as "all caught // up" when the truth is "switched off". available?: boolean; gateHeld: boolean; // Work in flight right now. activeCount?: number; }): LaneState { if (!available) return "unavailable"; // The gate decides first. A running lane behind a shut gate is HOLDING, not // running — its limit() returns 0 and the pool idle-waits, which looks exactly // like wedged unless something says otherwise. if (gateHeld) return "holding"; if (activeCount > 0) return "running"; return "idle"; } // No new palette. These map onto the station tones the channel line already // uses (see pipeline/tone.ts): a bespoke hue here would be wrong on both // bases (light, dark) at once. Deliberately NOT a second copy // of those maps — flow/OverviewPanel already made one, and three would be a // guarantee they drift. export const LANE_DOT: Record = { // The travelling pulse, paired with motion-reduce as everything animated here // is. running: `${STATION_DOT.running} motion-reduce:animate-none`, holding: STATION_DOT.attention, idle: STATION_DOT.neutral, unavailable: STATION_DOT.neutral, }; export const LANE_TEXT: Record = { running: STATION_TEXT.running, holding: STATION_TEXT.attention, idle: STATION_TEXT.neutral, unavailable: STATION_TEXT.neutral, }; // The word beside the dot. This — not the rail — is what assistive tech reads, // so it has to stand on its own. export const LANE_WORD: Record = { running: "Running", holding: "Holding", idle: "Idle", unavailable: "Off", }; // Re-exported so a lane figure formats its counts the same way a station does, // including the "—, never 0" rule: a zero would claim a measurement nobody took. export { formatCount };