MAJOR: death-turn recovery recognized before the write-off — credit losses understated by RecoveryRate × Remaining #123

Closed
opened 2026-10-01 15:31:08 +00:00 by Winnie · 0 comments
Owner

Found by the v0.6.0 review (issue #118). In the turn a loan dies (game.go:620-649), the recovery block runs FIRST: rec = RecoveryRate × Remaining is collected, Remaining -= rec, and the recovery is booked as income. Only then does the write-off run: d = Remaining − Allowance. The write-off is therefore Remaining × (1 − RecoveryRate), not the full principal, while the first recovery slice is counted as income AND shrinks the charge-off.

Over the loan's life the recognized credit loss understates the economic loss by exactly RecoveryRate × Remaining per defaulted loan, and equity ends overstated by the same amount. This violates ruling #78 ("the full unprovided principal is charged off in the turn the loan dies") and the code's own comment.

Verified: scratch test Rem=10000, RR=0.1, T=3: total write-offs 9000 + recovery income 2710 = recognized loss 6290 vs economic loss 7290 — understated by 1000 = RR×Rem. The shipped writeoff test asserts the current (wrong) numbers, so it encodes the bug.

Found by the v0.6.0 review (issue #118). In the turn a loan dies (game.go:620-649), the recovery block runs FIRST: rec = RecoveryRate × Remaining is collected, Remaining -= rec, and the recovery is booked as income. Only then does the write-off run: d = Remaining − Allowance. The write-off is therefore Remaining × (1 − RecoveryRate), not the full principal, while the first recovery slice is counted as income AND shrinks the charge-off. Over the loan's life the recognized credit loss understates the economic loss by exactly RecoveryRate × Remaining per defaulted loan, and equity ends overstated by the same amount. This violates ruling #78 ("the full unprovided principal is charged off in the turn the loan dies") and the code's own comment. Verified: scratch test Rem=10000, RR=0.1, T=3: total write-offs 9000 + recovery income 2710 = recognized loss 6290 vs economic loss 7290 — understated by 1000 = RR×Rem. The shipped writeoff test asserts the current (wrong) numbers, so it encodes the bug.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Winnie/bankwars#123
No description provided.