# The Credit Note Gate — the credit note that explains itself

Part of **The Engine Room** on simranjaiswal.in: automation engines that stop money going missing
between systems. This one is the gate a credit-note request must pass before the credit note exists:
seven questions in a fixed order, the first failure wins, and every answer is written on the request.

Live case, with the engine running in the browser: https://simranjaiswal.in/work/credit-note-gate

## What it does

Requests are processed in day order (ties by arrival). For each one, in this order, first failure wins:

1. **G1 · an invoice.** No invoice referenced → `REFUSED · NO_INVOICE`.
2. **G2 · room on the invoice.** Amount above what is still open on the invoice → `REFUSED · OVER_REMAINING`.
3. **G3 · a reason.** No reason code → `HELD · NO_REASON` (back to the requester).
4. **G4 · not already asked.** Same invoice, amount within 2%, within the duplicate window (default
   10 days) of an earlier request → `REFUSED · DUPLICATE`.
5. **G5 · not too often.** The customer's 3rd credit note in 30 days (default; counts notes actually
   issued) → `HELD · FREQUENCY` (review).
6. **G6 · who may say yes.** ≤ ₹5,000 `AUTO`; ≤ ₹50,000 `MANAGER`; above `FINANCE_HEAD`.
7. **G7 · the goodwill budget.** A `GOODWILL` credit that would take the requester's goodwill credits
   this quarter above 1% of the invoiced value in their name → `HELD · GOODWILL_CAP`.

Then the approver at that tier answers within 24 h with p = 0.85 (else the request `ESCALATED`s one
level and is answered there, 24–72 h later) and grants with a probability by reason: PRICING_ERROR
0.9, SHORT_SHIPPED 0.9, QUALITY 0.8, DUPLICATE_BILLING 0.95, GOODWILL 0.5. An approved credit reduces
the invoice's remaining, so later requests see it.

**₹ prevented** = refused + declined + held-not-yet-approved value. **Tie-out**: 500 = auto + approved
+ declined + escalated + held + refused, and ₹ requested = ₹ credited + ₹ prevented.

`--no-gate` approves everything and reports the leak: ₹ paid without an invoice, paid over the
remaining, paid twice, and credited beyond what was ever invoiced.

## The synthetic world

There is no client data here. `build_world()` generates a 1,500-invoice book for 60 customers over
90 days (amounts lognormal exp(N(10.2, 0.8)) clipped ₹3,000–3,00,000; 8% already part-credited, remaining
= 70%) and 500 requests from 10 requesters (6 sales, 3 service, 1 finance): 92% reference an invoice,
amount = invoice × share ~ N(0.35, 0.3) clipped 0.02–1 (blank-reference requests draw a lognormal amount),
78% carry a reason, 6% are exact duplicates of an earlier request within 10 days. The leak: goodwill is
15% of reasons overall but generated three times as often from sales as from anyone else
(0.15 = 0.6 × 3g + 0.4 × g). Randomness is mulberry32, a 32-bit generator the browser port implements
bit-for-bit; approvers draw from a second stream (seed + 1) so every policy sees the same requests.

## Run it

```
python3 engine.py                                   # reference: seed 42, auto ≤ ₹5k, manager ≤ ₹50k, dup window 10 d, 3rd credit in 30 d held, goodwill cap 1%
python3 engine.py --no-gate                         # everything approved: shows the leak
python3 engine.py --auto-limit 2000 --manager-limit 25000 --dup-window 30 --freq 2 --goodwill-cap 0.5   # tight
```

Stdlib only. `results.json` carries the world, decisions and ₹ per decision, ₹ credited and prevented,
the leak block, credits by reason code (count, ₹, approval rate), by requester (requests, goodwill
share, ₹ held, budget and cap), the time-to-decision distribution and the decision log.

## Reference run (seed 42)

See `results.json`. Headline: decisions AUTO / APPROVED / DECLINED / ESCALATED / HELD by reason /
REFUSED by reason, ₹ credited vs ₹ prevented, goodwill share by role, and the tie-out.

## Where the shape comes from

The billing-reversals work (https://simranjaiswal.in/work/billing-reversals), where one invoice in
six on a wholesaler's ledger was later credited back and a model could say which — this engine is the
gate that asks first. The approver probabilities are assumptions, printed. Nothing in this repository
is a client's data.

MIT.
