executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
ledger-error-diagnosisUse when a ledger will not agree — a trial balance that does not balance, a bank or control account that will not reconcile, a VAT return that does not tie to the VAT control account, a balance sheet where net assets do not equal shareholders' funds, or suspected duplicate, missing, mis-signed or mis-period transactions. Covers the arithmetic signatures tha…
Independent GitHub snapshot · Automated classification · Original documentation governs
Something does not agree. This is how you find out what, and fix it without making the record worse.
A difference is information. Never force it away.
Plugging a difference to suspense, journalling it to P&L "to tidy up", or deleting a transaction that looks wrong all convert a visible error into an invisible one. The books then balance and are wrong, which is strictly worse than not balancing — because nothing will ever flag it again.
Corrections are new entries, never overwrites or deletions. The audit trail is the point: an enquiry asks what happened, and "it was edited" is not an answer.
Do not scan the ledger. Halve the search space first — this usually takes minutes and turns an open-ended hunt into a short list.
"Play the accounts back to find where it broke" is a real thing, in three distinct forms. They cost very different amounts and answer different questions, so pick deliberately.
Do not scan forward through months. Binary-search them.
You have a period-end proof (control-account balance, or bank rec) that agrees at some early point and fails now. The error entered in exactly one period. So:
24 months collapses to about 5 checks instead of 24. The output is not "something is wrong" but "it broke in March 2026" — which is a short list of transactions rather than a hunt.
scripts/bisect_periods.py does this over a series of period-end expected-vs-actual balances and
names the first divergent period, plus how much entered in that period as opposed to being
inherited from before it. That distinction matters: a balance that is wrong because the opening
balance was already wrong is not an error in that period at all.
Most systems keep one, and it answers a different question: not when the balance broke but what was changed. QuickBooks Online has an Audit Log recording every create, edit and delete with user, timestamp and before/after values.
Use it when the numbers moved and nobody knows why — a prior period that used to reconcile and no longer does is almost always an edit or a deletion, and the log names it. This is the fastest route when a previously-clean period goes bad, and it is the only route that identifies a deletion, which by definition leaves nothing behind to find.
If the source documents are stored and indexed (financial-document-ingestion §6), the books can be
recomputed from them and diffed against what the system holds. The first divergence is the error, and
the rebuild also tells you the correct figure rather than just that the current one is wrong.
This is the strongest technique and the most expensive: it needs complete, indexed sources and stable posting rules. It is the pay-off for the document store — build the store as you go, and this becomes possible; skip it, and you are left with (a) and (b).
Order of attack: (b) if a clean period went bad · (a) to localise anything else · (c) when you need the right answer rather than just the location.
The number itself narrows the class before you look at a single transaction. These are classic and they hold:
| Signature | Almost certainly | Why |
|---|---|---|
| Divisible by 9 | Transposition — 54 keyed as 45 | Any digit swap yields a multiple of 9 |
| Divisible by 9, order of magnitude | Digit slide — 100 as 1,000 | Same arithmetic property |
| Exactly 2× a real transaction | Wrong side — debit posted as credit | The entry is out by twice its value |
| Equals a transaction exactly | Missing or duplicated entry | One posting absent or present twice |
| Small pence | Rounding or FX | Accumulated fractions, or a rate difference |
| Round hundreds/thousands | Missing whole transaction | Real invoices are rarely round; estimates are |
| Difference is a VAT fraction (÷6, ÷5) | VAT treated wrongly | Gross posted as net, or standard vs zero-rated |
Run the cheap checks first: divide by 9, divide by 2, and search for a transaction of exactly the
difference. scripts/diagnose_difference.py does all three and reports the candidate classes.
Detect: differences under ~£1 that persist; VAT lines where net + VAT ≠ gross by pennies.
Cause: recomputing VAT instead of taking the invoice figure; rounding at each line rather than
once at the end; float arithmetic.
Correct: post a documented rounding adjustment to a dedicated account — never to suspense, and
never silently. If it recurs, fix the rule, not the symptom: money should be integer pence, and
the invoice's own VAT figure is the one that counts (financial-document-ingestion §3).
Detect: bank line with no book entry; supplier statement showing invoices you do not hold; a gap
in an invoice number sequence; a direct debit present in prior months and absent this one.
Correct: post it from the source document, in its own period, not the current one.
VAT: if it falls in a filed period, this is an error correction — uk-vat §6 decides the route.
Detect: same date + amount + reference twice (V7 in financial-document-ingestion); a supplier
paid twice; a statement boundary where the last lines of one period repeat as the first of the next.
Distinguish carefully: genuine repeats exist. Standing orders, identical monthly subscriptions
and split invoices all look like duplicates. Check the source document before reversing anything.
Correct: reverse the duplicate with a journal referencing the original. Do not delete it —
deletion hides that a duplicate was ever posted, which is exactly what an enquiry wants to see
handled properly.
Detect: debtors/creditors control not agreeing the aged list; a payment with no matching invoice; income received with no sales invoice raised. Correct: obtain the document, then post. An accrual is not a substitute for an invoice you can still obtain — and for VAT, no valid invoice means no input claim, full stop.
Detect: the difference appears in one period and reverses in the next; year-end creditors understated; an invoice dated in one period paid and posted in another. Correct: move it to the correct period with accruals/prepayments. Cut-off errors are the most common year-end misstatement — anchor on the tax point and the delivery date, not the payment date.
Detect: difference is exactly 2× a transaction; a refund posted as an expense; a negative balance that cannot be negative (stock, most bank accounts). Correct: reverse and repost. A refund is negative income, not a cost — posting it as a cost overstates turnover and costs simultaneously and misstates VAT.
Detect: an expense category that moved sharply with no business reason; capital items in repairs;
director's personal spending in overheads.
Correct: reclassify by journal. This one has tax consequences — capital vs revenue changes
the corporation tax computation (uk-corporation-tax §2/§3), and personal spending belongs in the
director's loan account, where it may trigger s455.
Detect: small unexplained differences on foreign supplier accounts; balances that move without transactions. Correct: post the exchange difference to a realised/unrealised FX account. Record the rate used and its source.
Every correction, without exception:
uk-vat §6 decides adjust-on-next-return vs separate
disclosure. Deliberate errors are never quietly adjusted.posted_ref (financial-document-ingestion §6).If the correction does not fully clear the difference, you have found a second error. Do not absorb the remainder — repeat from §2. Two errors partially offsetting is common, and absorbing the remainder is how a plug hides one of them.
Escalate rather than quietly fixing when:
quickbooks-api §4).