Every accounting system faces the same question on its first day: what happens when a user wants to change something that was already posted? There are two possible answers, and they produce two completely different products.
One updates the row. The other posts a new entry that cancels it. The second answer is slower, uses more storage, and is the only one that leaves you able to prove what your books said last quarter.
The rule: history is appended to, not changed
A posted transaction is a statement about the past. It says that on a given date, with a given reference, these accounts moved by these amounts. That statement was used: it fed a report, a tax return, a board pack, a covenant calculation, a commission.
Changing it does not make the past different. It makes the past unknowable. Once the row that supported March’s revenue figure has been edited, there is no longer any way to demonstrate what March’s revenue figure was when you published it, or that the difference between the old number and the new one was a legitimate correction rather than anything else.
So the rule is absolute rather than a preference: a posted entry is never mutated. Corrections are new entries that reference the old ones. The mistake stays visible, the fix stays visible, and the relationship between them stays visible.
How a reversal actually works
A reversal is a contra entry. It takes the original entry and posts the mirror image: every debit becomes a credit for the same amount, every credit becomes a debit.
An invoice for $1,000 plus $75 tax posts three lines: receivable debited $1,075, revenue credited $1,000, tax payable credited $75. Reversing it posts receivable credited $1,075, revenue debited $1,000, tax payable debited $75. The two entries sum to zero across every affected account, so the net effect of the pair is nothing, and both remain in the ledger permanently.
Three implementation details separate a real reversal from a cosmetic one.
The link runs both ways. The reversal names the entry it cancels, and the original records that it has been reversed. One-directional linking means you can start from the correction and find the original, but reading the original in a report gives no hint that it was cancelled.
The reversal is dated when you found the error, not when the error was made. Dating the reversal back to the original’s date puts the correction in a period that has probably been reported. Reversals post into the current open period, which is the same constraint that makes accounting period locks work.
An entry can be reversed once. A second reversal of an already-reversed entry posts the cancelling amount twice, leaving the accounts wrong by the exact value of the transaction, and it is the kind of error that hides well because both entries look individually correct.
After reversing, you post the corrected entry as a new transaction. The net result across three entries is the right numbers plus a complete explanation of how they were arrived at.
Void, reverse, delete
The three words are used interchangeably in software interfaces and mean very different things.
| Delete | Void | Reverse | |
|---|---|---|---|
| What happens to the record | Removed | Kept, marked cancelled | Kept, plus an offsetting entry |
| Ledger effect | Silently disappears | None, because there was none yet | Cancelled by a new entry |
| When it is appropriate | A draft never posted | A document with no ledger effect yet, such as an unissued invoice | Anything that has posted |
| Visible afterwards | No | Yes | Yes, both sides |
| Safe in closed periods | Never | Depends on the document | Yes, the reversal lands in an open period |
| Audit position | Indefensible for posted rows | Acceptable with a reason recorded | The standard |
The decision rule is one question: has this affected the general ledger yet? If no, void it, keeping the document and the reason. If yes, reverse it. Delete belongs only to drafts, and a finance system that offers delete on a posted entry has told you what kind of system it is.
The restatement that could not be produced
A software company raises a funding round. Diligence asks a routine question: reconcile the monthly revenue in the management accounts against the statutory figures for the previous two years, and explain the differences.
The company’s accounting system permits editing posted invoices. Nobody abused this. Over two years, staff corrected amounts, changed dates, moved lines between accounts and fixed customer allocations, always for legitimate reasons, always by editing the original invoice and letting the ledger follow.
The reconciliation cannot be produced. Board packs from eighteen months ago show figures the ledger no longer contains, and there is no record explaining any individual difference, because each edit replaced its predecessor without recording it. Every discrepancy has to be investigated by hand from emails and exported spreadsheets that people happened to keep.
The result is not an accusation of fraud. It is six weeks of accountants at the company’s expense, a quality-of-earnings report with language about the reliability of historical records, and a materially weaker negotiating position for a founder whose books were honest the entire time. The cost of editable history is paid at the exact moment you can least afford it, and you cannot retrofit the fix, because the evidence that would have proved the books correct is the evidence that was overwritten.
A reversal-only system produces the same reconciliation as a query. Every difference is an entry, with a date, a user, a reason and a link to what it corrected.
What Oneop does
Oneop’s finance module has no path that updates a posted entry’s lines. Corrections post as linked mirror-image reversals, marked as reversals and joined back to the original in both directions, and the same entry cannot be reversed twice. The reversal must land in an open period, so a closed month cannot be reopened by reversing into it.
The invariants underneath are checked twice. Every posting path asserts that debits equal credits in the application before writing, and the ledger’s own transition to posted is re-checked by a PostgreSQL trigger that re-sums the lines and aborts the transaction if they differ, without trusting the application. The tolerance is a ten-thousandth of a unit, which is a float epsilon rather than a rounding allowance, so a one-cent difference is a rejection.
The same principle runs outside the ledger. Shipping stock posts the cost of goods inside the same transaction that decrements the stock, so the cost is recorded against the sale that produced it rather than reconstructed later, which is part of why inventory and the books do not need a reconciliation between them. The general argument for keeping operations and accounting on one record instead of syncing copies is made at why Oneop.
The test to run before you trust a ledger
Post an entry. Then try to change it.
If the system lets you edit the amount, you are not looking at a ledger, whatever the marketing says. If it offers to delete it, the same conclusion applies with more force. If it insists on a reversal, dates that reversal today, links it in both directions and refuses a second one, the books it produces will still be explainable in two years.
That property costs nothing while everything is fine, which is why it is easy to trade away. It is worth exactly what a diligence process, a tax inspection or a bank review is worth, on the day one of them arrives. The balancing rules that make reversals mechanically sound are covered in double-entry accounting for founders, and the broader argument for one durable record that automated actors write into rather than around is in the AI agent system of record.