Gating and exit codes

Shipmoor Team
July 13, 2026
7 min read

Claim Check checks whether a change did what the task asked, then reports one of four verdicts. This page covers what happens next: shipmoor claim-check gates every run, unconditionally. The exit code follows the verdict with nothing in between: READY and READY_WITH_GAPS exit 0; BLOCKED and INCONCLUSIVE exit 1. There is no flag, no config key, and no policy setting that changes this mapping. If you run the command in CI and fail a step on a nonzero exit code, a BLOCKED or INCONCLUSIVE verdict fails that step. That is the entire gating model.

If you used an earlier release of Claim Check: you may remember a --verdict-policy flag, a --would-block preview mode, and a gating.enabled config key that had to be switched on before a BLOCKED verdict could fail a build. None of that exists in 0.8.0. Gating used to be something you opted into. Now it is simply what the exit code means, and there is nothing left to turn on.

The four verdicts, and what they exit

The exit code is not a separate decision layered on top of the verdict under some policy. It is the verdict, expressed as a number.

VerdictWhat it meansExit code
READYThe deterministic floor is green, nothing is blocked, and nothing required is left underspecified.0
READY_WITH_GAPSThe floor is green and nothing is blocked, but something non-required is still open or unresolved.0
BLOCKEDA deterministic-floor check came back red, or the floor is green but a judge block was confirmed.1
INCONCLUSIVEThe floor is green and nothing is blocked, but a required item could not be resolved and routes to a human.1

The remaining exit codes are operational, not verdicts: 2 for a usage error, 3 for an engine crash. See CLI reference.

How the verdict is fused

Underneath, the verdict is decided by a fixed priority order, checked in this sequence:

  1. Any deterministic-floor check comes back red. That alone is BLOCKED. Nothing else matters once this is true; it always wins, regardless of anything else in the run.
  2. The floor is green, and the judge confirmed a block. Also BLOCKED. A judge block only counts once it has survived actually re-running its own cited test or command, hermetically, at the reviewed head. See BYO-Judge.
  3. The floor is green, nothing is blocked, and a required item is abstained or otherwise undecided. INCONCLUSIVE. This routes to a human instead of guessing in either direction.
  4. The floor is green, nothing is blocked, and nothing required is left underspecified. READY.
  5. The floor is green, nothing is blocked, and something non-required is still open. READY_WITH_GAPS.

Notice what’s missing from this list: there is no step where the judge, on its own, produces a passing verdict. The judge can only BLOCK (rule 2) or push a required item toward INCONCLUSIVE by abstaining (rule 3). It never independently passes an obligation. A green verdict always rides the deterministic floor, never the judge alone. See What is Claim Check for the three layers this priority order sits on top of.

An unapproved acceptance set is never a pass

The acceptance set feeds this fusion order too, and its approval state matters as much as its content. Three files are involved:

  • .shipmoor/acceptance.yaml: the human-authored, editable acceptance set. This is what --acceptance points to, and what you edit by hand.
  • .shipmoor/acceptance.yaml.draft: an auto-derived, unapproved draft, written when no acceptance.yaml is committed at that path. Every draft is disclosed as unapproved.
  • .shipmoor/acceptance.json: a frozen, hashed, committed pin used for tamper detection once a set is approved.

If no acceptance.yaml is committed, the gate can auto-derive one from the frozen intent instead of simply failing. How much that draft leans on a model is controlled by claim_check.authoring_mode:

ModeWhat happens
author (default)Hand-authored only. No model runs. You write .shipmoor/acceptance.yaml yourself, typically starting from shipmoor claim-check init.
autoLLM extraction derives a draft acceptance set from the frozen intent.
hybridThe same auto-derived draft, plus a human-confirm step before it counts as approved.

Approval means committing the file. There is no --yes flag and no config key that marks a draft approved from the command line. A run over an unapproved or draft acceptance set that would otherwise have come back READY is downgraded to INCONCLUSIVE instead. A draft is never an approved pass, no matter how clean the underlying change is.

What this means in CI

Wire the exit code into a required check and you get exactly the table above: BLOCKED and INCONCLUSIVE fail the step, every run, unconditionally. No config key turns a BLOCKED verdict into a passing build.

shipmoor claim-check . --floor-only --from origin/main --to HEAD
# exit 1 on BLOCKED or INCONCLUSIVE, no exceptions

If a team wants Claim Check as a required, blocking check, this is already the entire wiring: install the binary, run the command, let the step’s own exit code decide the job. No policy file is needed to make it block; it already does.

Keeping a step informational instead

If you want Claim Check to report without blocking the build, for a rollout period or for a check you are not ready to require yet, do it at the CI level, not the command level. There is no first-party advisory-mode flag that makes a single invocation exit 0 on a bad verdict. Two patterns work instead:

Run it as a separate, non-blocking step. Guard the step so its own exit code cannot fail the job, and still capture the result as an artifact:

      - name: Shipmoor Claim Check (informational for now)
        run: |
          shipmoor claim-check . --from origin/main --to HEAD \
            --json --output claim-check.json || true

      - uses: actions/upload-artifact@v4
        with:
          name: claim-check-result
          path: claim-check.json

Or, only fail the job on a different, separate condition you already control, such as your structural shipmoor scan --fail-on gate, and treat the claim-check step as a report to read rather than a required check.

Both patterns leave the command’s own exit-code behavior untouched. What changes is whether the surrounding job treats that exit code as load-bearing.

What you can actually tune: the floor policy file

The exit-code mapping itself has no dial. What does have one is a narrower, separate mechanism: the floor policy file, set with claim_check.policy_path in .shipmoor.yaml and defaulting to a shipped floor_policy.yaml (policy_version: "1.1.0").

# .shipmoor.yaml
claim_check:
  policy_path: ".shipmoor/floor_policy.yaml"

Copy the shipped file into your repo and point policy_path at your copy to adjust it. Its scope is deliberately narrow. It can toggle a couple of optional, cross-cutting requirements on or off, among them a scan-severity threshold and whether artifact or build validation is required for a given run.

It cannot touch the core of the floor. Every one of the following is enforced unconditionally, regardless of what the policy file says:

  • an open must-fix finding from the scan,
  • a required test transition,
  • a confirmed judge block,
  • a required acceptance item,
  • test integrity,
  • a green build,
  • green tests.

None of those are policy-configurable, in either direction. Treat the floor policy file as a narrow dial on a couple of optional extras, not as a general opt-in or opt-out system for the gate itself.

Next

  • What is Claim Check: the three layers the verdict is built from.
  • CLI reference: the full flag surface and the exit-code table.
  • Reading the verdict: the four verdicts and the VSA in detail.
  • BYO-Judge: sampling, the confidence threshold, and the pointer-must-resolve rule behind a confirmed block.
  • Providing intent: where intent comes from and how it reaches the acceptance set.
  • CI integration: wiring the floor into a GitHub Actions job and publishing the VSA.
  • Attestation artifacts: where a gating decision is recorded for later audit.
  • Test Evidence: attesting that tests actually ran, as a separate producer this gate can consume.
Last updated on July 13, 2026

Was this article helpful?

Your response is saved on this device.

Related Articles