# Editor IA slice 8a+8b — sync is an operation; its settings and the workers' live on their pages ## Context **Verified read-only against `6f6c307` (clean) on 2026-08-29.** This is the Sync and Workers thirds of the IA doc's slice 8 (`plans/editor-operations-ia.md:168-171`); the `/jobs` + `/jobs/active` + `/jobs/queue` fold is a later plan of its own. The noun-model row for Sync (`:57`): an operation, channel-scoped and cadence-triggered; `OperationDescriptor` gains `scope` and `trigger`; it gets a board row and `/operations/sync` (today's `/scheduler`) and "keeps its own runner"; the keep-latest checks and the saved-video backup on the same heartbeat (`editor/app/scheduler/runTick.ts:25-27`) are Storage chores and labelled so. The nav end state (`:66-80`) has the Operations group down to one entry. **Decided (operator, 2026-08-29):** (A) `/scheduler` → `/operations/sync`; `scope`/`trigger` on the descriptor; a `sync` catalog entry; the board's SyncRow becomes a rail row; a 307 redirect; the nav's interim "Schedule" entry goes; the Storage chores are labelled. (B) **The whole `syncScheduler` block — headline and advanced fields — is the sync operation's settings form on its page** (slice 3's rule), declared as `settingsBlock: "syncScheduler"`, with `saveSchedulerSettingsAction` its one writer and `/settings` preserving the block the way it preserves `digest`/`diarization`. (C) `WorkersField.tsx` moves to `/workers` with its own action writing only `settings.workers`. (D) The lane NOTE strings become one. OUT: the `/jobs` fold; any change to tick logic, `SchedulerRun`, `syncSchedulerState` or a settings key; `Field.tsx`/`CardField`; moving `editor/app/scheduler/{runTick,heartbeat,status, auth,actions,intervalPresets}.ts`. **What the census found — every place the IA doc's wording cannot be implemented literally, and what to do instead:** 1. **"Keeps its own runner" cannot be `runner`.** `OperationDescriptor.runner` is typed `AutoQueueKind` (`common/lib/operations.ts:1382`; `autoQueueState.ts` = `"transcription" | "download"`), `operations.test.ts:1245-1262` pins it `undefined` for every other id, and `operations/[id]/page.tsx:138` feeds it straight into `RunnerOperationView`. The heartbeat is not an auto-queue runner. **Instead:** `trigger: "cadence"` is the switch — the page builds the scheduler console as a server slot when `op.trigger === "cadence"` (the `operationSettings`/`laneSettings`/`channelWork` slot pattern, `page.tsx:152-214`) and `OperationDetail` renders it where it would otherwise draw `NoConsoleView` (`OperationDetail.tsx:113-115`). `runner` stays `undefined` on sync; the test says why. 2. **Sync has no band, so "a real rail row" is composed, not folded.** `OperationRail` draws one `RailRow` per `OperationBand` (`OperationRail.tsx:74-81`) and a band's populations are videos (`band.ts`); the sync row's figures are channels (`syncRow.ts:8-22`). `buildOperationBands` (`buildBands.ts:159-193`) must not gain a sync band — "coverage unknown" over a hollow outline for a thing with no per-video coverage. **Instead:** `OperationRail` takes `sync?: SyncRowView` and renders a `SyncRailRow` `
  • ` first in the same `