import type { AutoQueueStatusPayload } from "yt-dlp-transcript-common/views/autoQueueStatus"; import { LANES, type AutoQueueKind } from "yt-dlp-transcript-common/lib/autoQueueTypes"; import { deriveLaneState } from "yt-dlp-transcript-common/views/laneState"; import type { RailLaneState } from "./OperationRail"; import { idleReasonText } from "./dispatch"; // operation id -> the state of the lane that would dispatch it. // // SEVERAL OPERATIONS SHARE ONE LANE, and that is the fact worth seeing: every // backfill kind runs on one queue, so a diarization row reading "Holding" and // an attribution row reading "Holding" are one gate, not two. The rail draws // them separately because their WORK COUNTS have different cost bases, and maps // them onto the same lane state because their DISPATCH is not. // // Any operation the console has no lane for reads "Off" rather than "Idle" — // see deriveLaneState: an idle-looking lane claims "all caught up" where the // truth is "nothing would run this". // // ONE FOLD FOR FOUR LANES since slice 1.3. It used to be two: the runner lanes // off `runner.running`, and the two sweep lanes off an armed flag with their own // note table. Every lane is a runner lane now, so there is one rule — a stopped // runner is "Off", a held one is "Holding", one with units in flight is // "Running" — and the note is the runner's own idle reason rather than a second // vocabulary for the same states. // // LIVES IN ITS OWN MODULE because the board and every operation page draw the // same rail, and two copies of this fold would let two pages disagree about // which lane is holding. export function railStates( data: AutoQueueStatusPayload, ): Record { const out: Record = {}; const laneState = (kind: AutoQueueKind): RailLaneState => { const status = data[kind]; const running = status.runner.running; return { // A runner's feed is its policy tree, so `activeCount` is what tells // running from idle. A STOPPED runner is "Off", not "Idle" — it will // never pick anything up, which "Idle" does not say. state: !running ? "unavailable" : deriveLaneState({ gateHeld: status.held, activeCount: status.runner.inFlight.length, }), note: running ? idleReasonText(status.runner.idleReason, kind) : null, }; }; for (const kind of LANES) out[kind] = laneState(kind); // Each remaining band takes the state of the lane THAT BAND'S OPERATION // actually rides — asked of the payload, not assumed from the id. // // This loop used to hand every stateless band the backfill lane's state, on // the reasoning that everything which is not digest is backfill. That was // true only because those are the only two operation lanes registered TODAY. // An operation on a third queue would still get a band (the rail is built // from allOperations — every switched-on kind, whatever its queue) and would // then have advertised a hold belonging to a lane that would never dispatch // it. // // `lanes.operations` is the live membership the server already computed, so // this cannot drift from it the way a second registry read could. A band on no // lane gets no entry at all, and railStates' contract above supplies the rest: // no lane means "Off", never a borrowed "Idle". for (const band of data.lanes.bands) { if (out[band.id]) continue; const lane = LANES.find((k) => data.lanes.operations[k].some((op) => op.id === band.id), ); if (!lane) continue; out[band.id] = out[lane]; } return out; }