code wiki / _hdl_build / nx_text_recall.nx

nx_text_recall.nx source

↩ module page · 117 lines · 5980 B

1// nx_text_recall.nx -- SOVEREIGN render-coverage grader (operator doctrine 2026-07-29: "grow native 2// capabilities from the first byte up"; a borrowed ruler is a borrowed conclusion). 3// Replaces the Windows.Media.Ocr dependency for the question OCR was ALWAYS a proxy for: "did the 4// page's text actually get rendered?" -- answered from OUR OWN layout tree instead of a bitmap: 5// GROUND TRUTH = every TEXT box the parser produced (the page's words, as we understood them) 6// RENDERED = those with a real painted rect (h>0 and w>0) 7// Reports permille + the first missed runs BY NAME. Immune to the OCR cliffs that distorted three 8// decisions this week (sub-14px legibility, crop-window shifts, wrap-alignment blindness), fully 9// deterministic, and fast enough to run every leg. 10// usage: nx_text_recall <file.html> [width] [vec] 11import "nx_syscalls.nx" 12import "nx_browser_render.nx" 13 14func tr_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 15func tr_n(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{tr_w("-" as *u8);m=0-m} 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 } 16func tr_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; var go: i64=1; while go==1 { let c: i64=s[i]&0xff; if c>=48 { if c<=57 { v=v*10+(c-48); i=i+1 } else { go=0 } } else { go=0 } } return v } 17// count word-ish runs (>=2 chars of alnum) in a text span -- the same unit the OCR ruler counted, 18// so the two numbers stay comparable while we migrate off it. 19func tr_words(src: *u8, off: i64, len: i64) -> i64 { 20 var n: i64 = 0 21 var run: i64 = 0 22 var i: i64 = 0 23 while i < len { 24 let c: i64 = src[off+i] & 0xff 25 var isw: i64 = 0 26 if c >= 48 { if c <= 57 { isw = 1 } } 27 if c >= 65 { if c <= 90 { isw = 1 } } 28 if c >= 97 { if c <= 122 { isw = 1 } } 29 if isw == 1 { run = run + 1 } else { if run >= 2 { n = n + 1 } run = 0 } 30 i = i + 1 31 } 32 if run >= 2 { n = n + 1 } 33 return n 34} 35 36func main(argc: i64, argv: *i64) -> i64 { 37 if argc < 2 { tr_w("usage: nx_text_recall <file.html> [width] [vec]\n" as *u8); sys_exit(2); return 2 } 38 let lb: *i64 = sys_mmap(16) as *i64 39 let html: *u8 = sys_read_file(argv[1] as *u8, lb) 40 if (html as i64) == 0 { tr_w("cannot read\n" as *u8); sys_exit(3); return 3 } 41 var vw: i64 = 1024 42 if argc >= 3 { let w2: i64 = tr_atoi(argv[2] as *u8); if w2 > 0 { vw = w2 } } 43 if argc >= 4 { nx_layout_set_vec_measure(1) } 44 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page 45 page.raw = html 46 page.raw_len = lb[0] 47 page.dark_mode = 0 48 br_layout(page, vw) 49 let t: *LayoutTree = page.tree 50 let src: *u8 = page.buf 51 var tot: i64 = 0 52 var shown: i64 = 0 53 var nmiss: i64 = 0 54 var i: i64 = 0 55 while i < t.count { 56 let b: *LayoutBox = (t.boxes as *u8 + (i as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox 57 if b.kind == 4 { if b.text_len > 0 { 58 let wds: i64 = tr_words(src, b.text_off, b.text_len) 59 if wds > 0 { 60 tot = tot + wds 61 var vis: i64 = 0 62 if b.h > 0 { if b.w > 0 { vis = 1 } } 63 // ★HIDDEN vs LOST (the grader's own first finding, 2026-07-29): a 0x0 box whose 64 // PARENT is also 0x0 is a display:none subtree -- CORRECTLY not rendered (linkedin 65 // ships duplicate mobile/desktop variants; wikipedia hides its nav). A box with ONE 66 // zero axis (w=0,h>0 or h=0,w>0) was LAID OUT and starved = a real defect. Counting 67 // them together made an author's deliberate hide look like our bug -- exactly the 68 // conflation that makes a ruler a liar. 69 var hidden: i64 = 0 70 if vis == 0 { if b.w == 0 { if b.h == 0 { 71 if b.parent_idx >= 0 { 72 let pb: *LayoutBox = (t.boxes as *u8 + (b.parent_idx as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox 73 if pb.w == 0 { if pb.h == 0 { hidden = 1 } } 74 } 75 } } } 76 if hidden == 1 { tot = tot - wds } // not our text to render 77 if vis == 1 { shown = shown + wds } 78 else { if hidden == 0 { 79 if nmiss < 12 { 80 tr_w(" MISSED \"" as *u8) 81 var mn: i64 = b.text_len 82 if mn > 40 { mn = 40 } 83 sys_write(1, ((src as i64) + b.text_off) as *u8, mn) 84 tr_w("\" (w=" as *u8); tr_n(b.w); tr_w(" h=" as *u8); tr_n(b.h); tr_w(")\n" as *u8) 85 nmiss = nmiss + 1 86 } 87 } } 88 } 89 } } 90 i = i + 1 91 } 92 var pm: i64 = 0 93 if tot > 0 { pm = (shown * 1000) / tot } 94 tr_w("TEXT-RECALL rendered=" as *u8); tr_n(shown) 95 tr_w("/" as *u8); tr_n(tot) 96 tr_w(" words = " as *u8); tr_n(pm); tr_w(" permille page_h=" as *u8); tr_n(page.page_h) 97 tr_w(" boxes=" as *u8); tr_n(t.count) 98 // IMG-SRC CENSUS (2026-07-29): the zero-images question is settled by ONE number — how many laid 99 // boxes actually carry an <img src>. If this is 0 the extractor/k-map is the bug; if it is >0 the 100 // failure is downstream (fetch/decode/blit). 101 var nimg: i64 = 0 102 var nimgvis: i64 = 0 103 var q: i64 = 0 104 while q < t.count { 105 if page.bsrc_off[q] != (0 - 1) { 106 nimg = nimg + 1 107 let qb: *LayoutBox = (t.boxes as *u8 + (q as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox 108 if qb.h > 0 { if qb.w > 0 { nimgvis = nimgvis + 1 } } 109 } 110 q = q + 1 111 } 112 tr_w(" imgsrc=" as *u8); tr_n(nimg) 113 tr_w(" imgsrc_laid=" as *u8); tr_n(nimgvis) 114 tr_w("\n" as *u8) 115 sys_exit(0) 116 return 0 117}