Runbook: Release Orchestrator - Gate Evaluation Timeout
Audience: Platform on-call engineers responding to Stella Ops release promotions stalled or denied because the CVE-aware policy-engine gate timed out (or failed closed). Use this runbook to tune the policy-gate timeout, diagnose policy-engine reachability, and safely approve or fail-open a stuck gate.
Sprint: SPRINT_20260117_029_DOCS_runbook_coverage Task: RUN-004 - Release Orchestrator Runbooks
Reconciliation note (verify against
src/ReleaseOrchestrator): This runbook was reconciled against the implemented Release Orchestrator. The single real “gate timeout” in code today is the per-request HTTP timeout on the CVE-aware policy-engine gate call (ReleaseOrchestrator:Policy:TimeoutSeconds, default 10s), implemented inHttpPolicyEngineGateClient. On timeout the client fails closed (returns adenyverdict) unlessFailClosedis set tofalse. Earlier drafts referenced a generic per-gate timeout framework withstella orch/stella promotionsub-commands, acheck.orchestrator.gate-timeoutDoctor check, anOrchestratorGateTimeoutalert, and anorchestrator_gate_timeout_totalmetric — none of those exist in source. They have been corrected to the implemented surface or flagged as NOT IMPLEMENTED below.CLI caveat (updated 2026-07-03): the stubbed
stella release gatessub-commands (list/status/approve/reject) were removed from the CLI — they printed fabricated sample output.stella releasenow carries only the real HTTP-backed operator verbsapprove/reject/promote/deploy/rollback(ReleaseOperatorDecisionCommandGroup.cs). The gate-state surfaces are the Doctor check (check.release.promotion.gates) and the approvals REST API. Also:stella policy list(suggested by the Doctor remediation) is NOT an implementedstella policysub-command — use it only as a pointer, not a runnable command.
Metadata
| Field | Value |
|---|---|
| Component | Release Orchestrator |
| Severity | High |
| On-call scope | Platform team |
| Last updated | 2026-05-30 |
| Doctor check | check.release.promotion.gates (Release Pipeline plugin; default severity Warn) |
The Doctor check above is the real gate-health diagnostic (
src/Doctor/__Plugins/StellaOps.Doctor.Plugin.Release/Checks/PromotionGateHealthCheck.cs). It is not a dedicated timeout check — it reports gate configuration health (missing policies, unreachable attestor, missing approvers) and surfaces orchestrator/policy-engine reachability. There is nocheck.orchestrator.gate-timeoutcheck in source.
Symptoms
- [ ] Promotions blocked because the CVE-aware policy gate returned a
denyverdict - [ ] Logs show
Policy.Engine evaluate timed out after {N}sfromHttpPolicyEngineGateClient - [ ] Promotion gate-result row with
Type=policy-engine,Status=denied, and a message endingFail-closed: treating as deny.(the gate’sStatusvalues arepassed/denied/skipped; the policy-engine verdict’sDecisionisallow/deny/error) - [ ] Policy-engine call returns non-2xx (e.g.
400 POLICY_TENANT_HEADER_REQUIRED,401,5xx) and the gate fails closed - [ ]
stella doctor --check check.release.promotion.gatesreports a Warn (“Cannot retrieve promotion gates” / “Promotion gate check timed out”)
NOT IMPLEMENTED: there is no
OrchestratorGateTimeoutalert and noorchestrator_gate_timeout_totalmetric in source. The gate metrics that are emitted byReleaseOrchestratorPluginMonitorarestellaops_gate_evaluations_totalandstellaops_gate_evaluation_duration_ms. The module dossier’s metrics spec (docs/modules/release-orchestrator/operations/metrics.md) additionally listsstella_gate_evaluations_total,stella_gate_evaluation_duration_seconds, andstella_gate_blocks_total— note the doc uses astella_prefix while the emitter usesstellaops_; verify the exposed names on your build before wiring alerts.
Impact
| Impact Type | Description |
|---|---|
| User-facing | Promotions denied or stalled; release pipeline blocked until the gate succeeds or is overridden |
| Data integrity | No data loss; the promotion request is re-evaluable. Fail-closed deny is the safe default — a vulnerable release cannot slip through a temporary policy-engine outage |
| SLA impact | Release SLO violated if the policy-engine outage / slow evaluation persists |
Diagnosis
Quick checks
Run the Doctor gate-health check:
stella doctor --check check.release.promotion.gatesThis queries the orchestrator and (if reachable) the policy engine + attestor. A Warn with
connection_error_type=timeoutorCannot retrieve promotion gatespoints at an unreachable/slow orchestrator or policy engine.Inspect gate status for the release / configured gates for the environment.
REMOVED (2026-07-03): the stubbed
stella release gates status/listcommands were deleted from the CLI (they printed canned sample tables, no HTTP call). Use the Doctor check (stella doctor --check check.release.promotion.gates), the orchestrator logs, the approvals REST API, or the UI Gate policies / promotion decision cockpit (/releases/promotions/<id>) for ground truth.
Note on neighbouring command groups: the
stella orchgroup operates the Source & Job Orchestrator (sources/backfill/quotas) and has no gate sub-commands;stella promotionbuilds promotion attestations (assemble), not gate operations.
Deep diagnosis
Read the orchestrator logs for the policy-gate call. The CVE-aware gate (
HttpPolicyEngineGateClient) logs the following on the failure paths — grep the release-orchestrator container logs:Policy.Engine evaluate timed out after {Timeout}s for pack {PackId}/{Version}.Policy.Engine evaluate returned {Status} ...(non-2xx from the engine)Policy.Engine evaluate network failure ...Each of these routes into the fail-closed (deny) branch whenFailClosed=true.
Confirm the resolved policy pack. The gate resolves the pack in this order (
HttpPolicyEngineGateClient.ResolvePackAsync):- DB binding —
release_orchestrator.environment_policy_bindings(operator-managed) - Static config map
ReleaseOrchestrator:Policy:EnvironmentBindings(DEPRECATED back-compat) - Tenant default
ReleaseOrchestrator:Policy:DefaultPackId+DefaultPackVersion - If none resolves, the policy gate is skipped and legacy approval-policy logic runs. The log line
Resolved policy pack {PackId}@v{Ver} ... via {Source}shows which path won.
- DB binding —
Check policy-engine availability. The Doctor remediation for this check emits the literal string
stella policy listas its suggested next step (PromotionGateHealthCheck.cs). NOTE:listis not an implemented sub-command of thestella policygroup in source — the group exposessimulate,activate,lint,edit,test,new,history,explain,init,compile,version,submit,review,publish,rollback,sign,verify-signature,lattice,verdicts, andpromote, but nolist(and nostats). Treatstella policy listas Doctor remediation copy, not a runnable command on the current build; use a real policy sub-command (e.g.stella policy verdicts) or the policy-engine/healthendpoint to confirm reachability. Seepolicy-evaluation-slow.mdfor engine-side latency triage.Check attestor reachability if gates require attestations — the Doctor check probes the attestor
/healthendpoint and reportsattestor_unavailablewhen it cannot reach it:stella doctor --check check.attestation.*
Resolution
Immediate mitigation
Increase the policy-gate timeout by raising the per-request timeout used for the policy-engine call. This is the only real “gate timeout” knob:
// appsettings / environment override, section "ReleaseOrchestrator:Policy" "ReleaseOrchestrator": { "Policy": { "TimeoutSeconds": 30 // default is 10 } }Apply via the service’s configuration (env var
ReleaseOrchestrator__Policy__TimeoutSeconds=30) and restart/redeploy the release-orchestrator service. There is nostella orch config setcommand and no per-gategates.<name>.timeoutkey in source.Emergency fail-open (last resort). If the policy-engine is down and you must let promotions fall back to legacy approval-policy matching instead of denying, set fail-open. This intentionally weakens the CVE gate, so treat it as a temporary, audited rollback only:
"ReleaseOrchestrator": { "Policy": { "FailClosed": false } }To bypass the CVE-aware gate entirely, set
ReleaseOrchestrator:Policy:Enabled=false(master kill-switch).Override / approve a stuck gate. Manual approval and rejection are real, backend-wired operations on the approvals API, which require the
release:publishscope (policyReleaseOrchestratorPolicies.ReleaseApprove):POST /api/release-orchestrator/approvals/{id}/approve(and/reject), also mirrored under/api/v1/release-orchestrator/approvals. The approve/reject routes areAudited(AuditActions.Release.ApproveRelease/RejectRelease).
The former stubbed CLI shortcut (
stella release gates approve) was removed on 2026-07-03 — during an incident drive the approval through the real surfaces:# Real CLI action (HTTP-backed, requires release:publish): stella release approve <approval-id> --comment "Policy-engine outage - approved by <approver>" # Or call the approvals API directly: # POST /api/release-orchestrator/approvals/{approval-id}/approveThe dedicated scope to bypass release policy gates is
release:bypass(StellaOpsScopes.ReleaseBypass, in the canonical catalog). Verify which surfaces honor it before relying on a “skip gate” flow — there is nostella promotion gate skipcommand in source. The CLIstella release promote --forceadvertises bypassing non-blocking approval gates (its sample output skipsmanual-approval) but is itself a stubbed/sample-output command and performs no backend promotion.
Root cause fix
If the policy engine is slow or returning errors:
- Triage engine-side latency with the
policy-evaluation-slow.mdrunbook. - Confirm the orchestrator is calling the engine with the required tenant header — the client attaches
X-StellaOps-TenantId; without it the engine returns400 POLICY_TENANT_HEADER_REQUIREDand the gate fails closed. - Confirm the bypass-network/routing between release-orchestrator and policy-engine is intact — a misrouted call surfaces as
401and routes into the fail-closed branch.
If the gate configuration itself is unhealthy (Doctor reports missing_policies, attestor_unavailable, or no_approvers):
- Verify required policy packs are bound to the environment via
release_orchestrator.environment_policy_bindings(REST:EnvironmentPolicyBindingEndpoints, scopesrelease.policy-bindings.read/release.policy-bindings.write). - Ensure the attestor service is reachable if gates require attestations.
- Ensure approvers are configured for any gate that requires manual approval.
NOT IMPLEMENTED in source (forward-looking / roadmap only — do not run): gate-level retry/backoff (
gates.<name>.retries), gate result caching (gates.<name>.cache_ttl), per-gate circuit breakers (gates.<name>.circuit_breaker.*), evidence pre-fetching (gates.evidence_prefetch), evidence cache sizing (evidence.cache_*), and OPA worker tuning (policy config set opa.workers). A connector-level circuit breaker (ConnectorCircuitBreaker) exists for IntegrationHub connectors, but it is not a gate timeout control.
Verification
# Re-run the Doctor gate-health check. It reads persisted gateResults from the
# orchestrator's pending-approval API and reports blocking/advisory/unevaluated truth.
stella doctor --check check.release.promotion.gates
# The former `stella release gates status` command was removed 2026-07-03 (it printed
# stubbed sample output). Use the orchestrator logs / approvals API to confirm the fix.
The authoritative confirmation is the orchestrator log line on the next promotion: after raising TimeoutSeconds (or restoring the policy engine), re-submit the promotion and confirm the policy-gate verdict reads Policy pack {pack}@v{ver} returned allow ... (gate Outcome=approve, when the pack allows) rather than the fail-closed ... Fail-closed: treating as deny.
Prevention
- [ ] Policy-gate timeout: Tune
ReleaseOrchestrator:Policy:TimeoutSecondsto sit above the policy-engine’s expected P95 latency but below the orchestrator’s request-timeout. Default is 10s. - [ ] Fail-closed posture: Keep
FailClosed=true(the default) so a policy-engine outage denies rather than silently passes a release. - [ ] Policy pack bindings: Bind packs through the DB-backed
environment_policy_bindingstable; migrate off the deprecated config-mapEnvironmentBindings. - [ ] Monitoring: Alert on
stellaops_gate_evaluation_duration_ms(verify the exposed metric name on your build — emitter uses thestellaops_prefix). There is no dedicated gate-timeout counter to alert on.
Related Resources
- Doctor article:
docs/doctor/articles/release/promotion-gates.md - Architecture / module dossier:
docs/modules/release-orchestrator/(e.g.modules/promotion-manager.md,workflow/promotion.md,workflow/evidence-based-release-gates.md,gates/reachability-gate.md). The previously citeddocs/modules/release-jobengine/gates.mddoes not exist. - Error code:
GATE_TIMEOUT— seedocs/modules/release-orchestrator/appendices/errors.md. - Metrics:
docs/modules/release-orchestrator/operations/metrics.md(gate metrics). - Related runbooks:
orchestrator-promotion-stuck.md,policy-evaluation-slow.md - Dashboard: Grafana > Stella Ops > Gate Latency (verify panel/metric names against the emitted
stellaops_gate_*series).
