code wiki / _hdl_build / nx_gate_anchor_edit.nx
nx_gate_anchor_edit.nx source
↩ module page · 249 lines · 10237 B
1// nx_gate_anchor_edit.nx -- THE MECHANICAL HALF OF THE D001 ANCHOR RUNG (seq585; D001-B lane 2026-07-31).
2//
3// nx_gate_migrate is deliberately a VERIFIER and NEVER an auto-editor, so that it can never mangle 1918
4// bespoke gates. That is the right call -- but it leaves the ~953 unjudgeable gates with no mechanical EDIT
5// step, and an edit-per-gate routed through a session context does not scale to a 1057-gate lane. This organ
6// is that missing step. The division of labour is PRESERVED, not weakened: THE EDITOR PROPOSES A CANDIDATE
7// FILE, THE VERIFIER (nx_gate_migrate anchor) REMAINS THE SOLE AUTHORITY ON WHETHER IT MAY BE COMMITTED.
8// This organ never writes a gate in place -- only ever a separate candidate path -- so its blast radius is
9// bounded BY CONSTRUCTION, not by promise (rule 26 posture).
10//
11// THE TRANSFORM (narrow by construction; the local awk v4.x failures are encoded here as REFUSALS, not
12// hopes). Insert verdict= immediately before a GREEN or RED token, but ONLY where ALL of these hold:
13// (a) the line is NOT a comment (first non-blank bytes are not //). A mangled comment is invisible to a
14// behaviour-preserving oracle -- which is exactly how MEASURED -> MEASUverdict=RED shipped locally.
15// (b) the line ALSO contains sys_exit( or return -- the verdict line is the one that decides the exit.
16// (c) the token is STANDALONE: neither neighbouring byte is [A-Za-z0-9_], so MEASURED / RECOVERED /
17// TEXTURED can never be glued mid-word (MEASURED literally contains RED at index 5).
18// (d) the token is not ALREADY preceded by verdict= -- idempotent (rule 10), so re-runs are no-ops.
19// Every other byte is copied VERBATIM.
20//
21// Exit codes are distinct so a batch driver can branch without parsing prose:
22// 0 = candidate written 5 = NOEDIT (nothing matched -> hand-treat; never a silent success)
23// 2 = usage 4 = I/O error
24// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
25import "nx_syscalls.nx"
26import "nx_estr.nx"
27
28const AE_CAP: i64 = 1048576
29const AE_MODE: i64 = 0x1a4
30const AE_USAGE: i64 = 2
31const AE_IOERR: i64 = 4
32const AE_NOEDIT: i64 = 5
33const AE_SLASH: i64 = 47
34const AE_SPACE: i64 = 32
35const AE_TABCH: i64 = 9
36const AE_ANCHLEN: i64 = 8
37
38// [A-Za-z0-9_] -- the identifier alphabet. A GREEN/RED occurrence flanked by one of these is part of a
39// LONGER word and must never be touched.
40func ae_idch(c: i64) -> i64 {
41 var r: i64 = 0
42 if c >= 48 { if c <= 57 { r = 1 } }
43 if c >= 65 { if c <= 90 { r = 1 } }
44 if c >= 97 { if c <= 122 { r = 1 } }
45 if c == 95 { r = 1 }
46 return r
47}
48
49func ae_read(path: *u8, buf: *u8, cap: i64) -> i64 {
50 let fd: i64 = sys_openat_rd(path)
51 if fd < 0 { return 0 - 1 }
52 var n: i64 = 0
53 var go: i64 = 1
54 while go == 1 {
55 if n >= cap { go = 0 } else {
56 let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n)
57 if r <= 0 { go = 0 } else { n = n + r }
58 }
59 }
60 sys_close(fd)
61 return n
62}
63
64func ae_write(path: *u8, buf: *u8, n: i64) -> i64 {
65 let fd: i64 = sys_openat_wr(path, AE_MODE)
66 if fd < 0 { return 0 - 1 }
67 var w: i64 = 0
68 var go: i64 = 1
69 while go == 1 {
70 if w >= n { go = 0 } else {
71 let r: i64 = sys_write(fd, ((buf as i64) + w) as *u8, n - w)
72 if r <= 0 { go = 0 } else { w = w + r }
73 }
74 }
75 sys_close(fd)
76 var rc: i64 = 0
77 if w != n { rc = 0 - 1 }
78 return rc
79}
80
81// literal match of s (length sl) at buf[i], bounded by n
82func ae_at(buf: *u8, n: i64, i: i64, s: *u8, sl: i64) -> i64 {
83 var r: i64 = 1
84 if i + sl > n { r = 0 } else {
85 var k: i64 = 0
86 while k < sl { if buf[i+k] != s[k] { r = 0; k = sl } else { k = k + 1 } }
87 }
88 return r
89}
90
91// does the half-open line [a,b) contain needle?
92func ae_line_has(buf: *u8, a: i64, b: i64, s: *u8) -> i64 {
93 let sl: i64 = es_len(s)
94 var r: i64 = 0
95 var i: i64 = a
96 while i < b {
97 if ae_at(buf, b, i, s, sl) == 1 { r = 1; i = b } else { i = i + 1 }
98 }
99 return r
100}
101
102// is [a,b) a comment line? (first non-blank bytes are //)
103func ae_is_comment(buf: *u8, a: i64, b: i64) -> i64 {
104 var i: i64 = a
105 var go: i64 = 1
106 while go == 1 {
107 if i >= b { go = 0 } else {
108 let c: i64 = buf[i] as i64
109 if c == AE_SPACE { i = i + 1 } else { if c == AE_TABCH { i = i + 1 } else { go = 0 } }
110 }
111 }
112 var r: i64 = 0
113 if i + 1 < b { if buf[i] == (AE_SLASH as u8) { if buf[i+1] == (AE_SLASH as u8) { r = 1 } } }
114 return r
115}
116
117// Emit line [a,b) into out at offset o, inserting verdict= before qualifying tokens. nedit[0] += insertions.
118func ae_emit(buf: *u8, a: i64, b: i64, out: *u8, o: i64, nedit: *i64) -> i64 {
119 var p: i64 = o
120 // Gate the WHOLE LINE first: comments are never edited, and only the line that decides the exit is.
121 var elig: i64 = 0
122 if ae_is_comment(buf, a, b) == 0 {
123 if ae_line_has(buf, a, b, "sys_exit(" as *u8) == 1 { elig = 1 }
124 if ae_line_has(buf, a, b, "return " as *u8) == 1 { elig = 1 }
125 }
126 var i: i64 = a
127 while i < b {
128 var ins: i64 = 0
129 if elig == 1 {
130 var tl: i64 = 0
131 if ae_at(buf, b, i, "GREEN" as *u8, 5) == 1 { tl = 5 }
132 if ae_at(buf, b, i, "RED" as *u8, 3) == 1 { tl = 3 }
133 if tl > 0 {
134 var ok: i64 = 1
135 if i > a { if ae_idch(buf[i-1] as i64) == 1 { ok = 0 } }
136 if i + tl < b { if ae_idch(buf[i+tl] as i64) == 1 { ok = 0 } }
137 if i >= a + AE_ANCHLEN { if ae_at(buf, b, i - AE_ANCHLEN, "verdict=" as *u8, AE_ANCHLEN) == 1 { ok = 0 } }
138 if ok == 1 { ins = 1 }
139 }
140 }
141 if ins == 1 { p = es_cat(out, p, "verdict=" as *u8); nedit[0] = nedit[0] + 1 }
142 out[p] = buf[i]
143 p = p + 1
144 i = i + 1
145 }
146 return p
147}
148
149// whole-buffer transform: split on LF, emit each line (the LF is carried inside the line span)
150func ae_transform(buf: *u8, n: i64, out: *u8, nedit: *i64) -> i64 {
151 var o: i64 = 0
152 var ls: i64 = 0
153 var i: i64 = 0
154 while i < n {
155 if buf[i] == (10 as u8) { o = ae_emit(buf, ls, i + 1, out, o, nedit); ls = i + 1 }
156 i = i + 1
157 }
158 if ls < n { o = ae_emit(buf, ls, n, out, o, nedit) }
159 return o
160}
161
162func ae_t(src: *u8, want: *u8, name: *u8, pass: *i64, tot: *i64) -> i64 {
163 let n: i64 = es_len(src)
164 let out: *u8 = sys_mmap(AE_CAP)
165 let ne: *i64 = sys_mmap(16) as *i64
166 ne[0] = 0
167 let o: i64 = ae_transform(src, n, out, ne)
168 var ok: i64 = 1
169 let wl: i64 = es_len(want)
170 if o != wl { ok = 0 } else {
171 var i: i64 = 0
172 while i < o { if out[i] != want[i] { ok = 0; i = o } else { i = i + 1 } }
173 }
174 tot[0] = tot[0] + 1
175 if ok == 1 { pass[0] = pass[0] + 1; es_puts(" [PASS] " as *u8) } else { es_puts(" [FAIL] " as *u8) }
176 es_puts(name)
177 es_puts("\n" as *u8)
178 return ok
179}
180
181// Hermetic: synthetic buffers only, never writes into the shared runtime tree (the fsops-gate lesson).
182func ae_selftest() -> i64 {
183 let pass: *i64 = sys_mmap(16) as *i64
184 let tot: *i64 = sys_mmap(16) as *i64
185 pass[0] = 0
186 tot[0] = 0
187 es_puts("nx_gate_anchor_edit selftest -- the D001 anchor transform\n\n" as *u8)
188 ae_t(" x GREEN y sys_exit(0)\n" as *u8, " x verdict=GREEN y sys_exit(0)\n" as *u8, "T1 standalone GREEN on an exit line IS anchored" as *u8, pass, tot)
189 ae_t(" x RED sys_exit(1)\n" as *u8, " x verdict=RED sys_exit(1)\n" as *u8, "T2 standalone RED on an exit line IS anchored" as *u8, pass, tot)
190 ae_t(" MEASURED sys_exit(0)\n" as *u8, " MEASURED sys_exit(0)\n" as *u8, "T3 MEASURED (contains RED at idx 5) UNTOUCHED -- the word-gluing bug that shipped locally" as *u8, pass, tot)
191 ae_t(" // GREEN sys_exit(0)\n" as *u8, " // GREEN sys_exit(0)\n" as *u8, "T4 comment line UNTOUCHED -- a mangled comment is invisible to the oracle" as *u8, pass, tot)
192 ae_t(" x verdict=GREEN sys_exit(0)\n" as *u8, " x verdict=GREEN sys_exit(0)\n" as *u8, "T5 already-anchored is IDEMPOTENT (rule 10)" as *u8, pass, tot)
193 ae_t(" x GREEN y\n" as *u8, " x GREEN y\n" as *u8, "T6 GREEN on a NON-exit line UNTOUCHED -- only the deciding line is anchored" as *u8, pass, tot)
194 ae_t(" RECOVERED sys_exit(1)\n" as *u8, " RECOVERED sys_exit(1)\n" as *u8, "T7 RECOVERED UNTOUCHED (second real gluing casualty)" as *u8, pass, tot)
195 es_puts("\nNX-ANCHOR-EDIT-GATE passed " as *u8)
196 es_putn(pass[0])
197 es_puts("/" as *u8)
198 es_putn(tot[0])
199 var rc: i64 = 1
200 if pass[0] == tot[0] { rc = 0; es_puts(" verdict=GREEN (transform is narrow: gluing, comments, non-exit lines and re-runs all refused)\n" as *u8) } else { es_puts(" verdict=RED\n" as *u8) }
201 return rc
202}
203
204func main(argc: i64, argv: *i64) -> i64 {
205 if argc < 2 {
206 es_puts("usage: nx_gate_anchor_edit <src.nx> <candidate-out.nx> | selftest\n" as *u8)
207 sys_exit(AE_USAGE)
208 return AE_USAGE
209 }
210 let a1: *u8 = argv[1] as *u8
211 if ae_at(a1, es_len(a1), 0, "selftest" as *u8, 8) == 1 {
212 let src: i64 = ae_selftest()
213 sys_exit(src)
214 return src
215 }
216 if argc < 3 {
217 es_puts("usage: nx_gate_anchor_edit <src.nx> <candidate-out.nx> | selftest\n" as *u8)
218 sys_exit(AE_USAGE)
219 return AE_USAGE
220 }
221 let buf: *u8 = sys_mmap(AE_CAP)
222 let n: i64 = ae_read(a1, buf, AE_CAP)
223 if n <= 0 {
224 es_puts("ANCHOR-EDIT-FAIL unreadable-src\n" as *u8)
225 sys_exit(AE_IOERR)
226 return AE_IOERR
227 }
228 let out: *u8 = sys_mmap(AE_CAP)
229 let ne: *i64 = sys_mmap(16) as *i64
230 ne[0] = 0
231 let o: i64 = ae_transform(buf, n, out, ne)
232 if ne[0] == 0 {
233 es_puts("ANCHOR-EDIT NOEDIT no qualifying GREEN/RED token -- hand-treat this gate\n" as *u8)
234 sys_exit(AE_NOEDIT)
235 return AE_NOEDIT
236 }
237 if ae_write(argv[2] as *u8, out, o) != 0 {
238 es_puts("ANCHOR-EDIT-FAIL unwritable-candidate\n" as *u8)
239 sys_exit(AE_IOERR)
240 return AE_IOERR
241 }
242 es_puts("ANCHOR-EDIT CANDIDATE-WRITTEN edits=" as *u8)
243 es_putn(ne[0])
244 es_puts(" bytes=" as *u8)
245 es_putn(o)
246 es_puts(" (nx_gate_migrate anchor is the judge -- this is only a proposal)\n" as *u8)
247 sys_exit(0)
248 return 0
249}