Skip to content

· Ledger integrity

Why a posted entry should never change

Most accounting software will let you edit a transaction you posted last quarter. It is presented as flexibility. It is closer to a data-integrity bug that everyone agreed to stop calling one.

The convenience that eats your audit trail

Consider the ordinary case. You posted rent in March. In July someone notices it went to the wrong account. The obvious fix — open March, change the account, save — takes four seconds, and it silently rewrites history. March’s statements no longer match the March statements you already sent the client. Nothing records that they ever differed.

The damage is not the wrong account; that was already wrong. The damage is that the correction is invisible. A reviewer looking at the book in August sees a March that has always been correct, and has no way to learn that it was reported differently at the time. Every downstream artefact — the filed return, the exported P&L, the figure in an email — quietly disagrees with the ledger, and the ledger claims to have been right all along.

This is why the convention exists. Not pedantry, and not an artefact of paper: an accounting record is a claim about what was known when. Editing in place destroys the "when", which is most of the information.

What "immutable" has to mean to be worth anything

Almost every accounting product says it keeps an audit trail. Far fewer make the underlying record actually unchangeable, and the gap between those two claims is where the trouble lives. An audit log written by the same application code that performs the edit is a note the application takes about its own behaviour. It is accurate exactly as long as the code is correct and nobody reaches the database another way.

The stronger version is to make the edit impossible rather than merely recorded. In this product a posted journal entry cannot be updated or deleted at all — database triggers reject the attempt. That holds whether the request came from the app, from a migration, from a script someone ran at 2am, or from a bug in a code path nobody thought about. The interface cannot get it wrong because the interface is not the thing enforcing it.

It is worth being precise about what that buys. It does not make the numbers correct — nothing can do that. It means the numbers cannot change without leaving a trace, which is the property you actually need when someone asks why the figure moved.

So how do you fix a mistake?

The same way you would on paper, which is also the way an auditor expects to find it. You void the entry, which posts an offsetting entry on the original date, leaving the period’s totals undisturbed and both entries visible. Or you post a dated reversal, which puts the correction in the period where you noticed it. Which one is right depends on whether the original period is still open and whether anyone has relied on its numbers yet.

Both leave two rows where a lesser system leaves one edited row. That is not overhead, it is the record: the mistake, the correction, and the dates of each. A month later, when someone asks why March moved, the ledger answers the question instead of denying it happened.

The workflow cost is real but small — a few extra clicks on the rare occasion you need them. The cost of the alternative only appears later, at the worst possible moment, and lands on whoever has to reconstruct what happened.

The same argument applies to the AI

This reasoning is why the classifier in this product drafts entries and cannot post them. Not caution for its own sake, and not a temporary limitation waiting to be lifted once the model improves: a model that posts directly is a system where the ledger can change for reasons no human decided. That is the same defect as the in-place edit, arriving through a newer door.

So the classifier reads a statement, proposes entries, attaches its reasoning and a confidence score, and stops. Every proposal is a draft a person reviews, edits or rejects. The database function that advances an imported transaction is not capable of moving it to a posted state — the same structural approach as the immutability triggers, for the same reason.

The useful version of that constraint is that it makes the AI safe to actually use. You can let it work through a 300-line statement precisely because the worst case is a review queue with bad suggestions in it, not a ledger you have to unpick.

It is free, and it works this way by default.

Free forever, no card. See what it does.