Prism
A natural-language interface to a data warehouse that generates read-only queries inside permission boundaries and shows the definition behind every number it reports.
Ledger is a studio experiment in a problem almost every finance team has: documents arrive in a hundred formats and leave as the same nineteen fields. We built it to find out how much of the difficulty is model accuracy and how much is the engineering around it. The answer, consistently, was the engineering.
Technologies
Invoice processing is usually described as a reading problem. In practice it is a trust problem. A system that is right 95% of the time and cannot tell you which 5% it got wrong is unusable for accounting, because every record has to be checked anyway — which is the work you were trying to remove.
The interesting question is not “how accurate is extraction?” but “can the system reliably identify its own failures?” A pipeline that is right 90% of the time and knows exactly which cases it is unsure about removes far more work than one that is right 97% of the time and is uniformly confident.
We treated the language model as one component in an ordinary data pipeline rather than the pipeline itself. Documents are ingested, hashed and classified first. Extraction runs field by field against an explicit schema, and the model is required to emit a confidence value and permitted to emit null with a reason.
Everything after extraction is deterministic code: schema parsing, arithmetic checks, supplier reconciliation, policy rules. Deterministic checks are the part of the system that makes it trustworthy, because they fail the same way every time.
What the model cannot resolve becomes a review task scoped to the specific uncertain field — not the whole document. Reviewer corrections are stored and retrieved as precedent the next time a document from that supplier appears.
Ingestion, extraction and validation are separate workers communicating through a queue, so a slow OCR pass cannot block validation of documents already extracted, and any stage can be retried independently.
The reviewer interface is the product. It opens on the one field the system is unsure about, with the relevant region of the page already in view, and resolves in a single keystroke.
We deliberately did not build a chat interface. The reviewer does not want a conversation about an invoice; they want to confirm a number and move to the next one. Designing for the hundredth document of the morning rather than the first changed nearly every interface decision.
We assembled a fixture set of documents chosen for the ways they break things: rotated scans, tax shown per line rather than per invoice, two invoices in one PDF, credit notes formatted as invoices. Each fixture asserts an expected extraction and an expected routing decision.
The metric we optimised was not raw field accuracy but the rate at which the system silently produced a wrong value that passed validation. Those are the only failures that reach the ledger, and they are the only ones that matter.
Validation logic is covered by conventional unit tests. The extraction stage is held to a regression suite that runs on every change to prompts, schema or retrieval.
This is an experiment, not a delivered engagement, so there are no production figures to report. If it were deployed, these are the measures we would hold it to.
A natural-language interface to a data warehouse that generates read-only queries inside permission boundaries and shows the definition behind every number it reports.
An operations workflow that triages inbound requests, acts on the routine ones within written policy, and escalates everything else with its context already assembled.
We like ambitious problems — the ones with awkward constraints, messy data and a real cost attached to getting them wrong. Tell us what you are building and what makes it hard.