Thavasi Scrutiny: a zero-tolerance audit of every Indian customs checklist, with the evidence attached
Before a Customs House Agent files a Bill of Entry, someone has to check the draft checklist against the commercial invoice, the packing list, the bill of lading or air waybill, and the certificates — field by field. A wrong container number or a currency read as INR instead of USD is a penalty, a held consignment, or a re-filing. Cooper Compass, an IIT Bombay-incubated startup, needed that scrutiny to be systematic and defensible rather than a senior filer squinting at PDFs.
- 1
Built the product end-to-end as their delivery partner: React and TypeScript on the front, FastAPI and PostgreSQL behind it, with slow OCR pushed into a Redis-backed worker so an upload returns immediately and the browser polls for the result.
- 2
Local-first extraction — pdfplumber, camelot, pytesseract and openpyxl do the reading. A vision model is called only for genuinely scanned pages, behind a flag, so documents are not shipped to a third party by default.
- 3
A deterministic scrutiny engine compares 18 catalogued customs fields, 10 of them zero-tolerance, across air, sea, road and rail. Transport mode is resolved first, so a container number is never demanded of an air shipment.
- 4
Every extracted value carries its own provenance — document, page, extractor, cell, bounding box, raw text and confidence — captured at extraction time so the report can always show where a number came from.
Technical insight
The engineering decision that matters here is that the language model is never in the decision path. It gap-fills extraction on layouts the deterministic parsers miss, and it narrates why a flagged field differs — but matching, verdicts and ordering are pure functions of the inputs and a versioned rule config. Re-run an audit from six months ago against the config it ran under and you get the same findings, which is the difference between a tool a broker can defend to customs and a tool that merely sounds confident. The engine also refuses to guess: a value is only evidence for the field whose own printed label it sat under, so two similar-looking numbers in different comparison groups are never matched to each other. It reports discrepancies and never proposes a value.
18 fields
Audited per checklist, 10 at zero tolerance
Reproducible
Same inputs and rule version, same verdict
Local-first
OCR runs in-house, not in a third-party API