By default the claim check is advisory — it reports, and it never changes your exit code. A team can opt in to blocking a merge, but only on falsifiable, deterministic evidence against a confident intent. Everything weaker is refused in the engine, no matter what the policy file says.
What can — and cannot — block
A change can block only when all of these hold:
- the verdict is one of the two strongest rungs (
major_gap/inadmissiblein the policy vocabulary below), and - at least one expectation was checked deterministically and came back unmet, and
- the resolved intent’s confidence is not low, and
- the maturity is
gap_disclosedorverified.
The gate refuses to block — regardless of policy — when any of:
- the evidence is an advisory (non-deterministic) opinion, including anything from BYO-Judge,
- the maturity is
inferredorunprobed, - the intent confidence is low,
- the verdict is only a minor gap.
This floor lives in the engine, not the policy file. A policy can tighten the gate — require high confidence, disable a verdict from blocking — but it cannot loosen the floor. Lowering the confidence requirement, allowing non-deterministic evidence, or adding an unknown key is a policy validation error, not a configuration choice.
In practice: a one-line --intent guess never blocks even with gating fully on (single source ⇒ low confidence ⇒ the floor refuses); two agreeing sources can. See Providing intent.
Turning it on
-
Copy the shipped verdict policy somewhere your repo controls, e.g.
.shipmoor/verdict-policy.yaml. -
In its
gating:section, setenabled: true:gating: enabled: true min_intent_confidence: medium # high | medium (never low) block_on_major_gap: true block_on_inadmissible: true require_evidence_basis: deterministic -
Point scans at it:
shipmoor scan --diff main...HEAD --intent "…" --prompt "…" \ --verdict-policy .shipmoor/verdict-policy.yaml
When the gate fires, the scan exits non-zero and names the exact probe that triggered it:
Claim check GAP DISCLOSED · maturity: gap_disclosed · coverage: 100%
⊘ Gate: BLOCKED — The changed Kubernetes resources reference the service the intent named.
The exit code unifies with the structural finding gate: the scan exits 1 if either the --fail-on threshold or the claim-check gate fires. See Output formats & exit codes.
Calibrate before you enforce: --would-block
Don’t switch enforcement on cold. Preview first:
shipmoor scan --diff main...HEAD --intent "…" --prompt "…" \
--verdict-policy .shipmoor/verdict-policy.yaml --would-block
--would-block computes the gate as if enabled and prints what would have blocked — but always exits 0:
⊘ Gate: would block (preview) — The changed Kubernetes resources reference the service the intent named.
Even with the gate fully off, a change that would block already shows a Gate: disabled — would block if enabled line, so you can see the gate’s footprint before committing to it.
Recommended rollout: run in --would-block preview across your changes for about two weeks. Watch what it would have blocked, tune min_intent_confidence and which verdicts block, and only then set enabled: true. A gate a team learns to trust is one they previewed first.
Traceability
- Gating is per-changeset (one block decision per change) and global — per-domain enablement (gate only payments, only Kubernetes) is a likely future addition, not available today.
- The decision is recorded in the JSON result as
gate_decision(not_evaluated/passed/would_block/blocked) along with the policy version that produced it, so a block is always traceable to a specific probe, intent, and policy.
Next
- Reading the verdict — maturity, coverage, and confidence.
- Providing intent — why two agreeing sources matter.
- Configuration — where the policy file lives alongside the rest.