code wiki / (root) / nx_paperbench_cli.nx

nx_paperbench_cli.nx source

↩ module page · 207 lines · 10599 B

1// nx_paperbench_cli.nx -- callable MCP/API surface for the sovereign manuscript grader (AS-0). 2// 3// nx_paperbench score <slack> <bar> <axes_csv> [weights_csv] [mask_csv] 4// axes = 7 permille scores in canonical order: 5// claim_evidence,reproducibility,controls,limitations,baseline,data_provenance,stat_honesty 6// e.g. nx_paperbench score 250 600 1000,1000,200,1000,1000,1000,1000 -> capped 450 7// 8// nx_paperbench scan <path> <slack> <bar> 9// reads a REAL manuscript off disk and derives the axes mechanically: 10// claim_evidence = provenance tokens "[ev:" per numeric claim (digit run) 11// the other six = presence of the canonical section heading 12// HONEST SCOPE: section-presence is a REPORTING signal, not a quality signal. 13// REFORMS (arXiv:2308.07832) is itself a *reporting* standard, so this is the 14// right tier -- but a present-and-empty section scores the same as a good one. 15// Judging section CONTENT is the referee stage (AS-2), not the ruler. 16// 17// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 18import "nx_paperbench.nx" 19import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 20import "nx_syscalls.nx" 21const K_MAGIC_1048576: i64 = 1048576 22const K_MAGIC_1048560: i64 = 1048560 23 24func pc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 25func pc_q() -> i64 { let b: *u8 = sys_mmap(1); b[0] = 34 as u8; sys_write(1, b, 1); return 0 } 26func pc_key(name: *u8) -> i64 { pc_q(); pc_puts(name); pc_q(); pc_puts(":" as *u8); return 0 } 27// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 28// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 29// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 30// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 31func pc_num(v: i64) -> i64 { nxi_out(v); return 0 } 32func pc_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 33func pc_atoi(a: *u8) -> i64 { 34 var v: i64 = 0; var i: i64 = 0 35 while a[i] != (0 as u8) { 36 let ch: i64 = a[i] as i64 37 if ch >= 48 { if ch <= 57 { v = v * 10 + (ch - 48) } } 38 i = i + 1 39 } 40 return v 41} 42func pc_parse_csv(s: *u8, out: *i64, maxn: i64) -> i64 { 43 var cnt: i64 = 0; var cur: i64 = 0; var have: i64 = 0; var i: i64 = 0 44 let n: i64 = pc_strlen(s) 45 while i < n { 46 let c: i64 = s[i] as i64 47 if c >= 48 { if c <= 57 { cur = cur * 10 + (c - 48); have = 1 } } 48 if c == 44 { if cnt < maxn { out[cnt] = cur; cnt = cnt + 1 } cur = 0; have = 0 } 49 i = i + 1 50 } 51 if have == 1 { if cnt < maxn { out[cnt] = cur; cnt = cnt + 1 } } 52 return cnt 53} 54func pc_axis_name(i: i64) -> i64 { 55 if i == 0 { pc_puts("claim_evidence" as *u8); return 0 } 56 if i == 1 { pc_puts("reproducibility" as *u8); return 0 } 57 if i == 2 { pc_puts("controls" as *u8); return 0 } 58 if i == 3 { pc_puts("limitations" as *u8); return 0 } 59 if i == 4 { pc_puts("baseline" as *u8); return 0 } 60 if i == 5 { pc_puts("data_provenance" as *u8); return 0 } 61 if i == 6 { pc_puts("stat_honesty" as *u8); return 0 } 62 pc_puts("axis" as *u8); pc_num(i) 63 return 0 64} 65func pc_tier_name(t: i64) -> i64 { 66 if t == 0 { pc_puts("REJECT" as *u8); return 0 } 67 if t == 1 { pc_puts("WEAK" as *u8); return 0 } 68 if t == 2 { pc_puts("BORDERLINE" as *u8); return 0 } 69 if t == 3 { pc_puts("ACCEPT" as *u8); return 0 } 70 pc_puts("STRONG" as *u8) 71 return 0 72} 73func pc_read(path: *u8, buf: *u8, cap: i64) -> i64 { 74 let fd: i64 = sys_openat_rd(path) 75 if fd < 0 { return 0 - 1 } 76 var n: i64 = 0 77 var go: i64 = 1 78 while go == 1 { 79 let base: i64 = buf as i64 80 let r: i64 = sys_read(fd, (base + n) as *u8, cap - n) 81 if r <= 0 { go = 0 } else { n = n + r } 82 if n >= cap { go = 0 } 83 } 84 sys_close(fd) 85 return n 86} 87// one section axis: present -> 1000, absent -> 0 88func pc_sec(buf: *u8, n: i64, pat: *u8) -> i64 { 89 if pb_find(buf, n, pat) > 0 { return 1000 } 90 return 0 91} 92func pc_emit(axes: *i64, w: *i64, mk: *i64, slack: i64, bar: i64) -> i64 { 93 let comp: i64 = pb_composite(axes, w, mk, 7, slack) 94 let bars: *i64 = sys_mmap(4 * 8) as *i64 95 bars[0] = 300; bars[1] = 600; bars[2] = 850; bars[3] = 950 96 let tier: i64 = pb_tier(comp, bars, 4) 97 let weak: i64 = pb_weakest(axes, 7) 98 pc_key("axes" as *u8); pc_puts("{" as *u8) 99 var i: i64 = 0 100 while i < 7 { 101 if i > 0 { pc_puts("," as *u8) } 102 pc_q(); pc_axis_name(i); pc_q(); pc_puts(":" as *u8); pc_num(axes[i]) 103 i = i + 1 104 } 105 pc_puts("}," as *u8) 106 pc_key("weighted_mean" as *u8); pc_num(pb_weighted(axes, w, 7)); pc_puts("," as *u8) 107 pc_key("integrity_floor" as *u8); pc_num(pb_min_masked(axes, mk, 7)); pc_puts("," as *u8) 108 pc_key("slack" as *u8); pc_num(slack); pc_puts("," as *u8) 109 pc_key("composite" as *u8); pc_num(comp); pc_puts("," as *u8) 110 pc_key("tier" as *u8); pc_num(tier); pc_puts("," as *u8) 111 pc_key("tier_name" as *u8); pc_q(); pc_tier_name(tier); pc_q(); pc_puts("," as *u8) 112 pc_key("bars_source" as *u8); pc_q(); pc_puts("default-300-600-850-950" as *u8); pc_q(); pc_puts("," as *u8) 113 pc_key("weakest_axis" as *u8); pc_q(); pc_axis_name(weak); pc_q(); pc_puts("," as *u8) 114 pc_key("bar" as *u8); pc_num(bar); pc_puts("," as *u8) 115 pc_key("publishable" as *u8); pc_num(pb_publishable(axes, w, mk, 7, slack, bar)); pc_puts("," as *u8) 116 pc_key("voided" as *u8) 117 if comp == 0 { pc_num(1) } else { pc_num(0) } 118 return 0 119} 120func main(argc: i64, argv: *i64) -> i64 { 121 if argc < 3 { 122 pc_puts("{" as *u8); pc_key("error" as *u8); pc_q() 123 pc_puts("usage: nx_paperbench score <slack> <bar> <axes_csv> [weights_csv] [mask_csv] | scan <path> <slack> <bar>" as *u8) 124 pc_q(); pc_puts("}\n" as *u8); sys_exit(2); return 2 125 } 126 let verb: *u8 = argv[1] as *u8 127 // canonical weights + integrity mask (claim_evidence, controls, stat_honesty) 128 let w: *i64 = sys_mmap(7 * 8) as *i64 129 let mk: *i64 = sys_mmap(7 * 8) as *i64 130 var i: i64 = 0 131 while i < 7 { w[i] = 1; mk[i] = 0; i = i + 1 } 132 mk[0] = 1; mk[2] = 1; mk[6] = 1 133 let axes: *i64 = sys_mmap(7 * 8) as *i64 134 i = 0 135 while i < 7 { axes[i] = 0; i = i + 1 } 136 137 if pb_is_scan(verb) == 1 { 138 // ---- scan <path> <slack> <bar> 139 if argc < 5 { 140 pc_puts("{" as *u8); pc_key("error" as *u8); pc_q() 141 pc_puts("usage: nx_paperbench scan <path> <slack> <bar>" as *u8) 142 pc_q(); pc_puts("}\n" as *u8); sys_exit(2); return 2 143 } 144 let path: *u8 = argv[2] as *u8 145 let slack: i64 = pc_atoi(argv[3] as *u8) 146 let bar: i64 = pc_atoi(argv[4] as *u8) 147 let buf: *u8 = sys_mmap(K_MAGIC_1048576) 148 let n: i64 = pc_read(path, buf, K_MAGIC_1048560) 149 if n < 0 { 150 // FAIL LOUD: an unreadable manuscript is REPORTED, never scored as a zero paper 151 pc_puts("{" as *u8); pc_key("error" as *u8); pc_q() 152 pc_puts("manuscript unreadable -- refusing to score (an unreadable paper is not a bad paper)" as *u8) 153 pc_q(); pc_puts("," as *u8); pc_key("path" as *u8); pc_q(); pc_puts(path); pc_q() 154 pc_puts("}\n" as *u8); sys_exit(3); return 3 155 } 156 // claims are counted in the BODY only -- the bibliography is dense with 157 // digits that are citations, not assertions. 158 let body: i64 = pb_offset(buf, n, "## References" as *u8) 159 let claims: i64 = pb_claims(buf, body) 160 let cited: i64 = pb_find(buf, body, "[ev:" as *u8) 161 axes[0] = pb_axis(cited, claims) 162 axes[1] = pc_sec(buf, n, "## Reproducibility" as *u8) 163 axes[2] = pc_sec(buf, n, "## Negative Controls" as *u8) 164 axes[3] = pc_sec(buf, n, "## Limitations" as *u8) 165 axes[4] = pc_sec(buf, n, "## Baseline" as *u8) 166 axes[5] = pc_sec(buf, n, "## Data" as *u8) 167 axes[6] = pc_sec(buf, n, "n=" as *u8) 168 pc_puts("{" as *u8) 169 pc_key("tool" as *u8); pc_q(); pc_puts("nx_paperbench" as *u8); pc_q(); pc_puts("," as *u8) 170 pc_key("mode" as *u8); pc_q(); pc_puts("scan" as *u8); pc_q(); pc_puts("," as *u8) 171 pc_key("path" as *u8); pc_q(); pc_puts(path); pc_q(); pc_puts("," as *u8) 172 pc_key("bytes" as *u8); pc_num(n); pc_puts("," as *u8) 173 pc_key("body_bytes_scanned" as *u8); pc_num(body); pc_puts("," as *u8) 174 pc_key("numeric_claims" as *u8); pc_num(claims); pc_puts("," as *u8) 175 pc_key("provenance_tokens" as *u8); pc_num(cited); pc_puts("," as *u8) 176 pc_emit(axes, w, mk, slack, bar) 177 pc_puts("," as *u8); pc_key("scope" as *u8); pc_q() 178 pc_puts("section-presence is a REPORTING signal (REFORMS tier), not a content judgement; AS-2 referee judges content" as *u8) 179 pc_q(); pc_puts("}\n" as *u8) 180 sys_exit(0); return 0 181 } 182 // ---- score <slack> <bar> <axes_csv> [weights_csv] [mask_csv] 183 if argc < 5 { 184 pc_puts("{" as *u8); pc_key("error" as *u8); pc_q() 185 pc_puts("usage: nx_paperbench score <slack> <bar> <axes_csv> [weights_csv] [mask_csv]" as *u8) 186 pc_q(); pc_puts("}\n" as *u8); sys_exit(2); return 2 187 } 188 let slack: i64 = pc_atoi(argv[2] as *u8) 189 let bar: i64 = pc_atoi(argv[3] as *u8) 190 let got: i64 = pc_parse_csv(argv[4] as *u8, axes, 7) 191 if got < 7 { 192 pc_puts("{" as *u8); pc_key("error" as *u8); pc_q() 193 pc_puts("need 7 axis scores in permille (claim_evidence,reproducibility,controls,limitations,baseline,data_provenance,stat_honesty)" as *u8) 194 pc_q(); pc_puts("," as *u8); pc_key("got" as *u8); pc_num(got) 195 pc_puts("}\n" as *u8); sys_exit(1); return 1 196 } 197 if argc >= 6 { pc_parse_csv(argv[5] as *u8, w, 7) } 198 if argc >= 7 { pc_parse_csv(argv[6] as *u8, mk, 7) } 199 pc_puts("{" as *u8) 200 pc_key("tool" as *u8); pc_q(); pc_puts("nx_paperbench" as *u8); pc_q(); pc_puts("," as *u8) 201 pc_key("mode" as *u8); pc_q(); pc_puts("score" as *u8); pc_q(); pc_puts("," as *u8) 202 pc_emit(axes, w, mk, slack, bar) 203 pc_puts("," as *u8); pc_key("grounding" as *u8); pc_q() 204 pc_puts("REFORMS arXiv:2308.07832 + Pineau arXiv:2003.12206; composite VOIDs on a zero integrity axis and caps at floor+slack" as *u8) 205 pc_q(); pc_puts("}\n" as *u8) 206 sys_exit(0); return 0 207}