Tycho
Someone applies for finance and hands over a payslip and a bank statement. Are they real? Tycho reads each document into typed records, runs 7 independent checks, and returns one of 4 verdicts with every reason written down. A reviewer can read the reasoning and disagree with it.
Overview
Tycho checks the payslips and bank statements that people hand over when they apply for finance. Forged income documents are where credit fraud starts, and a human reviewer cannot inspect the internals of a PDF. Tycho can, and it writes down what it finds.
The documents are South African, so the checks are too. Payslips are tested against the SARS tax tables and the UIF ceiling. Statements are checked line by line against their own running balance. ID numbers and bank branch codes are validated against their built-in check digits.
Most verification systems answer pass or fail. The dangerous case is the one in between: a document the system could not read properly. Without care, "I checked nothing" looks the same as "I found nothing", and that is how a forgery gets cleared. Tycho returns 4 verdicts instead of 2:
- Authentic clears the document.
- Fraudulent refuses it.
- Suspicious sends it to a person.
- Unverifiable also sends it to a person. It exists so that an unreadable document can never slip through as Authentic.
The system can only reject a document based on values it read clearly. If it could not read clearly, the verdict is Unverifiable and a person looks. An unclear document is never quietly cleared.
Seven ways to look at one document
No single check is the fraud detector. Each layer examines the document in a different way, and no layer depends on another, so beating one leaves the rest intact. The weights are set so that no single layer can cross the review threshold on its own.
- Structure – what the file says about itself. A PDF is a database of objects with a history. Two independent parsers read it, and if they disagree about the structure, the disagreement is itself evidence.
- Typography – a digital PDF stores the exact position of every letter as numbers, so the check measures coordinates rather than pixels: baselines, letter spacing, a font that switches in the middle of an amount, and anything painted on top of existing text.
- Pixels – render the page, read it back with OCR, and compare the result against the text stored inside the file. Lines are matched by position, not content, so an edited line cannot dodge the comparison by changing what it says.
- Numbers – gross minus deductions equals net, to the cent. Previous balance plus transaction equals new balance, on every line. PAYE against the tax tables, and UIF against its legal maximum.
- Cross-document – does the story hold together within one submission, across months, and across everything ever submitted. Because every file is stored under its fingerprint, the same statement appearing under 2 different applicants is a single lookup.
- Issuer – the other layers infer; this one asks. Some banks publish a way to verify a statement directly, through a code printed on it or a public verification page. The answer is confirmed, refuted, or unavailable, and unavailable is recorded as not checked, never as a pass.
- Anomaly – a small model trained only on genuine documents, running locally. It is advisory: it can push a document toward review, but it can never raise a fraud flag on its own or be the only reason a document is refused.
Reading a PDF's edit history
A PDF can be saved with incremental updates: the edit is appended and the original stays inside the file. Each saved revision is a complete snapshot, so when that history exists, Tycho opens every revision and compares them. The finding is not "this file was edited". It is "the net pay was edited", with the exact box on the page where it happened.
How a verdict is decided
Every rule that fires feeds one of two channels. Weak signals add points to a risk score, because one odd detail is common and three form a pattern. Conclusive findings raise a flag, and a flag stands on its own.
A flag is only as good as the reading underneath it. If the net pay that failed arithmetic was read from a blurry photo, the honest conclusion is that the OCR might have misread it, not that the document is forged. A flag therefore only stands if every value it rests on was read at 90% confidence or higher. Below that, the flag is removed, the removal is recorded, and the verdict is forced to Unverifiable. It cannot fall through to Authentic: the system has just objected to the document, so it must not clear it.
Two more rules close obvious gaps. A rule that crashed has checked nothing, so a crash makes the document Suspicious instead of passing silently. And unreadable essential fields are a finding in their own right, which closes the loophole where someone submits a deliberately poor photo so that every arithmetic check skips.
What the analyst sees
A finding means nothing until you can see the document, so the review screen puts the two side by side. Every finding names its rule, states its reason in a plain sentence, and points at the exact box on the page it came from. Checks that did not run are listed in their own panel, because a check that did not run is not a check that passed.

The queue is ordered oldest first, with no re-sorting by score. The risk in a review queue is the document that ages at the bottom, not the one that just arrived. Every row shows its full reason, so nobody has to open a document to find out why it is waiting.

The engineering
Tycho is 8 services: 2 edge APIs, 5 processing workers, and the web app the analysts use. The services never call each other. They share one PostgreSQL database that holds the job queue, the event log, the verdicts, and the rule settings.
The queue lives in that database on purpose. A worker claims a step with SKIP LOCKED under a lease that it renews, does the slow work outside any transaction, then commits the result, the appended events, and the next step's enqueue together. Either all of it happens or none of it does. A reaper requeues any step whose lease expired, so a worker dying mid-document never strands the document.
Every verdict stores the exact rule weights that produced it, so any verdict can be explained and reproduced months later. The 34 catalogued rules are data, not code, which makes the February change to the SARS tax tables a settings update instead of a software release.
What I deliberately left out
There is no message broker. Keeping the queue inside PostgreSQL lets "finish this job, save the result, start the next one" run as a single transaction, which a separate broker cannot promise. There is no cache tier and no service mesh for the same reason: every extra part is an extra thing that can fail.
There is no large language model. Document data is never sent to a chat model, which keeps privacy simple and keeps every verdict explainable to the person who has to defend it. The only machine learning is the small local anomaly model, and it can suggest review but never reject.
The limits, stated up front
Re-exporting a document rewrites it from scratch. Sharing a statement from a banking app, or printing it to PDF, destroys the revision history, the original producer, and the original fonts. Most genuine documents arrive this way, and a forger can take the same route on purpose. The structure layer is therefore silent on these files, and a silent structure layer is never read as a clean one. The weight falls on the layers a re-export cannot launder: the arithmetic, the cross-document story, and the issuer's own answer.
The classic image checks are held back for a related reason. On a genuine payslip, the cloned-region check reported 18 duplicated regions. A check that accuses honest documents is worse than no check, so each image check stays advisory until its false-alarm rate has been measured on real documents.
Privacy by construction
POPIA is mapped condition by condition to a specific control in the system, not to a policy document. All processing and storage stays in one South African region, enforced by an outbound allow-list. No data store faces the internet. Retention follows what the law requires, and an unclassified document takes the longer retention tier on purpose.