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}