Decision states
Lifecycle
Section titled “Lifecycle”created ──► doc_uploaded ──► processing ──► approved │ │ rejected │ └─(challenge frames)──► manual_review ──► approved | rejected └── token expires (30 min) → verification simply never progressesnext_step (device view) maps: created → upload_document,
doc_uploaded → upload_selfie, processing → processing, final states → done.
Final states
Section titled “Final states”| State | Reversible? | Produced by |
|---|---|---|
approved | Attestable; product-level revocation only | Pipeline (all checks pass) or reviewer |
rejected | Create a new verification to retry | Pipeline hard-fail or reviewer |
manual_review | Yes — resolves to approved/rejected | Any uncertainty or suspicion |
Every path to rejected
Section titled “Every path to rejected”uploaded image is not an identity documentdocument expired on YYYY-MM-DDliveness check failed(+ the specific pose/consistency signals)face match below threshold (0.xx)- Reviewer rejection (with note)
Every path to manual_review
Section titled “Every path to manual_review”- Any
tamper signal: …from AI inspection MRZ validation failed: …(check digits)MRZ/visual disagreement: …low extraction confidence (0.xx)/quality: …/missing core identity fieldsliveness not confirmed/no active challenge issuedface match could not be computed/no face found on the document- Biometric stack unavailable (
face stack not installed) pipeline error: …(any exception — fail safe)
Full explanations of each signal: Fraud signals.
decision_reasons contract
Section titled “decision_reasons contract”Always present on final states; an ordered list of human-readable strings. Reviewer
decisions append (manual review (approve): <note>) so the full causal history
survives. Treat the strings as display/monitoring text, not a stable enum — match
on prefixes (tamper signal:, MRZ validation failed:) if you automate on them.