Verdicts
A run ends in one of five statuses. Three of them are not passes and not failures, and Certus never collapses them into either.
The five statuses
- VERIFIED
- Every obligation was discharged at or above the grade your policy requires, and no debt is outstanding.
- VERIFIED_WITH_DEBT
- Everything attempted passed. Obligations remain deferred under a feature key, to be discharged by later work.
- FAILED
- An oracle ran over recorded evidence and the evidence contradicts the claim. This is a statement about your code.
- INCONCLUSIVE
- The proof executed and established nothing: it was vacuous against BASE, coverage missed the changed code, or repeated runs disagreed.
- BLOCKED
- The environment could not boot, so nothing was attempted. This is a statement about Certus, not about your code.
The last three are distinct on purpose. A tool that reports “not proved” as “failed” trains people to ignore it, and a tool that reports it as “passed” is worse than no tool. Each of the three has a different owner and a different next action.
How the run status is decided
Certus folds every obligation's effective status into one verdict, in a fixed order. The first rule that matches wins.
- If the environment never booted, the verdict is
BLOCKED— even if oracle results look red. Nothing was proved, so nothing was refuted. - If any obligation failed, the verdict is
FAILED. - If any obligation is inconclusive, or was planned and never judged, the verdict is
INCONCLUSIVE. - If any obligation is deferred, the verdict is
VERIFIED_WITH_DEBT. - If obligations were discharged and none of the above applies, the verdict is
VERIFIED. - Otherwise the verdict is
INCONCLUSIVE.
Two consequences follow from the last rule and are worth knowing. A run with no obligations at all is INCONCLUSIVE, not VERIFIED — an empty proof is not a proof. So is a run whose every obligation was waived: waiving is a decision to merge without proof, and the verdict continues to say so.
BLOCKED is not a failure
BLOCKED means the twin environments never reached a ready state: a service did not start, a required variable was missing, a credential was refused, the isolation floor was unavailable. No claim was tested.
It never gates a merge and it is never rendered in the failure colour. On GitHub the check is neutral, on GitLab canceled, on Bitbucket STOPPED, on Azure DevOps notApplicable — never failed on any of them. A BLOCKED run still publishes the static review findings, because reading the code does not require booting it.
Every BLOCKED run carries a boot failure record: the last state reached, the transition that was attempted, a typed reason, per-process exit codes and log tails with the line of .certus/env.yaml that declared them. See substrate for how to read it.
INCONCLUSIVE means the proof was bad
This is the status people misread most often. It does not mean your change is suspect. It means Certus ran a proof and learned nothing from it, and it names which of the three ways happened.
- plan does not exercise the change
- The same plan passed on BASE. Whatever it proved was already true before your change, so it says nothing about your change.
- changed nodes not executed
- The run never reached the code you changed. Coverage has to be total over the changed nodes, not partial.
- determinism 2/3
- Repeated runs of the same proof disagreed. The count is reported exactly and never averaged into a grade.
The correct response is to fix the proof — widen the frontier, make the environment reproducible, or carry the claim as debt. It is not to go hunting for a bug.
Signing and the merge gate
Every verdict carries an evidence root: a signed hash over the evidence the run produced. It also records the digest of the policy that actually applied and a snapshot of the debt ledger as it stood, so the verdict can be re-evaluated later against the rules that were in force, not the rules in force today. A BLOCKED run with no root says so in words rather than printing a placeholder.
The gate passes for VERIFIED and VERIFIED_WITH_DEBT when no policy reason is outstanding — minimum grade met, debt within limits, negative control demonstrated, no model-only claim where your policy forbids them. FAILED, INCONCLUSIVE and BLOCKED never pass, and BLOCKED never gates either: it is Certus's problem to fix.
From the CLI, VERIFIED and VERIFIED_WITH_DEBT exit 0, FAILED exits 2, INCONCLUSIVE exits 3 and BLOCKED exits 4 — so a pipeline can treat the three non-passes differently.
When it says something unexpected
BLOCKEDon a change that obviously works- Nothing was tested. Read the boot failure record's reason and the service it names; the fix is almost always in
.certus/env.yamlor a missing environment variable. INCONCLUSIVEwhere you expected a pass- Read the reason. All three causes are about the proof, not the code: it also passed on BASE, it never ran your code, or it did not repeat.
VERIFIED_WITH_DEBTon a finished feature- Certus still has obligations deferred under that feature key. Open the claim to see which frontier they are waiting for — and check the feature key is the one you expect.
INCONCLUSIVEafter waiving everything- Correct. Waivers let a merge proceed; they do not turn an unproved run into a proved one.
FAILEDyou disagree with- Open the evidence root and replay the run. A failure names the oracle and the artifacts it read, so the disagreement is settled by looking, not by arguing.