Claim
Policy-as-code is load-bearing infrastructure — necessary for deterministic governance, insufficient alone. It evaluates declared configuration at selected checkpoints and returns an allow/deny verdict. It does not, by default, model authority, preserve evidence across lifecycle, or close drift between declared and observed state. Those four gaps are the four slots below.
Request vs transition
A request is a point event: "may this config be admitted?" A transition is a state change over a lifecycle: admitted → executed → mutated → reconciled. Policy-as-code excels at the first. Governance must bind the second.
The subtlety: an admitted request frequently produces post-admission state that the policy engine never re-evaluates. Drift accumulates silently. A governance system treats this drift as a first-class governed event; a policy-as-code system treats it as an operational concern.
The drift-model slots
Any deterministic governance system must fill these four slots. Policy-as-code natively fills zero.
PROCEED, HALT(code), ESCALATE(role), or ROLLBACK(scope). Advisory output is not a remediation mode.Filled cases
IV.a · Registry drift (naming authority)
governed_state : canonical registry@v7 (signed manifest)
observed_state : runtime_registry_snapshot (collector: ledger replay)
detection rule : hash(governed) ≠ hash(observed)
→ classify(divergence) ∈ {added, missing, mutated}
remediation mode : HALT(code=461, "registry_drift")
| ESCALATE(role=registry_owner)
evidence : phase-8 ledger entry bound to governed version
IV.b · Post-admission policy mutation
A request was admitted under policy P@v12. Between admission and execution, P is updated to v13 with a stricter clause. Policy-as-code has no continuing claim — the verdict was rendered. Governance must:
governed_state : (policy_id, version, admission_hash)
observed_state : (execution_context, current_policy_version)
detection rule : admission.version ≠ current.version
∧ delta(admission.version, current.version)
intersects(event.scope)
remediation mode : HALT(code=428, "stale_admission") | ROLLBACK
evidence : admission envelope + signed version diff
IV.c · Ungoverned surface emission
A surface emits an event the routing registry does not bind. Policy-as-code would return "no applicable policy" and allow; governance treats the absence itself as the violation.
governed_state : routing_registry@v4 (bound (surface, event_type) pairs)
observed_state : runtime_event { surface, event_type }
detection rule : (event.surface, event.type) ∉ routing_registry
remediation mode : HALT(code=404, "non_governed_surface")
IV.d · Authority delegation expiry
governed_state : authority_graph@v2 (delegation edges, expiry, revocation)
observed_state : ack_envelope.delegation_chain (per event)
detection rule : ∃ edge ∈ envelope.chain :
edge.expiry < now_clock(governed)
∨ edge.edge_id ∈ revocations
remediation mode : HALT(code=301, "authority_expired")
| ESCALATE(role=authority_owner)
Implication
Policy-as-code is the deterministic-evaluator primitive from § IV of the category paper. The remaining four criteria — authority model, evidence-backed ledger, lifecycle enforcement, drift closure — must be added around it. A system that equates policy-as-code with governance has filled one of five slots and claimed the set.
Treat policy-as-code as a substrate, not a ceiling. Invariants may lower to Rego; authority, evidence, and drift closure may not.