WhyDunit · UPI AutoPay revenue recovery
WhyDunit attributes every failed UPI AutoPay debit to one of four causes — execution window, notification failure, balance shortfall, or cancellation — and executes a bounded recovery action matched to that cause. When the cause is cancellation, it stops instead of spending.
A third of what merchants write off as churn was never the customer. Retrying those on a timer recovers a third of the money and burns the rest on people who already left.
01 — The evidence
ZM is returned for several different reasons. In this corpus no decline code is a reliable proxy for a cause — the most predictive one still misclassifies roughly a fifth of the time.
The bank told you it failed. It did not tell you why, and the one fact that would settle it — the customer’s balance — is not something a merchant can see.
02 — Four suspects
Every cause moves with something and is invariant to the rest. That signature separates them — not the code the bank sent.
Debited inside NPCI's 10:00–13:00 block. Moves with the hour; invariant to customer, bank and amount.
Pre-debit notice not delivered 24h ahead. Moves with the bank and with outage bursts.
No funds at the moment of debit. Moves with the customer and the day of the month.
The customer has stopped paying. Moves with nothing at all. Nothing fixes it.
03 — Why a timer can never fix it
A fixed-interval retry advances the date and preserves the time of day. Against a rule written in hours, every retry lands on the same spoke.
Naive retry · T+24h, T+72h, T+168h
of execution-window failures recovered. Not fewer — none.
WhyDunit · same day, 14:07
attribution accuracy on this class. mdt_00004 recovered on the first retry, 99.9% confidence.
04 — One customer, one year
These are the agent’s own audit rows for a single mandate, replayed as you scroll. Nothing here is staged — every line is read from the log the agent wrote while running.
Four cycles recovered. One held back because confidence fell to 0.54. Three retries in August that went nowhere. Then, in September, P(cancelled) crossed 0.95 and it stopped — the one decision a fixed-interval retry can never make, because a timer has no opinion about whether the customer is still there.
05 — At scale
Every policy gets the same three retries over the same failures. Deltas are paired bootstrap, 1,000 resamples clustered by mandate.
+29.8pp against naive retry [24.8, 35.5], at 1.79 retries per failure instead of 2.67. Attribution: 88.4% auto-classified at macro-F1 0.881 [0.857, 0.901].
06 — What it cannot do
Every figure here comes from one seeded run — seed 20260903, 270-day horizon. npm run verify regenerates the world and re-hashes ten artifacts against a committed manifest, on any CPU architecture.