code wiki / _hdl_build / nx_batt_planner_test.nx
nx_batt_planner_test.nx source
↩ module page · 98 lines · 6592 B
1import "nx_gate_gn.nx"
2// nx_batt_planner_test.nx -- gate for the R4 profit/risk planner. Runs the 4 candidate business models head-to-head
3// with ESTIMATED (illustrative) inputs, asserts the exact no-float economics, proves the risk flags surface the
4// fire/capital traps, catches a money-losing model, + LIAR-KILL (more volume flips a loss to a profit = data-driven,
5// not a hardcoded verdict) + NEG-CONTROL (price<cogs always loses). expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_batt_planner.nx"
8
9func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
10
11func mk_cfg() -> *RiskCfg {
12 let c: *RiskCfg = (sys_mmap(128)) as *RiskCfg
13 c.w_fire = 35; c.w_capital = 20; c.w_reg = 15; c.w_demand = 15; c.w_labor = 15
14 c.fire_high_line = 70; c.capital_line = 70; c.slow_breakeven_months = 36
15 return c
16}
17func mk_fin(id: i64, jobs: i64, price: i64, cogs: i64, labor: i64, fixed: i64, upfront: i64) -> *ModelScenario {
18 let m: *ModelScenario = (sys_mmap(128)) as *ModelScenario
19 m.id = id; m.monthly_jobs = jobs; m.avg_price_c = price; m.avg_cogs_c = cogs
20 m.monthly_labor_c = labor; m.monthly_fixed_c = fixed; m.upfront_c = upfront
21 m.fire = 0; m.capital = 0; m.regulatory = 0; m.demand = 0; m.labor_dep = 0
22 return m
23}
24func prow(name: *u8, r: *PlanResult) -> i64 {
25 gp(name); gp(" net$/mo=" as *u8); gn(r.net_monthly_c/100)
26 gp(" margin/1000=" as *u8); gn(r.margin_permille)
27 gp(" breakeven_mo=" as *u8); gn(r.breakeven_months)
28 gp(" risk=" as *u8); gn(r.risk_score)
29 gp(" flags[netneg=" as *u8); gn(r.flag_net_neg); gp(" fire=" as *u8); gn(r.flag_high_fire)
30 gp(" cap=" as *u8); gn(r.flag_capital_heavy); gp(" slow=" as *u8); gn(r.flag_slow_breakeven); gp("]\n" as *u8)
31 return 0
32}
33
34func main() -> i64 {
35 var pass: i64=0; var fail: i64=0
36 let cfg: *RiskCfg = mk_cfg()
37 gp("=== nx_batt_planner_test: profit/risk across the 4 candidate business models (inputs = ESTIMATES) ===\n" as *u8)
38
39 // M0 HYBRID drop-off + express
40 let m0: *ModelScenario = mk_fin(0, 240, 9000, 3000, 600000, 450000, 6000000)
41 m0.fire=35; m0.capital=50; m0.regulatory=45; m0.demand=50; m0.labor_dep=55
42 let r0: *PlanResult = (sys_mmap(128)) as *PlanResult
43 nx_plan_eval(m0, cfg, r0); prow("M0 HYBRID drop-off+express" as *u8, r0)
44
45 // M1 FULL SELF-SERVICE laundromat
46 let m1: *ModelScenario = mk_fin(1, 320, 5500, 1800, 300000, 700000, 12000000)
47 m1.fire=80; m1.capital=80; m1.regulatory=70; m1.demand=45; m1.labor_dep=25
48 let r1: *PlanResult = (sys_mmap(128)) as *PlanResult
49 nx_plan_eval(m1, cfg, r1); prow("M1 FULL self-service " as *u8, r1)
50
51 // M2 DROP-OFF / mail-in shop (low volume)
52 let m2: *ModelScenario = mk_fin(2, 130, 11000, 4200, 750000, 350000, 4500000)
53 m2.fire=25; m2.capital=35; m2.regulatory=35; m2.demand=55; m2.labor_dep=70
54 let r2: *PlanResult = (sys_mmap(128)) as *PlanResult
55 nx_plan_eval(m2, cfg, r2); prow("M2 DROP-OFF shop " as *u8, r2)
56
57 // M3 CORE-EXCHANGE / reman
58 let m3: *ModelScenario = mk_fin(3, 280, 9500, 4600, 650000, 600000, 9500000)
59 m3.fire=45; m3.capital=70; m3.regulatory=50; m3.demand=40; m3.labor_dep=50
60 let r3: *PlanResult = (sys_mmap(128)) as *PlanResult
61 nx_plan_eval(m3, cfg, r3); prow("M3 CORE-EXCHANGE " as *u8, r3)
62
63 // ===== assertions =====
64 // exact no-float economics on the winner
65 if r0.net_monthly_c==390000 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m0 net\n" as *u8) }
66 if r0.breakeven_months==16 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m0 breakeven\n" as *u8) }
67 if r0.risk_score==44 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m0 risk\n" as *u8) }
68 // winner is clean (no flags)
69 if r0.flag_net_neg==0 { if r0.flag_high_fire==0 { if r0.flag_capital_heavy==0 { if r0.flag_slow_breakeven==0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m0 slow\n" as *u8) } } else { fail=fail+1; gp(" FAIL m0 cap\n" as *u8) } } else { fail=fail+1; gp(" FAIL m0 fire\n" as *u8) } } else { fail=fail+1; gp(" FAIL m0 netneg\n" as *u8) }
70 // full self-service surfaces the HIGH-FIRE trap (the operator's #1 concern)
71 if r1.flag_high_fire==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m1 fire flag\n" as *u8) }
72 // low-volume pure drop-off LOSES money -> caught, never breaks even
73 if r2.flag_net_neg==1 { if r2.breakeven_months== -1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m2 breakeven\n" as *u8) } } else { fail=fail+1; gp(" FAIL m2 netneg\n" as *u8) }
74 // core-exchange is capital-heavy -> flagged
75 if r3.flag_capital_heavy==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL m3 cap flag\n" as *u8) }
76 // ranking: hybrid best, dropoff worst (data-driven, the engine discriminates)
77 if r0.net_monthly_c>r1.net_monthly_c { if r1.net_monthly_c>r3.net_monthly_c { if r3.net_monthly_c>r2.net_monthly_c { pass=pass+1 } else { fail=fail+1; gp(" FAIL rank3\n" as *u8) } } else { fail=fail+1; gp(" FAIL rank2\n" as *u8) } } else { fail=fail+1; gp(" FAIL rank1\n" as *u8) }
78
79 // LIAR-KILL: bump drop-off VOLUME 130->300 -> the loss flips to a profit (proves verdict tracks data, not hardcoded)
80 let m2b: *ModelScenario = mk_fin(2, 300, 11000, 4200, 750000, 350000, 4500000)
81 m2b.fire=25; m2b.capital=35; m2b.regulatory=35; m2b.demand=55; m2b.labor_dep=70
82 let r2b: *PlanResult = (sys_mmap(128)) as *PlanResult
83 nx_plan_eval(m2b, cfg, r2b)
84 gp(" LIAR dropoff@130 netneg=" as *u8); gn(r2.flag_net_neg); gp(" -> @300 netneg=" as *u8); gn(r2b.flag_net_neg); gp(" (must be 1 then 0)\n" as *u8)
85 if r2.flag_net_neg==1 { if r2b.flag_net_neg==0 { pass=pass+1 } else { fail=fail+1; gp(" FAIL liar\n" as *u8) } } else { fail=fail+1; gp(" FAIL liar-base\n" as *u8) }
86
87 // NEG-CONTROL: price < cogs always loses, regardless of volume
88 let mn: *ModelScenario = mk_fin(9, 1000, 1000, 4000, 0, 0, 100)
89 mn.fire=10; mn.capital=10; mn.regulatory=10; mn.demand=10; mn.labor_dep=10
90 let rn: *PlanResult = (sys_mmap(128)) as *PlanResult
91 nx_plan_eval(mn, cfg, rn)
92 gp(" NEGCTL price<cogs netneg=" as *u8); gn(rn.flag_net_neg); gp(" (must be 1)\n" as *u8)
93 if rn.flag_net_neg==1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL negctl\n" as *u8) }
94
95 gp("BATT-PLANNER pass=" as *u8); gn(pass); gp(" fail=" as *u8); gn(fail)
96 if fail==0 { gp(" verdict=GREEN -- RECOMMENDED = M0 HYBRID (best net + only model with no risk flags; full self-service = highest fire risk; pure drop-off loses at low volume)\n" as *u8); sys_exit(0); return 0 }
97 gp(" verdict=RED\n" as *u8); sys_exit(1); return 1
98}