code wiki / (root) / nx_mfrow.nx

nx_mfrow.nx source

↩ module page · 239 lines · 13023 B

1// nx_mfrow.nx -- UPDATE ONE ROW OF A TREECANON MANIFEST, AND NOTHING ELSE. 2// 3// WHY THIS EXISTS, measured 2026-08-16. The treecanon family has a generator (nx_treediff, nx_treehash), 4// two comparers (nx_treediverge, nx_hashdiverge) and a gate that refuses (nx_treecanon_gate). It has NO 5// surgical write. So when ONE file is converged across trees, the only sanctioned way to record it is to 6// REGENERATE THE WHOLE MANIFEST -- and the record is explicit that a whole-tree regeneration while a 7// sibling is mid-edit is the one action that blesses unreviewed bytes at scale. Measured the same day: 8// nx_treediverge reports 2,154 divergent paths, so that precondition is not merely risky, it is UNMET. 9// The result was a converged file that could not be recorded, and therefore an organ that could not be 10// rebuilt: nx_sov_build_run, laptop and NAS byte-identical, still refused by the canon gate. 11// ★A FAMILY WITH NO SURGICAL WRITE TURNS EVERY CORRECTION INTO A WHOLE-TREE REGENERATION, SO THE ONLY 12// SAFE-SIZED FIX IS THE ONE NOBODY CAN MAKE. 13// 14// SCOPE, deliberately narrow: one row, named by its relpath, in a manifest whose other bytes are 15// untouched. It does not scan a tree, does not compute a hash, and cannot invent a row. Recording a 16// convergence someone else proved is a DIFFERENT act from deciding one, and only the first belongs here. 17// license_tier: ORIGINAL Writes ONE named file, atomically. No hw writes (Rule 26). expect_exit: 0 18 19import "nx_gate_verdict.nx" 20import "nx_tool_run.nx" // tr_contains: the estate's substring primitive, not a fifth private copy 21 22const MFR_SP: i64 = 32 23const MFR_NL: i64 = 10 24const MFR_HEADROOM: i64 = 256 // output = input + this; a rewritten row can only grow by its own field widths 25 26func mfr_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 27func mfr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 28func mfr_n(v: i64) -> i64 { 29 let b: *u8 = sys_mmap(32) 30 let t: *u8 = sys_mmap(32) 31 if v == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 } 32 var m: i64 = v 33 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 34 var k: i64 = 0 35 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 36 var o: i64 = 0 37 while k > 0 { k = k - 1; b[o] = t[k]; o = o + 1 } 38 sys_write(1, b, o) 39 return 0 40} 41func mfr_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 } 42 43// Does buf[s,e) end with exactly this relpath as its LAST space-separated field? 44// The relpath is matched WHOLE: a suffix test would match nx_sov_build_run.nx against 45// _register_nx_sov_build_run.nx, and a manifest has thousands of near-identical names. 46func mfr_row_is(buf: *u8, s: i64, e: i64, rel: *u8) -> i64 { 47 var last: i64 = s 48 var i: i64 = s 49 while i < e { if buf[i] == (MFR_SP as u8) { last = i + 1 } i = i + 1 } 50 let rl: i64 = mfr_slen(rel) 51 if e - last != rl { return 0 } 52 var k: i64 = 0 53 while k < rl { if buf[last + k] != rel[k] { return 0 } k = k + 1 } 54 return 1 55} 56 57func mfr_spaces(buf: *u8, s: i64, e: i64) -> i64 { 58 var c: i64 = 0 59 var i: i64 = s 60 while i < e { if buf[i] == (MFR_SP as u8) { c = c + 1 } i = i + 1 } 61 return c 62} 63 64func mfr_put(dst: *u8, o: i64, s: *u8) -> i64 { 65 var i: i64 = 0 66 var oo: i64 = o 67 while s[i] != (0 as u8) { dst[oo] = s[i]; i = i + 1; oo = oo + 1 } 68 return oo 69} 70 71// ---- THE UPDATE ------------------------------------------------------------------------------------- 72// Returns rows matched. REFUSES (via the caller) on 0 or >1 -- see the laws at each site. 73func mfr_apply(path: *u8, rel: *u8, newsize: *u8, newhash: *u8) -> i64 { 74 let ln: *i64 = sys_mmap(16) as *i64 75 let buf: *u8 = sys_read_file(path, ln) 76 if (buf as i64) == 0 { mfr_w("NX-MFROW REFUSED: manifest unreadable -- " as *u8); mfr_w(path); mfr_w("\n" as *u8); return 0 - 1 } 77 let n: i64 = ln[0] 78 if n <= 0 { mfr_w("NX-MFROW REFUSED: manifest is EMPTY -- a rewriter that read nothing must not write anything\n" as *u8); return 0 - 1 } 79 80 // SIZED FROM THE INPUT, NOT GUESSED. sys_read_file gives the exact length, and a rewritten row can 81 // only grow by the width of the two fields being replaced, so input+HEADROOM is a derived bound and 82 // not a ceiling anyone has to tune. 83 let out: *u8 = sys_mmap(n + MFR_HEADROOM) 84 var o: i64 = 0 85 var rows: i64 = 0 86 var matched: i64 = 0 87 var badfmt: i64 = 0 88 var ls: i64 = 0 89 var i: i64 = 0 90 while i <= n { 91 var atend: i64 = 0 92 if i == n { atend = 1 } else { if buf[i] == (MFR_NL as u8) { atend = 1 } } 93 if atend == 1 { 94 if i > ls { 95 rows = rows + 1 96 if mfr_row_is(buf, ls, i, rel) == 1 { 97 matched = matched + 1 98 let nsp: i64 = mfr_spaces(buf, ls, i) 99 // FORMAT IS READ FROM THE ROW, NEVER ASSUMED. Two families share this directory: 100 // `<bytes> <relpath>` (nx_treediff) and `<sha> <bytes> <relpath>` (nx_treehash). 101 // Writing the wrong shape is how a comparer later parses ZERO rows and reports a 102 // confident CONVERGED -- the exact defect fixed in nx_treediverge the same day. 103 if nsp == 1 { 104 o = mfr_put(out, o, newsize) 105 out[o] = MFR_SP as u8; o = o + 1 106 o = mfr_put(out, o, rel) 107 } else { 108 if nsp == 2 { 109 if (newhash as i64) == 0 { badfmt = 1 } 110 else { 111 o = mfr_put(out, o, newhash) 112 out[o] = MFR_SP as u8; o = o + 1 113 o = mfr_put(out, o, newsize) 114 out[o] = MFR_SP as u8; o = o + 1 115 o = mfr_put(out, o, rel) 116 } 117 } else { badfmt = 1 } 118 } 119 } else { 120 var k: i64 = ls 121 while k < i { out[o] = buf[k]; o = o + 1; k = k + 1 } 122 } 123 } 124 if i < n { out[o] = MFR_NL as u8; o = o + 1 } 125 ls = i + 1 126 } 127 i = i + 1 128 } 129 130 mfr_w("NX-MFROW rows=" as *u8); mfr_n(rows) 131 mfr_w(" matched=" as *u8); mfr_n(matched) 132 mfr_w(" bytes_in=" as *u8); mfr_n(n) 133 mfr_w(" bytes_out=" as *u8); mfr_n(o) 134 mfr_w("\n" as *u8) 135 136 // ★A PATCH THAT CANNOT FAIL CANNOT BE TRUSTED TO HAVE APPLIED. A rewriter that finds nothing and 137 // writes the file back unchanged reports success for a no-op, which is how a correction silently 138 // does not happen. Zero matches is a REFUSAL, never a quiet pass. 139 if matched == 0 { mfr_w("NX-MFROW REFUSED: relpath not present in this manifest -- nothing was written\n" as *u8); return 0 } 140 // Ambiguity is a DIFFERENT defect and must not be silently resolved: a manifest holding two rows for 141 // one path has no single answer, and picking one would bless whichever came first. 142 if matched > 1 { mfr_w("NX-MFROW REFUSED: relpath appears more than once -- a registry with two rows for one path has no single answer; de-duplicate first. Nothing was written\n" as *u8); return 0 - 2 } 143 if badfmt == 1 { mfr_w("NX-MFROW REFUSED: the matched row is neither `<bytes> <relpath>` nor `<sha> <bytes> <relpath>`, or a hash row was given no hash. Nothing was written\n" as *u8); return 0 - 3 } 144 145 // ATOMIC: write a sibling temp then rename. A half-written manifest is worse than a stale one -- 146 // the canon gate would read a truncated registry and refuse every organ in the tree. 147 let tmp: *u8 = sys_mmap(512) 148 var t: i64 = mfr_put(tmp, 0, path) 149 t = mfr_put(tmp, t, ".mfrowtmp" as *u8) 150 tmp[t] = 0 as u8 151 let fd: i64 = sys_openat_wr(tmp, MODE_0644) 152 if fd < 0 { mfr_w("NX-MFROW REFUSED: cannot open temp for write; the manifest is untouched\n" as *u8); return 0 - 4 } 153 let wr: i64 = sys_write(fd, out, o) 154 sys_close(fd) 155 if wr != o { mfr_w("NX-MFROW REFUSED: short write to temp; the manifest is untouched\n" as *u8); return 0 - 5 } 156 sys_renameat(tmp, path) 157 mfr_w("NX-MFROW UPDATED " as *u8); mfr_w(path); mfr_w(" row=" as *u8); mfr_w(rel); mfr_w("\n" as *u8) 158 return 1 159} 160 161func mfr_selftest() -> i64 { 162 let ctr: *i64 = gv_ctr() 163 gv_head("nx_mfrow -- one row changes, every other byte survives" as *u8) 164 sys_mkdir("/tmp/nx_mfrow" as *u8, MODE_0755) 165 166 // 3-field (hash) fixture. The neighbour rows exist so "untouched" is a claim with witnesses. 167 let p3: *u8 = "/tmp/nx_mfrow/h.mf" as *u8 168 let f3: *u8 = "aaaa 111 a/one.nx\nbbbb 222 b/two.nx\ncccc 333 c/three.nx\n" as *u8 169 let fd3: i64 = sys_openat_wr(p3, MODE_0644) 170 sys_write(fd3, f3, mfr_slen(f3)); sys_close(fd3) 171 let r3: i64 = mfr_apply(p3, "b/two.nx" as *u8, "999" as *u8, "zzzz" as *u8) 172 gv_check("a 3-field hash row is rewritten and reports exactly one match", mfr_eq(r3, 1), ctr) 173 let l3: *i64 = sys_mmap(16) as *i64 174 let g3: *u8 = sys_read_file(p3, l3) 175 gv_check("the new hash and size are present", tr_contains(g3, l3[0], "zzzz 999 b/two.nx" as *u8), ctr) 176 gv_check("the row BEFORE it is untouched", tr_contains(g3, l3[0], "aaaa 111 a/one.nx" as *u8), ctr) 177 gv_check("the row AFTER it is untouched", tr_contains(g3, l3[0], "cccc 333 c/three.nx" as *u8), ctr) 178 gv_check("the OLD row is gone -- a rewriter that appends instead of replacing leaves two answers", mfr_eq(tr_contains(g3, l3[0], "bbbb 222 b/two.nx" as *u8), 0), ctr) 179 180 // 2-field (size) fixture -- the OTHER family, read from the row rather than assumed. 181 let p2: *u8 = "/tmp/nx_mfrow/s.mf" as *u8 182 let f2: *u8 = "111 a/one.nx\n222 b/two.nx\n" as *u8 183 let fd2: i64 = sys_openat_wr(p2, MODE_0644) 184 sys_write(fd2, f2, mfr_slen(f2)); sys_close(fd2) 185 let r2: i64 = mfr_apply(p2, "b/two.nx" as *u8, "888" as *u8, 0 as *u8) 186 gv_check("a 2-field size row is rewritten with no hash supplied", mfr_eq(r2, 1), ctr) 187 let l2: *i64 = sys_mmap(16) as *i64 188 let g2: *u8 = sys_read_file(p2, l2) 189 gv_check("the 2-field row keeps its shape: no phantom hash column appears", tr_contains(g2, l2[0], "888 b/two.nx" as *u8), ctr) 190 191 // NEG-CONTROLS. A rewriter that quietly does nothing is the defect this organ exists to avoid. 192 let rmiss: i64 = mfr_apply(p2, "nope/absent.nx" as *u8, "1" as *u8, 0 as *u8) 193 gv_check("neg-control-absent-relpath-REFUSES-rather-than-silently-rewriting-nothing", mfr_eq(rmiss, 0), ctr) 194 195 let pd: *u8 = "/tmp/nx_mfrow/d.mf" as *u8 196 let fdup: *u8 = "111 dup/x.nx\n222 dup/x.nx\n" as *u8 197 let fdd: i64 = sys_openat_wr(pd, MODE_0644) 198 sys_write(fdd, fdup, mfr_slen(fdup)); sys_close(fdd) 199 let rdup: i64 = mfr_apply(pd, "dup/x.nx" as *u8, "777" as *u8, 0 as *u8) 200 gv_check("neg-control-duplicate-relpath-REFUSES-rather-than-picking-the-first", mfr_eq(rdup, 0 - 2), ctr) 201 let ld: *i64 = sys_mmap(16) as *i64 202 let gd: *u8 = sys_read_file(pd, ld) 203 gv_check("and the ambiguous manifest is left EXACTLY as it was", tr_contains(gd, ld[0], "111 dup/x.nx" as *u8), ctr) 204 205 // A SUFFIX MATCH WOULD BE WRONG: thousands of manifest paths share tails. 206 let ps: *u8 = "/tmp/nx_mfrow/x.mf" as *u8 207 let fs2: *u8 = "111 a/build_run.nx\n222 a/nx_build_run.nx\n" as *u8 208 let fds: i64 = sys_openat_wr(ps, MODE_0644) 209 sys_write(fds, fs2, mfr_slen(fs2)); sys_close(fds) 210 let rs: i64 = mfr_apply(ps, "a/build_run.nx" as *u8, "555" as *u8, 0 as *u8) 211 let ls2: *i64 = sys_mmap(16) as *i64 212 let gs: *u8 = sys_read_file(ps, ls2) 213 gv_check("neg-control-a-LONGER-path-ending-in-the-same-text-is-NOT-matched", tr_contains(gs, ls2[0], "222 a/nx_build_run.nx" as *u8), ctr) 214 gv_check("and the intended row DID change, so the test is not passing by matching nothing", tr_contains(gs, ls2[0], "555 a/build_run.nx" as *u8), ctr) 215 216 return gv_verdict("nx_mfrow" as *u8, ctr, "one row changes, neighbours survive, and every ambiguity refuses" as *u8) 217} 218 219func main(argc: i64, argv: *i64) -> i64 { 220 if argc >= 2 { 221 let v: *u8 = argv[1] as *u8 222 if v[0] == (115 as u8) { let rc: i64 = mfr_selftest(); sys_exit(rc); return rc } 223 } 224 if argc < 4 { 225 mfr_w("usage: nx_mfrow <manifest> <relpath> <newsize> [newhash]\n" as *u8) 226 mfr_w(" nx_mfrow selftest\n" as *u8) 227 mfr_w(" Updates ONE row, named by its WHOLE relpath. Refuses on 0 matches, on >1, and on a row\n" as *u8) 228 mfr_w(" whose shape it does not recognise. Every other byte of the manifest is preserved.\n" as *u8) 229 mfr_w(" It does NOT hash or scan anything: supply the values something else already proved.\n" as *u8) 230 sys_exit(2) 231 return 2 232 } 233 var nh: *u8 = 0 as *u8 234 if argc >= 5 { nh = argv[4] as *u8 } 235 let r: i64 = mfr_apply(argv[1] as *u8, argv[2] as *u8, argv[3] as *u8, nh) 236 if r == 1 { sys_exit(0); return 0 } 237 sys_exit(1) 238 return 1 239}