code wiki / _hdl_build / nx_gramdec_gate.nx
nx_gramdec_gate.nx source
↩ module page · 238 lines · 10262 B
1// nx_gramdec_gate.nx -- NB10 gate: grammar-constrained decode (nx_gramdec_lib) teeth.
2// T1-T8 = automaton ruler teeth (no model). T9 = LIVE no-op equivalence: on an already-grammatical
3// greedy generation the constrained decode must be BIT-EXACT (prefix) with nsv_generate, zero
4// rejections, accept-stop. T10 = LIVE mask-fires (anti-vacuity + escape): an else-if-baited prompt
5// must (a) make the UNCONSTRAINED model emit `else if` (proves the bait bites -- the vacuity guard),
6// (b) under the mask produce grammar-VALID output with >=1 rejection and NO `else if`.
7// MUTATION PROOF (rung 5): flip GD_NEG_ALLOW_ELSEIF=1 in nx_gramdec_lib.nx, rebuild, run -> T3
8// accepts the else-if text and T10 sees the escape -> verdict=RED exit 1. Restore -> GREEN.
9// argv: [model.gguf] [probe] (default model /home/elderwesto/nx_stage/nx_15b_model.gguf;
10// "probe" prints raw outputs for tooth calibration instead of judging).
11// license_tier: ORIGINAL No hw writes (Rule 26).
12import "nx_gramdec_lib.nx"
13import "nx_gate_verdict.nx"
14
15const GG_MAXNEW: i64 = 120
16const GG_OCAP: i64 = 4000
17
18func gg_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
19func gg_wn(v: i64) -> i64 {
20 var m: i64 = v
21 if m < 0 { gg_w("-" as *u8); m = 0 - m }
22 let t: *u8 = sys_mmap(24)
23 var k: i64 = 0
24 if m == 0 { t[0] = 48 as u8; k = 1 }
25 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
26 let o: *u8 = sys_mmap(24)
27 var i: i64 = 0
28 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
29 sys_write(1, o, k)
30 return 0
31}
32func gg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
33func gg_cat(b: *u8, off: i64, s: *u8) -> i64 {
34 var i: i64 = 0
35 var o: i64 = off
36 while s[i] != (0 as u8) { b[o] = s[i]; o = o + 1; i = i + 1 }
37 return o
38}
39func gg_find(hay: *u8, hn: i64, needle: *u8, from: i64) -> i64 {
40 let m: i64 = gg_slen(needle)
41 if m == 0 { return 0 - 1 }
42 var i: i64 = from
43 while i + m <= hn {
44 var j: i64 = 0
45 var ok: i64 = 1
46 while j < m { if hay[i + j] != needle[j] { ok = 0; j = m } else { j = j + 1 } }
47 if ok == 1 { return i }
48 i = i + 1
49 }
50 return 0 - 1
51}
52
53static gg_pass: i64
54static gg_total: i64
55
56func gg_tooth(name: *u8, got: i64) -> i64 {
57 gg_total = gg_total + 1
58 gg_w(" T" as *u8)
59 gg_wn(gg_total)
60 gg_w(" " as *u8)
61 gg_w(name)
62 if got == 1 { gg_w(": PASS\n" as *u8); gg_pass = gg_pass + 1 } else { gg_w(": FAIL\n" as *u8) }
63 return 0
64}
65// validate a NUL-terminated literal through the whole-text ruler
66func gg_val(s: *u8) -> i64 { let n: i64 = gg_slen(s); return gd_validate(s, n) }
67
68// build the CLEAN round-1 sgn prompt (exact episode shape, cand2, no FNCASE rows)
69func gg_prompt_clean(pb: *u8) -> i64 {
70 var o: i64 = 0
71 o = gg_cat(pb, o, "Fix each buggy NishiLang function. Output only the corrected function on one line.\n" as *u8)
72 o = gg_cat(pb, o, "Buggy: func min2(a: i64, b: i64) -> i64 { return b }\n" as *u8)
73 o = gg_cat(pb, o, "Fixed: func min2(a: i64, b: i64) -> i64 { if a < b { return a } return b }\n" as *u8)
74 o = gg_cat(pb, o, "Buggy: func abs1(x: i64) -> i64 { return x }\n" as *u8)
75 o = gg_cat(pb, o, "Fixed: func abs1(x: i64) -> i64 { if x < 0 { return 0 - x } return x }\n" as *u8)
76 o = gg_cat(pb, o, "Buggy: func sgn(x: i64) -> i64 { return 0 }\n" as *u8)
77 o = gg_cat(pb, o, "Fixed: " as *u8)
78 return o
79}
80// build the ELSE-IF BAIT prompt (few-shots in else-if style -> greedy model copies the style)
81func gg_prompt_bait(pb: *u8) -> i64 {
82 var o: i64 = 0
83 o = gg_cat(pb, o, "Fix each buggy NishiLang function. Output only the corrected function on one line.\n" as *u8)
84 o = gg_cat(pb, o, "Buggy: func min2(a: i64, b: i64) -> i64 { return b }\n" as *u8)
85 o = gg_cat(pb, o, "Fixed: func min2(a: i64, b: i64) -> i64 { if a < b { return a } else { return b } }\n" as *u8)
86 o = gg_cat(pb, o, "Buggy: func clamp1(x: i64) -> i64 { return x }\n" as *u8)
87 o = gg_cat(pb, o, "Fixed: func clamp1(x: i64) -> i64 { if x < 0 { return 0 } else if x > 1 { return 1 } else { return x } }\n" as *u8)
88 o = gg_cat(pb, o, "Buggy: func sgn(x: i64) -> i64 { return 0 }\n" as *u8)
89 o = gg_cat(pb, o, "Fixed: " as *u8)
90 return o
91}
92// run one generation. which=0 -> nsv_generate (raw), 1 -> gdx_generate (masked). Greedy.
93// pb/plen prompt; tx out buffer; mt meta. returns text length.
94static gg_pb: *u8
95static gg_plen: i64
96func gg_gen(which: i64, tx: *u8, mt: *i64) -> i64 {
97 let gp: *i64 = sys_mmap(16 * 8) as *i64
98 gp[0] = gg_pb as i64
99 gp[1] = gg_plen
100 gp[2] = GG_MAXNEW
101 gp[3] = 1
102 gp[4] = tx as i64
103 gp[5] = GG_OCAP
104 gp[6] = mt as i64
105 gp[7] = 0 - 1
106 gp[8] = 0
107 gp[9] = 0
108 gp[10] = 0
109 gp[11] = 0
110 gp[12] = 0
111 if which == 1 { return gdx_generate(gp) }
112 return nsv_generate(gp)
113}
114
115func main(argc: i64, argv: *i64) -> i64 {
116 gg_w("nx_gramdec gate -- NB10 grammar-constrained decode: automaton ruler + live mask teeth\n\n" as *u8)
117 gg_pass = 0
118 gg_total = 0
119 // --- automaton teeth (no model) ---
120 gg_tooth("accepts correct early-return fn" as *u8, gg_val("func sgn(x: i64) -> i64 { if x > 0 { return 1 } if x < 0 { return 0 - 1 } return 0 }" as *u8))
121 gg_tooth("accepts legal } else { form" as *u8, gg_val("func f(x: i64) -> i64 { if x > 0 { return 1 } else { return 0 } }" as *u8))
122 var r3: i64 = 0
123 if gg_val("func f(x: i64) -> i64 { if x > 0 { return 1 } else if x < 0 { return 2 } return 0 }" as *u8) == 0 { r3 = 1 }
124 gg_tooth("rejects else-if chain" as *u8, r3)
125 var r4: i64 = 0
126 if gg_val("func f(x: i64) -> i64 { return abs(x) }" as *u8) == 0 { r4 = 1 }
127 gg_tooth("rejects helper call abs()" as *u8, r4)
128 var r5: i64 = 0
129 if gg_val("func f(x: i64) -> i64 { return -x }" as *u8) == 0 { r5 = 1 }
130 gg_tooth("rejects unary minus on identifier" as *u8, r5)
131 gg_tooth("accepts negative literal return -1" as *u8, gg_val("func f(x: i64) -> i64 { if x < 0 { return -1 } return 1 }" as *u8))
132 var r7: i64 = 0
133 if gg_val("func f(x: i64) -> i64 { if x > 0 { return 1 }" as *u8) == 0 { r7 = 1 }
134 gg_tooth("rejects truncated fn (open brace)" as *u8, r7)
135 // string literal body: poke the quote byte (34) -- never a bare "" in source
136 let sb: *u8 = sys_mmap(256)
137 var so: i64 = 0
138 so = gg_cat(sb, so, "func f(x: i64) -> i64 { return " as *u8)
139 sb[so] = 34 as u8
140 so = so + 1
141 so = gg_cat(sb, so, "x" as *u8)
142 sb[so] = 34 as u8
143 so = so + 1
144 so = gg_cat(sb, so, " }" as *u8)
145 sb[so] = 0 as u8
146 var r8: i64 = 0
147 if gd_validate(sb, so) == 0 { r8 = 1 }
148 gg_tooth("rejects string literal in body" as *u8, r8)
149 // --- live model teeth ---
150 var mpath: *u8 = "/home/elderwesto/nx_stage/nx_15b_model.gguf" as *u8
151 if argc >= 2 { mpath = argv[1] as *u8 }
152 var probe: i64 = 0
153 if argc >= 3 { let pv: *u8 = argv[2] as *u8; if pv[0] == (112 as u8) { probe = 1 } }
154 let irc: i64 = nsv_init_i8(mpath)
155 if irc != 0 {
156 gg_w("model init FAILED -> live teeth cannot run\n" as *u8)
157 gg_tooth("live no-op equivalence" as *u8, 0)
158 gg_tooth("live mask-fires on bait" as *u8, 0)
159 gg_w("\nNX-GRAMDEC-GATE passed " as *u8)
160 gg_wn(gg_pass)
161 gg_w("/" as *u8)
162 gg_wn(gg_total)
163 gg_w(" verdict=RED\n" as *u8)
164 return 1
165 }
166 gg_pb = sys_mmap(4096)
167 let tx1: *u8 = sys_mmap(4096)
168 let tx2: *u8 = sys_mmap(4096)
169 let mt1: *i64 = sys_mmap(64) as *i64
170 let mt2: *i64 = sys_mmap(64) as *i64
171 // T9: no-op equivalence on the clean sgn prompt
172 gg_plen = gg_prompt_clean(gg_pb)
173 let l1: i64 = gg_gen(0, tx1, mt1)
174 let l2: i64 = gg_gen(1, tx2, mt2)
175 if probe == 1 {
176 gg_w("PROBE clean raw (" as *u8)
177 gg_wn(l1)
178 gg_w("B):\n" as *u8)
179 if l1 > 0 { sys_write(1, tx1, l1) }
180 gg_w("\nPROBE clean gdx (" as *u8)
181 gg_wn(l2)
182 gg_w("B, rej=" as *u8)
183 gg_wn(mt2[6])
184 gg_w(", fin=" as *u8)
185 gg_wn(mt2[7])
186 gg_w("):\n" as *u8)
187 if l2 > 0 { sys_write(1, tx2, l2) }
188 gg_w("\n" as *u8)
189 }
190 var eq: i64 = 0
191 if l2 > 0 { if l2 <= l1 {
192 var zi: i64 = 0
193 eq = 1
194 while zi < l2 { if tx2[zi] != tx1[zi] { eq = 0; zi = l2 } else { zi = zi + 1 } }
195 } }
196 var t9: i64 = 0
197 if eq == 1 { if mt2[6] == 0 { if mt2[7] == 1 { if gd_validate(tx2, l2) == 1 { t9 = 1 } } } }
198 gg_tooth("live no-op equivalence (prefix bit-exact, 0 rej, accept-stop)" as *u8, t9)
199 // T10: bait -- raw must emit else-if (vacuity guard); masked must not, with >=1 rejection
200 gg_plen = gg_prompt_bait(gg_pb)
201 let b1: i64 = gg_gen(0, tx1, mt1)
202 let b2: i64 = gg_gen(1, tx2, mt2)
203 if probe == 1 {
204 gg_w("PROBE bait raw (" as *u8)
205 gg_wn(b1)
206 gg_w("B):\n" as *u8)
207 if b1 > 0 { sys_write(1, tx1, b1) }
208 gg_w("\nPROBE bait gdx (" as *u8)
209 gg_wn(b2)
210 gg_w("B, rej=" as *u8)
211 gg_wn(mt2[6])
212 gg_w(", fin=" as *u8)
213 gg_wn(mt2[7])
214 gg_w("):\n" as *u8)
215 if b2 > 0 { sys_write(1, tx2, b2) }
216 gg_w("\n" as *u8)
217 }
218 var baited: i64 = 0
219 if gg_find(tx1, b1, "else if" as *u8, 0) >= 0 { baited = 1 }
220 var noesc: i64 = 0
221 if gg_find(tx2, b2, "else if" as *u8, 0) < 0 { noesc = 1 }
222 var t10: i64 = 0
223 if baited == 1 { if noesc == 1 { if mt2[6] >= 1 { if b2 > 0 { if gd_validate(tx2, b2) == 1 { t10 = 1 } } } } }
224 gg_tooth("live mask-fires on bait (raw baited, masked clean+valid, >=1 rej)" as *u8, t10)
225 gg_w("\nNX-GRAMDEC-GATE passed " as *u8)
226 gg_wn(gg_pass)
227 gg_w("/" as *u8)
228 gg_wn(gg_total)
229 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
230 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
231 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
232 let ctr__dry: *i64 = gv_ctr()
233 ctr__dry[0] = gg_pass
234 ctr__dry[1] = gg_total
235 let rc__dry: i64 = gv_verdict("GRAMDEC-GATE" as *u8, ctr__dry, "grammar-constrained decode: ruler sound, live mask load-bearing, no-op path bit-exact)" as *u8)
236 sys_exit_group(rc__dry)
237 return rc__dry
238}