code wiki / (root) / nx_sov.nx

nx_sov.nx source

↩ module page · 304 lines · 12189 B

1// nx_sov.nx -- THE STANDARD SOVEREIGN DATA CLI (operator 2026-07-16: "this happens a lot -- make 2// writing nishi ecosystem formats THE STANDARD, integrated into our mcp/apis, interoperable with 3// 3rd party"). Root cause of the recurring no-TSV violations: nx_sov_ledger is a LIBRARY (needs an 4// organ authored) while `cat > x.tsv` is one command -- so sessions under pressure take the flat 5// path. THIS organ makes the sovereign path the one-command path: 6// put <prefix> <key> <value> write a string value (latest-wins) 7// put-file <prefix> <key> <file> write a file's bytes as the value (binary-safe, <=1MiB) 8// get <prefix> <key> print the latest value 9// has <prefix> <key> exit 0 present / 1 absent 10// import <prefix> <tsvfile> INTEROP IN: key<TAB>value rows -> sovereign store, and 11// writes the __ids__ index (newline-joined keys) so 12// nx_memory `index` / export can enumerate 13// export <prefix> <outfile> INTEROP OUT: __ids__ index -> key<TAB>value TSV at the 14// BOUNDARY (a DERIVED VIEW for 3rd parties, never the store) 15// The MCP surface: nx_memory (sibling, S17) already serves READS (stores/get/history/index) over 16// MCP; its put/tombstone write-cap increment will front THIS same store -- one substrate, CLI + 17// MCP two doors. Store = seg_store via nx_sov_ledger (sov_put/sov_get/sov_has). license_tier: ORIGINAL 18import "nx_sov_ledger.nx" 19import "nx_lib_std.nx" 20 21const NXSOV_CAP: i64 = 1048576 22 23func nxsov_read(path: *u8, buf: *u8, cap: i64) -> i64 { 24 let fd: i64 = sys_openat_rd(path) 25 if fd < 0 { return 0 - 1 } 26 var o: i64 = 0 27 var go: i64 = 1 28 while go == 1 { 29 let rem: i64 = cap - 1 - o 30 if rem <= 0 { go = 0 } 31 if go == 1 { 32 let q: *u8 = buf + o 33 let r: i64 = sys_read(fd, q, rem) 34 if r <= 0 { go = 0 } 35 if r > 0 { o = o + r } 36 } 37 } 38 sys_close(fd) 39 buf[o] = 0 as u8 40 return o 41} 42 43// import: parse key<TAB>value lines -> sov_put each; build the __ids__ index (newline-joined keys). 44func nxsov_import(prefix: *u8, tsvfile: *u8) -> i64 { 45 let buf: *u8 = sys_mmap(NXSOV_CAP) as *u8 46 let n: i64 = nxsov_read(tsvfile, buf, NXSOV_CAP) 47 if n <= 0 { std_putln("NXSOV import: unreadable/empty input" as *u8); return 1 } 48 let key: *u8 = sys_mmap(512) as *u8 49 let ids: *u8 = sys_mmap(NXSOV_CAP) as *u8 50 var ido: i64 = 0 51 var rows: i64 = 0 52 var i: i64 = 0 53 while i < n { 54 var e: i64 = i 55 var sc: i64 = 1 56 while sc == 1 { 57 if e >= n { sc = 0 } 58 if sc == 1 { if buf[e] == (10 as u8) { sc = 0 } else { e = e + 1 } } 59 } 60 // split at first TAB; skip comment (35) / blank lines 61 if e > i { 62 if buf[i] != (35 as u8) { 63 var t: i64 = i 64 var found: i64 = 0 65 while t < e { 66 if buf[t] == (9 as u8) { found = 1; t = e } else { t = t + 1 } 67 } 68 if found == 1 { 69 var tt: i64 = i 70 while buf[tt] != (9 as u8) { tt = tt + 1 } 71 let kl: i64 = tt - i 72 if kl > 0 && kl < 500 { 73 var k: i64 = 0 74 while k < kl { key[k] = buf[i + k]; k = k + 1 } 75 key[kl] = 0 as u8 76 let vs: i64 = tt + 1 77 let vl: i64 = e - vs 78 let vp: *u8 = buf + vs 79 sov_put(prefix, key, vp, vl) 80 // append key to the ids index 81 k = 0 82 while k < kl { ids[ido] = key[k]; ido = ido + 1; k = k + 1 } 83 ids[ido] = 10 as u8 84 ido = ido + 1 85 rows = rows + 1 86 } 87 } 88 } 89 } 90 i = e + 1 91 } 92 if rows > 0 { sov_put(prefix, "__ids__" as *u8, ids, ido) } 93 std_puts("NXSOV imported rows=" as *u8) 94 std_pdec(rows) 95 std_puts(" -> " as *u8) 96 std_putln(prefix) 97 if rows > 0 { return 0 } 98 return 1 99} 100 101// export: __ids__ index -> key<TAB>value TSV (a DERIVED interop view at the boundary). 102func nxsov_export(prefix: *u8, outfile: *u8) -> i64 { 103 let ids: *u8 = sys_mmap(NXSOV_CAP) as *u8 104 let idn: i64 = sov_get_copy(prefix, "__ids__" as *u8, ids, NXSOV_CAP) 105 if idn <= 0 { std_putln("NXSOV export: no __ids__ index (import or maintain one first)" as *u8); return 1 } 106 let key: *u8 = sys_mmap(512) as *u8 107 let val: *u8 = sys_mmap(NXSOV_CAP) as *u8 108 let fd: i64 = sys_openat_wr(outfile, 420) 109 if fd < 0 { std_putln("NXSOV export: cannot open outfile" as *u8); return 1 } 110 var rows: i64 = 0 111 var i: i64 = 0 112 while i < idn { 113 var e: i64 = i 114 var sc: i64 = 1 115 while sc == 1 { 116 if e >= idn { sc = 0 } 117 if sc == 1 { if ids[e] == (10 as u8) { sc = 0 } else { e = e + 1 } } 118 } 119 let kl: i64 = e - i 120 if kl > 0 && kl < 500 { 121 var k: i64 = 0 122 while k < kl { key[k] = ids[i + k]; k = k + 1 } 123 key[kl] = 0 as u8 124 let vn: i64 = sov_get_copy(prefix, key, val, NXSOV_CAP) 125 if vn >= 0 { 126 sys_write(fd, key, kl) 127 let tabc: *u8 = sys_mmap(4) as *u8 128 tabc[0] = 9 as u8 129 sys_write(fd, tabc, 1) 130 if vn > 0 { sys_write(fd, val, vn) } 131 tabc[0] = 10 as u8 132 sys_write(fd, tabc, 1) 133 rows = rows + 1 134 } 135 } 136 i = e + 1 137 } 138 sys_close(fd) 139 std_puts("NXSOV exported rows=" as *u8) 140 std_pdec(rows) 141 std_puts(" -> " as *u8) 142 std_putln(outfile) 143 std_putln("(derived interop view; the sovereign store remains the source of truth)" as *u8) 144 return 0 145} 146 147// fsck: crash-robustness audit (rung from the 2026-07-16 seg_store exoneration arc). The reader's 148// record walk (ss_scan_seglist) has NO bounds/kind validation, so a torn .docs (killed writer, 149// partial disk) would silently desync and serve garbage. This verb makes torn state VISIBLE: 150// for every manifest segment, re-walk its records with full validation -- kind must be 1|2, key/value 151// lengths must stay in-bounds -- and report the first corruption offset. Exit 0 clean / 1 torn. 152func nxsov_fsck(prefix: *u8) -> i64 { 153 let sp: *i64 = sys_mmap(8) as *i64 154 let ns: i64 = ss_manifest_dyn(prefix, sp) 155 if ns <= 0 { std_putln("NXSOV fsck: no manifest / empty store" as *u8); return 0 } 156 let segs: *i64 = sp[0] as *i64 157 var badsegs: i64 = 0 158 var recs: i64 = 0 159 var s: i64 = 0 160 while s < ns { 161 let path: *u8 = sys_mmap(512) as *u8 162 var o: i64 = 0 163 o = ss_cat(path, o, prefix) 164 o = ss_cat(path, o, segs[s] as *u8) 165 o = ss_cat(path, o, ".docs" as *u8) 166 path[o] = 0 as u8 167 let szp: *i64 = sys_mmap(16) as *i64 168 let b: *u8 = ss_readall(path, szp) 169 let sz: i64 = szp[0] 170 if sz < 0 { 171 badsegs = badsegs + 1 172 std_puts("NXSOV fsck MISSING " as *u8) 173 std_putln(path) 174 } 175 if sz >= 0 { 176 var bad: i64 = 0 177 var i: i64 = 0 178 while i < sz { 179 if i + 9 > sz { bad = 1 } 180 if bad == 0 { 181 let kind: i64 = b[i] as i64 182 if kind != 1 && kind != 2 { bad = 1 } 183 if bad == 0 { 184 let kl: i64 = ss_r32(b, i + 1) 185 if kl <= 0 { bad = 1 } 186 if bad == 0 { if i + 5 + kl + 4 > sz { bad = 1 } } 187 if bad == 0 { 188 let vl: i64 = ss_r32(b, i + 5 + kl) 189 if vl < 0 { bad = 1 } 190 if bad == 0 { if i + 5 + kl + 4 + vl > sz { bad = 1 } } 191 if bad == 0 { recs = recs + 1; i = i + 5 + kl + 4 + vl } 192 } 193 } 194 } 195 if bad == 1 { 196 badsegs = badsegs + 1 197 std_puts("NXSOV fsck TORN " as *u8) 198 std_puts(path) 199 std_puts(" at_off=" as *u8) 200 std_pdec(i) 201 std_puts(" of=" as *u8) 202 std_pdec(sz) 203 std_puts("\n" as *u8) 204 i = sz 205 } 206 } 207 } 208 s = s + 1 209 } 210 std_puts("NXSOV fsck segments=" as *u8) 211 std_pdec(ns) 212 std_puts(" records=" as *u8) 213 std_pdec(recs) 214 std_puts(" bad=" as *u8) 215 std_pdec(badsegs) 216 if badsegs == 0 { std_putln(" -> CLEAN" as *u8); return 0 } 217 std_putln(" -> TORN (quarantine/rotate the bad segments; latest-wins keys re-put heal)" as *u8) 218 return 1 219} 220 221func main(argc: i64, argv: *i64) -> i64 { 222 if argc < 3 { 223 std_putln("usage: nx_sov put <prefix> <key> <value> | put-file <prefix> <key> <file> | get <prefix> <key> | has <prefix> <key> | import <prefix> <tsvfile> | export <prefix> <outfile> | fsck <prefix>" as *u8) 224 sys_exit(2) 225 return 2 226 } 227 let a1: i64 = argv[1] 228 let verb: *u8 = a1 as *u8 229 let a2: i64 = argv[2] 230 let prefix: *u8 = a2 as *u8 231 if std_streq(verb, "put" as *u8) == 1 { 232 if argc < 5 { std_putln("put needs <prefix> <key> <value>" as *u8); sys_exit(2); return 2 } 233 let a3: i64 = argv[3] 234 let key: *u8 = a3 as *u8 235 let a4: i64 = argv[4] 236 let val: *u8 = a4 as *u8 237 sov_put_str(prefix, key, val) 238 std_putln("NXSOV put ok" as *u8) 239 sys_exit(0) 240 return 0 241 } 242 if std_streq(verb, "put-file" as *u8) == 1 { 243 if argc < 5 { std_putln("put-file needs <prefix> <key> <file>" as *u8); sys_exit(2); return 2 } 244 let b3: i64 = argv[3] 245 let key2: *u8 = b3 as *u8 246 let b4: i64 = argv[4] 247 let path: *u8 = b4 as *u8 248 let buf: *u8 = sys_mmap(NXSOV_CAP) as *u8 249 let n: i64 = nxsov_read(path, buf, NXSOV_CAP) 250 if n < 0 { std_putln("NXSOV put-file: unreadable" as *u8); sys_exit(1); return 1 } 251 sov_put(prefix, key2, buf, n) 252 std_puts("NXSOV put-file ok bytes=" as *u8) 253 std_pdec(n) 254 std_puts("\n" as *u8) 255 sys_exit(0) 256 return 0 257 } 258 if std_streq(verb, "get" as *u8) == 1 { 259 if argc < 4 { std_putln("get needs <prefix> <key>" as *u8); sys_exit(2); return 2 } 260 let c3: i64 = argv[3] 261 let key3: *u8 = c3 as *u8 262 let out: *u8 = sys_mmap(NXSOV_CAP) as *u8 263 let n2: i64 = sov_get_copy(prefix, key3, out, NXSOV_CAP) 264 if n2 < 0 { std_putln("NXSOV get: absent" as *u8); sys_exit(1); return 1 } 265 if n2 > 0 { sys_write(1, out, n2) } 266 sys_write(1, "\n" as *u8, 1) 267 sys_exit(0) 268 return 0 269 } 270 if std_streq(verb, "has" as *u8) == 1 { 271 if argc < 4 { std_putln("has needs <prefix> <key>" as *u8); sys_exit(2); return 2 } 272 let d3: i64 = argv[3] 273 let key4: *u8 = d3 as *u8 274 let h: i64 = sov_has(prefix, key4) 275 if h == 1 { std_putln("present" as *u8); sys_exit(0); return 0 } 276 std_putln("absent" as *u8) 277 sys_exit(1) 278 return 1 279 } 280 if std_streq(verb, "import" as *u8) == 1 { 281 if argc < 4 { std_putln("import needs <prefix> <tsvfile>" as *u8); sys_exit(2); return 2 } 282 let e3: i64 = argv[3] 283 let tf: *u8 = e3 as *u8 284 let rc: i64 = nxsov_import(prefix, tf) 285 sys_exit(rc) 286 return rc 287 } 288 if std_streq(verb, "export" as *u8) == 1 { 289 if argc < 4 { std_putln("export needs <prefix> <outfile>" as *u8); sys_exit(2); return 2 } 290 let f3: i64 = argv[3] 291 let of: *u8 = f3 as *u8 292 let rc2: i64 = nxsov_export(prefix, of) 293 sys_exit(rc2) 294 return rc2 295 } 296 if std_streq(verb, "fsck" as *u8) == 1 { 297 let rc3: i64 = nxsov_fsck(prefix) 298 sys_exit(rc3) 299 return rc3 300 } 301 std_putln("unknown verb" as *u8) 302 sys_exit(2) 303 return 2 304}