Turning on the gate

Shipmoor Team
June 11, 2026
4 min read

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 / inadmissible in 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_disclosed or verified.

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 inferred or unprobed,
  • 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

  1. Copy the shipped verdict policy somewhere your repo controls, e.g. .shipmoor/verdict-policy.yaml.

  2. In its gating: section, set enabled: 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
  3. 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

Last updated on June 11, 2026

Was this article helpful?

Your response is saved on this device.