code wiki / (root) / nx_recall_bench.nx

nx_recall_bench.nx source

↩ module page · 92 lines · 4777 B

1// nx_recall_bench.nx -- the R1+R2 measured-lift bench AS A SERVICE (evidence-fork organ). 2// Every call RE-RUNS the fusion + rerank benches live on the nx_ir_eval ruler and emits 3// the scorecard JSON -- numbers are recomputed at call time, never baked, so a caller 4// (the /compare C2/C5 evidence-fork, a workstream, a session) can fork the proof. 5// Verdict RED + exit 1 if any lift inverts (liar-killer: a regression cannot hide). 6// nx_recall_bench -> JSON scorecard 7// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 8import "fx.nx" 9import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 10import "nx_ir_eval.nx" 11import "nx_recall_fuse.nx" 12import "nx_recall_rerank.nx" 13import "syscalls.nx" 14const K_MAGIC_32768: i64 = 32768 15const K_MAGIC_65536: i64 = 65536 16 17func rb_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 18func rb_q() -> i64 { let b: *u8 = sys_mmap(1); b[0] = 34 as u8; sys_write(1, b, 1); return 0 } 19func rb_key(name: *u8) -> i64 { rb_q(); rb_puts(name); rb_q(); rb_puts(":" as *u8); return 0 } 20// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 21// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 22// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 23// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 24func rb_num(v: i64) -> i64 { nxi_out(v); return 0 } 25func rb_permil(fxv: i64) -> i64 { return (fxv * 1000 + K_MAGIC_32768) / K_MAGIC_65536 } 26 27func main() -> i64 { 28 // ---- R1 fixture: hybrid RRF fusion vs BM25-alone (the lexical-miss case) ---- 29 let g: *i64 = sys_mmap(5 * 8) as *i64 30 g[0] = 0; g[1] = 0; g[2] = 1; g[3] = 3; g[4] = 0 31 let bm: *i64 = sys_mmap(5 * 8) as *i64 32 bm[0] = 0; bm[1] = 1; bm[2] = 2; bm[3] = 3; bm[4] = 4 33 let dn: *i64 = sys_mmap(5 * 8) as *i64 34 dn[0] = 3; dn[1] = 2; dn[2] = 0; dn[3] = 1; dn[4] = 4 35 let sc: *i64 = sys_mmap(5 * 8) as *i64 36 rf_fuse(bm, 5, dn, 5, 5, sc) 37 let ford: *i64 = sys_mmap(5 * 8) as *i64 38 rf_order_by_score(sc, 5, ford) 39 let gb: *i64 = sys_mmap(5 * 8) as *i64 40 var i: i64 = 0 41 while i < 5 { gb[i] = g[bm[i]]; i = i + 1 } 42 let gf: *i64 = sys_mmap(5 * 8) as *i64 43 i = 0 44 while i < 5 { gf[i] = g[ford[i]]; i = i + 1 } 45 let ndcg_bm: i64 = ie_ndcg_at_k(gb, 5, 5) 46 let ndcg_fs: i64 = ie_ndcg_at_k(gf, 5, 5) 47 48 // ---- R2 fixture: sovereign cosine rerank vs fusion-baseline (buried doc) ---- 49 let q: *i64 = sys_mmap(4 * 8) as *i64 50 q[0] = 100; q[1] = 0; q[2] = 0; q[3] = 0 51 let em: *i64 = sys_mmap(5 * 4 * 8) as *i64 52 em[0] = 80; em[1] = 60; em[2] = 0; em[3] = 0 53 em[4] = 0; em[5] = 100; em[6] = 0; em[7] = 0 54 em[8] = 60; em[9] = 80; em[10] = 0; em[11] = 0 55 em[12] = 100; em[13] = 0; em[14] = 0; em[15] = 0 56 em[16] = 20; em[17] = 40; em[18] = 0; em[19] = 0 57 let cs: *i64 = sys_mmap(5 * 8) as *i64 58 rr_semantic_scores(q, 4, em, 5, cs) 59 let rord: *i64 = sys_mmap(5 * 8) as *i64 60 rr_order_by_cos(cs, 5, rord) 61 let fus: *i64 = sys_mmap(5 * 8) as *i64 62 fus[0] = 0; fus[1] = 2; fus[2] = 1; fus[3] = 3; fus[4] = 4 63 let gfb: *i64 = sys_mmap(5 * 8) as *i64 64 i = 0 65 while i < 5 { gfb[i] = g[fus[i]]; i = i + 1 } 66 let grr: *i64 = sys_mmap(5 * 8) as *i64 67 i = 0 68 while i < 5 { grr[i] = g[rord[i]]; i = i + 1 } 69 let ndcg_fb: i64 = ie_ndcg_at_k(gfb, 5, 5) 70 let ndcg_rr: i64 = ie_ndcg_at_k(grr, 5, 5) 71 72 // verdict: both lifts must hold, freshly recomputed 73 var red: i64 = 0 74 if ndcg_fs <= ndcg_bm { red = 1 } 75 if ndcg_rr <= ndcg_fb { red = 1 } 76 77 rb_puts("{" as *u8) 78 rb_key("api" as *u8); rb_q(); rb_puts("nishi-recall-bench" as *u8); rb_q(); rb_puts("," as *u8) 79 rb_key("v" as *u8); rb_num(1); rb_puts("," as *u8) 80 rb_key("ruler" as *u8); rb_q(); rb_puts("nx_ir_eval Q16.16 integer-exact" as *u8); rb_q(); rb_puts("," as *u8) 81 rb_key("r1_fusion_ndcg5_bm25_permil" as *u8); rb_num(rb_permil(ndcg_bm)); rb_puts("," as *u8) 82 rb_key("r1_fusion_ndcg5_fused_permil" as *u8); rb_num(rb_permil(ndcg_fs)); rb_puts("," as *u8) 83 rb_key("r2_rerank_ndcg5_baseline_permil" as *u8); rb_num(rb_permil(ndcg_fb)); rb_puts("," as *u8) 84 rb_key("r2_rerank_ndcg5_reranked_permil" as *u8); rb_num(rb_permil(ndcg_rr)); rb_puts("," as *u8) 85 rb_key("verdict" as *u8); rb_q() 86 if red == 0 { rb_puts("GREEN" as *u8) } else { rb_puts("RED" as *u8) } 87 rb_q(); rb_puts("," as *u8) 88 rb_key("note" as *u8); rb_q(); rb_puts("recomputed live per call; RED+exit1 on any lift inversion; fixtures = the gate-proven lexical-miss cases" as *u8); rb_q() 89 rb_puts("}\n" as *u8) 90 if red == 1 { sys_exit(1); return 1 } 91 sys_exit(0); return 0 92}