Unit states
Every unit resolves to exactly one coverage state. The state is what
vidi status, vidi report and vidi queue display; the disposition is
the pass/fail signal the gate reads.
Source of truth: GateState in crates/vidi-core/src/ledger/staleness.rs.
The states
| State | Meaning | Disposition |
|---|---|---|
| Fresh | The unit’s current hash equals a non-revoked, approved review’s subject digest, under a compatible profile and scope. The only covering state. | Covered |
| Stale | The unit still exists at the reviewed address, but its hash changed. | Gate-fail |
| Orphan | A non-revoked review whose subject no longer resolves to any unit — renamed, moved, or deleted. | Gate-fail |
| Unreviewed | No covering review at all. | Uncovered |
| Rejected | An exact-hash-matching review with verdict: rejected. Someone read these bytes and said no. | Uncovered |
| Migration-needed | A hash-matching approved review whose profileVersion, scopeModelVersion or node domain is incompatible. | Uncovered |
| Attested | A hash-matching approved review that does not claim the core equivalent criterion — for example a gh:viewed attestation. Surfaces as under-reviewed. | Uncovered |
The three dispositions
Covered: the unit passes. Only Fresh qualifies.
Gate-fail: the unit fails the gate on its own, regardless of policy.
Only Stale and Orphan. Both mean a review claims to describe code that is
no longer there, which is broken independently of any rule you configured. This
is why editing a vouched unit fails the gate in a repo with no policy.toml at
all.
Uncovered: not covered, but not an independent failure either. The trust
policy decides whether it matters. A default = "advisory" policy tolerates
these; a [[scope]] requiring a rank does not.
Two rules that are load-bearing
Migration-needed dominates Fresh. It is evaluated first, so a
profileVersion or scopeModelVersion mismatch never resolves to Fresh even
when the stored hash equals the current recompute. A review made under different
analysis rules is not silently honoured.
Over-report, never false-fresh. Every ambiguity resolves toward Stale,
Orphan or uncovered. The tool would rather say something needs review when it
does not than the reverse. See
Fail-closed by default.
Rejected is narrower than it looks
Rejected is reached only when a review inspected the current bytes:
- a rejected review on an older hash is
Stale, nothing has inspected what is there now - a rejected review whose address resolves to nothing is
Orphan
So Rejected means “someone looked at exactly this and declined it”. It is not
coverage, can never read Fresh, and never gate-fails on its own. The unit
falls to Unreviewed for gating purposes.
A malformed ledger line is a different thing entirely, and does exit non-zero.
Severity is advisory
vidi churn and the severity bands rank how much a change matters. They order
the re-review queue and never affect any state above. The gate reads only the
binary signal: exact hash, verdict, and profile compatibility.