nx_browser_render_own_test.nx source
↩ module page · 191 lines · 7923 B
1// nx_browser_render_own_test.nx -- Phase-5 render row: take the HTML
2// the browser fetched from OUR OWN site over sovereign HTTPS
3// (/tmp/nishi_own.html, produced by nx_browser_own_site_live_test)
4// and prove the render pipeline on it:
5//
6// 1. nx_html_to_text extracts readable text -> must contain
7// "Nishi Family" (the real h1) and be non-trivial
8// 2. the extracted text paints into an RGBA framebuffer via the
9// 5x7 bitmap font -> framebuffer must be NON-BLANK
10// 3. ASCII raster saved to /tmp/nishi_own_render.txt (visible proof)
11//
12// HONEST SCOPE: this renders the page's TEXT through the paint
13// substrate. Full CSS-cascade layout of arbitrary real-world pages
14// (style blocks, viewport meta) is the NEXT rung -- flagged, not
15// claimed. Compose-by-file with the fetch test keeps each gate row
16// single-responsibility.
17//
18// expect_exit: 0
19// license_tier: ORIGINAL
20
21import "nx_syscalls.nx"
22import "nx_html_to_text.nx"
23import "nx_css_color_decode.nx"
24import "nx_paint_solid_rect.nx"
25import "nx_paint_text.nx"
26import "nx_paint_fb_ascii_dump.nx"
27import "nx_gate_verdict.nx" // gv_puts/gv_num + GV_MODE_644: compose the base class, never re-type it
28
29// Find needle (NUL-terminated) in hay[0..hay_len); 1 if present.
30func ro_contains(hay: *u8, hay_len: i64, needle: *u8) -> i64 {
31 var nlen: i64 = 0
32 while needle[nlen] != (0 as u8) { nlen = nlen + 1 }
33 if nlen == 0 { return 1 }
34 var i: i64 = 0
35 while i + nlen <= hay_len {
36 var j: i64 = 0
37 var ok: i64 = 1
38 while j < nlen {
39 if hay[i + j] != needle[j] { ok = 0; j = nlen }
40 j = j + 1
41 }
42 if ok == 1 { return 1 }
43 i = i + 1
44 }
45 return 0
46}
47
48func main(argc: i64, argv: *i64) -> i64 {
49 // ARGV-DRIVEN, WITH THE ORIGINAL VALUES AS DEFAULTS (rule 19: add, never break).
50 // This organ hardcoded ALL THREE of its inputs -- the fixture path, the expected h1 marker and the
51 // raster output -- so it could prove the render pipeline on exactly ONE document, the homepage,
52 // forever. A render test that can only render one page cannot tell you whether the pipeline works
53 // on the pages you actually PUBLISH, which is the only question worth asking of it.
54 // Called with NO arguments it behaves byte-identically to before, so every existing caller and
55 // gate row is untouched and the default remains the homepage fixture.
56 var html_path: *u8 = "/tmp/nishi_own.html\x00" as *u8
57 var marker: *u8 = "Nishi Family\x00" as *u8
58 var out_path: *u8 = "/tmp/nishi_own_render.txt\x00" as *u8
59 if argc > 1 { html_path = argv[1] as *u8 }
60 if argc > 2 { marker = argv[2] as *u8 }
61 if argc > 3 { out_path = argv[3] as *u8 }
62
63 // ---- 1. Load the fetched page ----
64 let lenp: *i64 = sys_mmap(16) as *i64
65 let html: *u8 = sys_read_file(html_path, lenp)
66 let html_len: i64 = lenp[0]
67 // MEASURED 2026-08-15: this organ exited 10 with NO fixture and 0 with one, printing NOTHING in
68 // EITHER direction -- both read exactly like a crash to any caller.
69 // * AN ABSTENTION THAT PRINTS NOTHING IS INDISTINGUISHABLE FROM A CRASH, AND A PASS THAT PRINTS
70 // NOTHING CANNOT SAY WHAT IT PROVED.
71 // Every exit now ANNOUNCES. The exit CODES are deliberately unchanged so nothing keying on them
72 // breaks (rule 19: add, never rename).
73 if html as i64 == 0 {
74 gv_puts("BROWSER-RENDER-OWN SKIP(10): fixture ABSENT -- precondition missing, NOT a render failure. path=" as *u8)
75 gv_puts(html_path)
76 gv_puts("\n" as *u8)
77 return 10
78 }
79 if html_len < 64 {
80 gv_puts("BROWSER-RENDER-OWN SKIP(11): fixture present but only " as *u8)
81 gv_num(html_len)
82 gv_puts(" bytes -- precondition missing, NOT a render failure\n" as *u8)
83 return 11
84 }
85
86 // ---- 2. Extract text ----
87 // NO GUESSED CAP -- DERIVED FROM THE INPUT. Extracted text can never exceed the HTML it came from
88 // (markup is REMOVED, never added), so the buffer is sized from html_len and there is nothing to
89 // tune and no truncation possible by construction.
90 // MEASURED 2026-08-26, and it is why this was found at all: rendering /compare/browser (153102 B)
91 // through the OLD fixed 65536 cap returned EXACTLY 65536 bytes of text -- a cap reached in SILENCE,
92 // which is a measurement nobody knows is partial. /compare/librarian (74844 B) came back at 32135
93 // and was never affected, so the defect was INVISIBLE until a bigger page was actually rendered.
94 // ★A FIXED BUFFER THAT HAPPENS TO FIT THE FIRST PAGE YOU TRY IS A LATENT TRUNCATION, NOT A LIMIT.
95 let text_cap: i64 = html_len + 1
96 let text: *u8 = sys_mmap(text_cap)
97 let text_len: i64 = nx_html_to_text(html, html_len, text, text_cap)
98 if text_len < 16 {
99 gv_puts("BROWSER-RENDER-OWN FAIL(20): html_to_text yielded only " as *u8)
100 gv_num(text_len)
101 gv_puts(" bytes of readable text\n" as *u8)
102 return 20
103 }
104 if ro_contains(text, text_len, marker) != 1 {
105 gv_puts("BROWSER-RENDER-OWN FAIL(21): extracted text is missing the expected marker '" as *u8)
106 gv_puts(marker)
107 gv_puts("' -- text_len=" as *u8)
108 gv_num(text_len)
109 gv_puts("\n" as *u8)
110 return 21
111 }
112
113 // ---- 3. Paint first line of text into a framebuffer ----
114 // 80 cols x 16 rows of 6x8 cells = 480x128 px.
115 let fb_raw: *u8 = sys_mmap(NX_FRAMEBUFFER_BYTES)
116 let fb: *Framebuffer = fb_raw as *Framebuffer
117 let w: i64 = 480
118 let h: i64 = 128
119 let pixels: *u8 = sys_mmap(w * h * 4)
120 nx_framebuffer_init(fb, pixels, w, h)
121 nx_framebuffer_clear(fb)
122
123 // Take up to 76 chars of the first non-empty text line.
124 let line: *u8 = sys_mmap(128)
125 var li: i64 = 0
126 var ti: i64 = 0
127 while ti < text_len {
128 let c: i64 = text[ti] & 0xff
129 if c == 10 { if li > 0 { ti = text_len } }
130 if ti < text_len {
131 if c >= 32 { if li < 76 { line[li] = c as u8; li = li + 1 } }
132 ti = ti + 1
133 }
134 }
135 if li < 4 {
136 gv_puts("BROWSER-RENDER-OWN FAIL(30): first non-empty line too short to paint, chars=" as *u8)
137 gv_num(li)
138 gv_puts("\n" as *u8)
139 return 30
140 }
141 line[li] = 0 as u8
142 let white: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES)) as *CssColor
143 white.r = 255; white.g = 255; white.b = 255; white.a = 255
144 nx_paint_text(fb, 4, 4, line, li, white)
145
146 // ---- 4. Non-blank assertion + visible artifact ----
147 var lit: i64 = 0
148 var pi: i64 = 0
149 let total_px: i64 = w * h
150 while pi < total_px {
151 if (pixels[pi * 4] & 0xff) > 128 { lit = lit + 1 }
152 pi = pi + 1
153 }
154 if lit < 16 { // a real glyph row lights >= dozens
155 gv_puts("BROWSER-RENDER-OWN FAIL(40): framebuffer is BLANK -- lit subpixels=" as *u8)
156 gv_num(lit)
157 gv_puts(" of " as *u8)
158 gv_num(total_px)
159 gv_puts("\n" as *u8)
160 return 40
161 }
162
163 let dump_cap: i64 = (w + 1) * h
164 let dump: *u8 = sys_mmap(dump_cap)
165 let dn: i64 = nx_paint_fb_ascii_dump(fb, dump, dump_cap)
166 if dn <= 0 {
167 gv_puts("BROWSER-RENDER-OWN FAIL(41): ascii dump produced no bytes\n" as *u8)
168 return 41
169 }
170 let ofd: i64 = sys_openat_wr(out_path, GV_MODE_644)
171 if ofd > 0 { sys_write(ofd, dump, dn); sys_close(ofd) }
172 // PRINT THE VALUES, NOT JUST PASS/FAIL -- a gate that reports a boolean cannot say why it passed.
173 gv_puts("BROWSER-RENDER-OWN PASS(0): html=" as *u8)
174 gv_num(html_len)
175 gv_puts("B text=" as *u8)
176 gv_num(text_len)
177 gv_puts("B painted_chars=" as *u8)
178 gv_num(li)
179 gv_puts(" lit_subpixels=" as *u8)
180 gv_num(lit)
181 gv_puts("/" as *u8)
182 gv_num(total_px)
183 gv_puts(" raster=" as *u8)
184 gv_num(dn)
185 gv_puts("B src=" as *u8)
186 gv_puts(html_path)
187 gv_puts(" -> " as *u8)
188 gv_puts(out_path)
189 gv_puts("\n" as *u8)
190 return 0
191}