code wiki / _hdl_build / nx_craft_tile_gate.nx
nx_craft_tile_gate.nx source
↩ module page · 276 lines · 14823 B
1// nx_craft_tile_gate.nx -- GE30 REFEREE: the frame cut into row bands is BIT-IDENTICAL to the frame
2// drawn by one thread, and a band writes NOTHING outside the rows it owns.
3//
4// WHY THIS SUBJECT NEEDS ITS OWN GATE. nx_wasm_craft_gate proves the WORLD (raycast ground truth,
5// causal edits, determinism, the input edge contract) and nx_wasm_craft_vm_gate proves the SHIPPED
6// WASM fits and paints inside the memory it declares. Neither can see the defect GE30 introduces:
7// a frame assembled by N workers over ONE shared linear memory is correct only if the band pass
8// writes disjoint pixels and reads no scratch its neighbour writes. The old renderer failed the
9// second half by construction -- five wray outputs lived in ONE shared slot (O_ST 46-50), which is
10// invisible with one thread and a race with two -- so the decomposition is the subject here.
11//
12// THE LOAD-BEARING TOOTH IS A FULL PIXEL COMPARE, NOT A DIGEST. Two fresh arenas, same seed, same
13// camera: arena A drawn by render_impl (one thread, the shipped path), arena B drawn as N bands plus
14// one overlay. Every word of the WRITTEN EXTENT must agree -- rw x rh, the compact buffer the
15// one-pixel-per-ray law made the single owner of, never W*H, because a comparison over unwritten
16// memory is a claim about uninitialised bytes. A tiling defect lives at BAND SEAMS, so the band
17// counts include ones that do NOT divide the row count evenly, and a stride-sampling checksum is
18// deliberately not used anywhere in this file.
19//
20// ANTI-VACUITY, STATED BECAUSE "IDENTICAL" IS THE EASIEST GREEN TO FAKE: two blank frames are also
21// identical. So the gate first proves the frame is VARIED (many distinct colours) and that the
22// overlay pass genuinely CHANGES pixels; only then does agreement mean anything.
23// nx_craft_tile_gate
24// license_tier: ORIGINAL No hw writes (Rule 26).
25import "nx_syscalls.nx"
26import "nx_gate_verdict.nx"
27import "nx_wasm_craft.nx"
28
29const CT_SEED: i64 = 20260728 // craft's shipped identity seed (wc_spec v0)
30const CT_SLACK: i64 = 4096 // arena slack, matching the sibling gates' allocation shape
31const CT_SENTINEL: i64 = 123456789 // a colour word the renderer never writes
32const CT_MIN_DISTINCT: i64 = 40 // the varied-frame floor the world gate already uses
33const CT_BUCKETS: i64 = 4096
34const CT_WARM: i64 = 12 // ticks before measuring: the camera settles onto the ground
35const CT_BANDS_A: i64 = 2
36const CT_BANDS_B: i64 = 3
37const CT_BANDS_C: i64 = 5
38const CT_BANDS_D: i64 = 7
39const CT_BANDS_E: i64 = 16
40
41func ct_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
42func ct_n(v: i64) -> i64 { return gv_num(v) }
43
44func ct_arena() -> i64 {
45 let b: i64 = sys_mmap(CRAFT_TOTAL + CT_SLACK) as i64
46 init_impl(b, CT_SEED)
47 var t: i64 = 0
48 while t < CT_WARM { tick_impl(b, 0); t = t + 1 }
49 return b
50}
51// paint every framebuffer word with a value the renderer cannot produce
52// fill the WHOLE framebuffer, not just the written extent: a sentinel past rw*rh is how a write
53// beyond the compact extent gets caught rather than assumed absent.
54func ct_fill(base: i64, v: i64) -> i64 {
55 let f: *i64 = wfb(base)
56 var i: i64 = 0
57 while i < W*H { f[i] = v; i = i + 1 }
58 return 0
59}
60func ct_extent(base: i64) -> i64 { return wc_rw(base) * wc_rh(base) }
61// FULL pixel compare -- returns the count of disagreeing words (0 = bit-identical)
62func ct_diff(a: i64, b: i64) -> i64 {
63 let fa: *i64 = wfb(a)
64 let fb: *i64 = wfb(b)
65 let n: i64 = ct_extent(a)
66 var d: i64 = 0
67 var i: i64 = 0
68 while i < n { if fa[i] != fb[i] { d = d + 1 } i = i + 1 }
69 return d
70}
71// how many framebuffer words still hold the sentinel
72func ct_untouched(base: i64, v: i64) -> i64 {
73 let f: *i64 = wfb(base)
74 let e: i64 = ct_extent(base)
75 var n: i64 = 0
76 var i: i64 = 0
77 while i < e { if f[i] == v { n = n + 1 } i = i + 1 }
78 return n
79}
80// sentinel words PAST the written extent -- all of them must survive any band
81func ct_untouched_past(base: i64, v: i64) -> i64 {
82 let f: *i64 = wfb(base)
83 var n: i64 = 0
84 var i: i64 = ct_extent(base)
85 while i < W*H { if f[i] == v { n = n + 1 } i = i + 1 }
86 return n
87}
88// sentinel words INSIDE a pixel-row range [y0, y1) of the framebuffer
89// COMPACT geometry: ray-row py owns words [py*rw, (py+1)*rw)
90func ct_untouched_rows(base: i64, v: i64, y0: i64, y1: i64) -> i64 {
91 let f: *i64 = wfb(base)
92 let rw: i64 = wc_rw(base)
93 var n: i64 = 0
94 var y: i64 = y0
95 while y < y1 {
96 var x: i64 = 0
97 while x < rw { if f[y*rw + x] == v { n = n + 1 } x = x + 1 }
98 y = y + 1
99 }
100 return n
101}
102func ct_distinct(base: i64) -> i64 {
103 let f: *i64 = wfb(base)
104 let seen: *i64 = sys_mmap(CT_BUCKETS*8) as *i64
105 let e: i64 = ct_extent(base)
106 var q: i64 = 0
107 while q < CT_BUCKETS { seen[q] = 0; q = q + 1 }
108 var d: i64 = 0
109 var i: i64 = 0
110 while i < e {
111 let k: i64 = ((f[i] & 255)/16)*256 + (((f[i] >> 8) & 255)/16)*16 + ((f[i] >> 16) & 255)/16
112 if seen[k % CT_BUCKETS] == 0 { seen[k % CT_BUCKETS] = 1; d = d + 1 }
113 i = i + 1
114 }
115 return d
116}
117// draw one frame as N bands plus the single overlay pass, exactly as N workers would
118func ct_banded(base: i64, nb: i64) -> i64 {
119 let rows: i64 = wc_rh(base)
120 var k: i64 = 0
121 while k < nb {
122 let y0: i64 = rows*k/nb
123 let y1: i64 = rows*(k + 1)/nb
124 render_band_impl(base, y0, y1, k)
125 k = k + 1
126 }
127 render_overlay_impl(base)
128 return 0
129}
130// bit-identity of the one-thread frame and the nb-band frame, on two fresh arenas
131func ct_identical(nb: i64, ctr: *i64, name: *u8) -> i64 {
132 let a: i64 = ct_arena()
133 let b: i64 = ct_arena()
134 render_impl(a)
135 ct_banded(b, nb)
136 let d: i64 = ct_diff(a, b)
137 ct_w(" bands=" as *u8); ct_n(nb); ct_w(" differing_words=" as *u8); ct_n(d); ct_w("\n" as *u8)
138 gv_check(name, d == 0, ctr)
139 return d
140}
141
142func main(argc: i64, argv: *i64) -> i64 {
143 let ctr: *i64 = gv_ctr()
144 gv_head("nx_craft_tile_gate -- GE30: the banded frame is bit-identical to the single-thread frame, and a band owns its rows alone" as *u8)
145
146 // ---- the frame under test is VARIED, or every identity tooth below is vacuous --------------
147 let a0: i64 = ct_arena()
148 render_impl(a0)
149 let rows: i64 = wc_rh(a0)
150 let q0: i64 = wc_q(a0)
151 let cols: i64 = wc_rw(a0)
152 let dist: i64 = ct_distinct(a0)
153 ct_w(" q=" as *u8); ct_n(q0); ct_w(" ray_rows=" as *u8); ct_n(rows)
154 ct_w(" distinct_colours=" as *u8); ct_n(dist); ct_w(" tile_max=" as *u8); ct_n(TILE_MAX); ct_w("\n" as *u8)
155 gv_check("anti-vacuity-the-single-thread-frame-is-varied-not-blank" as *u8, dist > CT_MIN_DISTINCT, ctr)
156 gv_check("row-door-reports-a-positive-cut-matching-the-adaptive-quality" as *u8, (rows > 0) * (rows == H/q0), ctr)
157 gv_check("the-gate-measures-the-COMPACT-written-extent-not-the-whole-framebuffer" as *u8, (cols == W/q0) * (cols*rows < W*H), ctr)
158
159 // ---- the load-bearing identity, at band counts that do and do not divide evenly -------------
160 ct_identical(1, ctr, "one-band-equals-the-single-thread-frame-word-for-word" as *u8)
161 ct_identical(CT_BANDS_A, ctr, "two-bands-equal-the-single-thread-frame-word-for-word" as *u8)
162 ct_identical(CT_BANDS_B, ctr, "three-bands-uneven-cut-equal-the-single-thread-frame-word-for-word" as *u8)
163 ct_identical(CT_BANDS_C, ctr, "five-bands-uneven-cut-equal-the-single-thread-frame-word-for-word" as *u8)
164 ct_identical(CT_BANDS_D, ctr, "seven-bands-uneven-cut-equal-the-single-thread-frame-word-for-word" as *u8)
165 ct_identical(CT_BANDS_E, ctr, "sixteen-bands-equal-the-single-thread-frame-word-for-word" as *u8)
166
167 // ---- DISJOINTNESS: one band writes its own pixel rows and not one word beyond ---------------
168 // A band owns ray-rows [y0,y1), which are PIXEL rows [y0*q, y1*q) because each ray paints a qxq
169 // block. Fill with a sentinel, draw the middle band only, and require: every pixel inside the
170 // block was written, and every pixel outside it still holds the sentinel.
171 let b1: i64 = ct_arena()
172 ct_fill(b1, CT_SENTINEL)
173 let y0: i64 = rows/3
174 let y1: i64 = rows*2/3
175 render_band_impl(b1, y0, y1, 0)
176 let inside_left: i64 = ct_untouched_rows(b1, CT_SENTINEL, y0, y1)
177 let above_left: i64 = ct_untouched_rows(b1, CT_SENTINEL, 0, y0)
178 let below_left: i64 = ct_untouched_rows(b1, CT_SENTINEL, y1, rows)
179 let above_total: i64 = y0*cols
180 let below_total: i64 = (rows - y1)*cols
181 ct_w(" band[" as *u8); ct_n(y0); ct_w("," as *u8); ct_n(y1)
182 ct_w(") inside_unwritten=" as *u8); ct_n(inside_left)
183 ct_w(" above_kept=" as *u8); ct_n(above_left); ct_w("/" as *u8); ct_n(above_total)
184 ct_w(" below_kept=" as *u8); ct_n(below_left); ct_w("/" as *u8); ct_n(below_total); ct_w("\n" as *u8)
185 gv_check("the-band-writes-every-pixel-row-it-owns" as *u8, inside_left == 0, ctr)
186 gv_check("the-band-writes-nothing-above-its-first-row" as *u8, (above_left == above_total) * (above_total > 0), ctr)
187 gv_check("the-band-writes-nothing-below-its-last-row" as *u8, (below_left == below_total) * (below_total > 0), ctr)
188 gv_check("the-band-writes-nothing-past-the-compact-extent-into-unwritten-framebuffer" as *u8, ct_untouched_past(b1, CT_SENTINEL) == W*H - ct_extent(b1), ctr)
189
190 // ---- the bands PARTITION the frame: every pixel written exactly once across the whole cut ---
191 let b2: i64 = ct_arena()
192 ct_fill(b2, CT_SENTINEL)
193 var k: i64 = 0
194 while k < CT_BANDS_C {
195 render_band_impl(b2, rows*k/CT_BANDS_C, rows*(k + 1)/CT_BANDS_C, k)
196 k = k + 1
197 }
198 let left2: i64 = ct_untouched(b2, CT_SENTINEL)
199 ct_w(" five bands leave " as *u8); ct_n(left2); ct_w(" of " as *u8); ct_n(ct_extent(b2)); ct_w(" written-extent words unwritten\n" as *u8)
200 gv_check("the-full-cut-covers-the-frame-leaving-no-pixel-unwritten" as *u8, left2 == 0, ctr)
201
202 // ---- CLAMPS: a band past the cut, and an empty band, write nothing rather than past the end --
203 let b3: i64 = ct_arena()
204 ct_fill(b3, CT_SENTINEL)
205 render_band_impl(b3, rows + 4, rows + 40, 0)
206 gv_check("neg-control-a-band-entirely-past-the-row-count-writes-nothing" as *u8, ct_untouched(b3, CT_SENTINEL) == ct_extent(b3), ctr)
207 render_band_impl(b3, 0, 0, 0)
208 gv_check("neg-control-an-empty-band-writes-nothing" as *u8, ct_untouched(b3, CT_SENTINEL) == ct_extent(b3), ctr)
209
210 // ---- the OVERLAY genuinely draws, so "identical" is a claim about something ------------------
211 let b4: i64 = ct_arena()
212 let b5: i64 = ct_arena()
213 ct_banded(b4, CT_BANDS_A) // bands + overlay
214 render_band_impl(b5, 0, wc_rh(b5), 0) // bands only, overlay withheld
215 let od: i64 = ct_diff(b4, b5)
216 ct_w(" overlay changes " as *u8); ct_n(od); ct_w(" words\n" as *u8)
217 gv_check("neg-control-the-overlay-pass-changes-pixels-so-identity-is-not-vacuous" as *u8, od > 0, ctr)
218
219 // ---- per-worker scratch is PRIVATE: distinct ids address distinct slots, inside the arena ----
220 let s0: i64 = O_TILE + 0*TILE_W*8
221 let s1: i64 = O_TILE + 1*TILE_W*8
222 let slast: i64 = O_TILE + (TILE_MAX - 1)*TILE_W*8 + TILE_W*8
223 ct_w(" scratch slot0=" as *u8); ct_n(s0); ct_w(" slot1=" as *u8); ct_n(s1)
224 ct_w(" end=" as *u8); ct_n(slast); ct_w(" arena=" as *u8); ct_n(CRAFT_TOTAL); ct_w("\n" as *u8)
225 gv_check("two-worker-ids-address-two-different-scratch-slots" as *u8, s1 - s0 == TILE_W*8, ctr)
226 gv_check("the-ray-outs-of-one-slot-cannot-reach-the-next-slot" as *u8, TILE_HOUT + 5 <= TILE_W, ctr)
227 gv_check("every-worker-slot-lies-inside-the-declared-arena" as *u8, slast <= CRAFT_TOTAL, ctr)
228 gv_check("the-scratch-region-starts-past-every-other-region-so-no-existing-offset-moved" as *u8, O_TILE >= O_PERF, ctr)
229 // an out-of-range worker id is CLAMPED into the arena rather than trusted
230 let b6: i64 = ct_arena()
231 ct_fill(b6, CT_SENTINEL)
232 render_band_impl(b6, 0, wc_rh(b6), TILE_MAX + 9)
233 gv_check("an-out-of-range-worker-id-is-clamped-and-still-draws-its-band" as *u8, ct_untouched(b6, CT_SENTINEL) == 0, ctr)
234
235 // ---- THE RACE PROOF A SEQUENTIAL GATE CAN ACTUALLY GIVE ------------------------------------
236 // Bands here run one after another, so a shared scratch produces IDENTICAL bytes and every
237 // identity tooth above stays green while the browser races. Stating that limit and testing
238 // around it: a band must write ITS OWN slot and no other. ⚠The first cut of this tooth ran the
239 // band as worker 0 and asserted worker 1 was clean -- and a planted mutant that funnels EVERY
240 // worker into slot 0 survived it, because a worker-0 band writing slot 0 is what correct code
241 // does too. The tooth only bites when the band runs as a NON-ZERO worker: slot 1 must change,
242 // slot 0 must not. Both halves are required; either alone passes for the wrong reason.
243 let b7: i64 = ct_arena()
244 let sc0: *i64 = (b7 + O_TILE) as *i64
245 let sc1: *i64 = (b7 + O_TILE + 1*TILE_W*8) as *i64
246 var j: i64 = 0
247 while j < TILE_W { sc0[j] = CT_SENTINEL; sc1[j] = CT_SENTINEL; j = j + 1 }
248 render_band_impl(b7, 0, wc_rh(b7), 1)
249 var kept0: i64 = 0
250 var moved1: i64 = 0
251 j = 0
252 while j < TILE_W {
253 if sc0[j] == CT_SENTINEL { kept0 = kept0 + 1 }
254 if sc1[j] != CT_SENTINEL { moved1 = moved1 + 1 }
255 j = j + 1
256 }
257 ct_w(" band as worker 1: slot0 words kept=" as *u8); ct_n(kept0); ct_w("/" as *u8); ct_n(TILE_W)
258 ct_w(" slot1 words written=" as *u8); ct_n(moved1); ct_w("\n" as *u8)
259 gv_check("a-band-drawn-as-worker-1-writes-its-own-scratch-slot" as *u8, moved1 > 0, ctr)
260 gv_check("a-band-drawn-as-worker-1-leaves-every-word-of-worker-0-scratch-untouched" as *u8, kept0 == TILE_W, ctr)
261
262 // ---- the digest door discriminates (a ruler that returns one number for everything is none) --
263 let d4: i64 = wc_fbdigest(b4)
264 let d4b: i64 = wc_fbdigest(b4)
265 let d5: i64 = wc_fbdigest(b5)
266 ct_w(" digest(with overlay)=" as *u8); ct_n(d4); ct_w(" (without)=" as *u8); ct_n(d5); ct_w("\n" as *u8)
267 gv_check("the-frame-digest-is-stable-on-an-unchanged-frame" as *u8, d4 == d4b, ctr)
268 gv_check("neg-control-the-frame-digest-separates-two-different-frames" as *u8, d4 != d5, ctr)
269 let a1: i64 = ct_arena()
270 let a2: i64 = ct_arena()
271 render_impl(a1)
272 ct_banded(a2, CT_BANDS_D)
273 gv_check("the-digest-agrees-with-the-full-compare-on-the-banded-frame" as *u8, wc_fbdigest(a1) == wc_fbdigest(a2), ctr)
274
275 return gv_verdict("craft_tile_gate" as *u8, ctr, "the decomposition below the browser: bands are disjoint, cover the frame and reproduce the single-thread bytes exactly; the Worker wiring and the shared memory it runs over are GE30's page half" as *u8)
276}