Most of close is not judgement. It is preparing the same entries and matching the same items, by hand, from several systems, every month. This is the automation that takes the routine off accountants' desks without letting anything unusual reach the books unreviewed.
Role
Designed and owns
Scale
Recurring entries, every close
Systems
Python, AWS S3, Oracle GL
Status
In production
01 — The situation
What was actually happening
Recurring journal entries were assembled by hand each close: figures pulled from files in storage, from the ERPs and from outside services, calculated in spreadsheets, then keyed into the ledger. Reconciliations followed the same pattern, with people matching items line by line.
Much of that matching effort went into items that were not really exceptions at all: the same transaction written with a different reference format, a rounded amount, a trailing space in a name. The genuinely wrong items were in there too, but they were hard to see among the merely untidy ones.
Automation that posts to the ledger is only acceptable if every entry is explainable and nothing unusual reaches the books unreviewed.
02 — The constraint
Why the obvious fix does not work
Speed was never the hard requirement. The ledger is the record auditors, lenders and the board rely on, and an automated entry that nobody can explain is worse than a slow manual one.
So the constraint was twofold. Every posted entry had to be traceable back to the source data that produced it. And anything that looked unusual had to stop and wait for a person, rather than post and be found later.
03 — The approach
What I built
Python pulls the inputs from AWS S3, the ERPs and external services, performs the calculations and posts the resulting journal entries to the Oracle General Ledger. Each entry carries a reference to the batch of source data it came from.
Before anything posts, an anomaly gate compares it with what is expected for that account. Entries inside the expected range post automatically. Anything outside it is held, with the reason attached, for an accountant to approve or correct.
Reconciliation runs alongside. Exact matches clear first, then fuzzy matching pairs items that differ only in formatting or rounding. Confident matches clear automatically, borderline ones are proposed to a person, and only the true exceptions are left for investigation.
Two paths, one principle. Postings pass an anomaly gate before they reach the ledger, and reconciliation items clear automatically only when the match is certain. Everything else waits for a person, with the reason visible.04 — Judgement
Decisions, and what each one cost
Every one of these had a defensible alternative. The trade-off is stated because the trade-off is the point.
Decision 01
Hold, do not post and flag
An unusual entry that posts and is flagged afterwards is already in the books. Holding it before posting keeps the ledger clean and puts the review at the only point where it can prevent an error.
Cost: some legitimate but unusual entries wait for a person, which adds a review step to close.
Decision 02
Every hold carries its reason
A held entry with no explanation just moves the investigation to the accountant. Attaching why it was held, in plain terms, turns review into a quick decision rather than a search.
Cost: the checks have to be simple enough to explain, which rules out some cleverer methods.
Decision 03
Confidence tiers for fuzzy matching
A single match threshold is either too strict to help or too loose to trust. Separating certain matches, probable matches and non-matches lets the machine clear the first group and a person confirm the second.
Cost: the tiers need tuning, and the middle band still asks for human time.
Decision 04
Traceable to the source batch
Every automated entry points back to the data that produced it, so any figure in the ledger can be explained to an auditor, and the same batch cannot be posted twice.
Cost: extra bookkeeping in the automation itself, which is invisible until the day it matters.
05 — Outcome
What changed
Routine entries post themselves, calculated from source data rather than keyed by hand.
Only true exceptions reach an accountant, each with the reason it was held or left unmatched.
Every automated entry is traceable back to the batch of source data that produced it.
Review time moved to judgement, away from preparing entries and matching untidy but correct items.
Python
AWS S3
Oracle General Ledger
Anomaly detection
Fuzzy matching
Reconciliation
06 — Retrospective
What I would do differently
Honestly assessed, with hindsight
I would log every accountant decision on a held entry from the first day. Each approval or correction is a label on whether the check was right, and that record is exactly what you need to tune the thresholds with evidence rather than instinct.
I would also agree the definition of an exception with the accountants before building the matching, not after. What counts as a formatting difference and what counts as a real discrepancy is an accounting judgement, and the automation is only as good as that agreement.