REFERENCE
The Dunning Recompute Engine
Five event types feed one engine. Read all state, compute correct status, apply minimal diff. Disagreement is structurally impossible because one engine sees everything.
The recompute engine replaces per-event blind handlers with a single component that reads all account state, computes what dunning status should be, and applies the minimal diff. Every event triggers a full re-evaluation.
One engine, one truth. Every event — regardless of type — triggers the same full re-evaluation. The engine gathers all signals, computes the correct state, applies the minimal diff, and emits domain events.
| Table | Owner | What It Stores | Who Reads | Who Writes |
|---|---|---|---|---|
| subs_dunning | Area 3 | Dunning state per account | A3 recompute, NinjaPanel | A3 recompute only |
| subs_account | Shared | Account flags, billing profile | A1, A2, A3 | A1 (profiles), A3 (bad_debt flag) |
| subs_customer | Shared | Stripe ↔ CF customer mapping | A1, A2, A3 | A1 (setup), A2 (checkout) |
| subs_mandate | Area 3 | Payment mandates | A3 recompute | A3 recompute |
| subs_stuck_events | Area 3 | Unprocessed events | A3 recompute, ops | A3 recompute |
Shared tables (subs_account, subs_customer) are written by multiple areas — changes require cross-team coordination.
Payment confirmed. Engine clears dunning state, resets retry counters, and removes any bad_debt flags.
Payment declined. Engine evaluates retry eligibility, updates dunning state, and may escalate consequences.
Invoice ready for collection. Engine checks if the account is already in dunning and adjusts state accordingly.
Subscription state changed. Engine re-evaluates whether dunning state is still consistent with current subscriptions.
Refund processed. Engine recalculates account standing based on the updated payment history.
| Metric | Before (Blind Handlers) | After (Recompute Engine) |
|---|---|---|
| Coverage | 19% — each handler covers one event | 100% — engine evaluates all signals |
| Resolution | Days — manual investigation | Minutes — next event triggers full recompute |
| Disagreement | Common — handlers overwrite each other | Impossible — one engine sees everything |
- 19% → 100%
- coverage
- days → minutes
- resolution
- common → impossible
- disagreement
One engine, one truth. The recompute model eliminates disagreement by design — every event triggers a full re-evaluation of dunning state.