The contract gate is designed so that merging a breaking contract change requires a cryptographic proof that a CodeRifts decision approved the exact diff being merged — a proof the CI runner verifies itself, and that branch protection makes non-optional.
| Property | Provided by |
|---|---|
| The decision covers the real merge candidate, not a substituted clean spec | Artifacts derived from git diff base...head in the runner — never caller input (Gap-5) |
| The approval is authentic (issued by CodeRifts, not forged) | Ed25519 signature verified offline against the pinned keyring (keyring/pinned-keys.json), never a key fetched from the server under test |
| The approval is for this exact change set | v4 receipt body_hash binding — the receipt is bound to the specific decision envelope built from the diff |
| The approval is an ALLOW, not just "few breaking changes" | Pass requires execution_action ∈ {CONTINUE, CONTINUE_WITH_MONITORING}. With require_verified_monitoring: true the gate verifies a cr.monitor.attest.v1 token offline against a pinned monitoring keyring (CWM passes only on delivered_acked); by default it passes CWM on the host's claim. The token proves a monitoring-key holder observed the delivery — not that a human read it, not that the sink targets the right audience. |
| The proof is unbypassable at merge | GitHub branch protection: CodeRifts / contract-gate as a required status check |
The first four are enforced by the action itself (fail-closed). The last one is what makes it matter — without a required status check, the gate only advises.
The gate verifies offline against a bundled keyring and never asks the server it is
verifying for the verification key (that would re-trust the thing under test). Currently pinned:
kid = 2026-07-k1 (Ed25519). Rotation is additive — add the new key entry in a PR; both old and
new keys stay valid so in-flight receipts still verify. An unpinned kid fails closed (UNKNOWN_KEY).
Branch protection is a GitHub feature, and GitHub lets repository administrators bypass required checks unless you explicitly forbid it. For true enforcement:
- UI: enable Include administrators (or "Do not allow bypassing the above settings") on the protection rule.
- API: set
"enforce_admins": true(the providedscripts/require-contract-gate.shdoes this).
With enforce_admins: true, even an admin cannot merge a PR whose CodeRifts / contract-gate check
is failing or missing. Without it, an admin can override — document who holds admin, because that is
your remaining trust boundary. Other standard GitHub escape hatches (disabling the rule, deleting the
workflow) are also admin-only actions and should be governed the same way.
- It does not stop a change from being written — it stops it from being merged to a
protected branch. (The in-process
@coderifts/agent-guardis the write-time layer; this is the server-independent merge-time layer.) - It governs the contract artifact families it classifies (openapi/graphql/grpc/asyncapi/
mcp-manifest). A contract expressed in an unclassified file would not be detected — extend
src/artifacts.jsclassifiers as needed.
The artifact is not the contract. The bullet above is about files this gate fails to classify;
this one is about a change it cannot see at all. The gate keys off the PR's head diff of contract
files. An implementation edit under an unchanged spec changes the served behaviour and produces
nothing for the gate to weigh: the contract diff is empty, the receipt covers a change set that
does not describe what actually shipped, and a green check means only that the artifact did not
move. A handler that starts returning null for a field the schema still marks required, a
response that quietly changes shape, an authorization check deleted behind a byte-identical
OpenAPI file — none of those are contract changes as far as this gate is concerned, and none of
them are caught here. Governing the artifact is not the same as governing the behaviour it
describes, and this gate does not diff served behaviour.