Skip to content

Part 2 of 7 · Budget variance reporter series ~5 min read

How the period data arrives

This system will only ever be as good as what it is fed, and there is one input decision that determines whether it is useful or merely arithmetic: whether you give it a trial balance or the transactions behind it.

Key takeaways

  • A trial balance gives you the variance; only transactions give you the reason.
  • The minimum row is code, date, amount, description and source document.
  • Periods get restated after they close, and the system has to absorb that.
  • A restated period is re-imported whole, never patched, and the report is regenerable.
  • The import is idempotent, so a re-sent export changes nothing.

Transactions, not balances

A trial balance tells you repairs was £2,400 over budget. The transactions tell you £2,150 of that was one compressor. Those two facts lead to entirely different conversations, and only the second one is worth having.

code         6210            the nominal account
date         2026-07-11      the posting date
amount       2150.00         signed
description  Compressor repair — unit 2
source       PINV-4471       the purchase invoice reference
supplier     Ashford Plant   where available
period       2026-07         which period it was posted into

The period field being separate from the date is not pedantry. A transaction dated 28 June and posted into July is exactly the kind of thing that produces a false variance in both months, and having both fields is what lets the timing filter recognise it.

The import

How a nominal transaction export is importedA vertical chain of five steps entered by a box labelled Export lands, as a scheduled CSV or through an API. Step one stores the file in S3 exactly as received. Step two asks which period it covers, taken from the file rather than inferred from dates; if unclear it exits to Ask, because a period is never assumed. Step three asks whether this period has already been imported, checking a DynamoDB periods table; if so it exits to Restatement, which replaces the period whole while keeping both versions. Step four loads the transactions, one row each. Step five is Ready to compare, a complete period. A note says a period is replaced whole or not at all, because patching an import is how ledgers drift.AWS ACCOUNTExport landsscheduled CSV or APIStore the fileS3, as receivedWhich period?from the file, not the dateAsknever assume a periodunclearSeen this period?already importedDynamoDB periodsimport historyRestatementreplace whole, keep bothyesLoad the transactionsone row eachReady to comparea complete periodA period is replaced whole or not at all. Patching an import is how ledgers drift.
Fig 1. How a period export is imported. The restatement path is the one that matters: periods get reopened and re-closed routinely, and a system that cannot absorb that will be wrong within two months.
  • Storage
  • Database
  • App integration
  • Machine learning
  • Management
  • People

Restatements

Periods are reopened. An accrual is corrected, a misposting is fixed, a late invoice is dated back. In a small business this happens to roughly one period in three, and it usually happens after a report has already gone out.

So a re-import of a period already imported is a restatement, not an error. The whole period is replaced — every transaction, not a diff — and both versions are kept. The report for that period is regenerated, and it says at the top that it is a restatement with the date of the original. That last sentence is what stops two different versions of July circulating with no way to tell them apart.

Why replace whole

Patching an import — applying only the rows that changed — requires knowing which rows changed, and accounting exports rarely carry stable row identifiers. Two imports of the same period with a corrected misposting will differ in ways that are hard to diff correctly, and a wrong diff produces a ledger that is subtly wrong in a way nobody will find. Replacing whole is boring, obviously correct, and costs nothing at these volumes.

Idempotency

How a re-sent period export is handledA horizontal row of five boxes. Same file twice: the digest is identical. Nothing happens: there is no re-import. Changed file: a different digest. Restatement: the period is replaced and both versions are kept. Report regenerated: and labelled as a restatement. A note says the digest decides, and an identical file is a duplicate rather than a restatement.RE-SENDING AN EXPORTSame file twiceidentical digestNothing happensno re-importChanged filedifferent digestRestatementreplace, keep bothReport regeneratedand labelled as suchThe digest decides. An identical file is not a restatement; it is a duplicate.
Fig 2. What happens when an export is sent twice. The file digest separates a harmless duplicate from a genuine restatement, and only the second one regenerates anything.
  • Machine learning
  • Management
  • Analytics

Next: how a budget gets shaped so that it does not manufacture variances all by itself.

All posts