nx_gen_ui_gate.nx source
↩ module page · 157 lines · 7642 B
1// nx_gen_ui_gate.nx -- the REFEREE for gen G19 (nx_gen_ui_emit): the /gen companion page is EMITTED from data,
2// deterministic, behaviourally complete, fail-closed on a missing key, and THE SERVED FILE IS THE EMITTED FILE.
3// DONE-RULE (gen.plan G19): two emits from the live conf are byte-identical; the page carries every required
4// behaviour marker; a conf missing a key REFUSES by name and writes nothing; the bytes at the daemon's served path
5// equal the emitted bytes (so a hand edit to the served page is a RED, never a silent fork of the design).
6// FIXTURE LAW: scratch under /tmp/<gate>/, cleared at SETUP; the neg-control conf is DERIVED from the live conf
7// at run time (never a checked-in fixture a scanner could find), and a tooth asserts the fixture reached its condition.
8// license_tier: ORIGINAL expect_exit: 0
9import "nx_syscalls.nx"
10import "nx_gate_verdict.nx"
11import "nx_tool_run.nx"
12
13const UG_ELF: *u8 = "/volume1/homes/elderwesto/nishihost/nx_gen_ui_emit.elf" as *u8
14const UG_CONF: *u8 = "/volume1/homes/elderwesto/nishihost/knowledge/gen_ui.conf" as *u8
15const UG_SERVED: *u8 = "/volume1/ai/gen/elara_ui.html" as *u8
16const UG_DIR: *u8 = "/tmp/nx_gen_ui_gate" as *u8
17const UG_A: *u8 = "/tmp/nx_gen_ui_gate/a.html" as *u8
18const UG_B: *u8 = "/tmp/nx_gen_ui_gate/b.html" as *u8
19const UG_BAD_CONF: *u8 = "/tmp/nx_gen_ui_gate/bad.conf" as *u8
20const UG_BAD_OUT: *u8 = "/tmp/nx_gen_ui_gate/bad.html" as *u8
21const UG_DROP_KEY: *u8 = "api_base|" as *u8
22const UG_MODE_DIR: i64 = 511
23const UG_MODE_FILE: i64 = 420
24const UG_CAP: i64 = 262144
25const UG_MIN_PAGE: i64 = 4096
26const UG_TIMEOUT_MS: i64 = 10000
27const UG_EXIT_REFUSED: i64 = 3
28const UG_CH_NL: i64 = 10
29
30func ug_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
31func ug_find(buf: *u8, n: i64, needle: *u8) -> i64 {
32 let nl: i64 = ug_len(needle)
33 if nl <= 0 { return 0 - 1 }
34 var i: i64 = 0
35 while i + nl <= n {
36 var j: i64 = 0
37 var same: i64 = 1
38 var scan: i64 = 1
39 while scan == 1 { if j >= nl { scan = 0 } else { if buf[i + j] != needle[j] { same = 0; scan = 0 } else { j = j + 1 } } }
40 if same == 1 { return i }
41 i = i + 1
42 }
43 return 0 - 1
44}
45func ug_starts(buf: *u8, at: i64, n: i64, pre: *u8) -> i64 {
46 var i: i64 = 0
47 while pre[i] != (0 as u8) { if at + i >= n { return 0 } if buf[at + i] != pre[i] { return 0 } i = i + 1 }
48 return 1
49}
50
51// fork the emitter with (conf, out); returns its exit code (tr semantics: negative = harness failure, -5 = timeout)
52func ug_run(conf: *u8, outp: *u8) -> i64 {
53 let argv: *i64 = sys_mmap(32) as *i64
54 argv[0] = UG_ELF as i64
55 argv[1] = conf as i64
56 argv[2] = outp as i64
57 argv[3] = 0
58 let cap: *u8 = sys_mmap(UG_CAP)
59 let olen: *i64 = sys_mmap(16) as *i64
60 olen[0] = 0
61 return tr_run_capture_to(UG_ELF, argv, cap, UG_CAP - 1, olen, UG_TIMEOUT_MS)
62}
63
64// byte-identity of two files (0 when either is unreadable)
65func ug_same(pa: *u8, pb: *u8) -> i64 {
66 let la: *i64 = sys_mmap(16) as *i64
67 let lb: *i64 = sys_mmap(16) as *i64
68 la[0] = 0; lb[0] = 0
69 let a: *u8 = sys_read_file(pa, la)
70 let b: *u8 = sys_read_file(pb, lb)
71 if (a as i64) == 0 { return 0 }
72 if (b as i64) == 0 { return 0 }
73 if la[0] != lb[0] { return 0 }
74 var i: i64 = 0
75 while i < la[0] { if a[i] != b[i] { return 0 } i = i + 1 }
76 return 1
77}
78
79// the neg-control conf: the LIVE conf with every line starting UG_DROP_KEY removed. Returns lines dropped.
80func ug_write_bad_conf() -> i64 {
81 let lp: *i64 = sys_mmap(16) as *i64
82 lp[0] = 0
83 let b: *u8 = sys_read_file(UG_CONF, lp)
84 if (b as i64) == 0 { return 0 - 1 }
85 let n: i64 = lp[0]
86 let fd: i64 = sys_openat_wr(UG_BAD_CONF, UG_MODE_FILE)
87 if fd < 0 { return 0 - 2 }
88 var dropped: i64 = 0
89 var i: i64 = 0
90 while i < n {
91 let ls: i64 = i
92 var eol: i64 = i
93 var scan: i64 = 1
94 while scan == 1 { if eol >= n { scan = 0 } else { if b[eol] == (UG_CH_NL as u8) { scan = 0 } else { eol = eol + 1 } } }
95 var stop: i64 = eol
96 if stop < n { stop = stop + 1 }
97 if ug_starts(b, ls, n, UG_DROP_KEY) == 1 { dropped = dropped + 1 } else { sys_write(fd, ((b as i64) + ls) as *u8, stop - ls) }
98 i = stop
99 }
100 sys_close(fd)
101 return dropped
102}
103
104func main() -> i64 {
105 gv_head("nx_gen_ui_gate -- G19: the /gen page is emitted from data, deterministic, complete, fail-closed, and the served file is the emitted file" as *u8)
106 let ctr: *i64 = gv_ctr()
107
108 // SETUP: fresh scratch every run (idempotent) -- a leftover output could never satisfy a tooth by accident
109 sys_mkdir(UG_DIR, UG_MODE_DIR)
110 sys_unlinkat(UG_A)
111 sys_unlinkat(UG_B)
112 sys_unlinkat(UG_BAD_OUT)
113 sys_unlinkat(UG_BAD_CONF)
114
115 // T1 the emitter emits from the LIVE conf
116 let rc1: i64 = ug_run(UG_CONF, UG_A)
117 let la: *i64 = sys_mmap(16) as *i64
118 la[0] = 0
119 let a: *u8 = sys_read_file(UG_A, la)
120 var na: i64 = 0
121 if (a as i64) != 0 { na = la[0] }
122 gv_check("emit-succeeds-on-the-live-conf" as *u8, (rc1 == 0) & (na > UG_MIN_PAGE), ctr)
123
124 // T2 deterministic: a second emit is byte-identical
125 let rc2: i64 = ug_run(UG_CONF, UG_B)
126 gv_check("two-emits-are-byte-identical" as *u8, (rc2 == 0) & (ug_same(UG_A, UG_B) == 1), ctr)
127
128 // T3 required behaviours are present in the emitted page (each a separate tooth so a regression names itself)
129 gv_check("page-carries-the-nx-derived-stamp" as *u8, ug_find(a, na, "NX-DERIVED" as *u8) >= 0, ctr)
130 gv_check("page-posts-chat-to-the-daemon" as *u8, ug_find(a, na, "/api/chat" as *u8) >= 0, ctr)
131 gv_check("page-submits-studio-renders-async" as *u8, ug_find(a, na, "/api/batch" as *u8) >= 0, ctr)
132 gv_check("page-surfaces-a-render-error-instead-of-spinning" as *u8, ug_find(a, na, "if(r.error)" as *u8) >= 0, ctr)
133 gv_check("page-surfaces-a-chat-refusal-instead-of-an-empty-bubble" as *u8, ug_find(a, na, "could not answer" as *u8) >= 0, ctr)
134 gv_check("page-has-chat-gallery-and-studio-tabs" as *u8, (ug_find(a, na, "id=t-chat" as *u8) >= 0) & (ug_find(a, na, "id=t-gallery" as *u8) >= 0) & (ug_find(a, na, "id=t-studio" as *u8) >= 0), ctr)
135 gv_check("page-links-the-family-gallery" as *u8, ug_find(a, na, "/gallery" as *u8) >= 0, ctr)
136 gv_check("gallery-tab-is-the-conversation-album-by-day" as *u8, (ug_find(a, na, "/api/album" as *u8) >= 0) & (ug_find(a, na, "dayh" as *u8) >= 0), ctr)
137
138 // T4 NEG-CONTROL: a conf missing a required key refuses by name and writes NOTHING
139 let dropped: i64 = ug_write_bad_conf()
140 let lbad: *i64 = sys_mmap(16) as *i64
141 lbad[0] = 0
142 let bc: *u8 = sys_read_file(UG_BAD_CONF, lbad)
143 var badlacks: i64 = 0
144 if (bc as i64) != 0 { if ug_find(bc, lbad[0], UG_DROP_KEY) < 0 { badlacks = 1 } }
145 gv_check("fixture-reached-condition-bad-conf-lacks-the-key" as *u8, (dropped >= 1) & (badlacks == 1), ctr)
146 let rcb: i64 = ug_run(UG_BAD_CONF, UG_BAD_OUT)
147 gv_check("neg-control-missing-key-refuses-with-exit-3" as *u8, rcb == UG_EXIT_REFUSED, ctr)
148 let lbo: *i64 = sys_mmap(16) as *i64
149 lbo[0] = 0
150 let bo: *u8 = sys_read_file(UG_BAD_OUT, lbo)
151 gv_check("neg-control-missing-key-writes-nothing" as *u8, (bo as i64) == 0, ctr)
152
153 // T5 THE FLIP TOOTH: what the daemon serves IS what the emitter emits (a hand edit to the served page is a RED)
154 gv_check("served-page-is-the-emitted-page" as *u8, ug_same(UG_A, UG_SERVED) == 1, ctr)
155
156 return gv_verdict("GEN-UI-GATE" as *u8, ctr, "G19 done-rule: emitted from data, deterministic, behaviourally complete, fail-closed on a missing key, served bytes equal emitted bytes" as *u8)
157}