code wiki / _hdl_build / nx_ocr_legibility_census.nx
nx_ocr_legibility_census.nx source
↩ module page · 209 lines · 12358 B
1// nx_ocr_legibility_census.nx -- THE MECHANICAL LEGIBILITY JUDGE (operator 2026-07-03: "it should be an
2// ocr compare between what we generate and what chrome and bing do", replacing eyeball mockups).
3//
4// Pipeline this scores: the SAME bench page (known ground truth) rendered by (a) OUR browser core at
5// 100% + at 2x zoom (labeled), (b) Chrome headless, (c) Edge headless -- all read by the SAME neutral
6// OCR instrument (Windows.Media.Ocr; a 3rd-party MEASURING INSTRUMENT like qemu/openssl oracles, never
7// a runtime dependency). This organ is the SOVEREIGN SCORER: word-level RECALL (what fraction of the
8// ground-truth words the OCR recovered from the render = how much of the page a reader can actually
9// read) + F1, integer PERMILLE, SQuAD normalization (mirrors nx_qa_score's proven metric semantics:
10// lowercase, non-alnum->space, drop articles, multiset match).
11//
12// HONESTY/TEETH: the verdict is HARNESS INTEGRITY, never the score -- C1 truth is substantial (>=25
13// tokens); C2 NEG/liar-kill: garbage text scores ~0 against the truth (metric can't be rigged); C3 all
14// four OCR files present (a missing incumbent row would silently inflate us); C4 report artifacts
15// written. The SCORES are printed raw, whatever they say. license_tier: ORIGINAL expect_exit: 0
16import "nx_syscalls.nx"
17const K_MAGIC_16384: i64 = 16384
18const K_MAGIC_8192: i64 = 8192
19const K_MAGIC_2000: i64 = 2000
20const K_MAGIC_65536: i64 = 65536
21const K_MAGIC_1024: i64 = 1024
22
23func oc_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
24func oc_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
25func oc_app(buf: *u8, pos: i64, s: *u8) -> i64 { var p: i64=pos; var i: i64=0; while s[i]!=(0 as u8) { buf[p]=s[i]; p=p+1; i=i+1 } return p }
26func oc_appd(buf: *u8, pos: i64, v: i64) -> i64 {
27 var p: i64=pos
28 var m: i64=v
29 if m<0 { buf[p]=45 as u8; p=p+1; m=0-m }
30 let t: *u8=sys_mmap(28)
31 var k: i64=0
32 if m==0 { t[0]=48 as u8; k=1 }
33 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
34 var i: i64=0
35 while i<k { buf[p]=t[k-1-i]; p=p+1; i=i+1 }
36 return p
37}
38func oc_write_file(path: *u8, data: *u8, n: i64) -> i64 {
39 let fd: i64 = sys_openat_wr(path, 0x1a4)
40 if fd<=0 { return 0 - 1 }
41 sys_write(fd, data, n)
42 sys_close(fd)
43 return n
44}
45// read a text file NUL-terminated; returns len (0 if absent)
46func oc_read(path: *u8, out: *u8, cap: i64) -> i64 {
47 let lp: *i64 = sys_mmap(16) as *i64
48 lp[0] = 0 - 1
49 let b: *u8 = sys_read_file(path, lp)
50 if lp[0] <= 0 { out[0]=0 as u8; return 0 }
51 var n: i64 = lp[0]
52 if n > cap-2 { n = cap-2 }
53 var i: i64=0
54 while i<n { out[i]=b[i]; i=i+1 }
55 out[n]=0 as u8
56 return n
57}
58
59// ---- the metric (mirrors nx_qa_score's SQuAD semantics: norm, tokenize, multiset common) ----
60func oc_norm(src: *u8, dst: *u8) -> i64 {
61 var i: i64=0
62 var j: i64=0
63 while src[i]!=(0 as u8) {
64 var c: i64 = src[i] as i64
65 if c>=65 { if c<=90 { c=c+32 } }
66 var keep: i64=0
67 if c>=97 { if c<=122 { keep=1 } }
68 if c>=48 { if c<=57 { keep=1 } }
69 if keep==1 { dst[j]=(c as u8) } else { dst[j]=(32 as u8) }
70 j=j+1; i=i+1
71 }
72 dst[j]=(0 as u8)
73 return j
74}
75func oc_is_article(buf: *u8, off: i64, len: i64) -> i64 {
76 if len==1 { if buf[off]==(97 as u8){ return 1 } }
77 if len==2 { if buf[off]==(97 as u8){ if buf[off+1]==(110 as u8){ return 1 } } }
78 if len==3 { if buf[off]==(116 as u8){ if buf[off+1]==(104 as u8){ if buf[off+2]==(101 as u8){ return 1 } } } }
79 return 0
80}
81func oc_tok(buf: *u8, blen: i64, toff: *i64, tlen: *i64, maxn: i64) -> i64 {
82 var n: i64=0
83 var start: i64 = 0-1
84 var i: i64=0
85 while i<=blen {
86 var sp: i64=1
87 if i<blen { if buf[i]!=(32 as u8) { sp=0 } }
88 if sp==0 { if start<0 { start=i } }
89 else {
90 if start>=0 {
91 let ln: i64 = i-start
92 if oc_is_article(buf,start,ln)==0 { if n<maxn { toff[n]=start; tlen[n]=ln; n=n+1 } }
93 start = 0-1
94 }
95 }
96 i=i+1
97 }
98 return n
99}
100func oc_teq(pb: *u8, po: i64, pl: i64, gb: *u8, go: i64, gl: i64) -> i64 {
101 if pl!=gl { return 0 }
102 var k: i64=0
103 while k<pl { if pb[po+k]!=gb[go+k] { return 0 } k=k+1 }
104 return 1
105}
106// scores[0]=recall permille, scores[1]=f1 permille, scores[2]=pred tokens, scores[3]=gold tokens
107func oc_score(pred: *u8, gold: *u8, scores: *i64) -> i64 {
108 let pb: *u8=sys_mmap(K_MAGIC_16384)
109 let gb: *u8=sys_mmap(K_MAGIC_16384)
110 let pl: i64=oc_norm(pred,pb)
111 let gl: i64=oc_norm(gold,gb)
112 let ptoff: *i64=sys_mmap(K_MAGIC_8192) as *i64
113 let ptlen: *i64=sys_mmap(K_MAGIC_8192) as *i64
114 let gtoff: *i64=sys_mmap(K_MAGIC_8192) as *i64
115 let gtlen: *i64=sys_mmap(K_MAGIC_8192) as *i64
116 let np: i64=oc_tok(pb,pl,ptoff,ptlen,1000)
117 let ng: i64=oc_tok(gb,gl,gtoff,gtlen,1000)
118 scores[2]=np
119 scores[3]=ng
120 if ng==0 { scores[0]=0; scores[1]=0; return 0 }
121 if np==0 { scores[0]=0; scores[1]=0; return 0 }
122 let used: *i64=sys_mmap(K_MAGIC_8192) as *i64
123 var g: i64=0
124 while g<ng { used[g]=0; g=g+1 }
125 var common: i64=0
126 var p: i64=0
127 while p<np {
128 var gg: i64=0
129 var found: i64=0
130 while gg<ng {
131 if found==0 { if used[gg]==0 {
132 if oc_teq(pb,ptoff[p],ptlen[p], gb,gtoff[gg],gtlen[gg])==1 { used[gg]=1; common=common+1; found=1 }
133 } }
134 gg=gg+1
135 }
136 p=p+1
137 }
138 scores[0]=(1000*common)/ng
139 scores[1]=(K_MAGIC_2000*common)/(np+ng)
140 return 0
141}
142
143func main() -> i64 {
144 oc_puts("OCR-LEGIBILITY census: the SAME page + the SAME OCR judge over our render vs Chrome vs Edge\n" as *u8)
145 let CAP: i64=K_MAGIC_16384
146 let truth: *u8=sys_mmap(CAP)
147 let ours: *u8=sys_mmap(CAP)
148 let ours2: *u8=sys_mmap(CAP)
149 let chrome: *u8=sys_mmap(CAP)
150 let edge: *u8=sys_mmap(CAP)
151 let tn: i64=oc_read("knowledge/status/ocr_bench_truth.txt\x00" as *u8, truth, CAP)
152 let on: i64=oc_read("knowledge/status/ocr_bench_ours_ocr.txt\x00" as *u8, ours, CAP)
153 let o2n: i64=oc_read("knowledge/status/ocr_bench_old8_ocr.txt\x00" as *u8, ours2, CAP)
154 let cn: i64=oc_read("knowledge/status/ocr_bench_chrome_ocr.txt\x00" as *u8, chrome, CAP)
155 let en: i64=oc_read("knowledge/status/ocr_bench_edge_ocr.txt\x00" as *u8, edge, CAP)
156
157 let so: *i64=sys_mmap(64) as *i64
158 let so2: *i64=sys_mmap(64) as *i64
159 let sc: *i64=sys_mmap(64) as *i64
160 let se: *i64=sys_mmap(64) as *i64
161 oc_score(ours, truth, so)
162 oc_score(ours2, truth, so2)
163 oc_score(chrome, truth, sc)
164 oc_score(edge, truth, se)
165
166 oc_puts(" SCORECARD (recall = permille of ground-truth words the OCR could read off the render; all @100%)\n" as *u8)
167 oc_puts(" nishi 16px recall=" as *u8); oc_num(so[0]); oc_puts(" f1=" as *u8); oc_num(so[1]); oc_puts(" (tokens " as *u8); oc_num(so[2]); oc_puts("/" as *u8); oc_num(so[3]); oc_puts(")\n" as *u8)
168 oc_puts(" nishi 8px-ctl recall=" as *u8); oc_num(so2[0]); oc_puts(" f1=" as *u8); oc_num(so2[1]); oc_puts(" (small-text control; the ORIGINAL monospace baseline was 153)\n" as *u8)
169 oc_puts(" chrome recall=" as *u8); oc_num(sc[0]); oc_puts(" f1=" as *u8); oc_num(sc[1]); oc_puts("\n" as *u8)
170 oc_puts(" edge recall=" as *u8); oc_num(se[0]); oc_puts(" f1=" as *u8); oc_num(se[1]); oc_puts("\n" as *u8)
171
172 // teeth
173 var pass: i64=0
174 var ttl: i64=0
175 let gtoks: i64 = so[3]
176 ttl=ttl+1; oc_puts(" C1 truth substantial (>=25 tokens, got " as *u8); oc_num(gtoks); oc_puts("): " as *u8)
177 if gtoks>=25 { pass=pass+1; oc_puts("PASS\n" as *u8) } else { oc_puts("FAIL\n" as *u8) }
178 let sneg: *i64=sys_mmap(64) as *i64
179 oc_score("zzz qqq flurb xxxt gnort wibble\x00" as *u8, truth, sneg)
180 ttl=ttl+1; oc_puts(" C2 NEG/liar-kill: garbage scores ~0 vs truth (recall=" as *u8); oc_num(sneg[0]); oc_puts("): " as *u8)
181 if sneg[0]<100 { pass=pass+1; oc_puts("PASS\n" as *u8) } else { oc_puts("FAIL\n" as *u8) }
182 ttl=ttl+1; oc_puts(" C3 all four OCR inputs present (no silent side-drop): " as *u8)
183 if on>0 { if o2n>0 { if cn>0 { if en>0 { pass=pass+1; oc_puts("PASS\n" as *u8) } else { oc_puts("FAIL\n" as *u8) } } else { oc_puts("FAIL\n" as *u8) } } else { oc_puts("FAIL\n" as *u8) } } else { oc_puts("FAIL\n" as *u8) }
184
185 // report artifacts
186 let hb: *u8=sys_mmap(K_MAGIC_65536)
187 var hp: i64=0
188 hp=oc_app(hb,hp,"<!doctype html><html><head><title>OCR legibility: nishi vs chrome vs edge</title></head><body style=\x27background:#0b1020;color:#dbe4ff;font-family:monospace;padding:24px\x27><h2>OCR legibility judge -- same page, same OCR instrument, every render</h2><p style=\x27color:#8fa3cc\x27>recall = permille of ground-truth words Windows OCR could read off the render. The mechanical replacement for eyeball font mockups.</p><table style=\x27border-collapse:collapse\x27><tr><th style=\x27text-align:left;padding:4px 12px\x27>render</th><th style=\x27text-align:left;padding:4px 12px\x27>recall</th><th style=\x27text-align:left;padding:4px 12px\x27>f1</th></tr>\x00" as *u8)
189 hp=oc_app(hb,hp,"<tr><td style=\x27padding:3px 12px\x27>nishi 16px (new default)</td><td style=\x27padding:3px 12px;color:#f59e0b\x27>\x00" as *u8); hp=oc_appd(hb,hp,so[0]); hp=oc_app(hb,hp,"</td><td style=\x27padding:3px 12px\x27>\x00" as *u8); hp=oc_appd(hb,hp,so[1]); hp=oc_app(hb,hp,"</td></tr>\x00" as *u8)
190 hp=oc_app(hb,hp,"<tr><td style=\x27padding:3px 12px\x27>nishi 8px (small-text control; original monospace baseline was 153)</td><td style=\x27padding:3px 12px\x27>\x00" as *u8); hp=oc_appd(hb,hp,so2[0]); hp=oc_app(hb,hp,"</td><td style=\x27padding:3px 12px\x27>\x00" as *u8); hp=oc_appd(hb,hp,so2[1]); hp=oc_app(hb,hp,"</td></tr>\x00" as *u8)
191 hp=oc_app(hb,hp,"<tr><td style=\x27padding:3px 12px\x27>chrome @100%</td><td style=\x27padding:3px 12px;color:#22c55e\x27>\x00" as *u8); hp=oc_appd(hb,hp,sc[0]); hp=oc_app(hb,hp,"</td><td style=\x27padding:3px 12px\x27>\x00" as *u8); hp=oc_appd(hb,hp,sc[1]); hp=oc_app(hb,hp,"</td></tr>\x00" as *u8)
192 hp=oc_app(hb,hp,"<tr><td style=\x27padding:3px 12px\x27>edge @100%</td><td style=\x27padding:3px 12px;color:#22c55e\x27>\x00" as *u8); hp=oc_appd(hb,hp,se[0]); hp=oc_app(hb,hp,"</td><td style=\x27padding:3px 12px\x27>\x00" as *u8); hp=oc_appd(hb,hp,se[1]); hp=oc_app(hb,hp,"</td></tr>\x00" as *u8)
193 hp=oc_app(hb,hp,"</table><p style=\x27color:#7c8db5;margin-top:14px\x27>renders: <a style=\x27color:#8ab4ff\x27 href=\x27ocr_bench_ours.png\x27>ours 16px</a> · <a style=\x27color:#8ab4ff\x27 href=\x27ocr_bench_old8.png\x27>ours old-8px</a> · <a style=\x27color:#8ab4ff\x27 href=\x27ocr_bench_chrome.png\x27>chrome</a> · <a style=\x27color:#8ab4ff\x27 href=\x27ocr_bench_edge.png\x27>edge</a>. Judge = Windows.Media.Ocr (same instrument every side; a measuring tool, not a runtime dependency). Scorer sovereign (SQuAD-normalized word recall/F1, integer permille).</p></body></html>\x00" as *u8)
194 let hw: i64=oc_write_file("knowledge/status/ocr_legibility.html\x00" as *u8, hb, hp)
195 let lb: *u8=sys_mmap(K_MAGIC_1024)
196 var lp2: i64=0
197 lp2=oc_app(lb,lp2,"OCR-LEGIBILITY ours=\x00" as *u8); lp2=oc_appd(lb,lp2,so[0])
198 lp2=oc_app(lb,lp2," ours2x=\x00" as *u8); lp2=oc_appd(lb,lp2,so2[0])
199 lp2=oc_app(lb,lp2," chrome=\x00" as *u8); lp2=oc_appd(lb,lp2,sc[0])
200 lp2=oc_app(lb,lp2," edge=\x00" as *u8); lp2=oc_appd(lb,lp2,se[0])
201 lp2=oc_app(lb,lp2," (recall permille)\x0A\x00" as *u8)
202 let lw: i64=oc_write_file("knowledge/status/ocr_legibility.log\x00" as *u8, lb, lp2)
203 ttl=ttl+1; oc_puts(" C4 report artifacts written: " as *u8)
204 if hw>0 { if lw>0 { pass=pass+1; oc_puts("PASS\n" as *u8) } else { oc_puts("FAIL\n" as *u8) } } else { oc_puts("FAIL\n" as *u8) }
205
206 oc_puts("OCR-LEGIBILITY-GATE passed " as *u8); oc_num(pass); oc_puts("/" as *u8); oc_num(ttl)
207 if pass==ttl { oc_puts(" verdict=GREEN (scores above are the measurement; open knowledge/status/ocr_legibility.html)\n" as *u8); sys_exit(0); return 0 }
208 oc_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
209}