← SIMRANJAISWAL.INTHE ENGINE ROOM · 09 · COLLECTIONS

The morning list

Two models on this site rank invoices by who will pay late and when. A ranking is not a day's work. This engine turns it into one: one line per customer, promises on top, a cool-down so nobody is called twice in three days, and a capacity of four collectors × eighteen contacts split so each carries the same rupees. Then it runs the list for ten mornings and races it against the two lists every collections desk actually uses — biggest first and oldest first. It is running below, in your browser, on 900 open invoices.

◆ LIVE ENGINE · RUNS IN YOUR BROWSER · PYTHON REFERENCE PUBLIC
0OPEN INVOICES ON THE MORNING OF DAY 0 · 120 CUSTOMERS
0CONTACTS · 4 COLLECTORS × 18 · CAPACITY IS A NUMBER, NOT A HOPE
0MORE CASH BY DAY 10 THAN "BIGGEST FIRST" · REFERENCE RUN · ₹ LAKH
0FEWER CONTACTS TO GET THERE · TEN MORNINGS · SAME FOUR PEOPLE
01 · THE JOB

The who-pays-late model told the desk which invoices would slip. The payment-date model told it when. Neither told four collectors what to do at 09:30 on Tuesday. The list is where a ranking becomes cash — or, sorted the wrong way, where it becomes 720 phone calls.

A collections desk has a fixed number of conversations in it. Four people, eighteen contacts each, and a book of 900 open invoices belonging to 120 customers: the maths says most of the book is not getting called today, so the whole game is which seventy-two conversations. "Biggest first" calls the same large customer five times about five invoices. "Oldest first" spends the morning on the debts that have already stopped moving. In case 05 and case 08, the models produced a ranking — P(slip) per invoice, a payment date per invoice — and the ranking was the easy half. The Chase List is the other half: RANK made into SEAL of the Leak Ledger. It bundles, it remembers who was called on Friday, it puts a broken promise above a big score, and it splits the day so the senior collector's rupees are within 15% of everyone else's.

02 ·THE ENGINEMODELS → SCORES → ONE LIST → FOUR PEOPLE → TOMORROW
07:30 EVERY WORKING MORNING · EVERY OPEN INVOICE GETS A SCORE = AMOUNT × P(SLIP) · SCORES ARE SUMMED PER CUSTOMER INTO ONE LINE · CUSTOMERS CALLED IN THE LAST THREE DAYS WAIT, UNLESS A PROMISE FELL DUE · THE LIST IS CUT AT CAPACITY AND SPLIT BY RUNNING RUPEES · WHAT DOES NOT FIT IS TOMORROW'S LIST, ONE DAY OLDER.

The engine is deliberately boring: it does not re-train the model, it does not guess who is in a good mood, and it does not let a collector pick. The score is one multiplication, the bundle is a sum, the cool-down is a number of days, and the split is greedy — the next line goes to whoever is carrying the least. Each rule is a sentence a collections manager can read and disagree with, which is what makes the list something the desk will actually follow: when a customer is on it, the line says why.

03 ·THE RULESWHAT "ON THE LIST" MEANS, EXACTLY
STEPRULEWHAT IT DOES
P(slip)Clipped logistic of 0.9 × prior late rate + 0.015 × days past due − 0.5, clipped to 0.02–0.98The stand-in for the who-pays-late model. In life this column comes from the model; the list does not care which.
ScoreAmount × P(slip) for every overdue invoice. Not-yet-due invoices enter only if due within 3 days and above the courtesy threshold (₹1,00,000)Rupees at risk, not rupees. A ₹5 lakh invoice with a 10% slip risk ranks below a ₹1 lakh invoice at 70%.
a · BundleOne line per customer: all their eligible invoices, score = Σ, P(slip) = ₹-weighted meanOne conversation covers the account. "Biggest first" makes five calls to the same customer.
b · Cool-downSkip customers contacted in the last 3 days — unless a promise fell dueA customer called on Friday is not called on Monday. Nagging is not chasing.
c · PromisesA promise due today or overdue puts the customer at the top of the list, above any scorePromise follow-ups are the cheapest cash on the desk; a promise nobody follows up teaches the customer that promises are free.
d · Capacity4 collectors × 18 contacts. Priority accounts go to the senior first; then each line goes to the collector with the lowest running ₹ who still has a slot (greedy, first minimum on ties). Check: every collector's ₹ within 15% of the meanThe list is cut where the day ends, not where hope does. The balance check is printed, not enforced — the greedy split normally passes it.
e · Roll-overWhatever does not fit today is on tomorrow's list, one day older, with a higher P(slip) and so a higher scoreNothing falls off. A line that keeps rolling is a capacity problem, and the roll-over count says so.
OutcomeEach contact pays within 5 days with p = 0.35 + 0.4 × (1 − P(slip)); of the rest, 30% promise to pay in 5 days; the remainder is nothing. One draw per contact, in assignment order; the landing day (1–5) is a second draw only when it paysThe synthetic customer. Printed, so the comparison is fair: all three lists face the same customers and the same draws in the same order.
Tie-out900 = paid + open; today's lines = assigned + rolled; contacts = Σ collectorsIf any breaks, the list is not published.
# the split, in this order — the sentence a collections manager can disagree with (engine.py)
for e in lines:                                       # priority accounts to the senior first
    if e["priority"] and remaining[0] > 0:
        e["coll"] = 0; remaining[0] -= 1; running[0] += e["value"]; assigned.append(e)
    else:
        pool.append(e)
for e in pool:                                        # then greedy: the collector with the lowest running ₹
    k = -1
    for j in range(N_COLL):
        if remaining[j] > 0 and (k < 0 or running[j] < running[k]): k = j
    if k < 0: e["coll"] = None; continue                 # no slot left: tomorrow, one day older
    e["coll"] = k; remaining[k] -= 1; running[k] += e["value"]; assigned.append(e)
04 ·RUN ITTHE ENGINE, LIVE, ON A BOOK YOU CONTROL
SEED
A 900-INVOICE BOOK IS GENERATED FROM THE PRINTED RULES AND WORKED FOR TEN MORNINGS BY THREE LISTS IN YOUR BROWSER. NOTHING LEAVES THIS PAGE.
CASH BY DAY 10 · THE MORNING LIST VS BIGGEST FIRST

Run ten mornings to see what the list collects.

DAY 1 · FROM THE BOOK TO THE CALLS

Two things to try. Set the cool-down to zero and watch the contacts climb while the cash barely moves — the same customers get called again before their money has had time to land. Then drop capacity to ten per collector: the roll-over count stops being zero after day 1 and the list starts carrying an ageing tail, which is the moment a desk is understaffed by arithmetic rather than by feel. The two naive lists are always run alongside on the same customers and the same draws; the slider "list shown below" only changes which one the panel describes.

05 ·WHAT IT FINDSTHE REFERENCE RUN · SEED 42

Cash landed, day by day

CUMULATIVE ₹ · THREE LISTS · SAME BOOK, SAME CUSTOMERS, SAME DRAWS · THE HEADLINE IS READ AT DAY 10
THE MORNING LISTBIGGEST FIRSTOLDEST FIRST

Who carried what

₹ LAKH PER COLLECTOR OVER TEN DAYS · THE BAND IS ±15% OF THE SHOWN LIST'S MEAN

What rolled to tomorrow

LINES NOT CALLED, BY DAY · THREE LISTS

Three lists, ten mornings

Day 1, top of the list

06 ·WATCHHOW IT RUNS WHEN NOBODY IS LOOKING
WHENWHAT HAPPENSWHO SEES IT
07:30 dailyPull open invoices, yesterday's contact log and open promises; take P(slip) from the model's nightly score. Refuse to build if the ledger is older than 26 hours or the model score is missing for more than 2% of invoices.A failed build pages the owner; yesterday's list stays up, marked stale. A missing score never becomes a silent zero.
07:32Score, bundle, cool-down, promises on top, cut at capacity, split by running ₹. Tie out: lines = assigned + rolled; contacts = Σ collectors. Any gap → no publish.The collections manager. A tie-out failure is the engine finding a bug in itself.
07:35Publish four lists, one per collector: customer, invoices, ₹, P(slip), why it is here, "after 10:00" where the customer asked. Promise follow-ups first.Each collector sees only their list. The senior sees the priority accounts at the top of theirs.
18:00Outcomes logged: paid, promised (with a date), nothing. Tomorrow's cool-down and promise queue are built from this log, not from memory.Nobody has to remember who they called. The log is the memory.
WeeklyThree numbers on one chart: cash landed against the two naive lists on the same book, contacts per ₹ lakh, lines rolled over per day. Capacity is discussed only when the roll-over chart stops being flat.Leadership — the WATCH stage of the Leak Ledger.
07 · THE TAKEAWAY

A model is not a plan; a list is. The ranking on this site is the easy half. The hard half is seventy-two conversations a day, chosen so that one call covers an account, a promise is never left to lapse, and nobody is rung on Monday about the thing they were rung about on Friday. Print the rules, cut the list where the day ends, and the same four people collect more with fewer calls — which is the only kind of collections improvement that survives the collector who has a bad week.

THE BOOK IS SYNTHETIC AND GENERATED FROM THE RULES PRINTED IN engine.py (SEED 42; CAPACITY, COOL-DOWN AND THRESHOLD AS SHOWN ON THE SLIDERS). NO CLIENT DATA. P(SLIP) HERE IS A PRINTED STAND-IN FOR THE MODEL IN THE WHO-PAYS-LATE CASE; THE CUSTOMER RESPONSE IS A PRINTED ASSUMPTION AND IS GENEROUS (A CONTACT THAT PAYS CLEARS THE WHOLE BUNDLE; NOBODY PAYS WITHOUT BEING ASKED), SO READ THE THREE LISTS AGAINST EACH OTHER, NOT AGAINST A REAL DESK. THE LIST LOGIC IS THE REAL SHAPE OF THE CHASE ROUTINE BEHIND THE 62% → 90% ON-TIME COLLECTIONS AT A PROCUREMENT STARTUP AND THE 95% PAYMENT ADHERENCE AT A LOGISTICS FIRM; OUTCOME FIGURES IN THOSE CASES ARE AS REPORTED THERE. 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.

A ranking and no list? A chase-list engine is a two-to-three-week SEAL: your book, your collectors, your capacity — built every morning from the model's score, with a tie-out that refuses to publish a list that does not add up.

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