Close the books on proof,
not confidence.
Finco reconciles Razorpay settlements, bank statements and Tally ledgers. It resolves what it can prove, refuses to close what it cannot, and hands you a ranked queue of the decisions only a human can make.
Figures are read from the current run, not typed in. The model never touches them.
A five-stage cascade, and a rule for what it may not do.
Exact reference, fee-adjusted, date-shift, subset-sum, fuzzy. Each stage only claims what it can show, field by field. A fuzzy match caps at 0.75 and never auto-closes. When several answers are valid the engine abstains and files an exception instead of guessing. A group is only as provable as its weakest leg, and only the bank proves money moved.
No floats anywhere near a rupee. Decimal for intermediate arithmetic, integer paise for storage, enforced by a scan of the source tree.
Matching, rules, tiering and cash never import the LLM. CI enforces it. Anything a model wrote is shown in violet, so you always know.
Ambiguous, duplicate, chargeback and batch cases escalate regardless of confidence. Coverage is never bought with a guess.
The thing a finance
person draws by hand
when explaining a
settlement.
Gross collected, each deduction taken off it by a versioned rule, the expected net, what the bank actually credited, and the residual. In the product every line is hoverable and the gap is clickable: it filters the queue to exactly the exceptions that carry it.
A rule shrinks an exception. It never passes or fails one. “₹3,240 unexplained after rule X applied”, not “₹19,000 mismatch”.
Open the reconciliationGROSS COLLECTED -
├─ deductions, per rule, per row -
└─ EXPECTED NET -
vs BANK CREDITED -
─────────────────────────────────────────────────
UNEXPLAINED -missing_in_bank · 1 event · residual - ├─ stage fee_adjusted held confidence - │ └─ agreed amount, date · disagreed reference │ base - → result - └─ rule - v- explained -
Every decision carries its proof tree.
Stage attempted, fields agreed and disagreed, the confidence derivation, the rules considered and what each explained, down to the raw source row. A reviewer can re-derive any auto-close by hand. Empty evidence is a bug, not a state.
- Tell the agent what an exception is, in a sentence. It shows what it would do and waits.
- Over ₹50,000 you type the amount. Closing a chargeback without a dispute reference needs an acknowledgement.
- If the order you named does not exist, it lists the near matches and declines to pick one for you.
Policy as versioned code, back-tested before it can touch a run.
An edit creates version N+1. A database trigger refuses anything else. Every exception cites the rule id and version that shrank it.
A draft runs against every exception a human already resolved. Would explain, would partially explain, would wrongly close. A rule that would wrongly close anything is told so.
When three payouts share a pattern, the controller drafts a rule and shows it in violet. It waits for a back-test and a human. Always.
Measured against ground truth it cannot see.
A seeded adversarial generator writes the corpus and the answer key: truncated UTRs, split settlements, a mid-period rate change, duplicate vouchers, chargebacks nobody booked. The engine is scored against it on every run. The gates block merge, and false auto-resolutions is the one that matters.
Same seed, same rule set, byte-identical output. No wall-clock in logic, no unordered iteration. Replay any run under new rules and diff exactly which decisions moved.
- false auto resolutionsgate == 0-
- recallgate >= 90%-
- precisiongate == 100%-
- determinismgate byte-identical-
See the queue shrink in front of you.
The demo corpus runs in about a second. Every number on this page came from it.