The declarative policy checklist every case must satisfy — deterministic checks, thresholds on AI verdicts, and retry behaviour
Goal Rules
Goal Rules are the policy layer of 9thSense. Every agent carries a checklist of rules in its definition; a case cannot complete until every rule passes. Rules turn raw check results — extracted fields, fraud verdicts, match scores — into decisions: approve, retry, review, or deny.
They are declarative JSON, versioned with the agent, and snapshotted into every case — so the audit record shows not just what was decided, but exactly what policy decided it.
Anatomy of a rule
{
"id": "passport_validity_6m",
"severity": "hard_stop",
"check": "date_after",
"params": {
"field": "date_of_expiry",
"source": "passport",
"min_gap_days": 180,
"on_fail_message": "Your passport does not have the required 6 months of validity."
},
"on_deny": {
"message": "Passport expires within 6 months.",
"max_retries": 0,
"remediate_type": ""
}
}
| Field | Purpose |
|---|---|
id | Stable identifier; shows up in goal progress and the audit trail. |
severity | hard_stop (fail = case denied, no retry) or require (must pass, resubmission allowed). |
check | Which comparator or verdict to evaluate. |
params | Check-specific configuration: source document, field, thresholds, user-facing failure message. |
on_deny | What happens on failure: reviewer message, max_retries, and which document slot to ask the applicant to resubmit (remediate_type). |
Check types
Deterministic comparators — always the same answer for the same input, zero model involvement:
| Check | Evaluates |
|---|---|
field_contains / field_equals | An extracted field contains or equals a value. |
field_gte / field_lte | Numeric threshold (balance, income, age). |
date_after / date_before | Date validity with configurable gaps (expiry buffers, statement recency). |
format_valid | The field matches its type's format — including ID checksums: PAN structure, Aadhaar and GSTIN check digits. A synthesized ID number almost never survives a real checksum. |
cross_field | Consistency between fields on the same document (period vs transaction dates, totals vs line items). |
Verdict thresholds — gate on the confidence of fraud and integrity checks:
| Check | Evaluates |
|---|---|
liveness_confidence_gte | Liveness verdict for the session or selfie. |
deepfake_confidence_below | Deepfake risk stays under your ceiling. |
face_match_gte | Likeness between selfie and ID photo. |
face_anchor_unbroken | The same person stayed on camera all session. |
lipsync_confidence_below | AV desync risk under threshold. |
integrity_risk_below | Document integrity risk under threshold. |
cross_match_field_gte | Cross-document agreement per field. |
Custom (AI-evaluated) — for policy that can't be expressed as a comparator, write the rule in plain language and the platform evaluates it against the extracted data:
{
"id": "outbound_to_thailand",
"severity": "hard_stop",
"check": "custom",
"params": {
"prompt": "Check whether the FINAL destination of this flight is Thailand. Ignore transit cities.",
"sources": ["outbound_flight"],
"on_fail_message": "Your outbound flight does not end in Thailand."
},
"on_deny": { "message": "Outbound flight not to Thailand.", "max_retries": 1, "remediate_type": "outbound_flight" }
}
Custom rules run against already-extracted JSON, never the raw image — so they are cheap, fast, and auditable.
Severity and remediation
| Severity | On failure |
|---|---|
hard_stop | Case denied immediately. Use for disqualifiers: wrong nationality, failed checksum, deepfake verdict. |
require | Case blocked; applicant may resubmit the document named in remediate_type up to max_retries times. Use for fixable problems: blurry upload, stale statement, low balance. |
Put the user-facing explanation in params.on_fail_message and keep it actionable but non-specific for fraud rules — tell a genuine user how to fix a blurry upload; never tell a fraudster which detector caught them. The precise reason lives in on_deny.message for your reviewers.
Goal progress
As checks complete, each rule's state is tracked on the case as goal progress — visible in the dashboard, the API (GET /v1/cases/{id}), and conversational agents use it to tell the applicant what is still outstanding. When every rule passes, the case moves to completed (or to review if your policy routes flagged cases through a human).
Every rule's outcome is shown on the case with its severity — here a video-KYC case where the deterministic rules (consent, geo, PAN format) passed but the liveness verdict threshold fired a warning:
Rule evaluations table on a case — ten rules with pass, skip, and warn results: consent logged, geo in India, and PAN format passing as hard stops; Aadhaar freshness and video liveness score warning; face match, name match, single person in frame, and single speaker passing
And a clean run — an Income Verification Agent case where both income-threshold rules passed and the case auto-approved, with the extracted fields alongside:
Completed Income Verification Agent case — verdict Approved with 2 of 2 rules passed (Form 16 gross and payslip gross thresholds), and the extracted ITR acknowledgement fields shown below
Where to see them in action
Build a KYC Agent
A complete agent with nationality, validity, funds, and custom AI rules. See Build a KYC Agent.
Checks Overview
The fraud checks whose verdicts these rules gate. See Checks Overview.