Orchestrator Runbook (DOCS-ORCH-34-003)
Last source review: 2026-10-07
Audience: operators running the Stella Ops Orchestrator (scheduling and run execution). Purpose: pre-flight checks, day-to-day run/schedule operations, incident response, health/metrics, and offline/air-gap procedures for the Orchestrator surface.
Source verification (2026-10-07,
58fd27c7f0232bf40be341a159fe06d6931be314): Scheduler run execution is composed bysrc/JobEngine/StellaOps.JobEngine.WebService, registered asjobengine. Native run/schedule routes remain/api/v1/scheduler/..., with the read-only compatibility surface under/api/v1/jobengine/....Scheduler:Worker:Embedded=trueis the declared default; heavy worker registration additionally requires real JobEngine storage. Disabling the embedded flag does not make the consolidatedjobengine-workera dispatch implementation. Recheck the hostProgram.csand JobEngine architecture before changing worker placement; do not restore the retired standalone Scheduler host.
Pre-flight
- Ensure PostgreSQL reachable and a queue transport (Redis or NATS) configured; liveness at
GET /healthzand readiness atGET /readyzreturn HTTP 200 ({ "status": "ok" }/{ "status": "ready" }, both anonymous). There is no aggregate/admin/healthendpoint and the probes do not report queue depth — useGET /api/v1/scheduler/runs/queue/lagfor depth. - Verify tenant allowlist and scopes configured in Authority. The orchestrator authorization scopes are
orch:read,orch:operate,orch:quota, andorch:backfill; the underlying scheduler surface also acceptsscheduler:read,scheduler:operate, andscheduler:admin. (There is noorchestrator:*scope.) Source symbols:StellaOpsScopes.OrchRead/OrchOperate/OrchQuota/OrchBackfill,StellaOpsScopes.SchedulerRead/SchedulerOperate/SchedulerAdmin. - Policy and handler scope checks on run/schedule endpoints.
RunEndpointsandScheduleEndpointsattachSchedulerPolicies.Readto their route groups; mutations and run preview additionally attachSchedulerPolicies.Operate. The consolidated policies requirescheduler:readandscheduler:operaterespectively. HandlerEnsureScopechecks usescheduler.runs.read/.write/.manage/.previewandscheduler.schedules.read/.write. Both productionTokenScopeAuthorizerand development/testHeaderScopeAuthorizeruse the sameScopeHierarchy: an exact grant satisfies the handler;scheduler:readsatisfies its read checks,scheduler:operatesatisfies write/manage/preview, andscheduler:adminsatisfies the hierarchy. Read permission does not grant a mutation. The handler hierarchy does not replace either attached ASP.NET policy, so provision both coarse policy scopes for a normal run/schedule mutation token; additional dotted grants are not required merely to satisfy the handler. Recheck the two endpoint modules, both authorizers,ScopeHierarchy, and the policy registration inProgram.cs. The JobEngine read projection endpoints useSchedulerPolicies.JobEngineRead(scheduler:readororch:read) and no additional handler gate. - Outside an explicit local harness, storage resolves
STELLAOPS_POSTGRES_JOBENGINE_CONNECTIONfirst, then the equally owner-specific host/test overridePostgres:JobEngine:ConnectionString. The consolidated resolver does not consult predecessor Scheduler aliases or a generic shared connection. Absence fails closed. Database-less local harness mode requiresTestingLocalHarness, orScheduler:LocalHarness:Enabled=truein Development/Testing; it is not implied by a development environment alone. RecheckProgram.csandConsolidatedJobEnginePersistenceExtensions.ResolveConnectionString. - Plugin bundles present and signatures verified (scheduler job plugins are discovered from plugin DLLs at startup via
PluginHost.LoadPlugins).
Common operations
- Create a run:
POST /api/v1/scheduler/runs/(group Read + endpoint Operate policies; handlerscheduler.runs.manage). The body must reference an existingscheduleId(404 if it does not exist); onlytrigger: manualruns may be created through this endpoint. (Source:RunEndpoints.CreateRunAsync.) - Cancel a run:
POST /api/v1/scheduler/runs/{runId}/cancel(group Read + endpoint Operate policies; handlerscheduler.runs.write). Best-effort; returns HTTP 409 if the run is already terminal. (Source:RunEndpoints.CancelRunAsync.) - Retry a run:
POST /api/v1/scheduler/runs/{runId}/retry(group Read + endpoint Operate policies; handlerscheduler.runs.manage). Creates a new manual run withretryOfpointing at the original; the original must be terminal. - Stream status:
GET /api/v1/scheduler/runs/{runId}/stream— Server-Sent Events (text/event-stream), not WebSocket. Emitsinitial,queueLag,heartbeat,stateChanged,segmentProgress,deltaSummary, andcompletedevents (plus anotFoundevent if the run row disappears mid-stream). (Source:RunStreamCoordinator.) - List runs / read state:
GET /api/v1/scheduler/runs/(filters:scheduleId,state,createdAfter,limit,cursor,sort),GET /api/v1/scheduler/runs/{runId},GET /api/v1/scheduler/runs/{runId}/deltas— all read endpoints apply policyscheduler:read+ fine-grainedscheduler.runs.read. - Preview impact:
POST /api/v1/scheduler/runs/preview(group Read + endpoint Operate policies; handlerscheduler.runs.preview). Resolves the impacted image set for ascheduleIdor inlineselector— optionally narrowed byproductKeys/vulnerabilityIdsandusageOnly— and returns a bounded sample (sampleSizeclamped to 1–50). Read-only; does not create a run. (Source:RunEndpoints.PreviewImpactAsync.) - Manage schedules: under
/api/v1/scheduler/schedules— list (GET /), read (GET /{scheduleId}), create (POST /), update (PATCH /{scheduleId}), soft-delete (DELETE /{scheduleId}; system-managed schedules cannot be deleted), and pause/resume (POST /{scheduleId}/pauseand/resume). List/read apply policyscheduler:read+ fine-grainedscheduler.schedules.read; all mutations (create/update/delete/pause/resume) require both group Read and endpoint Operate policies plus handlerscheduler.schedules.write. Pausing a schedule is the direct lever to stop its scheduled runs. (The CLI has no source-pause command: the formerorchgroup was withdrawn on 2026-10-01 (SPRINT_20260928_008 PCD-129) with unsupported management calls; that withdrawal does not retire the current JobEngine reads above.) (Source:ScheduleEndpoints.) - Console job view (read-only):
GET /api/v1/jobengine/jobs,/api/v1/jobengine/jobs/{jobId},/api/v1/jobengine/jobs/{jobId}/detail, and DAG edges/api/v1/jobengine/dag/job/{jobId}/parentsand/children. These project scheduler runs into JobEngine job records; they requirescheduler:readororch:read. (Source:JobEngineJobEndpointExtensions.) - CLI: there is no
orchcommand group. Itssources,backfillandquotassubcommands were withdrawn on 2026-10-01 (SPRINT_20260928_008 PCD-129) with unsupported management calls. Drive runs and schedules via the HTTP API above. SBOM exploration is the separate top-levelstella sbom ...command (CommandFactory.BuildSbomCommand).
Incident response
- Queue backlog: Check queue depth with
GET /api/v1/scheduler/runs/queue/lag(returns per-queuetransport/queue/depth, plustotalDepth/maxDepth) or thescheduler_queue_depthgauge. Check supported embedded-worker capacity or pause the offending schedule (POST /api/v1/scheduler/schedules/{scheduleId}/pause); verify no stuck plugin. - Repeated failures: Inspect the run record
errorfield and the run-evidence payload from/api/v1/jobengine/jobs/{jobId}/detail(available scheduler evidence; queue, lease, quota, dead-letter and release-script proof fields may be absent when no durable proof is recorded). Compare against the originating schedule/plugin version. - Plugin auth errors: rotate the relevant connector/source credentials in Authority/Console; the scheduler re-reads tenant-scoped credentials on the next run.
- Source/scheduler runaway: pause the offending schedule (see Schedules above); confirm the queue drains via the queue-lag endpoint or
scheduler_queue_depth.
Health checks
GET /healthz— liveness (anonymous, HTTP 200{ "status": "ok" }).GET /readyz— readiness (anonymous, HTTP 200{ "status": "ready" }).GET /api/v1/scheduler/runs/queue/lag— queue depth summary (policyscheduler:read+ fine-grainedscheduler.runs.read, same two-layer model as the other run reads).- Metrics (meter
StellaOps.Scheduler.Queue):scheduler_queue_enqueued_total,scheduler_queue_deduplicated_total,scheduler_queue_ack_total,scheduler_queue_retry_total,scheduler_queue_deadletter_total,scheduler_queue_depth(gauge), tagged bytransport/queue. - Metrics (meter
StellaOps.Scheduler.Worker):scheduler_run_duration_seconds,scheduler_runs_active,scheduler_planner_runs_total,scheduler_runner_segments_total,scheduler_runner_backlog,scheduler_graph_jobs_total, and related counters/histograms. - Logs/traces: the
StellaOps.JobEngine.Schedulingactivity source tags spans withtenant_id,schedule_id,run_id/job_id,http.method, andhttp.route(source:SchedulerTelemetryMiddleware).
Determinism/immutability
- Use owner APIs for run transitions; do not edit persisted rows directly. The owner updates run state, progress and evidence through
RunRepository.UpdateAsync/TryUpdateProgressAsync, so run rows are not an append-only ledger. Retries create a fresh run linked viaretryOfrather than re-running the original in place. - Idempotency is carried on
RunReason.QueueIdempotencyKey(surfaced asidempotencyKeyin the JobEngine job detail). There is norunTokenorinputsHashconcept in the current implementation. - State machine:
Planning → Queued → Running → Completed | Error | Cancelled; terminal states are enforced byRunStateMachine(cancel/retry validate terminality).
Offline/air-gap
- Keep plugin bundles and schedule specs in sealed storage; no remote fetch.
- The graph-job backfill tool (
StellaOps.Scheduler.Tools→Scheduler.Backfill) ingests GraphBuildJob payloads from a local NDJSON file (--source,--batch,--dry-run,--timeout-seconds,--pg) — useful for seeding or replaying jobs offline. - Mutating run/schedule/source operations are written to the scheduler audit trail (
ISchedulerAuditService/AddAuditEmission); export audit data through the platform audit/export tooling for offline analysis. (There is no dedicated per-run NDJSON ledger export endpoint on the scheduler service itself.)
Quick checks
- [ ]
GET /healthzandGET /readyzreturn 200; queue depth normal (/api/v1/scheduler/runs/queue/lag). - [ ] Latest plugin bundle signatures valid.
- [ ] No secrets in logs (spot-check redaction).
- [ ] Error budget within SLO (see
docs/modules/telemetry/guides/metrics-and-slos.md).
