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}