Skip to main content

Write-off is a flag on the invoice, not a status

Uncollectible debt needs an exit from the chase queue (without one, MISSING grows forever and zombies bury live collections work — AR design §10). We record it as nullable written_off_at / written_off_by / written_off_reason columns on invoices, owner-only and reversible — not as a new status value and not as a collection-activity row alone.

Why not a status: status is load-bearing in every money predicate (check-allocation pool, invoice_ar_summary, invoice_drift, send_invoices, effective-overdue derivation). A new enum value would silently drop a written-off invoice out of the check-allocation pool, so a late check that arrives anyway could no longer be applied and would strand as leftover. With the flag, the invoice keeps its status: a surprise payment still lands, and the AR page flags "payment received on written-off invoice" for the owner to decide reinstatement. The failure direction is also safer — a predicate that forgets to exclude the flag chases dead debt (annoying, visible) rather than losing an incoming payment (silent).

Why not activity-only: other surfaces (KPI card, recon report, dashboards) read invoices, not collection activities; debt written off only in the activity log would still count as missing everywhere else, and the two pages must never disagree on a dollar.

Written-off is distinct from dead money (void/deleted with payments = accidental erasure); the two are never summed together. (Decided 2026-08-14 in the AR-page grilling session.)