nx_craft_emit.nx source
↩ module page · 169 lines · 10009 B
1// nx_craft_emit.nx -- THE SOVEREIGN CRAFT SHIP LANE (retires _ops/nx_emit_game.sh's laptop/WSL
2// dependency for /world/craft): gate-check -> .nx -> .wat -> .wasm -> page -> live docroot,
3// every stage BYTE-ASSERTED before the next runs (the emit script's founding law, organ form:
4// a green tool on empty input is not a check -- a 0-byte .wat once shipped a 20-byte "game").
5// The page itself is built IN-PROCESS by gpe_build (nx_game_page_emit as a LIB -- one emitter,
6// not a fork), and the deploy is tmp+rename with a READ-BACK byte+marker assert (what LANDED
7// is the claim, never what was written). Gate RED = refuses to emit anything at all.
8// usage: nx_craft_emit (runs from nishihost cwd like every registered tool)
9// exit: 0 SHIPPED | 2 gate-red | 3 wat | 4 wasm | 5 page | 6 deploy | 7 readback
10// license_tier: ORIGINAL No hw writes (Rule 26).
11import "nx_syscalls.nx"
12import "nx_game_page_emit.nx"
13
14const CE_GATE: *u8 = "nx_wasm_craft_gate.elf"
15const CE_CWAT: *u8 = "nx_compile_wat.elf"
16const CE_WATC: *u8 = "nx_wat_compiler.elf"
17const CE_SRC: *u8 = "buildroot/runtime/nx_wasm_craft.nx"
18const CE_WAT: *u8 = "buildroot/_build/nx_wasm_craft_emit.wat"
19const CE_WASM: *u8 = "buildroot/_build/nx_wasm_craft_emit.wasm"
20const CE_TMP: *u8 = "sites/nishifamily/world/craft.html.stage"
21const CE_OUT: *u8 = "sites/nishifamily/world/craft.html"
22const CE_TITLE: *u8 = "NISHI CRAFT - SOVEREIGN 3D"
23const CE_NATIVE: *u8 = "nx_desktop_craft"
24// the REVIEW STAGE (identity v2 = NISHI SHORE): same gated wasm, second spec, second page --
25// one engine, many worlds is the emission lever actually being pulled
26const CE_TMP2: *u8 = "sites/nishifamily/world/beach.html.stage"
27const CE_OUT2: *u8 = "sites/nishifamily/world/beach.html"
28const CE_TITLE2: *u8 = "NISHI SHORE - REVIEW STAGE"
29const CE_CTRL2: *u8 = "the flat-light REVIEW STAGE: mixed beachwear across the cast (bred, stable per girl) · same engine, same controls as <a href=\"craft\">NISHI CRAFT</a> · ?review=1 auto-frames the nearest girl<br>ISEKAI: cross to <a href=\"craft\">NISHI CRAFT</a> or <a href=\"vale\">NISHI VALE</a> — level, ledger and party come along"
30// v3 = the medieval VALE: the third world, built from data rows alone. Your traveler carries
31// his ledger and party between all three -- the passport lives under one key for every world.
32const CE_TMP3: *u8 = "sites/nishifamily/world/vale.html.stage"
33const CE_OUT3: *u8 = "sites/nishifamily/world/vale.html"
34const CE_TITLE3: *u8 = "NISHI VALE - THE MEDIEVAL HIGHLAND"
35const CE_CTRL3: *u8 = "deep woods, cold snowline, cave-riddled stone — and wardens who hunt WIDE by day · your traveler arrives with his ledger, his level and his party from <a href=\"craft\">NISHI CRAFT</a> or <a href=\"beach\">NISHI SHORE</a> · <b>G</b> invites a bonded girl to your party · same controls"
36const CE_CTRL: *u8 = "click canvas = MOUSELOOK (Esc frees) · <b>WASD</b> move · <b>SPACE</b> jump · L/R-click or <b>E</b>/<b>B</b> break/place · <b>Q</b> cycles 7 slots (blocks · HOE · SEEDS) · till grass, plant, let rain or a pond do the rest, break the GOLDEN crop = harvest · <b>E</b> on a girl = meet her, <b>G</b> invites her to your party · nights are the wardens' · <b>H</b> home · gamepad + touch<br>ISEKAI: your level, ledger and party travel with you — walk into <a href=\"beach\">NISHI SHORE</a> or <a href=\"vale\">NISHI VALE</a> · <a href=\"craft_immersion\">what is broken and what is next</a>"
37const CE_MIN_WAT: i64 = 500000
38const CE_MIN_WASM: i64 = 50000
39const CE_MIN_PAGE: i64 = 100000
40const CE_MODE: i64 = 0x1a4
41
42func ce_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
43func ce_puts(s: *u8) -> i64 { sys_write(1, s, ce_slen(s)); return 0 }
44func ce_pn(v: i64) -> i64 {
45 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
46 var m: i64 = v
47 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
48 let t: *u8 = sys_mmap(32)
49 var k: i64 = 0
50 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
51 let o: *u8 = sys_mmap(32)
52 var i: i64 = 0
53 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
54 sys_write(1, o, k)
55 return 0
56}
57// the nx_aw_push fork-a-sovereign-sub-ELF pattern (spine shared with nx_emu_probe_wasm_gate)
58func ce_run(elf: *u8, a1: *u8, a2: *u8) -> i64 {
59 let pid: i64 = sys_fork()
60 if pid == 0 {
61 let argv: *i64 = sys_mmap(64) as *i64
62 argv[0] = elf as i64
63 var ai: i64 = 1
64 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 }
65 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 }
66 argv[ai] = 0
67 let envp: *i64 = sys_mmap(16) as *i64
68 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64
69 envp[1] = 0
70 sys_execve(elf, argv, envp)
71 sys_exit(127)
72 }
73 let st: *i64 = sys_mmap(16) as *i64
74 sys_wait4(pid, st, 0)
75 return (st[0] >> 8) & 0xff
76}
77func ce_find(hay: *u8, n: i64, needle: *u8) -> i64 {
78 let nl: i64 = ce_slen(needle)
79 if nl == 0 { return 1 }
80 var i: i64 = 0
81 while i + nl <= n {
82 var j: i64 = 0
83 var hit: i64 = 1
84 while j < nl { if hay[i + j] != needle[j] { hit = 0; j = nl } else { j = j + 1 } }
85 if hit == 1 { return 1 }
86 i = i + 1
87 }
88 return 0
89}
90func ce_fsize(p: *u8) -> i64 {
91 let box: *i64 = sys_mmap(16) as *i64
92 let b: *u8 = sys_read_file(p, box)
93 if (b as i64) == 0 { return 0 - 1 }
94 return box[0]
95}
96
97func main() -> i64 {
98 // 1) THE GATE DECIDES: a RED world ships nothing (the emit script's step-2 law)
99 ce_puts("[1/5] gate " as *u8)
100 let g: i64 = ce_run(CE_GATE, 0 as *u8, 0 as *u8)
101 if g != 0 { ce_puts("RED rc=" as *u8); ce_pn(g); ce_puts(" -- REFUSED, nothing emitted\n" as *u8); return 2 }
102 ce_puts("GREEN\n" as *u8)
103
104 // 1b) THE FEEL ORACLE: every tunable inside its banked, cited reference band (the KAT
105 // pattern applied to feel) -- out-of-band tuning cannot ship through this lane
106 ce_puts("[1b/5] feel-oracle " as *u8)
107 let g2: i64 = ce_run("nx_gamefeel_oracle_gate.elf" as *u8, 0 as *u8, 0 as *u8)
108 if g2 != 0 { ce_puts("RED rc=" as *u8); ce_pn(g2); ce_puts(" -- REFUSED, nothing emitted\n" as *u8); return 2 }
109 ce_puts("GREEN\n" as *u8)
110
111 // 2) .nx -> .wat (byte-asserted: the historic silent 0-byte .wat is the class this kills)
112 let r1: i64 = ce_run(CE_CWAT, CE_SRC, CE_WAT)
113 let wn1: i64 = ce_fsize(CE_WAT)
114 ce_puts("[2/5] wat rc=" as *u8); ce_pn(r1); ce_puts(" bytes=" as *u8); ce_pn(wn1); ce_puts("\n" as *u8)
115 if wn1 < CE_MIN_WAT { ce_puts("EMIT-FAIL: wat under floor\n" as *u8); return 3 }
116
117 // 3) .wat -> .wasm (magic-checked -- a "GREEN" assembler on empty input still writes a stub)
118 let r2: i64 = ce_run(CE_WATC, CE_WAT, CE_WASM)
119 let box: *i64 = sys_mmap(16) as *i64
120 let wasm: *u8 = sys_read_file(CE_WASM, box)
121 ce_puts("[3/5] wasm rc=" as *u8); ce_pn(r2); ce_puts(" bytes=" as *u8); ce_pn(box[0]); ce_puts("\n" as *u8)
122 if (wasm as i64) == 0 { ce_puts("EMIT-FAIL: no wasm\n" as *u8); return 4 }
123 if box[0] < CE_MIN_WASM { ce_puts("EMIT-FAIL: wasm under floor\n" as *u8); return 4 }
124 if wasm[0] != (0 as u8) { ce_puts("EMIT-FAIL: bad magic\n" as *u8); return 4 }
125 if wasm[1] != (97 as u8) { ce_puts("EMIT-FAIL: bad magic\n" as *u8); return 4 }
126 if wasm[2] != (115 as u8) { ce_puts("EMIT-FAIL: bad magic\n" as *u8); return 4 }
127 if wasm[3] != (109 as u8) { ce_puts("EMIT-FAIL: bad magic\n" as *u8); return 4 }
128
129 // 4) the page, IN-PROCESS (gpe_build is the ONE emitter; no second template can drift)
130 let out: *u8 = sys_mmap(GPE_OUT_CAP)
131 let pn: i64 = gpe_build(wasm, box[0], CE_TITLE, CE_NATIVE, CE_CTRL, 0, out)
132 ce_puts("[4/5] page bytes=" as *u8); ce_pn(pn); ce_puts("\n" as *u8)
133 if pn < CE_MIN_PAGE { ce_puts("EMIT-FAIL: page under floor\n" as *u8); return 5 }
134
135 // 5) deploy tmp+rename, then READ BACK: bytes equal AND the loader marker present in what
136 // LANDED -- the filesystem is the oracle for an evidence row
137 if ce_ship(out, pn, CE_TMP, CE_OUT) != 0 { return 6 }
138 // 5b) THE REVIEW STAGE: identity v2 over the SAME gated wasm bytes
139 let out2: *u8 = sys_mmap(GPE_OUT_CAP)
140 let pn2: i64 = gpe_build(wasm, box[0], CE_TITLE2, CE_NATIVE, CE_CTRL2, 2, out2)
141 if pn2 < CE_MIN_PAGE { ce_puts("EMIT-FAIL: shore page under floor\n" as *u8); return 5 }
142 if ce_ship(out2, pn2, CE_TMP2, CE_OUT2) != 0 { return 6 }
143 // 5c) THE THIRD WORLD, same gated wasm bytes -- one engine, three identities
144 let out3: *u8 = sys_mmap(GPE_OUT_CAP)
145 let pn3: i64 = gpe_build(wasm, box[0], CE_TITLE3, CE_NATIVE, CE_CTRL3, 3, out3)
146 if pn3 < CE_MIN_PAGE { ce_puts("EMIT-FAIL: vale page under floor\n" as *u8); return 5 }
147 if ce_ship(out3, pn3, CE_TMP3, CE_OUT3) != 0 { return 6 }
148 return 0
149}
150
151func ce_ship(out: *u8, pn: i64, tmpp: *u8, outp: *u8) -> i64 {
152 let fd: i64 = sys_openat_wr(tmpp, CE_MODE)
153 if fd < 0 { ce_puts("EMIT-FAIL: stage open\n" as *u8); return 6 }
154 var off: i64 = 0
155 while off < pn {
156 let w: i64 = sys_write(fd, ((out as i64) + off) as *u8, pn - off)
157 if w <= 0 { sys_close(fd); ce_puts("EMIT-FAIL: stage write\n" as *u8); return 6 }
158 off = off + w
159 }
160 sys_close(fd)
161 if sys_renameat(tmpp, outp) < 0 { ce_puts("EMIT-FAIL: rename\n" as *u8); return 6 }
162 let box2: *i64 = sys_mmap(16) as *i64
163 let back: *u8 = sys_read_file(outp, box2)
164 if (back as i64) == 0 { ce_puts("EMIT-FAIL: readback\n" as *u8); return 7 }
165 if box2[0] != pn { ce_puts("EMIT-FAIL: readback bytes " as *u8); ce_pn(box2[0]); ce_puts(" != " as *u8); ce_pn(pn); ce_puts("\n" as *u8); return 7 }
166 if ce_find(back, box2[0], "WebAssembly.instantiate" as *u8) == 0 { ce_puts("EMIT-FAIL: loader marker missing\n" as *u8); return 7 }
167 ce_puts("[5/5] SHIPPED " as *u8); ce_pn(pn); ce_puts(" bytes -> " as *u8); ce_puts(outp); ce_puts(" (read back, marker verified)\n" as *u8)
168 return 0
169}