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}