Free learning / 50-minute financial ledger proof lab
Double-entry posting: balanced does not mean correct
Execute balanced wrong-account, wrong-party and duplicate postings in SQLite. Compare partial writes with atomic rollback, then retain an original journal through reversal and correction.
No account needed. Use your own copy for writing and keep the original as a reference.
Engineering lab library / Run locally
Choose your next agent lab.
Start with the durable workflow reference, then choose the boundary you want to test. Open its walkthrough for setup, commands and expected observations.
Synthetic records. No provider key or model inference. Runs locally with the standard library.
Start here / Python 3.11+ · Standard library
Double-entry meaning, atomic posting and correction history
Expose balanced business errors, preserve incomplete-collection state after rollback and trace an original journal through correction.
Python 3.11+ · Standard library · In-memory SQLite · Fictional USD minor units · No network
Original LockedIn Labs workshop · 50 minutes. Python 3.11+ standard library. Follow rows, sums and a SQL transaction first. The program creates a fresh in-memory SQLite ledger for each fictional case and closes it afterward. No network, bank, payment adapter, account credentials or persistent database is used. All amounts are integer USD minor units; 12500 means USD 125.00.
You will distinguish bookkeeping vocabulary, balance, business meaning, transaction completeness, duplicate prevention and explicit correction history. The financial reconciliation guide compares case and credit extracts. This workshop inspects the posting beneath those extracts; it does not implement a payment system or determine real policy.
1. Learn the accounting words before choosing fields
A journal groups the entry lines that record an event. A ledger organizes postings by account. Debit and credit name opposite accounting sides; they do not universally mean loss and gain. In double-entry bookkeeping, posted debit totals and credit totals must agree. IRS Publication 583 provides an introductory primary reference for journals, ledgers and equal sides. The exercise supplies its own fictional chart and posting instruction, rather than deriving a real accounting policy from that general rule.
Our chart is deliberately small:
| Account | Fictional meaning | How this fixture records it |
|---|---|---|
cash | Book cash asset | Debit increases its net debit; credit decreases it |
receivable | Amount owed on a booked invoice | Debit increases it; a collection credits the matching party |
revenue | Already-booked service revenue | Credit creates a negative net-debit value in this report |
A trial balance compares account debit and credit totals. Our trial_net_debit_minor is their signed difference: positive amounts are net debits and negative amounts are net credits. A zero difference is an arithmetic check, not evidence that the account, party or source event was right.
A subsidiary ledger preserves detail beneath a control account, such as receivables by customer. The fixture represents this as separate A and B buckets. It is not a full customer ledger, chart of accounts or reporting standard. A credit balance in B's bucket is recorded explicitly; the program does not silently relabel it as a valid settlement of A's invoice.
2. State the collection target independently
Every case starts with a supplied already-booked invoice for party A:
Opening journal INVOICE-A:
Debit receivable A 12500
Credit revenue 12500
Independent supplied instruction PAY-1:
Collect that existing invoice once for A.
Expected final net-debit buckets:
cash: 12500
receivable_A: 0
receivable_B: 0
revenue: -12500The opening invoice is a fixture assumption. This lesson does not decide when a real service may recognize revenue, whether a payment has settled, or which business unit owns a source. Cash here is a ledger account, not a read of a bank balance. A collection should reduce this existing receivable rather than book that revenue a second time under the supplied instruction.
Read instruction and expected_net_debit_minor separately from actual rows. The expectation is not derived from a successful insert or a zero trial sum. The six visual frames explain eight independently reset SQL cases; the browser does not execute the ledger or move money.
UNDERSTAND THE SYSTEM
Balanced entries can still describe the wrong business event
Six authored frames explain eight actual in-memory SQLite cases. Default amounts are fictional USD minor units: 12500 means USD 125.00. The diagram does not execute SQL or move money; journal balance and the independent collection target are separate observations.
Watch one example, step by step.
Read the full worked example
- 011 · Equal sides do not choose the account
The wrong-account receipt debits cash and credits revenue instead of the existing receivable. Every journal balances and the trial net is zero. Yet A still has a 12500 receivable and revenue is credited twice across the opening invoice and receipt. The independent collection target fails.
ACTUAL WRONG-ACCOUNT ROWS: Trial net 0 · A receivable 12500 · target mismatch
- 022 · An aggregate can hide the wrong party
Wrong-party debits cash and credits B's receivable. The aggregate receivable reaches zero, but A retains a debit 12500 and B a credit 12500. Keep those buckets separate. Neither the overall trial balance nor matching account totals can explain away the party mismatch.
ACTUAL RECEIVABLE DETAIL: Aggregate receivable 0 · A +12500 · B −12500
- 033 · A duplicate can balance twice
Duplicate-naive inserts two balanced PAY-1 receipts, leaving cash 25000 and A at credit 12500. The separately reset guarded case stores one exact operation receipt: identical delivery replays its journal, while changing the party under the same key conflicts. Balance, operation identity and intended effect are separate checks.
SEPARATELY RESET CASES: Naive cash 25000 · guarded cash 12500
- 044 · Rollback protects integrity, not completion
Partial-naive commits the journal and first debit separately, then the authored exception leaves trial net 12500. Partial-atomic rolls the same incomplete attempt back. Its only remaining journal is the opening invoice, so trial net is zero while A is still owed and no collection is posted.
ACTUAL TRANSACTION COMPARISON: Atomic: receipt absent · A still owes 12500
- 055 · Correct the book while keeping its history
Reversal first posts the wrong-account receipt. A new journal references that original and inserts its inverse lines; the intermediate balances return to the opening state. A separate correction then posts the intended collection. All four journals remain, and final buckets match the supplied target. No real cash is refunded or collected by these rows.
ACTUAL RETAINED HISTORY: Original + reversal + correction · final target matches
- 066 · Receive the business contract, not a green sum
The receiver locates the original instruction, exact journal/entry rows, operation receipt and any reversal reference. The fixture target is independent of the balance calculation. The receiving team still needs authoritative source, account/party mapping, access, policy and installed-adapter evidence before any real financial operation.
RECEIVING BOUNDARY: Local equality · explicit unresolved external evidence
Read the connections in plain English
- 01Collection instruction → Journal identity
Retain the source and operation identities rather than treating matching amounts as sufficient.
- 02Journal identity → Debit / credit lines
The normal writer validates balance before committing its complete transaction.
- 03Debit / credit lines → General-ledger totals
Equal debits and credits establish only the local arithmetic relationship.
- 04Debit / credit lines → Receivable detail
Do not discard the receivable party while rolling up account totals.
- 05General-ledger totals → Receiving decision
A zero trial difference cannot approve the posting by itself.
- 06Receivable detail → Receiving decision
Inspect the independent target and actual party/account effects.
- 07Journal identity → Receiving decision
A reversal references a retained original; correcting the book is not a bank operation.
Check your understanding: Does a zero trial balance prove that the collection is correct?
No. Wrong-account, wrong-party and duplicate-naive all have zero trial difference while failing the supplied collection target. Partial-atomic also has zero difference with no collection posted. Compare the independent instruction and exact account/party effects, and keep real source or settlement evidence separate.
3. Run eight actual posting cases
Download and read the runner. Keep an untouched reference. Predict the trial difference and whether the independent collection target matches before reading JSON output:
python3 --version
python3 fde-ledger-posting.py > ledger-12500.json
python3 fde-ledger-posting.py --amount-minor 12501 > ledger-12501.jsonThe changed amount is one minor unit larger. Accepted amounts are integers from 1 through 1000000; the fixture makes no currency conversion or rounding decision. Use the money-contract workshop for units, currency identity, precision and explicit rounding questions.
| Case | Actual trial net at default amount | What remains wrong or unresolved |
|---|---|---|
correct | 0 | Local buckets match the supplied target; external source is untested |
wrong-account | 0 | A still owes 12500; revenue has been credited twice |
wrong-party | 0 | A still owes 12500; B has a credit 12500 despite aggregate receivables zero |
duplicate-naive | 0 | Cash is 25000 and A has a credit 12500 after two balanced receipts |
duplicate-guarded | 0 | One receipt; identical replay returns it and changed-party payload conflicts |
partial-naive | 12500 | First debit remains committed without its credit |
partial-atomic | 0 | Only the opening invoice remains; the collection is still unposted |
reversal | 0 | Original, inverse and corrected history remain; no real payment operation occurred |
A successful process exit only means the report was produced. Inspect post_results, journals, entries, actual_net_debit_minor and business_differences. An intentionally bad case can exit successfully while reporting a false collection match. That is counterexample evidence, not a pass for a learner or a real financial operation.
4. Find the balanced error in the actual rows
Use this written ledger alongside your original prediction:
wrong-account:
receipt: debit cash 12500 / credit revenue 12500
every_journal_balanced: true
trial_net_debit_minor: 0
receivable_A: 12500 # not cleared
revenue: -25000 # opening invoice plus wrong credit
wrong-party:
receipt: debit cash 12500 / credit receivable B 12500
receivable_A: 12500
receivable_B: -12500
aggregate receivables: 0 # conceals the party mismatch
partial-atomic:
post result: rolled_back / injected_after_first_line
remaining journals: opening invoice only
trial_net_debit_minor: 0
cash: 0 / receivable_A: 12500
matches_supplied_collection_target: falseWrong-party demonstrates why a general-ledger account total can agree while its underlying business allocation is wrong. Do not drop party identity when building a reconciliation extract. Wrong-account demonstrates why equal amounts and equal sides cannot choose the correct classification. These are distinct gaps for the responsible source and accounting owners.
In the atomic partial case, rollback preserves the opening state. It does not complete the collection or authorize another attempt. The naive partial case uses SQLite autocommit for individual inserts, then deliberately raises after the first entry. The atomic case instead runs BEGIN IMMEDIATE, inserts the journal/lines and rolls the same exception back. This is a controlled local exception and real SQL rollback, not a process kill, concurrent-worker test or unknown remote commit outcome.
5. Preserve operation identity and correction history
The transactional writer checks at least two entry lines and a zero sum before committing. Its receipt binds an operation key to the exact normalized posting payload and journal ID. In duplicate-guarded, the outcomes are:
first PAY-1: applied -> journal 2
identical PAY-1: replayed -> journal 2
PAY-1 changed to B: conflict -> journal 2 unchangedThe payload retains source reference, journal kind, ordered lines, account, party, side, amount and any reversal reference. The operation receipt and posting commit together. A key alone is not enough to accept a different intent. The naive comparison deliberately skips this receipt boundary while still checking balance, so two balanced postings can represent duplicate work. No source reference or operation label authenticates a caller.
For reversal, inspect all three snapshots: the initial wrong posting, the state after its inverse, and the final correction. Journal 2 remains unchanged. Journal 3 points to journal 2 with reverses_journal_id and swaps each original side. That intermediate state returns to the opening invoice balances. Journal 4 separately records the intended collection with a new operation key and the same source reference. All four journals, including the opening invoice, remain.
This writer preserves history through inserts; the database is not a tamper-proof or immutable ledger. The fixture permits at most one reversing journal for an original and implements no partial-reversal workflow or production approval. Correcting these book entries does not refund, collect or undo real cash at another service. An authorized workflow owner must define those separate actions.
Read the small schema and post. Account names, sides, positive integer amounts and receivable parties have database checks. Journal balance and exact receipt binding are enforced by this writer inside its transaction. Direct privileged SQL can bypass application rules. This one-connection in-memory exercise tests no production permissions, concurrent posting, durable recovery, currencies, period close, accounting standard, tax rule or real payment rail. Use your organization's reviewed ledger and posting contract rather than this fixture.
6. Receive the posting as a financial-services pod
Rotate three roles across a changed run:
- Builder: retain original command, runtime, source instruction, exact journal and entry IDs, post status and account/party residuals. Locate the transaction.
- Receiver: change the amount by one minor unit without author takeover. Reproduce one balanced wrong result and the atomic still-unposted result. Trace a reversal without deleting the original evidence.
- Source/accounting and application owners: agree the source identity, account and party mapping, operation scope, correction authority and real receiving-adapter evidence. Retain any unresolved business action explicitly.
Each participant keeps an individual record:
Learner / run / exact command / Python and SQLite versions:
Prediction before execution:
Source instruction / currency / amount unit:
Actual journal and entry IDs / operation receipt:
Debit and credit totals / actual party-level buckets:
Independent expected buckets / specific residual:
My contribution / assistance received:
Changed amount / prediction / observed result:
Receiving action actually attempted / assistance:
Remaining action / accountable owner / next bounded source or adapter check:For a real receiving exercise, use an approved synthetic adapter and agreed posting contract. Ask an accounting owner to explain one mismatched classification or customer residual. Then identify the exact external source evidence still needed before calling a payment complete. Neither local trial equality nor the fictional target match supplies that evidence.
7. Defend the boundary in an interview
Explain: Why can two balanced journal entries still be duplicate work? Use the naive PAY-1 receipts and cash 25000 beside the original 12500 target.
Debug: Why does aggregate receivables zero fail to settle A? Locate both party buckets and the actual credit line, rather than proposing a new tolerance.
Design: Describe the independent posting instruction, atomic validation, scoped operation identity, original/correction lineage, source authority and receiving test. Distinguish book correction from an external compensation.
Primary references checked 28 October 2026: IRS · Bookkeeping systems, Python SQLite transactions, and SQLite transactions. The chart, synthetic invoice, posting cases, visual frames and receiving exercise are original instruction, not an accounting policy or tax recommendation.