code wiki / (root) / nx_beneish_gate.nx

nx_beneish_gate.nx source

↩ module page · 97 lines · 5344 B

1// nx_beneish_gate.nx -- BENEISH M-SCORE GATE (forensic manipulation detection). 2// Proves the exact M-score on a benign firm and a manipulator, the -1.78 threshold classification, and 3// the fail-closed composition: a missing index yields INCOMPLETE, never a fraud accusation on partial data. 4// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 5 6import "nx_beneish_lib.nx" 7 8func bg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 9func bg_putn(v: i64) -> i64 { 10 let t: *u8 = sys_mmap(32) 11 var o: i64 = 0 12 var m: i64 = v 13 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m } 14 let d: *u8 = sys_mmap(32) 15 var k: i64 = 0 16 if m == 0 { d[0] = 48 as u8; k = 1 } 17 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 18 var i: i64 = 0 19 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 } 20 sys_write(1, t, o) 21 return 0 22} 23func bg_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 { 24 if got == want { 25 cnt[0] = cnt[0] + 1 26 bg_puts(" PASS " as *u8); bg_puts(name); bg_puts(" = " as *u8); bg_putn(got); bg_puts("\n" as *u8) 27 return 1 28 } 29 cnt[1] = cnt[1] + 1 30 bg_puts(" FAIL " as *u8); bg_puts(name); bg_puts(" got " as *u8); bg_putn(got) 31 bg_puts(" want " as *u8); bg_putn(want); bg_puts("\n" as *u8) 32 return 0 33} 34func bg_ckstr(cnt: *i64, name: *u8, got: *u8, want: *u8) -> i64 { 35 if mt_streq(got, want) == 1 { 36 cnt[0] = cnt[0] + 1 37 bg_puts(" PASS " as *u8); bg_puts(name); bg_puts(" = " as *u8); bg_puts(got); bg_puts("\n" as *u8) 38 return 1 39 } 40 cnt[1] = cnt[1] + 1 41 bg_puts(" FAIL " as *u8); bg_puts(name); bg_puts(" got " as *u8); bg_puts(got); bg_puts("\n" as *u8) 42 return 0 43} 44 45func main(argc: i64, argv: *i64) -> i64 { 46 let cnt: *i64 = sys_mmap(16) as *i64 47 cnt[0] = 0 48 cnt[1] = 0 49 50 bg_puts("NISHI-BENEISH-GATE (M-score forensic manipulation detection, integer-exact)\n" as *u8) 51 52 // ---- M1: a BENIGN firm -- all indices = 1.000 (1000 bp), zero accruals. M x1000 = -2480. ---- 53 // hand-check: -4840000 + (920+528+404+892+115-172-327)*1000 + 4679*0 = -4840000 + 2360000 = -2480000; /1000 = -2480. 54 let bm: i64 = ben_mscore(1000, 1000, 1000, 1000, 1000, 1000, 0, 1000) 55 bg_ck(cnt, "M1 benign firm M-score x1000 = -2480" as *u8, bm, 0 - 2480) 56 bg_ck(cnt, "M1a benign -> NOT a manipulator" as *u8, ben_is_manipulator(bm), 0) 57 bg_ckstr(cnt, "M1b verdict = LIKELY-CLEAN" as *u8, ben_verdict_str(bm), "LIKELY-CLEAN" as *u8) 58 59 // ---- M2: a MANIPULATOR -- inflated receivables (DSRI 1.5), sales growth (SGI 1.3), high accruals (TATA 0.1=100bp) ---- 60 // -4840000 + 920*1500 + 528*1000 + 404*1000 + 892*1300 + 115*1000 - 172*1000 + 4679*100 - 327*1000 61 // = -4840000 + 1380000 + 528000 + 404000 + 1159600 + 115000 - 172000 + 467900 - 327000 = -1284500; /1000 = -1284. 62 let mm: i64 = ben_mscore(1500, 1000, 1000, 1300, 1000, 1000, 100, 1000) 63 bg_ck(cnt, "M2 manipulator M-score x1000 = -1284" as *u8, mm, 0 - 1284) 64 bg_ck(cnt, "M2a M -1.284 > -1.78 threshold -> MANIPULATOR flagged" as *u8, ben_is_manipulator(mm), 1) 65 bg_ckstr(cnt, "M2b verdict = MANIPULATION-RISK" as *u8, ben_verdict_str(mm), "MANIPULATION-RISK" as *u8) 66 67 // ---- M3: the THRESHOLD is exact -- M just above -1.78 flags, just below does not ---- 68 // construct via TATA (coefficient 4.679): find tata making M cross -1780. 69 // baseline (indices 1000, tata 0) M x1000 = -2480. each +1 tata adds 4679/1000 = 4.679 to M x1000. 70 // to reach -1780 from -2480 need +700 -> tata ~ 700000/4679 ~ 149.6. tata=150 -> add 4679*150/1000=701.85 -> M=-1778.15 -> -1778 > -1780 flag. 71 let just_over: i64 = ben_mscore(1000, 1000, 1000, 1000, 1000, 1000, 150, 1000) 72 bg_ck(cnt, "M3 tata=150 -> just over threshold -> flagged" as *u8, ben_is_manipulator(just_over), 1) 73 let just_under: i64 = ben_mscore(1000, 1000, 1000, 1000, 1000, 1000, 140, 1000) 74 bg_ck(cnt, "M3a tata=140 -> just under threshold -> not flagged" as *u8, ben_is_manipulator(just_under), 0) 75 76 // ---- M4: an individual index moves the score in the right direction (higher DSRI -> higher M) ---- 77 var rises: i64 = 0 78 if ben_mscore(1200, 1000, 1000, 1000, 1000, 1000, 0, 1000) > ben_mscore(1000, 1000, 1000, 1000, 1000, 1000, 0, 1000) { rises = 1 } 79 bg_ck(cnt, "M4 higher receivables index raises the M-score" as *u8, rises, 1) 80 81 // ---- M5: FAIL-CLOSED -- a missing index yields INCOMPLETE, never a fraud verdict on partial data ---- 82 let inc: i64 = ben_mscore(1000, BEN_NA, 1000, 1000, 1000, 1000, 0, 1000) 83 bg_ck(cnt, "M5 missing index -> BEN_INCOMPLETE" as *u8, inc, BEN_INCOMPLETE) 84 bg_ck(cnt, "M5a INCOMPLETE is NOT a manipulator accusation" as *u8, ben_is_manipulator(inc), 0) 85 bg_ckstr(cnt, "M5b verdict = INCOMPLETE (no fraud call on partial facts)" as *u8, ben_verdict_str(inc), "INCOMPLETE" as *u8) 86 87 bg_puts("nx_beneish_gate: pass=" as *u8); bg_putn(cnt[0]) 88 bg_puts(" fail=" as *u8); bg_putn(cnt[1]); bg_puts("\n" as *u8) 89 if cnt[1] == 0 { 90 bg_puts("BENEISH nx_beneish: VERDICT=GREEN (exact M-score; manipulator flagged, benign cleared, INCOMPLETE on missing data)\n" as *u8) 91 sys_exit(0) 92 return 0 93 } 94 bg_puts("BENEISH nx_beneish: VERDICT=RED\n" as *u8) 95 sys_exit(1) 96 return 1 97}