Free learning / 50-minute reconciliation lab
Financial reconciliation: when matching amounts are not enough
Learn case and ledger matching, distinguish a repeated delivery from two credit entries, and run thirteen synthetic comparisons before handing over an exception.
No account needed. Use your own copy for writing and keep the original as a reference.
Engineering lab library / Run locally
Explain the difference. Prove the comparison.
Predict thirteen cases, reproduce a false credit-kind match and distinguish repeated delivery from two distinct ledger entries.
Real read-only Python comparisons of invented case and credit records. No database, model, network or money movement. A match describes this snapshot; it does not close a case.
Start here / Python 3.11+ · Standard library
Case-to-ledger reconciliation lab
Compare thirteen actual read-only results, reproduce a false match and investigate duplicate entry identities.
Python 3.11+ · standard library only · synthetic USD records
A colleague asks, “The money is back. Can I finish this case?” The case expects temporary credit, but a credit record says final. Both say USD 125.00. Before you build an agent, learn to explain that difference.
Reconciliation means comparing related records, explaining differences and getting those differences resolved by the responsible owners. This original workshop gives you a visual explanation, a runnable comparison and a review exercise. Start with Financial-services business 101 if the terms are new.
Allow 50–70 minutes. You need Python 3.11 or newer and a terminal. Every record is invented; there are no accounts, keys, packages, network calls or financial writes. The advanced Academy reconciliation lesson adds architecture decisions, worked examples and knowledge checks under the existing training access controls.
1. Understand the two stories
Think about comparing an order and a shipment. Equal quantities do not establish the same order, and a shipping label does not prove delivery. In this exercise, the case tracks an investigation and an expected credit. The ledger extract describes the credit entries actually observed. You need both, with their meanings intact.
| Term | What it means here | What it does not prove |
|---|---|---|
| Case | The investigation and expected action | That money was posted |
| Original transaction | The debit being disputed | The identity of a later credit |
| Ledger entry | One identified accounting record | The final investigation outcome |
| Posting state | Whether this credit is pending, posted or reversed | That all case work is complete |
| Provisional credit | Temporary credit during the applicable investigation process | A final case decision |
| Reconciliation exception | A specific unresolved difference or missing record | Permission to edit either source |
| Duplicate delivery | An identical repeat of the same stable entry ID | That two different entries are the same financial effect |
The lab's case expects one positive USD credit. Its extract contains only credit records for that case, not a complete general ledger. This is a deliberately small business contract, not a universal bank matching algorithm.
2. Follow one disagreement
Read these two synthetic records before stepping through the diagram:
| Field | Case expectation | Observed credit |
|---|---|---|
| Case | SYNTHETIC-CASE-104 | SYNTHETIC-CASE-104 |
| Account | SYNTHETIC-ACCOUNT-7 | SYNTHETIC-ACCOUNT-7 |
| Original transaction | SYNTHETIC-DEBIT-81 | SYNTHETIC-DEBIT-81 |
| Amount and currency | 12500 minor units, USD | 12500 minor units, USD |
| Credit kind | provisional | final |
| Separate state | investigation open | credit posted |
The amount is USD 125.00, represented by an integer to avoid binary floating-point equality surprises. Other currencies may use different scales. Keep currency explicit; this lab never converts or nets amounts.
The references and money agree. The credit kind does not. A useful handoff names that disagreement and asks the case and ledger owners to resolve it. It does not rewrite final as provisional to make the comparison pass.
UNDERSTAND THE SYSTEM
Check the credit type as well as the amount
Compare one invented dispute case with its credit extract. Step through the records, the disagreement and the handoff. These are teaching fixtures, not a live ledger.
See what moves and why.
Read the connections in plain English
- 01Case expectation → Same transaction?
Read the identity of the expected business event.
- 02Credit extract → Same transaction?
Validate the scoped records; do not join on amount alone.
- 03Same transaction? → Compare the meaning
Only the matching scope enters this comparison.
- 04Credit extract → Compare the meaning
USD 125.00 posted final is not an expected provisional credit.
- 05Compare the meaning → Reconciliation owner
Route the specific mismatch without changing either source.
- 06Reconciliation owner → Supported handoff
Document unresolved work and a receiving owner.
Check your understanding: Two USD 125.00 records arrive. Can you remove one as a duplicate?
Only an identical repeat of the same stable entry ID is a duplicate delivery in this exercise. Two different entry IDs may represent two financial effects. Preserve both and investigate; equal amounts are not an identity.
3. Run the reconciliation lab
Download fde-financial-reconciliation.py from the lab panel into a local folder. Predict the four highlighted distinctions: wrong credit kind, repeated delivery, two distinct entries and incomplete extract. Then run:
python3 fde-financial-reconciliation.py
python3 fde-financial-reconciliation.py --json > reconciliation-guarded.json
python3 fde-financial-reconciliation.py --omit-credit-kind --json > reconciliation-broken.jsonThe first command prints a compact report. The JSON preserves each case's full input and result. Inspect state, reason, matched_entry_ids, duplicate_deliveries, owner, next_action and trace together. The records are read-only; running the lab changes no case or ledger.
| Scenario | Guarded reason | What you should explain |
|---|---|---|
matched-provisional | matched_snapshot | Matching temporary credit leaves the investigation open |
wrong-transaction | reference_mismatch | An equal amount can belong to another transaction |
amount-mismatch | amount_mismatch | A one-cent difference stays visible |
currency-mismatch | currency_mismatch | EUR and USD are not interchangeable |
pending-credit | credit_not_posted | Pending is not posted |
wrong-credit-kind | credit_kind_mismatch | Provisional and final carry different meanings |
missing-credit | missing_credit | The complete scoped extract has no expected entry |
repeated-delivery | matched_snapshot | One entry ID, identical content, one repeated delivery |
conflicting-entry | conflicting_entry | One ID carries different payloads; no last-arrival guess |
two-credit-entries | multiple_credit_entries | Two different IDs need an explanation, not deduplication by amount |
partial-extract | incomplete_extract | Missing coverage means unknown, not absent |
reversed-credit | unsupported_posting_state | A reversed record cannot support a posted-credit statement |
matched-final | matched_snapshot | Matching final evidence still does not certify notices or close a case |
In the deliberately broken report, only wrong-credit-kind changes its decision: the code falsely calls the snapshot matched. Compare expected_kind and kind in its inputs. Both processes can exit successfully; only the guarded comparison preserves this business rule. The other twelve scenarios retain their guarded business decisions; the trace records the omitted check wherever it was reached.
4. Change the code and prove the boundary
In a copy of the script, add these scenarios to scenarios(). Predict the result before running:
("wrong-account", case,
replace(extract, entries=(replace(entry, account_id="SYNTHETIC-ACCOUNT-OTHER"),))),
("debit-direction", case,
replace(extract, entries=(replace(entry, direction="debit"),))),
("unknown-posting", case,
replace(extract, entries=(replace(entry, status="unrecognized"),))),Expect reference_mismatch, invalid_credit and unsupported_posting_state. Each should leave matched_entry_ids empty. Keep the original input, your prediction, actual trace and next owner. Repeat the run and explain why the same snapshot should produce the same result.
Then challenge the contract: what if a valid credit is split into two entries? The current one-credit rule deliberately requests reconciliation. Do not weaken it to “sum everything.” First agree which entries belong together, how reversals and versions work, and what the business considers a complete match. Write a counterexample that would fool a simple sum before implementing your extension.
5. Design the adapter an FDE would have to ship
The complete flag and record fields are trusted fixtures. In a deployed system, a server-side adapter must establish the permitted workspace and account, source identity, pagination coverage, version and freshness. A model or caller cannot grant itself that authority. HTTP 200 for one page is not proof that you saw every relevant record.
The duplicate rule assumes an immutable snapshot. If the real source revises entries under the same ID, represent and order those revisions explicitly; taking the latest network arrival is not a version strategy. Source changes between reads also need an agreed snapshot or reconciliation policy. This local script does not prove concurrent adapters, production authorization or eventual consistency.
An agent can help explain a verified difference or draft a handoff. Keep record comparison deterministic, preserve source evidence and give unresolved work an accountable owner. Choosing the reconciliation interval, case closure rules and customer communication process belongs with the institution's authorized owners.
6. Rehearse the receiving-owner review
Use a peer, facilitator or recorded self-rehearsal. A worksheet does not book a mentor. Allow 15 minutes:
- Explain case, transaction, entry and provisional credit without field names.
- Show the wrong-credit-kind inputs and reproduce the deliberately broken match.
- Compare repeated-delivery with two-credit-entries. Explain why you keep both distinct IDs.
- Have the reviewer change the account or posting state and predict the result.
- Hand over one exception and identify the adapter evidence still needed.
Use this sample as a structure, then write your own from an unseen case:
Case: SYNTHETIC-CASE-104
Source: SYNTHETIC-EXTRACT-4, complete scoped teaching fixture
Expected: posted provisional credit, USD 125.00
Observed: posted final credit, USD 125.00, SYNTHETIC-CREDIT-9
Difference: credit_kind_mismatch
Owner: case and ledger operations
Next action: resolve the credit-kind mapping against authoritative records
Remaining case work: investigation open; communications checked separatelyKeep the dictionary, diagram explanation, guarded and broken reports, changed code, unseen results and review notes. A receiving engineer should be able to reproduce the exception without your narration.
7. Sources and next practice
Sources checked 22 October 2026. The comparison rules, records and review exercise are original teaching material.
- CFPB Regulation E, error-resolution procedures distinguishes provisional credit, investigation and final resolution for its scope. This lab does not implement legal deadlines or determine applicability to another financial product.
- Python decimal documentation explains exact decimal arithmetic and why binary floating-point equality matters in accounting. Our bounded USD exercise uses integer minor units.
Continue with the receiving-owner review workbook, or open the protected financial reconciliation lesson for architecture challenges and knowledge checks.