Home › Use Cases › Reconcile one instalment plan against its receipts ledger on one as-at date
Use caseUC0316
🧪 Use-case kit · runnable

Reconcile one instalment plan against its receipts ledger on one as-at date

A small, forkable project that does one job end to end. Run once for real, and every figure on these pages captured from that run.

The business caseThe problem this solves

An account signs a payment plan and then money arrives — on time, late, short, twice, from the wrong card, and occasionally back out again as a return or a refund. The servicing system posts every movement and keeps a running standing, and on 14 of these 60 accounts that standing is built on money the plan never kept. Somebody has to open the file, read every note printed under a row, decide which receipts are actually money, notice whether the plan was amended, and say where the account really stands before anybody chases it. Opening one account file, adding up the ledger by eye, reading each note under a row to decide whether the money is really there, checking the account notes for a rescheduling, re-deriving the instalment schedule by hand and comparing the printed applied to column against where the money should have gone.

Audience

A servicing or collections desk working an arrears list, and the reconciliation clerk behind it. Whoever decides that this account gets a dunning letter, a late fee, or nothing at all this month. Every number on these pages came from one real run of this code, not from a vendor page.

The inputThe actual account file

The corpus is 60 account file, 0.14 MB (txt 60). It is generated because it has to be. A real receipts ledger is somebody's payment history, and the exact shapes this kit measures — a POSTED row that was recalled by the payer's bank, a lodgement keyed twice, a rescheduling that was quoted and refused — are the rows a servicer would least want published. Generating it also makes the key DERIVED rather than written: each account is built as a structure, the panels are rendered from it, and IPR-2026 is applied to the same structure by src/policy.py. There is no second place the answer lives.

The corpus

  • The 60 account filegenerated from a fixed seed, so no real record, person or institution appears in it.
  • Where each came fromdata/SOURCES.md states where every byte came from. Every account holder is an invented trading name, every plan number and receipt reference is arithmetic on the file index, and there is no personal data at all — evals/check_labels.py sweeps all 60 files for five families of identifier on every run and reports 0.

Swap this folder for your own material and the kit is pointed at your account file. That is the whole change — there is no database to migrate.

One account file, as the model receives itIPR-0001.txt · 1 of 60
==============================================================================
INSTALMENT PLAN RECONCILIATION FILE                        IPR-0001
Account: ACC-3100 - Northgate Studio (invented)
Plan: PLN-0001   annual membership   As at: 2026-03-10   Procedure: IPR-2026
==============================================================================

PLAN TERMS AS SIGNED
  contract total                    2432.00
  down payment                       243.00   due 2026-01-08
  instalments                             5   monthly from 2026-02-08
  grace period                            5   days
  late fee                            15.00
  lapse threshold                    875.60
  cure window                            21   days

SCHEDULE AS SET
  INSTALMENT   DUE DATE           AMOUNT
  DOWN         2026-01-08         243.00
  1            2026-02-08         437.80
  2            2026-03-08         437.80
  3            2026-04-08         437.80
  4            2026-05-08         437.80
  5            2026-06-08         437.80

RECEIPTS LEDGER AS POSTED BY THE SERVICING SYSTEM
  RECEIPT    RECEIVED           AMOUNT  METHOD        STATUS    APPLIED TO  MEMO
  RCP-0100   2026-01-07         243.00  direct debit  POSTED    DOWN        plan deposit
  RCP-0101   2026-02-06         437.80  card          POSTED    1           instalment 1
  RCP-0102   2026-03-09         437.80  direct debit  POSTED    2           instalment 2

ACCOUNT STANDING AS THE SYSTEM HOLDS IT
  paid to date            1118.60
  next due                 437.80   on 2026-04-08
  arrears                    0.00
  status                  CURRENT

ACCOUNT NOTES
  Payer moved the collection day to the 12th for one cycle only; the plan cadence is unchanged.

Abridged — the file continues.

The outcomeWhat a good result looks like

One account in, one row out: what the plan has actually received, the amendment the file records, every ledger row this procedure treats differently from the ledger that printed it, and one verdict from a closed set of five — LAPSED, FEE-DUE, IN-ARREARS, AHEAD or CURRENT. The verdict, the arrears and the next due line are re-derived in pure code from the readings and the plan register, so they follow the procedure whatever the reply said.

And when it cannot

And what it does when it cannot. On both scored runs 60 of 60 replies parsed and nothing stopped at the ceiling, so there is no unparsed row to report. What it gets WRONG is published by name: 5 accounts on r001-installment-recon came back carrying money that was returned, recalled or double-keyed (counted_money_that_never_arrived), and the pure-code station cannot see it — the row is real, the date parses, the amount is an integer, and the plan register knows nothing about any receipt.

Where it fitsWhat did work

Every line below is a measured result from this kit's own runs, with the figure that supports it. The headline above is not softened by any of them.

  • Your ledger's bad rows are announced by a keyword — every reversal says "returned" and every duplicate says "duplicate" — the free rules floor
    on the 14 accounts where a receipt really was returned or double-posted the free floor beats the paid arm 7 to 5. Write the regex.
  • Your notes are written by people, and a note about a refund is as likely to be about another plan or an earlier attempt as about this row — the paid arm
    the free floor is 0 of 12 on the accounts carrying that decoy and the paid arm is 10
  • Plans get rescheduled, and requests to reschedule get refused in the same notes field with the same figures — the paid arm
    every refused wording carries a real effective date, a whole-number count and a real amount, so a date test and a shape test both pass. The floor applies all 6
  • You need the arrears figure and the verdict to follow the procedure whatever the reply said — the station either way
    src/recheck.py discards the reply's verdict and recomputes it; on r002-installment-recon that moved the verdict from 35 right to 51

At a glanceHow the whole thing runs

73–75%rechecked all correct pct
1,279 msp50, end to end
$2.97per 1,000 account file · google/gemini-3-flash

Run once, for real, on 2026-09-06. Every figure on these pages was captured from that run — nothing is written from intent.

14 steps, grouped by the question that sends you to them rather than by build order. Each tile carries the one figure that step is about, and opens the page behind it.

Should you use this?What you bring, where it stops, and when not to use it

Before you commit an afternoon to this, these are the answers that decide it. Each one is rendered from the record it lives in — and links the page that holds it in full.

What do I have to bring?Replace data/corpus/*.txt with your own account files in the same shape and data/plans.json with your own register, then rebuild the key by labelling them. ⚠︎ WHAT STOPS BEING TRUE THE MOMENT YOU DO. Corpus lens →
When is this the wrong choice?Avoid: Paying for a call. That is the case against the best-fitting scenario (“Your ledger's bad rows are announced by a keyword — every reversal says "returned" and every duplicate says "duplicate"”). 4 scenarios scored in all, each with its own. Eval lens →
Where does it stop working?A ledger that is not fixed-width columns. src/ledger.py's row regex is the shape these files print; a CSV or a JSON export needs a different parser and nothing above it changes. 5 recorded failure modes, each from a run rather than a guess. Corpus lens →
What was never verified?A third scored run. Two were fired and they are one account apart; a third would narrow the spread and was not bought. 7 items this kit says it could not check. Eval lens →
Can I run this on a model I control?Yes — any OpenAI-compatible endpoint, including one on your own hardware. The shipped adapter takes its host from BASE_URL and its model from MODEL, so nothing in src/ changes. The published figures come from 1 model on the fast tier, one provider, one key. Prompt lens →
And if it fits — what do I stand up?6 artifacts with a stated home and a stated egress, and 3 decisions each with what you provision past its ceiling — plus what was not measured. That is the next page, not this one. step 14 — Run it in your environment →

Not asked of this kit — 2 questions: clone (a fresh clone of this kit runs with nothing fetched); judge (nothing here is graded by a model).

Last verified 2026-09-06 — r002-installment-recon. Every figure on these pages was captured from that run.

Run itHow this reaches your data

Every result on this page was produced by pure code over checked-in files, with no API key — which is why you can read the numbers before anyone spends anything.

Run this on your own data

  • The pipeline, its eval harness and the runs behind every numberdeployed inside your environment, on your own model endpoints, against your own documents.
  • The corpus above is the shape, not the limitit is a folder swap, and there is no database to migrate.

Talk to us →

Checked before this shipped — A clean checkout with no key configured renders the whole board, both free floors, all seven committed runs and every screenshot. python3 -m evals.check_labels and python3 tools/build_corpus.py --check both run on a machine with nothing installed.

A living map of modern AI — kept current every morning