nx_worldpipe_render_gate.nx source
↩ module page · 234 lines · 11739 B
1// nx_worldpipe_render_gate.nx -- GATE for the rung "erosion reaches the PUBLISHED picture".
2//
3// THE SUBJECT IS NOT "DOES EROSION WORK". nx_worldpipe_erode_gate already proves that, 21/21, over the
4// full 102,400-cell population. The subject HERE is the single behavioural claim nx_worldpipe_render
5// makes and that a green erosion gate cannot make for it: that the bake changes the heights AT THE
6// EXACT POINTS THE RENDERER TURNS INTO PIXELS, and that a consumer which does not bake is untouched.
7// A capability can be proven and still never reach a surface; this gate measures the reaching.
8//
9// EVERY ASSERTION IS BOUND TO A DENOMINATOR (gv_subjects), and the denominators are the two real
10// populations: the whole hydrology grid, and the whole hero sample lattice the render loop walks.
11// No sampling.
12//
13// ANTI-VACUITY. "The picture changed" is passed by a uniform offset, by added noise, and by any bug
14// that perturbs every height equally -- so a tooth that only counts changed points is not a tooth.
15// This gate additionally requires the changes to be NON-UNIFORM (at least two distinct delta values
16// among the changed points), which a constant offset cannot satisfy.
17//
18// NEGATIVE CONTROLS, NAMED SO A CENSUS CAN FIND THEM:
19// neg-control-wp_erode-INERT-... proves the opt-in is real: before any bake every one of the
20// 102,400 cells reads exactly zero, so an importer that never
21// bakes is byte-identical. This is the "nobody else moves" claim.
22// neg-control-zero-tick-budget-... proves the instrument does not manufacture erosion: asked for a
23// zero budget it must return every sampled height to its
24// pre-bake value and report zero material moved.
25//
26// license_tier: ORIGINAL expect_exit: 0 No hw writes (Rule 26).
27import "nx_syscalls.nx"
28import "nx_gate_verdict.nx"
29import "nx_worldpipe.nx"
30
31// Seed and budget are the RENDERER'S, not the gate's -- a gate that exercises a different world or a
32// different budget than the thing it certifies is measuring a different subject.
33const WRG_SEED: i64 = 1
34const WRG_TICKS: i64 = 8
35// The render's hero lattice, copied from nx_worldpipe_render so these are the very points that become
36// pixels: 97 x 97 samples at 110 world units, centred by subtracting 48.
37const WRG_TN: i64 = 97
38const WRG_SP: i64 = 110
39const WRG_OFF: i64 = 48
40const WRG_ART: *u8 = "knowledge/nx_worldpipe_eroded.png"
41
42func wrg_hero_x(i: i64) -> i64 { return (i - WRG_OFF)*WRG_SP }
43
44// Independent recomputation of the derived talus, written HERE so the lib's answer is checked against
45// a second implementation of the same definition rather than against itself. This catches the failure
46// that matters -- a derivation that silently returns a constant, or reads the wrong surface -- and it
47// is deliberately the ONLY duplicated arithmetic in this file.
48func wrg_talus_oracle() -> i64 {
49 let gn: i64 = HYW
50 let n: i64 = gn * gn
51 let g: *i64 = sys_mmap(n*8) as *i64
52 var y: i64 = 0
53 while y < gn {
54 var x: i64 = 0
55 while x < gn { g[y*gn + x] = wp_flow_h(x*HYCELL - HYSPAN, y*HYCELL - HYSPAN); x = x + 1 }
56 y = y + 1
57 }
58 var sum: i64 = 0
59 var y2: i64 = 0
60 while y2 < gn {
61 var x2: i64 = 0
62 while x2 < gn {
63 let k: i64 = y2*gn + x2
64 let h: i64 = g[k]
65 var m: i64 = 0
66 if x2 > 0 { let da: i64 = wp_iabs(h - g[k-1]); if da > m { m = da } }
67 if x2 < gn - 1 { let db: i64 = wp_iabs(h - g[k+1]); if db > m { m = db } }
68 if y2 > 0 { let dc: i64 = wp_iabs(h - g[k-gn]); if dc > m { m = dc } }
69 if y2 < gn - 1 { let dd: i64 = wp_iabs(h - g[k+gn]); if dd > m { m = dd } }
70 sum = sum + m
71 x2 = x2 + 1
72 }
73 y2 = y2 + 1
74 }
75 return sum / n
76}
77
78// Fill dst with wp_height at every hero lattice point, in render order.
79func wrg_sample_hero(dst: *i64) -> i64 {
80 var gz: i64 = 0
81 while gz < WRG_TN {
82 var gx: i64 = 0
83 while gx < WRG_TN {
84 dst[gz*WRG_TN + gx] = wp_height(wrg_hero_x(gx), wrg_hero_x(gz))
85 gx = gx + 1
86 }
87 gz = gz + 1
88 }
89 return WRG_TN * WRG_TN
90}
91
92func main() -> i64 {
93 let c: *i64 = gv_ctr()
94 gv_head("=== nx_worldpipe_render_gate -- does stage-3.5 erosion reach the PUBLISHED picture? ===" as *u8)
95
96 wp_init(WRG_SEED)
97 let nspr: i64 = wp_hydro_bake()
98 gv_puts(" world: seed=" as *u8); gv_num(WRG_SEED)
99 gv_puts(" hydrology springs=" as *u8); gv_num(nspr); gv_puts("\n" as *u8)
100
101 let gn: i64 = HYW
102 let n: i64 = gn * gn
103 gv_subjects("hydrology-grid-cells-full-population" as *u8, n, c)
104
105 // ---- neg-control: the opt-in is the BAKE. Nothing has baked yet, so every cell must read zero.
106 var inert: i64 = 0
107 var y1: i64 = 0
108 while y1 < gn {
109 var x1: i64 = 0
110 while x1 < gn {
111 if wp_erode(x1*HYCELL - HYSPAN, y1*HYCELL - HYSPAN) != 0 { inert = inert + 1 }
112 x1 = x1 + 1
113 }
114 y1 = y1 + 1
115 }
116 gv_puts(" before any bake: non-zero wp_erode readings=" as *u8); gv_num(inert)
117 gv_puts(" of=" as *u8); gv_num(n); gv_puts("\n" as *u8)
118 gv_check("neg-control-wp_erode-INERT-at-EVERY-cell-before-a-bake-so-a-non-baking-consumer-is-byte-identical" as *u8,
119 inert == 0, c)
120
121 // ---- the hero lattice: the points that become pixels, sampled BEFORE the bake
122 let hn: i64 = WRG_TN * WRG_TN
123 gv_subjects("render-hero-lattice-points-full-population" as *u8, hn, c)
124 let pre: *i64 = sys_mmap(hn*8) as *i64
125 let post1: *i64 = sys_mmap(hn*8) as *i64
126 let zero: *i64 = sys_mmap(hn*8) as *i64
127 let post2: *i64 = sys_mmap(hn*8) as *i64
128 wrg_sample_hero(pre)
129
130 // ---- the derived talus, checked against an independent recomputation
131 let tl: i64 = wp_erode_talus_derived()
132 let tlo: i64 = wrg_talus_oracle()
133 gv_puts(" derived talus=" as *u8); gv_num(tl)
134 gv_puts(" independent oracle=" as *u8); gv_num(tlo); gv_puts("\n" as *u8)
135 gv_check("terrain-has-relief-so-the-derived-talus-is-a-measurement-not-a-default" as *u8, tl > 0, c)
136 gv_check("derived-talus-EQUALS-an-independent-recomputation-so-it-is-the-formula-not-a-constant" as *u8,
137 tl == tlo, c)
138
139 // ---- the bake the renderer makes
140 let tl2: i64 = wp_erode_bake_derived(WRG_TICKS)
141 let moved: i64 = wp_erode_stat(1)
142 let hi0: i64 = wp_erode_stat(2)
143 let hi1: i64 = wp_erode_stat(3)
144 gv_puts(" bake: ticks=" as *u8); gv_num(wp_erode_stat(0))
145 gv_puts(" talus=" as *u8); gv_num(tl2)
146 gv_puts(" material_moved=" as *u8); gv_num(moved)
147 gv_puts(" hypsometric_permil " as *u8); gv_num(hi0)
148 gv_puts(" -> " as *u8); gv_num(hi1); gv_puts("\n" as *u8)
149 gv_check("bake-at-the-renderers-budget-MOVED-material" as *u8, moved > 0, c)
150 gv_check("bake_derived-reports-the-same-talus-it-derived" as *u8, tl2 == tl, c)
151
152 wrg_sample_hero(post1)
153 var changed: i64 = 0
154 var firstd: i64 = 0
155 var distinct2: i64 = 0
156 var i2: i64 = 0
157 while i2 < hn {
158 let d: i64 = post1[i2] - pre[i2]
159 if d != 0 {
160 changed = changed + 1
161 if firstd == 0 { firstd = d } else { if d != firstd { distinct2 = 1 } }
162 }
163 i2 = i2 + 1
164 }
165 var permil: i64 = 0
166 if hn > 0 { permil = changed * 1000 / hn }
167 gv_puts(" render lattice: heights changed by the bake=" as *u8); gv_num(changed)
168 gv_puts(" of=" as *u8); gv_num(hn)
169 gv_puts(" permil=" as *u8); gv_num(permil)
170 gv_puts(" second_distinct_delta=" as *u8); gv_num(distinct2); gv_puts("\n" as *u8)
171 gv_check("THE-RUNG-erosion-changes-the-heights-at-the-points-the-renderer-turns-into-pixels" as *u8,
172 changed > 0, c)
173 gv_check("anti-vacuity-the-deltas-are-NON-UNIFORM-so-a-constant-offset-or-a-global-perturbation-cannot-pass" as *u8,
174 distinct2 == 1, c)
175
176 // The paired cell: the SAME detector must FIRE on the baked world and stay SILENT on the unbaked
177 // one. The silent side is the pre-bake full-grid census taken above -- reused rather than
178 // re-measured, because by this point the world IS baked and a second reading here would be a
179 // reading of the wrong state dressed up as a control.
180 var sees_after: i64 = 0
181 if changed > 0 { sees_after = 1 }
182 var sees_before: i64 = 0
183 if inert != 0 { sees_before = 1 }
184 gv_bite("bite-render-sampler-sees-erosion-ONLY-after-a-bake" as *u8, sees_after, sees_before, c)
185
186 // ---- neg-control: a zero-tick budget must return every sampled height to its pre-bake value
187 let tl3: i64 = wp_erode_bake_derived(0)
188 let moved0: i64 = wp_erode_stat(1)
189 wrg_sample_hero(zero)
190 var restored: i64 = 0
191 var i4: i64 = 0
192 while i4 < hn { if zero[i4] == pre[i4] { restored = restored + 1 } i4 = i4 + 1 }
193 gv_puts(" zero-tick budget: material_moved=" as *u8); gv_num(moved0)
194 gv_puts(" lattice points back at their pre-bake height=" as *u8); gv_num(restored)
195 gv_puts(" of=" as *u8); gv_num(hn); gv_puts(" talus=" as *u8); gv_num(tl3); gv_puts("\n" as *u8)
196 gv_check("neg-control-zero-tick-budget-moves-NO-material" as *u8, moved0 == 0, c)
197 gv_check("neg-control-zero-tick-budget-restores-EVERY-lattice-point-so-the-organ-cannot-manufacture-erosion" as *u8,
198 restored == hn, c)
199
200 // ---- determinism: the published picture must be reproducible by anybody else
201 wp_erode_bake_derived(WRG_TICKS)
202 wrg_sample_hero(post2)
203 var same: i64 = 0
204 var i5: i64 = 0
205 while i5 < hn { if post2[i5] == post1[i5] { same = same + 1 } i5 = i5 + 1 }
206 gv_puts(" determinism: lattice points identical across two bakes=" as *u8); gv_num(same)
207 gv_puts(" of=" as *u8); gv_num(hn); gv_puts("\n" as *u8)
208 gv_check("two-bakes-at-one-seed-and-budget-agree-at-EVERY-lattice-point" as *u8, same == hn, c)
209
210 // ---- the artifact, as a PRECONDITION not a verdict: if the renderer has never been run there is
211 // nothing to look at, and "I could not look" is not "it is broken".
212 let afd: i64 = sys_openat_rd(WRG_ART)
213 var have: i64 = 0
214 var abytes: i64 = 0
215 var amagic: i64 = 0
216 if afd >= 0 {
217 let hdr: *u8 = sys_mmap(16)
218 let got: i64 = sys_read(afd, hdr, 8)
219 abytes = sys_lseek(afd, 0, 2)
220 sys_close(afd)
221 have = 1
222 if got == 8 { if hdr[0] == (137 as u8) { if hdr[1] == (80 as u8) { if hdr[2] == (78 as u8) { if hdr[3] == (71 as u8) { amagic = 1 } } } } }
223 }
224 gv_puts(" artifact " as *u8); gv_puts(WRG_ART)
225 gv_puts(": present=" as *u8); gv_num(have)
226 gv_puts(" bytes=" as *u8); gv_num(abytes)
227 gv_puts(" png_signature=" as *u8); gv_num(amagic); gv_puts("\n" as *u8)
228 if gv_need("knowledge/nx_worldpipe_eroded.png (run nx_worldpipe_render first)" as *u8, have, c) == 1 {
229 gv_check("the-rendered-artifact-on-disk-carries-a-real-PNG-signature" as *u8, amagic == 1, c)
230 }
231
232 return gv_verdict("nx_worldpipe_render_gate" as *u8, c,
233 "The rung is REACH, not correctness: erosion was proven by nx_worldpipe_erode_gate and was still inert in production because no consumer baked. Every tooth here is bound to a full population -- 102,400 hydrology cells and 9,409 hero lattice points, the very points the renderer turns into pixels -- and the two negative controls are the load-bearing ones: an unbaked world reads exactly zero at every cell (so no other importer moves), and a zero-tick budget restores every sampled height (so the organ cannot manufacture the erosion it reports). Scope, declared: this gate measures HEIGHTS, not pixels; that the PNG on disk decodes and that the live page serves it are proven outside, by nx_page_verify." as *u8)
234}