nx_jslogic_census.nx source
↩ module page · 413 lines · 18868 B
1// nx_jslogic_census.nx -- THE RULER for the JS/HTML-INTEROP-ONLY law (operator standing order
2// 2026-08-12: "we shouldnt be building into the js strings -- nishi os from the first bit up, js
3// and html only as an interop layer for 3rd-party systems"). It measures the AUTHORED JavaScript
4// living inside the page emitter's string literals so the migration into the wasm engine has a
5// number that can only go DOWN (the nx_sov_guard2 / nx_magicratchet ratchet shape).
6//
7// MECHANISM (comments are SKIPPED -- a scanner that reads comments measures the documentation):
8// tokenize the NishiLang source into CODE / //-COMMENT / STRING states (backslash escapes inside
9// strings; REAL newlines inside literals are legal and stay in-string). Literal bytes count only
10// between the literal containing <script> and the literal containing </script> (inclusive), so
11// HTML/CSS chrome outside the script region is never charged. The base64 wasm payload and
12// gpe_num-emitted values are BUFFER emissions, not literals -- data crossing the boundary is
13// lawful and is not counted. DECLARED IMPRECISION: the two boundary literals carry a few bytes
14// of enclosing HTML, so totals are a small UPPER bound on authored JS.
15//
16// CLASSES from knowledge/jslogic_class.conf rows `<fnv64-decimal> <CLASS>` where CLASS is
17// INTEROP (shim: decode/instantiate/blit/input/context plumbing) | LOGIC (game/engine behavior
18// that belongs in the wasm) | SHADER (GLSL display path -- judged separately). A literal whose
19// hash is not in the conf lands in UNKNOWN -- ITS OWN BUCKET, never silently merged; editing a
20// classified literal changes its hash and forces re-classification by construction.
21//
22// usage: nx_jslogic_census check [srcpath] -> census + ratchet vs knowledge/status/jslogic.baseline
23// nx_jslogic_census snapshot [srcpath] -> census + deliberately re-record the baseline
24// nx_jslogic_census rows [srcpath] -> per-literal rows (hash, bytes, class, head) for conf work
25// exit: 0 GREEN (logic+unknown <= baseline) | 1 RED rose vs baseline | 2 usage | 3 unreadable-src
26// Journals every run: knowledge/status/jslogic.jrnl (epoch TAB totals). license_tier: ORIGINAL
27// No hw writes (Rule 26).
28import "nx_syscalls.nx"
29const JC_MAGIC_1024: i64 = 1024
30
31const JC_SRC_DEF: *u8 = "buildroot/runtime/nx_game_page_emit.nx"
32const JC_CONF: *u8 = "knowledge/jslogic_class.conf"
33const JC_BASE: *u8 = "knowledge/status/jslogic.baseline"
34const JC_JRNL: *u8 = "knowledge/status/jslogic.jrnl"
35const JC_MAXLIT: i64 = 4096
36
37func jc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
38func jc_puts(s: *u8) -> i64 { sys_write(1, s, jc_slen(s)); return 0 }
39func jc_pn(v: i64) -> i64 {
40 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
41 var m: i64 = v
42 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
43 let t: *u8 = sys_mmap(32)
44 var k: i64 = 0
45 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
46 let o: *u8 = sys_mmap(32)
47 var i: i64 = 0
48 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
49 sys_write(1, o, k)
50 return 0
51}
52func jc_find(hay: *u8, off: i64, n: i64, needle: *u8) -> i64 {
53 let nl: i64 = jc_slen(needle)
54 if nl == 0 { return 1 }
55 var i: i64 = off
56 while i + nl <= n {
57 var j: i64 = 0
58 var hit: i64 = 1
59 while j < nl { if hay[i + j] != needle[j] { hit = 0; j = nl } else { j = j + 1 } }
60 if hit == 1 { return 1 }
61 i = i + 1
62 }
63 return 0
64}
65// FNV-1a 64 over [off, off+len)
66func jc_fnv(b: *u8, off: i64, len: i64) -> i64 {
67 var h: i64 = 0xcbf29ce484222325
68 var i: i64 = 0
69 while i < len {
70 h = h ^ (b[off + i] as i64)
71 h = h * 0x100000001b3
72 i = i + 1
73 }
74 if h < 0 { h = 0 - h }
75 return h
76}
77// read a decimal integer at s[pos..], skipping leading spaces; advances pos
78func jc_rdint(s: *u8, pos: *i64, n: i64) -> i64 {
79 var i: i64 = pos[0]
80 var go: i64 = 1
81 while go == 1 { if i >= n { go = 0 } else { if s[i] == (32 as u8) { i = i + 1 } else { go = 0 } } }
82 var v: i64 = 0
83 var any: i64 = 0
84 var g2: i64 = 1
85 while g2 == 1 {
86 if i >= n { g2 = 0 } else {
87 let c: i64 = s[i] as i64
88 if c >= 48 { if c <= 57 { v = v*10 + (c-48); any = 1; i = i + 1 } else { g2 = 0 } } else { g2 = 0 }
89 }
90 }
91 pos[0] = i
92 if any == 0 { return 0 - 1 }
93 return v
94}
95
96func main(argc: i64, argv: *i64) -> i64 {
97 var vk: i64 = 0 - 1
98 if argc < 2 { vk = 0 } // no-arg contract = check (beat/clock rosters fork with no args)
99 if argc >= 2 {
100 let verb: *u8 = argv[1] as *u8
101 if jc_find(verb, 0, jc_slen(verb), "check" as *u8) == 1 { if jc_slen(verb) == 5 { vk = 0 } }
102 if jc_find(verb, 0, jc_slen(verb), "snapshot" as *u8) == 1 { vk = 1 }
103 if jc_find(verb, 0, jc_slen(verb), "rows" as *u8) == 1 { if jc_slen(verb) == 4 { vk = 2 } }
104 }
105 if vk < 0 { jc_puts("usage: nx_jslogic_census check|snapshot|rows [srcpath]\n" as *u8); return 2 }
106 var src: *u8 = JC_SRC_DEF
107 if argc > 2 { src = argv[2] as *u8 }
108
109 let ln: *i64 = sys_mmap(16) as *i64
110 let b: *u8 = sys_read_file(src, ln)
111 if (b as i64) == 0 { jc_puts("JSLOGIC-CENSUS FAIL: unreadable src\n" as *u8); return 3 }
112 let n: i64 = ln[0]
113
114 // conf: hash -> class (0 INTEROP, 1 LOGIC, 2 SHADER)
115 let CH: *i64 = sys_mmap(JC_MAGIC_1024*8) as *i64
116 let CC: *i64 = sys_mmap(JC_MAGIC_1024*8) as *i64
117 var nc: i64 = 0
118 let cl: *i64 = sys_mmap(16) as *i64
119 let cb: *u8 = sys_read_file(JC_CONF, cl)
120 if (cb as i64) != 0 {
121 var ci: i64 = 0
122 while ci < cl[0] {
123 // line
124 var ce: i64 = ci
125 var cs: i64 = 1
126 while cs == 1 { if ce >= cl[0] { cs = 0 } else { if cb[ce] == (10 as u8) { cs = 0 } else { ce = ce + 1 } } }
127 if ce > ci { if cb[ci] != (35 as u8) {
128 let pp: *i64 = sys_mmap(16) as *i64
129 pp[0] = ci
130 let hv: i64 = jc_rdint(cb, pp, ce)
131 if hv >= 0 {
132 var cls: i64 = 0 - 1
133 if jc_find(cb, pp[0], ce, "INTEROP" as *u8) == 1 { cls = 0 }
134 if jc_find(cb, pp[0], ce, "LOGIC" as *u8) == 1 { cls = 1 }
135 if jc_find(cb, pp[0], ce, "SHADER" as *u8) == 1 { cls = 2 }
136 if cls >= 0 { if nc < JC_MAGIC_1024 { CH[nc] = hv; CC[nc] = cls; nc = nc + 1 } }
137 }
138 } }
139 ci = ce + 1
140 }
141 }
142
143 // ---- tokenize: CODE / COMMENT / STRING; collect literal spans ----
144 let LS: *i64 = sys_mmap(JC_MAXLIT*8) as *i64
145 let LE: *i64 = sys_mmap(JC_MAXLIT*8) as *i64
146 var nl2: i64 = 0
147 var i: i64 = 0
148 var st: i64 = 0 // 0 code, 1 comment, 2 string
149 var lit0: i64 = 0
150 var esc: i64 = 0
151 var over: i64 = 0
152 while i < n {
153 let c: i64 = b[i] as i64
154 if st == 0 {
155 if c == 47 { if i + 1 < n { if (b[i+1] as i64) == 47 { st = 1; i = i + 1 } } }
156 if st == 0 { if c == 34 { st = 2; lit0 = i + 1; esc = 0 } }
157 } else { if st == 1 {
158 if c == 10 { st = 0 }
159 } else {
160 if esc == 1 { esc = 0 } else {
161 if c == 92 { esc = 1 }
162 if c == 34 {
163 if nl2 < JC_MAXLIT { LS[nl2] = lit0; LE[nl2] = i; nl2 = nl2 + 1 } else { over = 1 }
164 st = 0
165 }
166 }
167 } }
168 i = i + 1
169 }
170 if over == 1 { jc_puts("JSLOGIC-CENSUS FAIL: literal cap JC_MAXLIT exceeded -- REFUSING a partial census\n" as *u8); return 3 }
171
172 // ---- script region: count literals from the one containing <script> through </script> ----
173 var injs: i64 = 0
174 var regions: i64 = 0
175 var openk: i64 = 0 - 1 // index of the literal that OPENS the script region (see the uncharged pass)
176 var tI: i64 = 0
177 var tL: i64 = 0
178 var tS: i64 = 0
179 var tU: i64 = 0
180 var njs: i64 = 0
181 var k: i64 = 0
182 while k < nl2 {
183 let s0: i64 = LS[k]
184 let e0: i64 = LE[k]
185 var opened: i64 = 0
186 if injs == 0 {
187 // an opener literal may OPEN and CLOSE in the same literal; handle open first
188 var has: i64 = 0
189 var p2: i64 = s0
190 while p2 + 8 <= e0 { if b[p2]==(60 as u8) { if b[p2+1]==(115 as u8) { if b[p2+2]==(99 as u8) { if b[p2+3]==(114 as u8) { if b[p2+4]==(105 as u8) { if b[p2+5]==(112 as u8) { if b[p2+6]==(116 as u8) { if b[p2+7]==(62 as u8) { has = 1; p2 = e0 } } } } } } } } p2 = p2 + 1 }
191 if has == 1 { injs = 1; regions = regions + 1; opened = 1; if openk < 0 { openk = k } }
192 }
193 if injs == 1 {
194 let len: i64 = e0 - s0
195 let hv: i64 = jc_fnv(b, s0, len)
196 var cls: i64 = 0 - 1
197 var q: i64 = 0
198 while q < nc { if CH[q] == hv { cls = CC[q]; q = nc } else { q = q + 1 } }
199 if cls == 0 { tI = tI + len }
200 if cls == 1 { tL = tL + len }
201 if cls == 2 { tS = tS + len }
202 if cls < 0 { tU = tU + len }
203 njs = njs + 1
204 if vk == 2 {
205 jc_puts("LIT hash=" as *u8); jc_pn(hv)
206 jc_puts(" bytes=" as *u8); jc_pn(len)
207 jc_puts(" class=" as *u8)
208 if cls == 0 { jc_puts("INTEROP" as *u8) }
209 if cls == 1 { jc_puts("LOGIC" as *u8) }
210 if cls == 2 { jc_puts("SHADER" as *u8) }
211 if cls < 0 { jc_puts("UNKNOWN" as *u8) }
212 jc_puts(" head=" as *u8)
213 var hshow: i64 = 40
214 if len < hshow { hshow = len }
215 var h2: i64 = 0
216 while h2 < hshow {
217 var cc2: i64 = b[s0+h2] as i64
218 if cc2 < 32 { cc2 = 46 }
219 if cc2 > 126 { cc2 = 46 }
220 let ob: *u8 = sys_mmap(4)
221 ob[0] = cc2 as u8
222 sys_write(1, ob, 1)
223 h2 = h2 + 1
224 }
225 jc_puts("\n" as *u8)
226 }
227 // close AFTER counting the closer literal
228 var has2: i64 = 0
229 var p3: i64 = s0
230 while p3 + 9 <= e0 { if b[p3]==(60 as u8) { if b[p3+1]==(47 as u8) { if b[p3+2]==(115 as u8) { if b[p3+3]==(99 as u8) { if b[p3+4]==(114 as u8) { if b[p3+5]==(105 as u8) { if b[p3+6]==(112 as u8) { if b[p3+7]==(116 as u8) { if b[p3+8]==(62 as u8) { has2 = 1; p3 = e0 } } } } } } } } } p3 = p3 + 1 }
231 if has2 == 1 { if opened == 0 { injs = 0 } }
232 }
233 k = k + 1
234 }
235
236 // ---- UNCHARGED EMITTED JS -- the coverage axis the region rule structurally cannot reach ----
237 // The region walk above is SOURCE-ORDER: it charges only literals lying between the literal that
238 // carries the script opener and the one that carries the closer, AS THEY APPEAR IN THE FILE. A
239 // page emitter that defines its JS-emitting helper functions ABOVE that opener emits those bytes
240 // into the SAME page and the walk never reaches them, so they are charged to NOTHING and the
241 // ratchet is blind to them. MEASURED 2026-09-01 on nx_game_page_emit.nx: 66 literals / 37,061 B
242 // uncharged, containing the entire hair solver, the entire cloth solver and the whole WebGPU
243 // tier -- i.e. exactly the code the interop-only law exists to find.
244 // THE EMITTER HELPER IS DERIVED FROM THE ARTIFACT, NEVER CHOSEN: walk back from the opener
245 // literal's own quote to the paren that opens its call and take the identifier before it. A
246 // hard-coded name would make this ruler subject-specific and would rot at the next emitter.
247 // DELIBERATELY NOT FOLDED INTO logic_unknown: the baseline was banked without these bytes, so
248 // folding would move the bar and the number in the same step and no reading would be comparable
249 // -- and this population is not all JS (a few HTML chrome literals ride the same helper). This
250 // axis ANNOUNCES and COUNTS and hands over a worklist; it never changes an existing verdict.
251 var uchl: i64 = 0
252 var uchb: i64 = 0
253 var openline: i64 = 0
254 let hname: *u8 = sys_mmap(160)
255 var hlen: i64 = 0
256 if openk >= 0 {
257 var q: i64 = LS[openk] - 2
258 var g3: i64 = 1
259 while g3 == 1 { if q < 0 { g3 = 0 } else { if b[q] == (40 as u8) { g3 = 0 } else { q = q - 1 } } }
260 if q > 0 {
261 let e3: i64 = q - 1
262 var s3: i64 = e3
263 var g4: i64 = 1
264 while g4 == 1 {
265 if s3 < 0 { g4 = 0 } else {
266 let cc: i64 = b[s3] as i64
267 var okc: i64 = 0
268 if cc >= 97 { if cc <= 122 { okc = 1 } }
269 if cc >= 65 { if cc <= 90 { okc = 1 } }
270 if cc >= 48 { if cc <= 57 { okc = 1 } }
271 if cc == 95 { okc = 1 }
272 if okc == 1 { s3 = s3 - 1 } else { g4 = 0 }
273 }
274 }
275 s3 = s3 + 1
276 var w3: i64 = s3
277 while w3 <= e3 { if hlen < 150 { hname[hlen] = b[w3]; hlen = hlen + 1 } w3 = w3 + 1 }
278 hname[hlen] = 0 as u8
279 }
280 var z: i64 = 0
281 while z < LS[openk] { if b[z] == (10 as u8) { openline = openline + 1 } z = z + 1 }
282 openline = openline + 1
283 }
284 if hlen > 0 {
285 var lncur: i64 = 1
286 var lnpos: i64 = 0
287 var k2: i64 = 0
288 while k2 < openk {
289 while lnpos < LS[k2] { if b[lnpos] == (10 as u8) { lncur = lncur + 1 } lnpos = lnpos + 1 }
290 var ls2: i64 = LS[k2]
291 var gg: i64 = 1
292 while gg == 1 { if ls2 == 0 { gg = 0 } else { if b[ls2-1] == (10 as u8) { gg = 0 } else { ls2 = ls2 - 1 } } }
293 var le2: i64 = LS[k2]
294 var gh: i64 = 1
295 while gh == 1 { if le2 >= n { gh = 0 } else { if b[le2] == (10 as u8) { gh = 0 } else { le2 = le2 + 1 } } }
296 if jc_find(b, ls2, le2, hname) == 1 {
297 let ulen: i64 = LE[k2] - LS[k2]
298 uchl = uchl + 1
299 uchb = uchb + ulen
300 if vk == 2 {
301 jc_puts("UNCHARGED bytes=" as *u8); jc_pn(ulen)
302 jc_puts(" line=" as *u8); jc_pn(lncur)
303 jc_puts(" head=" as *u8)
304 var uh: i64 = 40
305 if ulen < uh { uh = ulen }
306 var h3: i64 = 0
307 while h3 < uh {
308 var c3: i64 = b[LS[k2]+h3] as i64
309 if c3 < 32 { c3 = 46 }
310 if c3 > 126 { c3 = 46 }
311 let ob3: *u8 = sys_mmap(4)
312 ob3[0] = c3 as u8
313 sys_write(1, ob3, 1)
314 h3 = h3 + 1
315 }
316 jc_puts("\n" as *u8)
317 }
318 }
319 k2 = k2 + 1
320 }
321 }
322
323 let logic_unknown: i64 = tL + tU
324 jc_puts("JSLOGIC-CENSUS src-literals=" as *u8); jc_pn(nl2)
325 jc_puts(" js-literals=" as *u8); jc_pn(njs)
326 jc_puts(" regions=" as *u8); jc_pn(regions)
327 jc_puts(" interop=" as *u8); jc_pn(tI)
328 jc_puts(" logic=" as *u8); jc_pn(tL)
329 jc_puts(" shader=" as *u8); jc_pn(tS)
330 jc_puts(" unknown=" as *u8); jc_pn(tU)
331 jc_puts(" logic_unknown=" as *u8); jc_pn(logic_unknown)
332 jc_puts(" uncharged_lits=" as *u8); jc_pn(uchl)
333 jc_puts(" uncharged_bytes=" as *u8); jc_pn(uchb)
334 jc_puts("\n" as *u8)
335 if uchb > 0 {
336 jc_puts("JSLOGIC-CENSUS UNCHARGED-JS lits=" as *u8); jc_pn(uchl)
337 jc_puts(" bytes=" as *u8); jc_pn(uchb)
338 jc_puts(" helper=" as *u8); jc_puts(hname)
339 jc_puts(" opener_src_line=" as *u8); jc_pn(openline)
340 jc_puts(" -- emitted by helpers DEFINED ABOVE the opener, so the source-order region rule cannot reach them. NOT in logic_unknown (the baseline was banked without them). Worklist: the rows verb prints one UNCHARGED line each.\n" as *u8)
341 }
342
343 // journal (epoch TAB totals) -- evidence on success AND failure
344 let jb: *u8 = sys_mmap(256)
345 var jo: i64 = 0
346 var ep: i64 = sys_now_realtime_sec()
347 var m2: i64 = ep
348 let td: *u8 = sys_mmap(32)
349 var tk: i64 = 0
350 if m2 == 0 { jb[jo] = 48 as u8; jo = jo + 1 }
351 while m2 > 0 { td[tk] = (48 + (m2 % 10)) as u8; m2 = m2 / 10; tk = tk + 1 }
352 while tk > 0 { tk = tk - 1; jb[jo] = td[tk]; jo = jo + 1 }
353 let jrest: *u8 = "\tjslogic\t" as *u8
354 var jr: i64 = 0
355 while jrest[jr] != (0 as u8) { jb[jo] = jrest[jr]; jo = jo + 1; jr = jr + 1 }
356 var vals: *i64 = sys_mmap(6*8) as *i64
357 vals[0] = tI
358 vals[1] = tL
359 vals[2] = tS
360 vals[3] = tU
361 var vi: i64 = 0
362 while vi < 4 {
363 var vv: i64 = vals[vi]
364 if vv == 0 { jb[jo] = 48 as u8; jo = jo + 1 }
365 var vt: i64 = 0
366 while vv > 0 { td[vt] = (48 + (vv % 10)) as u8; vv = vv / 10; vt = vt + 1 }
367 while vt > 0 { vt = vt - 1; jb[jo] = td[vt]; jo = jo + 1 }
368 if vi < 3 { jb[jo] = 9 as u8; jo = jo + 1 }
369 vi = vi + 1
370 }
371 jb[jo] = 10 as u8
372 jo = jo + 1
373 let jfd: i64 = sys_openat_append(JC_JRNL, 0x1a4)
374 if jfd >= 0 { sys_write(jfd, jb, jo); sys_fsync(jfd); sys_close(jfd) }
375
376 if vk == 2 { return 0 }
377 if vk == 1 {
378 let sb: *u8 = sys_mmap(64)
379 var so: i64 = 0
380 var sv: i64 = logic_unknown
381 if sv == 0 { sb[so] = 48 as u8; so = so + 1 }
382 var st2: i64 = 0
383 while sv > 0 { td[st2] = (48 + (sv % 10)) as u8; sv = sv / 10; st2 = st2 + 1 }
384 while st2 > 0 { st2 = st2 - 1; sb[so] = td[st2]; so = so + 1 }
385 sb[so] = 10 as u8
386 so = so + 1
387 let bfd: i64 = sys_openat_wr(JC_BASE, 0x1a4)
388 if bfd < 0 { jc_puts("JSLOGIC-CENSUS FAIL: cannot write baseline\n" as *u8); return 3 }
389 sys_write(bfd, sb, so)
390 sys_fsync(bfd)
391 sys_close(bfd)
392 jc_puts("JSLOGIC-CENSUS SNAPSHOT baseline logic_unknown=" as *u8); jc_pn(logic_unknown); jc_puts("\n" as *u8)
393 return 0
394 }
395 // check: ratchet vs baseline (absent baseline = UNPROVEN, refuse loudly rather than pass)
396 let bl: *i64 = sys_mmap(16) as *i64
397 let bb: *u8 = sys_read_file(JC_BASE, bl)
398 if (bb as i64) == 0 { jc_puts("JSLOGIC-CENSUS RED: no baseline banked -- run snapshot deliberately first\n" as *u8); return 1 }
399 let bp: *i64 = sys_mmap(16) as *i64
400 bp[0] = 0
401 let base: i64 = jc_rdint(bb, bp, bl[0])
402 if base < 0 { jc_puts("JSLOGIC-CENSUS RED: baseline unparsable\n" as *u8); return 1 }
403 if logic_unknown > base {
404 jc_puts("JSLOGIC-CENSUS RED: logic_unknown " as *u8); jc_pn(logic_unknown)
405 jc_puts(" ROSE vs baseline " as *u8); jc_pn(base)
406 jc_puts(" -- new JS-authored logic is refused by the interop-only law\n" as *u8)
407 return 1
408 }
409 jc_puts("JSLOGIC-CENSUS GREEN logic_unknown=" as *u8); jc_pn(logic_unknown)
410 jc_puts(" <= baseline " as *u8); jc_pn(base)
411 jc_puts("\n" as *u8)
412 return 0
413}