code wiki / _hdl_build / nx_patch_guard.nx

nx_patch_guard.nx source

↩ module page · 176 lines · 7956 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} 61func pg_cols(q: *u8, ls: i64, le: i64, sp: *i64) -> i64 { 62 var c: i64 = 0 63 var p: i64 = ls 64 while c < PG_NCOLMAX { 65 var e: i64 = p 66 var s: i64 = 1 67 while s == 1 { if e >= le { s = 0 } else { if q[e] == (PG_TAB as u8) { s = 0 } else { e = e + 1 } } } 68 sp[c*PG_PAIR] = p 69 sp[c*PG_PAIR+1] = e 70 c = c + 1 71 if e >= le { return c } 72 p = e + 1 73 } 74 return c 75} 76func pg_span_is(q: *u8, a: i64, b: i64, z: *u8) -> i64 { 77 let zn: i64 = pg_slen(z) 78 if b - a != zn { return 0 } 79 var i: i64 = 0 80 while i < zn { if q[a+i] != z[i] { return 0 } i = i + 1 } 81 return 1 82} 83func pg_atoi_span(q: *u8, a: i64, b: i64) -> i64 { 84 var v: i64 = 0 85 var got: i64 = 0 86 var i: i64 = a 87 while i < b { 88 let c: i64 = q[i] as i64 89 if c >= PG_ZERO { if c <= PG_NINE { v = v * 10 + (c - PG_ZERO); got = 1 } } 90 i = i + 1 91 } 92 if got == 0 { return 0 - 1 } 93 return v 94} 95func main(argc: i64, argv: *i64) -> i64 { 96 if argc < 3 { 97 pg_werr("usage: nx_patch_guard check <target> [plane-prefix]\n" as *u8) 98 sys_exit(PG_EXIT_USAGE) 99 return PG_EXIT_USAGE 100 } 101 let verb: *u8 = argv[1] as *u8 102 let target: *u8 = argv[2] as *u8 103 var prefix: *u8 = PG_PREFIX 104 if argc > 3 { prefix = argv[3] as *u8 } 105 if verb[0] != (99 as u8) { 106 pg_werr("usage: nx_patch_guard check <target> [plane-prefix]\n" as *u8) 107 sys_exit(PG_EXIT_USAGE) 108 return PG_EXIT_USAGE 109 } 110 let q: *u8 = sys_mmap(PG_PLANECAP) 111 let qn: i64 = sts_load(prefix, q, PG_PLANECAP - PG_SLACK) 112 let sp: *i64 = sys_mmap(PG_SPB) as *i64 113 var maxp: i64 = PG_DEFMAX 114 var consec: i64 = 0 115 var rows: i64 = 0 116 var seen: i64 = 0 117 var scanned: i64 = 0 118 var i: i64 = 0 119 while i < qn { 120 var le: i64 = i 121 var s: i64 = 1 122 while s == 1 { if le >= qn { s = 0 } else { if q[le] == (PG_NL as u8) { s = 0 } else { le = le + 1 } } } 123 if le > i { 124 if scanned < PG_MAXROWS { 125 let nc: i64 = pg_cols(q, i, le, sp) 126 if nc >= PG_NCOL { 127 rows = rows + 1 128 let ts: i64 = sp[PG_C_TARGET*PG_PAIR] 129 let te: i64 = sp[PG_C_TARGET*PG_PAIR+1] 130 if pg_span_is(q, ts, te, "__config__" as *u8) == 1 { 131 let cv: i64 = pg_atoi_span(q, sp[PG_C_NOTE*PG_PAIR], sp[PG_C_NOTE*PG_PAIR+1]) 132 if cv > 0 { maxp = cv } 133 } else { 134 if pg_span_is(q, ts, te, target) == 1 { 135 seen = seen + 1 136 let ks: i64 = sp[PG_C_KIND*PG_PAIR] 137 let ke: i64 = sp[PG_C_KIND*PG_PAIR+1] 138 if pg_span_is(q, ks, ke, "patch" as *u8) == 1 { consec = consec + 1 } 139 if pg_span_is(q, ks, ke, "rewrite" as *u8) == 1 { consec = 0 } 140 if pg_span_is(q, ks, ke, "gate" as *u8) == 1 { consec = 0 } 141 } 142 } 143 } 144 scanned = scanned + 1 145 } 146 } 147 i = le + 1 148 } 149 let out: *u8 = sys_mmap(PG_OUTCAP) 150 var o: i64 = 0 151 o = pg_puts(out, o, "PATCH-GUARD target=" as *u8) 152 o = pg_puts(out, o, target) 153 o = pg_puts(out, o, " consecutive_patches=" as *u8) 154 o = pg_puti(out, o, consec) 155 o = pg_puts(out, o, " max=" as *u8) 156 o = pg_puti(out, o, maxp) 157 o = pg_puts(out, o, " target_rows=" as *u8) 158 o = pg_puti(out, o, seen) 159 o = pg_puts(out, o, " ledger_rows=" as *u8) 160 o = pg_puti(out, o, rows) 161 o = pg_puts(out, o, " (envelope: 4096 rows scanned, 256KB plane, 5-col; threshold is a CONFIG row not code)\n" as *u8) 162 if consec >= maxp { 163 o = pg_puts(out, o, "VERDICT=REFUSE rule-3: " as *u8) 164 o = pg_puti(out, o, consec) 165 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) 166 sys_write(PG_STDOUT, out, o) 167 sys_exit(PG_EXIT_REFUSE) 168 return PG_EXIT_REFUSE 169 } 170 o = pg_puts(out, o, "VERDICT=OK patch permitted, " as *u8) 171 o = pg_puti(out, o, maxp - consec) 172 o = pg_puts(out, o, " remaining before rule-3 requires a rewrite.\n" as *u8) 173 sys_write(PG_STDOUT, out, o) 174 sys_exit(0) 175 return 0 176}