code wiki / _hdl_build / nx_patch_guard.nx

nx_patch_guard.nx source

↩ module page · 179 lines · 8128 B

1// nx_patch_guard.nx -- F803 THE PATCH-CASCADE STRUCTURAL TOOTH (ecosystem-as-editor law, operator 2026-07-20). 2// Mechanizes CLAUDE rule-3: "if the second fix does not resolve it, STOP patching -- rewrite the function or 3// module from scratch with a clear understanding of the root cause." Patch-cascade was the editor coverage 4// board's LAST original GAP: a known failure mode of EVERY model (keep poking at a symptom, each patch 5// obscuring intent and adding regression traps) that was covered by process law ALONE -- no structural tooth. 6// This is the READ-ONLY verdict organ over the patch-ledger plane knowledge/store/patchledger- (seats append 7// rows via nx_store_put; SAME division as nx_debt_view over debt- and nx_route_diff over the live API: the 8// plane is data, the organ is the verdict). A seat calls `check <target>` BEFORE its next fix; N consecutive 9// patch-rows on that target since the last rewrite|gate row = REFUSE -> rewrite now. 10// nx_patch_guard check <target> [plane-prefix] -> VERDICT=OK (exit 0) | VERDICT=REFUSE (exit 3) 11// LEDGER ROW (appended via nx_store_put <prefix> put <actor> <id> <target> <kind> <session> <note>): 12// col0 id | col1 target | col2 kind (config|patch|rewrite|gate) | col3 session | col4 note 13// CONFIG row: id=0 target=__config__ kind=config note=<max-consecutive-patches integer> (rule-11: 14// the threshold is DATA, never a magic number in code; absent/unreadable config -> PG_DEFMAX, fail-safe). 15// A rewrite|gate row RESETS the counter -- that is the rule-3 escape hatch made mechanical: prove the rewrite 16// (or a GREEN gate) and the guard opens again. Enforcement-wiring into the nx_ws_cycle debt-gate = filed rung. 17// ENVELOPE (declared in output): 256KB plane read, 4096 rows scanned, 6 cols. Fixture gates prove correctness 18// NEVER scale -- the scale tooth lives in the gate plan (ark v1 lesson). 19// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 20import "nx_store_seed_lib.nx" 21import "nx_syscalls.nx" 22 23const PG_PREFIX: *u8 = "knowledge/store/patchledger-" as *u8 24const PG_PLANECAP: i64 = 262144 25const PG_SLACK: i64 = 4096 26const PG_NL: i64 = 10 27const PG_TAB: i64 = 9 28const PG_NCOLMAX: i64 = 8 29const PG_PAIR: i64 = 2 30const PG_SPB: i64 = 128 31const PG_MAXROWS: i64 = 4096 32const PG_DEFMAX: i64 = 2 33const PG_OUTCAP: i64 = 4096 34const PG_STDOUT: i64 = 1 35const PG_STDERR: i64 = 2 36const PG_C_TARGET: i64 = 1 37const PG_C_KIND: i64 = 2 38const PG_C_NOTE: i64 = 4 39const PG_NCOL: i64 = 5 40const PG_EXIT_USAGE: i64 = 2 41const PG_EXIT_REFUSE: i64 = 3 42const PG_ZERO: i64 = 48 43const PG_NINE: i64 = 57 44 45func pg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 46func pg_werr(s: *u8) -> i64 { sys_write(PG_STDERR, s, pg_slen(s)); return 0 } 47func pg_puts(b: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var j: i64 = 0; while s[j] != (0 as u8) { b[o] = s[j]; o = o + 1; j = j + 1 } return o } 48func pg_putsl(b: *u8, off: i64, q: *u8, a: i64, e: i64) -> i64 { var o: i64 = off; var i: i64 = a; while i < e { b[o] = q[i]; o = o + 1; i = i + 1 } return o } 49func pg_puti(b: *u8, off: i64, v: i64) -> i64 { 50 var o: i64 = off 51 var m: i64 = v 52 if m < 0 { b[o] = 45 as u8; o = o + 1; m = 0 - m } 53 let t: *u8 = sys_mmap(28) 54 var k: i64 = 0 55 if m == 0 { t[0] = PG_ZERO as u8; k = 1 } 56 while m > 0 { t[k] = (PG_ZERO + (m % 10)) as u8; m = m / 10; k = k + 1 } 57 var i: i64 = 0 58 while i < k { b[o] = t[k - 1 - i]; o = o + 1; i = i + 1 } 59 return o 60} 61// TAB-split one line [ls,le) into sp pairs; returns column count 62func pg_cols(q: *u8, ls: i64, le: i64, sp: *i64) -> i64 { 63 var c: i64 = 0 64 var p: i64 = ls 65 while c < PG_NCOLMAX { 66 var e: i64 = p 67 var s: i64 = 1 68 while s == 1 { if e >= le { s = 0 } else { if q[e] == (PG_TAB as u8) { s = 0 } else { e = e + 1 } } } 69 sp[c*PG_PAIR] = p 70 sp[c*PG_PAIR+1] = e 71 c = c + 1 72 if e >= le { return c } 73 p = e + 1 74 } 75 return c 76} 77// does span [a,b) equal NUL-terminated z? 78func pg_span_is(q: *u8, a: i64, b: i64, z: *u8) -> i64 { 79 let zn: i64 = pg_slen(z) 80 if b - a != zn { return 0 } 81 var i: i64 = 0 82 while i < zn { if q[a+i] != z[i] { return 0 } i = i + 1 } 83 return 1 84} 85// parse span [a,b) as a non-negative integer; -1 if no digits 86func pg_atoi_span(q: *u8, a: i64, b: i64) -> i64 { 87 var v: i64 = 0 88 var got: i64 = 0 89 var i: i64 = a 90 while i < b { 91 let c: i64 = q[i] as i64 92 if c >= PG_ZERO { if c <= PG_NINE { v = v * 10 + (c - PG_ZERO); got = 1 } } 93 i = i + 1 94 } 95 if got == 0 { return 0 - 1 } 96 return v 97} 98func main(argc: i64, argv: *i64) -> i64 { 99 if argc < 3 { 100 pg_werr("usage: nx_patch_guard check <target> [plane-prefix]\n" as *u8) 101 sys_exit(PG_EXIT_USAGE) 102 return PG_EXIT_USAGE 103 } 104 let verb: *u8 = argv[1] as *u8 105 let target: *u8 = argv[2] as *u8 106 var prefix: *u8 = PG_PREFIX 107 if argc > 3 { prefix = argv[3] as *u8 } 108 if verb[0] != (99 as u8) { 109 pg_werr("usage: nx_patch_guard check <target> [plane-prefix]\n" as *u8) 110 sys_exit(PG_EXIT_USAGE) 111 return PG_EXIT_USAGE 112 } 113 let q: *u8 = sys_mmap(PG_PLANECAP) 114 let qn: i64 = sts_load(prefix, q, PG_PLANECAP - PG_SLACK) 115 let sp: *i64 = sys_mmap(PG_SPB) as *i64 116 var maxp: i64 = PG_DEFMAX 117 var consec: i64 = 0 118 var rows: i64 = 0 119 var seen: i64 = 0 120 var scanned: i64 = 0 121 var i: i64 = 0 122 while i < qn { 123 var le: i64 = i 124 var s: i64 = 1 125 while s == 1 { if le >= qn { s = 0 } else { if q[le] == (PG_NL as u8) { s = 0 } else { le = le + 1 } } } 126 if le > i { 127 if scanned < PG_MAXROWS { 128 let nc: i64 = pg_cols(q, i, le, sp) 129 if nc >= PG_NCOL { 130 rows = rows + 1 131 let ts: i64 = sp[PG_C_TARGET*PG_PAIR] 132 let te: i64 = sp[PG_C_TARGET*PG_PAIR+1] 133 if pg_span_is(q, ts, te, "__config__" as *u8) == 1 { 134 let cv: i64 = pg_atoi_span(q, sp[PG_C_NOTE*PG_PAIR], sp[PG_C_NOTE*PG_PAIR+1]) 135 if cv > 0 { maxp = cv } 136 } else { 137 if pg_span_is(q, ts, te, target) == 1 { 138 seen = seen + 1 139 let ks: i64 = sp[PG_C_KIND*PG_PAIR] 140 let ke: i64 = sp[PG_C_KIND*PG_PAIR+1] 141 if pg_span_is(q, ks, ke, "patch" as *u8) == 1 { consec = consec + 1 } 142 if pg_span_is(q, ks, ke, "rewrite" as *u8) == 1 { consec = 0 } 143 if pg_span_is(q, ks, ke, "gate" as *u8) == 1 { consec = 0 } 144 } 145 } 146 } 147 scanned = scanned + 1 148 } 149 } 150 i = le + 1 151 } 152 let out: *u8 = sys_mmap(PG_OUTCAP) 153 var o: i64 = 0 154 o = pg_puts(out, o, "PATCH-GUARD target=" as *u8) 155 o = pg_puts(out, o, target) 156 o = pg_puts(out, o, " consecutive_patches=" as *u8) 157 o = pg_puti(out, o, consec) 158 o = pg_puts(out, o, " max=" as *u8) 159 o = pg_puti(out, o, maxp) 160 o = pg_puts(out, o, " target_rows=" as *u8) 161 o = pg_puti(out, o, seen) 162 o = pg_puts(out, o, " ledger_rows=" as *u8) 163 o = pg_puti(out, o, rows) 164 o = pg_puts(out, o, " (envelope: 4096 rows scanned, 256KB plane, 5-col; threshold is a CONFIG row not code)\n" as *u8) 165 if consec >= maxp { 166 o = pg_puts(out, o, "VERDICT=REFUSE rule-3: " as *u8) 167 o = pg_puti(out, o, consec) 168 o = pg_puts(out, o, " consecutive patches on this target with no rewrite or GREEN gate between them. STOP patching -- rewrite the function or module from a clear root-cause understanding, then append a rewrite row to reopen the guard.\n" as *u8) 169 sys_write(PG_STDOUT, out, o) 170 sys_exit(PG_EXIT_REFUSE) 171 return PG_EXIT_REFUSE 172 } 173 o = pg_puts(out, o, "VERDICT=OK patch permitted, " as *u8) 174 o = pg_puti(out, o, maxp - consec) 175 o = pg_puts(out, o, " remaining before rule-3 requires a rewrite.\n" as *u8) 176 sys_write(PG_STDOUT, out, o) 177 sys_exit(0) 178 return 0 179}