← SIMRANJAISWAL.INTHE ENGINE ROOM · 02 · COLLECTIONS

The ladder that climbs itself

Fifty customers, four hundred invoices, and a finance executive chasing from memory. This engine is the six-rung reminder ladder from the collections case written down as a machine: every open invoice climbs the same rungs on the same days, one message per customer per day, never on a weekend, paused for a promise or a dispute, handed over at fifty days. It runs below, in your browser, against two other ways of chasing the same book — not chasing, and shouting.

◆ LIVE ENGINE · RUNS IN YOUR BROWSER · PYTHON REFERENCE PUBLIC
0INVOICES IN THE REFERENCE BOOK · 50 CUSTOMERS · TERMS 30
0NUDGE → STATEMENT → CALL → ESCALATE → PROMISE → FINAL
0EXTRA CASH BY DAY 150 VS NO LADDER · REFERENCE RUN · ₹ LAKH
0PAID WITHIN A WEEK OF DUE · LADDER VS NO LADDER · %
01 · THE JOB

At the logistics firm the invoices went out on time and one in four came back on time. Nobody had been asked. The ladder fixed that — and then had to be run every day, by hand, by the same person it was meant to relieve.

A reminder ladder is easy to design and hard to keep. Rung one is a courtesy three days before due; rung six is a final notice at thirty-five days past; in between are a statement, a call and an escalation, each on its own day with its own tone. Written down, it took adherence at Shine Logistics to 95% and receivables down 20%. Kept by hand, it drifts: the Friday rungs slip to Monday, two invoices to one customer become two emails on one morning, a promise to pay is remembered by whoever took the call. The engine below is the ladder as a state machine — every invoice knows its rung, every rung knows its day, and the only human decision left is what the tone of each message should be. It is the SEAL of the Leak Ledger for the biggest leak of all: money that is owed, undisputed, and simply not asked for.

02 ·THE ENGINEONE INVOICE, SIX RUNGS, THREE EXITS
EVERY OPEN INVOICE CLIMBS LEFT TO RIGHT ON DAYS COUNTED FROM ITS DUE DATE · A PAYMENT EXITS IT AT ANY RUNG · A PROMISE AT R3 OR R4 HOLDS THE LADDER FOR A WEEK, THEN RESUMES AT R6 IF BROKEN · A DISPUTE PARKS IT UNTIL RESOLVED · AT DUE + 50 IT LEAVES FOR THE HANDOVER LIST.

The engine has no opinion about tone and no memory of the customer's excuses. It answers one question per invoice per morning — which rung is due today? — then applies three rules before anything is sent: not on a weekend, one message per customer, nothing while a promise or a dispute is open. What makes it trustworthy is what it refuses to do: it will not send a statement on Saturday, will not send the same customer three emails, and will not chase an invoice the customer has said is wrong.

03 ·THE RULESWHAT "DUE TODAY" MEANS, EXACTLY
RUNGWHENWHAT HAPPENS
R1 · nudgedue − 3A friendly note that the invoice falls due this week, statement attached.
R2 · statementdue + 3Every open invoice for the customer in one statement. Half the "we never got it" replies are true.
R3 · calldue + 10A phone call. With probability 0.35 the customer promises to pay within the promise window.
R4 · escalationdue + 20To the account owner on our side. Same promise chance.
R5 · promise holdfrom R3 / R4The ladder pauses for the window (7 days). Paid in time → kept. Not paid → broken, resume at R6 that day.
R6 · final noticedue + 35The last message from us.
Handoverdue + 50On to the handover list; in-house contact stops. The agency chases at the base rate; its fees are not modelled.
Weekend ruleday mod 7 ∈ {5, 6}No contact. The rung slides to the next weekday (day 0 is a Monday).
Batchingevery dayOne message per customer per day: all rungs due for that customer go in one contact. Contacts are counted, not rungs.
Disputesissue → resolutionOff the ladder. On resolution the invoice rejoins at the rung its age implies.
Payingevery dayOne draw per open invoice: pays if the draw is under its hazard — the segment's base rate, plus an uplift for five days after a contact, doubled during a promise.
# the morning, for one customer (engine.py) — which rungs are due, then one message
for i in by_cust[c]:
    if paid or handed or promise_open or dispute_open: continue
    # sched = due + offset, slid off weekends
    due_rungs = [no for no in RUNG_NO if no > s["last_sent"] and s["sched"][no] <= t]
    if due_rungs: s["last_sent"] = due_rungs[-1]; batch.append((i, due_rungs[-1]))
if batch:
    contacts += 1                          # ONE message per customer per day
    # the promise draw, only if a call actually happens
    if max(r for _, r in batch) in (3, 4) and rng.random() < 0.35:
        for i, r in batch:
            if r in (3, 4): S[i]["promise_until"] = t + promise_days
04 ·RUN ITTHE LADDER, LIVE, ON A BOOK YOU CONTROL
SEED
A 400-INVOICE BOOK IS GENERATED FROM THE PRINTED RULES AND CHASED THREE WAYS FOR 150 DAYS IN YOUR BROWSER. NOTHING LEAVES THIS PAGE.
EXTRA CASH BY DAY 150 · VS NO LADDER

Run the ladder to see what it collects.

THE RUNG FUNNEL · INVOICES THAT REACHED EACH RUNG

Three things to try. Press NO LADDER: the same customers, the same book, nobody asks — watch the cash curve sag and the unpaid pile up at day 150. Press SHOUTING: a contact every two days from the day after due. It collects more than silence and less than the ladder, at twice the messages, because after the fourth contact the customer stops reading — and it hands far more to the agency. Then drag the tempo to +10 and see what a ladder that starts a week late costs: the promise rate holds, the adherence does not. The rung days are a business decision, so they are a slider, not a constant.

05 ·WHAT IT FINDSTHE REFERENCE RUN · SEED 42 · THREE POLICIES, ONE BOOK

Cash collected, day by day

CUMULATIVE · ₹ LAKH · SAME 400 INVOICES, SAME RANDOM STREAM
LADDERSHOUTINGNO LADDER

The rung funnel

LADDER · INVOICES THAT REACHED EACH RUNG · OF 400

Contacts per customer, 150 days

CUSTOMERS IN EACH BAND · LADDER VS SHOUTING
LADDERSHOUTING

Three policies, side by side

Who the ladder works on

06 ·WATCHHOW IT RUNS WHEN NOBODY IS LOOKING
WHENWHAT HAPPENSWHO SEES IT
07:00 dailyPull open invoices, payments to midnight, disputes and promises. For each invoice: which rung is due today? Refuse to run if the payment feed is older than 26 hours — a stale feed chases people who have paid.A failed run pages the owner. Nobody is chased on a stale feed.
07:02Batch: one message per customer, all rungs due, statement attached. Weekend and holiday check. Tie out: open invoices = on the ladder + on hold + disputed + handed over. Any gap → no send.Finance sees the day's send list before it goes; the tie-out failure is the engine finding a bug in itself.
07:05Send. Log the rung, the day and the channel against the invoice — the memory the business never had.The customer gets one message, on a weekday, with everything on it.
Promise + windowThe day a promise expires unpaid, the invoice resumes at R6 that morning — no reminder to remind.The account owner, with the promise date on the line.
WeeklyTwo numbers on one chart: adherence this week, contacts per customer. Rung days and tone reviewed only when that chart moves.Leadership — the WATCH stage of the Leak Ledger.
07 · THE TAKEAWAY

Chasing is not a mood; it is a calendar. The ladder works because it is boring — the same rung on the same day in the same tone, whoever is on leave. The engine adds the three refusals a person cannot keep up: not on a weekend, one message per customer, nothing while a promise is open. Shouting collects less at twice the cost. Silence collects least of all, and calls it patience.

THE BOOK IS SYNTHETIC AND GENERATED FROM THE RULES PRINTED IN engine.py (SEED 42; HAZARDS AND UPLIFTS AS PRINTED THERE — CHOSEN, NOT MEASURED). NO CLIENT DATA. THE LADDER'S SHAPE, THE BATCHING, THE WEEKEND RULE AND THE PROMISE HOLD ARE THE REAL SHAPE OF THE COLLECTIONS WORK AT A LOGISTICS FIRM; THE OUTCOME FIGURES IN THAT CASE (ADHERENCE →95%, RECEIVABLES −20%) ARE AS REPORTED THERE, NOT PRODUCED HERE. AGENCY FEES AFTER HANDOVER ARE NOT MODELLED. THE BROWSER ENGINE IS A LINE-FOR-LINE PORT OF THE PYTHON AND REPRODUCES results.json EXACTLY ON THE REFERENCE SETTINGS — THE STATUS LINE ABOVE SAYS SO WHEN IT DOES.

Invoices that go out on time and come back late? A dunning engine is a two-to-four-week SEAL: your rungs, your tone, your batching rules — running every morning with a log of who was asked, when, and what they promised.

Start with a TRACE → engine.py README results.json The case it came from →