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}