Why Recouped doesn’t let a language model touch money

Reconciliation has one right answer per line. A model that is usually right is the wrong tool for it. Where the model sits in Recouped, where it does not, and what that costs.

What language models are good at

A payout statement from a payment platform is not a clean table. It is a CSV with a column that changed name in March, a PDF with the totals in a footer, a memo field that says “refund for order 4471 partial” in one row and “RFND 4471” in the next. Reading that is a language problem. Language models are good at language problems. They can read a statement in a format nobody wrote a parser for, pull out the fields that matter, and say what a row is in plain English.

They are also good at the other end of the job: turning a list of exceptions into a paragraph an owner can read on a phone. “Seven refunds issued in June were not synced to the ledger; revenue is overstated by $2,204.00” is a sentence a model writes well, given the numbers.

Those are the two places a model earns its place: reading the messy input, and explaining the finished output.

What they are bad at

Arithmetic. Not in the sense that a model cannot add two numbers, but in the sense that it is not guaranteed to. A model produces the most likely next token. Most of the time, for most sums, the most likely token is the right digit. Sometimes it is not, and there is no signal when it isn’t. The wrong answer arrives in the same confident register as the right one.

Consistency. Ask a model the same question twice and you can get two answers. Ask it to match ten thousand rows and it will match them slightly differently on Tuesday than on Monday. A reconciliation that cannot be re-run to the same result is not a reconciliation. It is an opinion.

Being wrong the same way twice. Deterministic code has bugs, and a bug is repeatable. You find it, you write a test, it stays fixed. A model’s errors are not repeatable in that way. You cannot write a test for “the model occasionally decides these two amounts are the same transaction.” You can measure how often it happens. You cannot make it stop.

Why reconciliation is the worst place for a probabilistic step

Three things make reconciliation different from most work a model could do.

The answer exists. For every line on a payout statement there is exactly one correct disposition: it matches a specific line in the bank feed and a specific entry in the ledger, or it does not. There is nothing to estimate. A step that estimates is adding uncertainty to a question that has none.

Errors are silent. A mismatched line does not look wrong. It looks like a matched line. The total still ties, or nearly ties, and nearly is close enough for most people not to look further. The whole reason reconciliation exists is that money errors do not announce themselves. A process that can introduce its own quiet errors defeats its purpose.

The output is signed. A reconciliation is something a person puts their name on. An accountant signing a month is saying the exceptions are what the workpapers say they are. If the workpapers came from a process that is right most of the time, the signature means less than it should, and the person signing usually does not know it.

Put those together. A probabilistic matching step is an unbounded, undetectable, unrepeatable source of error inserted into the one process whose job is to find error. That is the argument. Everything else is implementation.

How Recouped is built

The engine that decides whether two amounts are the same money is a tiered rules engine. The first tier matches on hard keys: a payout ID that appears on both the platform statement and the bank line, a charge ID that appears in the ledger. The next tier matches on amount and date within a tolerance that is written down. The next handles the known shapes of disagreement: a payout that nets several days of charges, a refund that lands in a later period than its charge, a fee that the platform reports gross and the ledger records net.

Every tier is a rule. Every rule has a name and a version. When a line is matched, the log records which rule matched it and why. When no rule matches, the line is an exception, and it says so. The engine never guesses at the remainder. It reports it.

A language model sits at two edges of that engine and nowhere inside it. At the front, it reads statements in formats the parsers do not yet handle and proposes a structured version, which goes through validation before the engine sees it. At the back, it takes the engine’s finished list of exceptions, each one already quantified, and writes the sentence a person will read. It does not add. It does not match. It does not decide. If you took the model out entirely, the reconciliation would still be correct. It would just be harder to read.

What this costs

It costs coverage. A model will read anything. A rules engine handles the formats it has rules for. When a client shows up with a platform Recouped has not seen, someone has to write the parser and the rules, and until they do, that platform is not supported. That is slower than pointing a model at the file and shipping.

It costs some elegance. Tolerances, tiers, and versioned rules are less exciting than a model that appears to understand money.

It buys three things. The same input produces the same output, every time, which is what makes a reconciliation something you can re-run. Every match carries its reason, which is what makes it something you can check. And when the engine does not know, it says so, which is the one property a reconciliation cannot do without.

That is the trade. Recouped takes it on purpose.

Run a free check

One reconciliation pass on one month of your data: platform to bank to books, exceptions listed with amounts. Nothing is retained.

Request a check