Operational Readiness Review (dev-to-ops handoff gate)
Before a dev-owned scope (a resource group, a workload, an environment) becomes
the operations team’s responsibility, the Operational Readiness Review (ORR)
runs automatically: it evaluates the whole scope against the governance,
security, RBAC, and reliability rules that ops depends on, grounds each detected issue
in the exact rule that produced it, and returns one decision - clear,
needs_review, or blocked - keyed to the ownership-transfer event. It is the
deployment-preflight pass and the
assurance-twin posture assessment, composed into a single
handoff gate so nothing crosses the dev-to-ops boundary un-reviewed.
This closes a class of failures that a per-change review misses: a workload can be individually compliant on every merge yet still arrive at ops with an over-privileged managed identity, a guest principal holding Owner, no diagnostic settings, or no backup - because no single change introduced the whole gap. The ORR reviews the accumulated posture of the scope at the moment of handoff, not one diff.
Implementation status: The deterministic review and injected orchestration are implemented, but the upstream runtime doesn’t invoke them automatically. See Implementation status for the evidence and remaining integration work.
Customer-agnostic: the trigger label, the required-rule set, and the severity that gates a handoff are all config or fork-supplied. Upstream ships the machinery and the generic ReadinessReport shape, never a customer’s specific handoff policy (generic-scope.instructions.md).
Where it sits: the ORR is a read-only review built on the assurance twin. It holds no privileged identity and executes nothing. Every proposed fix still flows through
risk-gate -> executor -> delivery, preserving the read-only surface rule in app-shape.instructions.md.
Why a distinct gate
Section titled “Why a distinct gate”The pieces already exist; what was missing is the handoff as a first-class milestone. Three surfaces overlap but none of them, alone, is the dev-to-ops gate:
| Existing surface | What it reviews | Why it is not the handoff gate |
|---|---|---|
| deployment-preflight | one deploy: can this change land in the target scope | scoped to a single terraform apply / fix PR, not the accumulated posture |
| assurance-twin proactive review | one change event: does this diff violate a rule | per-diff; a scope can pass every diff and still fail as a whole |
assurance-twin PostureAssessmentReport | the whole estate on demand | not bound to an ownership-transfer event; nobody is required to run it before ops takes over |
The ORR binds the whole-scope assessment to the ownership-transfer event and makes it a required, audited, observation-first gate.
Where it sits in the loop
Section titled “Where it sits in the loop”The ORR is triggered, not polled. When a scope is proposed for handoff, an
ownership_transfer signal enters event-ingest, is normalized like any event,
and drives one review pass:
ownership_transfer signal -> event-ingest (normalize) -> assurance-twin: run every applicable rule over the scope projection -> deploy-preflight: run the feasibility probes over the scope -> checklist evidence: evaluate rules, artifacts, metrics, drills, and approvals -> compose -> ReadinessReport (clear | needs_review | blocked) -> blocked + enforce mode -> gate the handoff, route fixes to risk-gate/HIL -> audit (Saga)Both inputs are deterministic-first (T0-flavored): static evaluation over the twin projection resolves most detected issues; bounded, read-only probes confirm the rest. Nothing in the pass mutates anything.
Trigger
Section titled “Trigger”The ownership_transfer signal is the CSP-neutral event that starts the review.
It is emitted by whatever the fork wires as the handoff moment:
- a pull-request label (
ops-handoff-requested) on the IaC repo, or - a resource tag applied to the scope (
lifecycle-stage: handoff), or - an explicit operator request through the console (
request_ops_handoff).
The signal carries the target scope (resource-group-equivalent or narrower, the same scope hierarchy the rule-governance overrides use), the submitter identity, and the target environment. It never carries a role or a privileged token.
Review dimensions
Section titled “Review dimensions”The ORR runs the full applicable rule set over the scope. Five dimensions are the ones ops most depends on and that a per-change review most often misses:
| Dimension | Representative check | Sourced from |
|---|---|---|
policy_guardrail | disallowed resource types, public access, missing encryption | rule-catalog-collection.md |
identity_rbac | over-privileged workload identity, guest holding Owner, standing privileged access, wildcard-action role, Owner-count over limit | the workload RBAC least-privilege rule pack (managed-identity.role-assignment.*, subscription.role-assignment.*, resource-group.role-assignment.*) |
reliability | no backup / PITR, no diagnostic settings, no zone redundancy | catalog reliability rules |
dependency_ordering | required links (private endpoint, NSG, diagnostic settings) present before handoff | deployment-preflight probe |
best_practice | framework controls with explicit rule, probe, artifact, metric, drill, and approval requirements | rule-catalog/best-practices/ plus ARB bindings |
The identity_rbac dimension is the one the ORR adds that neither preflight nor
per-change review covered before: preflight’s identity_rbac probe checks the
executor’s permission to deploy, while the ORR checks the workload’s own
least-privilege posture using the authored RBAC rules. See
architecture.instructions.md § Rule Catalog.
ReadinessReport
Section titled “ReadinessReport”The pass assembles detected issues into a ReadinessReport - a generalization of the
PostureAssessmentReport (assurance-twin.md) bound to an
ownership-transfer event. Each detected issue keeps the same three required parts:
- evidence - a CSP-neutral citation of the rule, probe, or Best Practice control that produced
it. Checklist detected issues also retain
control_idand the unmetrequirement_refs. A detected issue that cannot cite a source is a defect, the same rule the T2 verifier and preflight probes follow. - severity - preserves the source value: posture levels such as
lowthroughcritical, or preflightwarning/blocking. The coordinator records the resolved gate separately in the detected issue’sblockingboolean. - resolution - how to clear it, mapped to a concrete fix ActionType
(for the RBAC dimension,
remediate.right-size-role) or to guidance when no autofix exists.
Decision semantics
Section titled “Decision semantics”| Decision | Meaning |
|---|---|
clear | no detected issues |
needs_review | detected issues exist but none is blocking (warnings only) |
blocked | at least one blocking detected issue |
The report always records the truthful decision. Whether that decision gates
the handoff is a separate flag, blocks_handoff, true only when the ORR ran in
enforce mode - the same truthful-decision / separate-gate split the
deployment-preflight blocks_deploy flag uses.
Observation-first
Section titled “Observation-first”Every ORR ships in observation mode: it reports blockers truthfully but
blocks_handoff stays false, so an unproven review can never wrongly stop a
real handoff on a false positive. Promotion to enforce is per-environment and
gated on a measured false-positive rate on the frozen scenario set, the same
promotion discipline the ActionType contract and the
preflight probes apply.
Action bridging
Section titled “Action bridging”A blocked ORR does not just list problems. Each detected issue with an autofix carries
a observation mode fix-PR proposal built from the rule’s fix
ActionType, exactly as the assurance twin does. For the identity dimension that
is remediate.right-size-role, which narrows an over-broad grant to least
privilege; because RBAC changes carry a resource_group impact scope and
AsymmetricRollback, they route to human approval through
risk-classification.md and never auto-execute. The ORR
proposes; a human approves; the executor applies. The console and ChatOps remain
read-only surfaces.
Proposal contract
Section titled “Proposal contract”The proposal builder is deterministic and holds these invariants:
| Invariant | Behavior |
|---|---|
| Grounded only | A proposal exists only when the detected issue’s own cited control or rule maps to a fix ActionType in the caller-supplied lever map. An unmapped detected issue produces no proposal; the ORR holds for review rather than inventing a lever. |
| Observation mode only | Every proposal carries shadow, even when the ORR gate itself runs in enforce. The review cannot raise an ActionType above its own promotion state. |
| Distinct approver | The handoff submitter cannot approve their own fix. Principals are compared after Unicode NFKC folding, so an encoding variant of the submitter is still a self-approval attempt. Any such attempt is denied and audited before any proposal is built. |
| No executor identity | A proposal records the submitter and approver as accountability facts only. It carries no credential, token, or executor principal. |
| Deterministic identity | The same scope, environment, cited evidence, resource, and ActionType always derive the same idempotency key, so a redelivered proposal is a downstream no-op. |
Delivery is two-phase audited: the service records the proposal intent with the
approver identity, publishes each proposal through the RemediationProposalPublisher
seam, then records delivery. A publisher failure records the failed delivery with
the delivered count and propagates; it never reports a silent success and never
falls back to a direct call.
Environment promotion
Section titled “Environment promotion”The ORR is the enforcement point for environment promotion (dev -> staging ->
prod). The ownership_transfer signal carries the target environment, and the
gate tightens with it: a promotion into prod treats any critical detected issue as
blocking regardless of the profile default, reusing the prod-downgrade posture
that every mutating ActionType already declares
(risk-classification.md). The environment classifier and
promotion order are specified in
risk-classification.md;
the ORR consumes them and doesn’t define them.
Module placement
Section titled “Module placement”The ORR introduces no new privileged surface and minimal new code: it composes
the existing core/assurance_twin/ and core/deploy_preflight/ subsystems and
adds a thin coordinator plus one normalized signal.
| Component | Responsibility |
|---|---|
ownership_transfer signal | normalized event (scope + submitter + target environment) that triggers the review; emitted by a fork-wired handoff moment |
core/assurance_twin/report | run every applicable rule over the scope projection (reused) |
core/deploy_preflight | run the feasibility probes over the scope (reused) |
core/readiness/checklist | combine explicit requirement outcomes without treating missing evidence as a pass |
| ORR coordinator | compose posture, preflight, and checklist results, apply the environment gate, set blocks_handoff |
composition/readiness.py | run posture, preflight, and optional checklist evidence concurrently, audit success/failure, and publish the serialized report |
composition/readiness_evidence.py | project ARB artifacts, evidence expiry, and owner bindings into typed outcomes |
core/readiness/remediation | derive deterministic, grounded, observation mode-only fix proposals and reject self-approval |
| delivery intent | a fork binds ReadinessReportPublisher to a Checks API annotation / console ReadPanel, and RemediationProposalPublisher to the risk-gate -> executor ingress |
The coordinator imports only shared/ contracts and providers, like every other
core subsystem (project-structure.md).
It holds no cloud SDK and no privileged identity.
Implementation status
Section titled “Implementation status”The repository implements the deterministic review and an injected application service. It doesn’t
yet compose those pieces into the running control plane, so the current evidence supports
implemented, not an operationally validated handoff gate.
Implementation scope
Section titled “Implementation scope”| Area | State | Evidence | Notes |
|---|---|---|---|
| Ownership-transfer signal, report model, detected issue reduction, environment gate, and Best Practice checklist evaluation | implemented | core/readiness/, test_coordinator.py, and test_checklist.py | The pure coordinator preserves grounded detected issues, fails safely on unknown severity, and separates the truthful decision from blocks_handoff. |
| Concurrent posture, preflight, and checklist orchestration with append-only audit and report delivery | implemented | composition/readiness.py, test_readiness_service.py, and test_readiness_checklist_service.py | The service uses injected providers. Assessment and delivery failures are audited and propagated. |
| Architecture Review Board (ARB) artifact, owner, freshness, and expiry projection into checklist outcomes | implemented | composition/readiness_evidence.py and test_readiness_evidence.py | Missing bindings remain unknown, and expired evidence becomes failed; neither is treated as a pass. |
Automatic ownership_transfer ingest and production posture, checklist, and report-publisher bindings | not-started | Provider seams in shared/providers/readiness.py and the injected service above | The current runtime and bootstrap don’t construct or register OperationalReadinessService; callers can only invoke it through their own composition. |
| Grounded observation mode fix proposal, distinct-approver boundary, and two-phase delivery audit | implemented | core/readiness/remediation.py, composition/readiness.py, test_remediation.py, and test_readiness_remediation_service.py | Proposals stay observation mode, cite a mapped lever or hold for review, record approver identity, block self-approval, and never reach an executor. |
RemediationProposalPublisher binding to the safety check and executor ingress | not-started | Provider seam in shared/providers/readiness.py | No composition root binds the seam, so no proposal reaches a live safety check yet. |
Implementation history
Section titled “Implementation history”| Date | State | Change | Evidence | Remaining |
|---|---|---|---|---|
| 2026-08-13 | in-progress | Adopted the implementation ledger; earlier provenance wasn’t reconstructed. Recorded the implemented deterministic and orchestration surfaces separately from the unbound runtime workflow. | Current change; 48 passed from the five focused core and composition test files cited above. | Bind the event, providers, publisher, approval, and fix path, then collect governed runtime evidence. |
| 2026-08-16 | in-progress | Added the deterministic fix-proposal builder, the RemediationProposalPublisher seam, and the propose_remediations bridge that records approver identity, blocks self-approval, keeps proposals observation mode, and two-phase audits delivery. | Current change; 86 passed from uv run pytest -q --no-cov services/core-control-plane/tests/core/readiness/ services/core-control-plane/tests/composition/test_readiness_remediation_service.py services/core-control-plane/tests/composition/test_readiness_service.py services/core-control-plane/tests/composition/test_readiness_checklist_service.py. | Bind the proposal publisher to the safety check ingress, register ownership_transfer at event ingest, and collect a governed runtime receipt. |
| 2026-08-16 | in-progress | Hardened the fix identity and the distinct-approver check: idempotency-key material is length-prefixed so a separator inside a field cannot collide two detected issues, and principals are compared after Unicode NFKC folding. | Current change; 88 passed from uv run pytest -q --no-cov services/core-control-plane/tests/core/readiness/ services/core-control-plane/tests/composition/test_readiness_remediation_service.py services/core-control-plane/tests/composition/test_readiness_service.py services/core-control-plane/tests/composition/test_readiness_checklist_service.py. | Unchanged from the row above. |
Remaining work
Section titled “Remaining work”- Register and normalize
ownership_transferat event ingest, invoke the review through the accountable event-driven workflow, and add an integration test that proves replay-safe delivery. - Bind production posture, checklist evidence, and report-publisher implementations at the composition root, then record a governed runtime receipt for one complete observation mode review.
- Emit grounded, observation mode-only fix proposals with a distinct-approver boundary, and add
tests proving approver identity is recorded, self-approval is blocked, and the review service
never executes a managed-resource change
(
test_remediation.py,test_readiness_remediation_service.py). - Bind
RemediationProposalPublisherto the safety check ingress at the composition root and record one governed receipt showing a proposal reaching the Var approval flow without the review service holding an executor identity. - Keep enforcement disabled until frozen-scenario observation mode evidence meets the configured false-positive threshold and the authoritative promotion registry records the transition.
Safety posture
Section titled “Safety posture”- Read-only review, gated execution: the ORR and every detected issue are
read-only; the only path to a mutation is a proposal that enters
risk-gate -> executor, with the seven safeguards (stop-condition, rollback, impact scope limit, dry-run, resource lock, idempotency, audit entry) enforced there. - Approval and execution stay distinct:
HandoffApprovalcarries a distinct principal’s decision, andOperationalReadinessService.propose_remediationsdenies and audits a self-approval attempt before building any proposal. The proposal publisher is not yet bound to the live safety check, so the end-to-end Var approval flow remains open. - Fail closed: a stale twin (inventory freshness beyond
freshness_ttl) refuses to certify a handoff rather than certify on stale state; an ungroundable detected issue holds for review; an unproven review stays observation mode. - Audited: The current service records the ORR decision,
blocks_handoff, submitter, target scope, environment, and delivery/assessment failures in append-only state-store audit entries. Fix entries additionally record the approver identity, the observation mode, the proposal count, and the delivered count on failure. Saga agent attribution must be added with the future event-driven approval workflow.
Next steps
Section titled “Next steps”| To learn about | Read |
|---|---|
| The whole-graph review the ORR composes | assurance-twin.md |
| The single-deploy feasibility pass it reuses | deployment-preflight.md |
| The RBAC least-privilege rules the identity dimension fires | rule-catalog-collection.md |
| The cross-agent workflow that runs the gate | agent-workflows.md § 11 |
| The environment model the gate consumes | risk-classification.md § Environment Promotion |
| The risk classification each proposed fix resolves against | risk-classification.md |