code wiki / (root) / nx_debt_strategy_gate.nx

nx_debt_strategy_gate.nx source

↩ module page · 65 lines · 3318 B

1// nx_debt_strategy_gate.nx -- proves the debt-payoff strategist on hand-verified fixtures: monthly interest, 2// avalanche vs snowball target selection, a full single-debt payoff (3 months, $1.52 interest), the avalanche- 3// minimises-interest invariant on a 2-debt case, and the underwater (can't-meet-minimums) hardship signal. 4// Exits 0 iff all pass. license_tier: ORIGINAL 5import "nx_gate.nx" 6import "nx_debt_strategy.nx" 7 8func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 { 9 if got == want { st[0] = st[0] + 1; gw(" PASS " as *u8); gw(name); gw("\n" as *u8) } 10 else { st[1] = st[1] + 1; gw(" FAIL " as *u8); gw(name); gw(" got=" as *u8); gn(got); gw(" want=" as *u8); gn(want); gw("\n" as *u8) } 11 return 0 12} 13 14func main() -> i64 { 15 let st: *i64 = sys_mmap(16) as *i64 16 st[0] = 0; st[1] = 0 17 18 // -- monthly simple interest (cents) -- 19 chk("month_interest($100 @ 12%) = 100c" as *u8, ds_month_interest(10000, 1200), 100, st) 20 chk("month_interest($2000 @ 10%) = 1666c" as *u8, ds_month_interest(200000, 1000), 1666, st) 21 22 // -- single debt: $100 @ 12% APR, $50/mo min, no extra -> 3 months, $1.52 total interest -- 23 let d1: *i64 = sys_mmap(8 * 4) as *i64 24 d1[0] = 10000; d1[1] = 1200; d1[2] = 5000 25 let o1: *i64 = sys_mmap(16) as *i64 26 ds_simulate(d1, 1, 0, DS_AVALANCHE, o1) 27 chk("single-debt payoff months = 3" as *u8, o1[0], 3, st) 28 chk("single-debt total interest = 152c" as *u8, o1[1], 152, st) 29 30 // -- target selection: balances [1000,500], APRs [20%,10%] -- 31 let bal: *i64 = sys_mmap(8 * 4) as *i64 32 bal[0] = 100000; bal[1] = 50000 33 let dt: *i64 = sys_mmap(8 * 8) as *i64 34 dt[0] = 100000; dt[1] = 2000; dt[2] = 1000 35 dt[3] = 50000; dt[4] = 1000; dt[5] = 1000 36 chk("avalanche target = highest APR (idx 0)" as *u8, ds_avalanche_target(bal, dt, 2), 0, st) 37 chk("snowball target = lowest balance (idx 1)" as *u8, ds_snowball_target(bal, 2), 1, st) 38 39 // -- avalanche vs snowball on a 2-debt case: A=$200 @ 24%, B=$100 @ 0%, +$80/mo extra -- 40 let d2: *i64 = sys_mmap(8 * 8) as *i64 41 d2[0] = 20000; d2[1] = 2400; d2[2] = 1000 42 d2[3] = 10000; d2[4] = 0; d2[5] = 1000 43 let oa: *i64 = sys_mmap(16) as *i64 44 let os: *i64 = sys_mmap(16) as *i64 45 ds_simulate(d2, 2, 8000, DS_AVALANCHE, oa) 46 ds_simulate(d2, 2, 8000, DS_SNOWBALL, os) 47 chk("avalanche total interest = 680c" as *u8, oa[1], 680, st) 48 chk("snowball total interest = 1023c" as *u8, os[1], 1023, st) 49 var inv: i64 = 0 50 if oa[1] <= os[1] { inv = 1 } 51 chk("INVARIANT: avalanche interest <= snowball interest" as *u8, inv, 1, st) 52 53 // -- underwater: $1000 @ 60% APR, $1/mo min -> cannot even cover interest -- 54 let d3: *i64 = sys_mmap(8 * 4) as *i64 55 d3[0] = 100000; d3[1] = 6000; d3[2] = 100 56 chk("underwater: can_meet_minimums = 0" as *u8, ds_can_meet_minimums(d3, 1, 0), 0, st) 57 let o3: *i64 = sys_mmap(16) as *i64 58 ds_simulate(d3, 1, 0, DS_AVALANCHE, o3) 59 chk("underwater: months = -1 (hardship signal)" as *u8, o3[0], 0 - 1, st) 60 61 gw("nx_debt_strategy_gate: PASS=" as *u8); gn(st[0]); gw(" FAIL=" as *u8); gn(st[1]); gw("\n" as *u8) 62 if st[1] == 0 { gw("nx_debt_strategy: GREEN (avalanche/snowball, hand-verified, underwater-aware)\n" as *u8); return 0 } 63 gw("nx_debt_strategy: RED\n" as *u8) 64 return 1 65}