nx_store_seed_lib.nx source
↩ module page · 696 lines · 40982 B
1// nx_store_seed_lib.nx -- THE canonical GENERIC store-seed codec (operator 2026-07-17: unify the
2// ~30 bespoke per-plane seeders). Migrates ANY flat staging buffer (# and blank lines skipped) into
3// ANY sovereign seg-store prefix as records key "q:<seq>"=row + "q:n"=count, and reconstructs a
4// newline-joined buffer byte-identical to the flat body. Prefix is a PARAMETER (gates isolate).
5// This is nx_frontier_store's frs_* promoted to the shared home; frontier + commontask delegate here.
6// license_tier: ORIGINAL No hw writes (Rule 26).
7import "nx_seg_store.nx"
8import "nx_syscalls.nx"
9import "nx_record_tsv.nx" // rtv_to_tsv + nxr_count -- the compatibility view (seq1326 rung 3)
10
11const STS_WCAP: i64 = 8388608 // RETIRED as the writer cap (see sts_seed); kept only for callers that still name it
12const STS_ROWOVH: i64 = 32 // per-entry seg-store header: kind + u32 klen + u32 vlen, with margin
13const STS_WSLACK: i64 = 65536 // count row + commit slack
14// ---- PLANE LOCK (seq1544 follow-on) -------------------------------------------------------------
15// MEASURED 2026-07-30: 55 files call sts_seed; only THREE take any lock. sts_seed is LOAD-ALL /
16// WRITE-ALL -- it REPLACES the whole plane from the caller's buffer -- so two unlocked writers that
17// overlap LOSE DATA, silently and by construction:
18// A loads (n rows) | B loads (n rows) | A commits (n+1) | B commits (n+1, WITHOUT A's row)
19// A's row is simply gone, and the next reader sees a declared/found mismatch it will blame on a
20// "prior writer dropped rows" -- which is exactly what it is, but the cause is the MISSING LOCK.
21//
22// WHY THIS IS A CALLER-HELD LOCK AND NOT AN sts_seed INTERNAL: the critical section is the whole
23// READ-MODIFY-WRITE (load -> mutate -> seed), not the commit alone. A lock taken inside sts_seed would
24// cover only the write half and leave the exact race above wide open. Worse, flock is per OPEN FILE
25// DESCRIPTION, so locking inside sts_seed would DEADLOCK the three callers that already hold
26// <prefix>plock on their own fd -- same process, different fd, blocks forever.
27//
28// ADDITIVE AND OPT-IN: nothing here changes existing behaviour. A caller wraps its RMW:
29// let lk: i64 = sts_lock(prefix) // <=0 means could not lock: refuse, do not proceed unlocked
30// ... sts_load_honest ... mutate ... sts_seed ...
31// sts_unlock(lk)
32// The lock file is <prefix>plock -- the SAME name nx_debt/nx_ecomat_put/nx_frontier_put already use
33// by hand, so adopting this composes with them instead of introducing a second, incompatible lock.
34// ─── DUPLICATE LOCK API REMOVED 2026-07-31 (ws=debt-intelligence) ─────────────────────────────────
35// This file defined sts_lock/sts_unlock TWICE -- here (the original) and again at the STS_LOCKMODE
36// block below. Harmless-looking while the compiler silently picked one; a HARD BUILD FAILURE for
37// EVERY consumer the moment the duplicate-definition guard went fail-closed on 2026-07-31, which is
38// how it was found (nx_debtcluster could not compile, and neither could any other store-seed
39// consumer -- nx_debtlive/nx_debt included).
40// THE SURVIVOR IS THE LOWER ONE, ON MERIT, NOT ON POSITION: it names the failing PATH on an open
41// error instead of letting "cannot lock" blame flock, and its sts_unlock issues an explicit
42// LOCK_UN before close rather than relying on close to drop the flock implicitly.
43// ★LAW: A DUPLICATE DEFINITION IS NOT A STYLE PROBLEM -- IT IS AN UNDECLARED COIN FLIP OVER WHICH
44// IMPLEMENTATION RUNS, AND IT SURVIVES EXACTLY UNTIL SOMETHING STARTS CHECKING.
45
46const STS_HASH: i64 = 35 // '#'
47const STS_NL: i64 = 10 // '\n'
48const STS_Q: i64 = 113 // 'q'
49const STS_COLON: i64 = 58 // ':'
50const STS_ZERO: i64 = 48 // '0'
51const STS_NINE: i64 = 57 // '9'
52const STS_KIND_LIVE: i64 = 1 // seg-store live-record kind (2 = tombstone)
53const STS_KEYCAP: i64 = 64
54const STS_NUMCAP: i64 = 28
55const STS_OUTCAP: i64 = 16
56const STS_BASE10: i64 = 10
57const STS_KPFX: i64 = 2 // "q:" prefix length
58const STS_EXIT_MMAP: i64 = 9
59const STS_MMAP_ERRMAX: i64 = 4096
60const STS_PROBE_WINDOW: i64 = 4096 // detect-only probe span past the declared q:n
61const STS_PROBE_MISS_RUN: i64 = 64 // consecutive misses that end the probe (sparse-tail guard)
62const STS_ERRFD: i64 = 2
63
64// CHECKED allocator (seq350, INCIDENT-0720): under host memory exhaustion sys_mmap returns an
65// error code in the top page; every unchecked caller then writes to it and SEGFAULTS (observed at
66// 0xfffffffffffffff4 = -ENOMEM, with multi-GB cores). This is the SHARED home of the seg-store
67// reader family (nx_debt/nx_debt_hygiene/nx_ws_cycle/nx_sweep_daemon all load through here), so the
68// check lives here ONCE and every member inherits it on its next rebuild. Fail LOUD with a
69// structured constant message (allocation-free by construction), never a segfault.
70func sts_werr(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(STS_ERRFD, s, n); return 0 }
71func sts_mm(n: i64) -> *u8 {
72 let p: *u8 = sys_mmap(n)
73 let v: i64 = p as i64
74 if v < 0 { if v > (0 - STS_MMAP_ERRMAX) {
75 sts_werr("STORE-RED {\"error\":\"mmap-fail\",\"lib\":\"nx_store_seed_lib\",\"hint\":\"host memory exhausted; see debt seq350 / INCIDENT-0720\"}\n" as *u8)
76 sys_exit(STS_EXIT_MMAP)
77 } }
78 return p
79}
80
81const STS_NXR_HDR: i64 = 6
82const STS_NXR_N: i64 = 78
83const STS_NXR_X: i64 = 88
84const STS_NXR_R: i64 = 82
85const STS_NXR_1: i64 = 49
86
87// FORMAT AUTO-DETECT (seq1326 rung 3) -- MUST STAY IDENTICAL TO _hdl_build/nx_store_seed_lib.nx.
88// ⚠⚠⚠DO NOT DROP THIS BLOCK WHEN REWRITING THIS FILE. It was clobbered twice on 2026-07-30 (14:12:33 and
89// 14:22:33) by full-file writes from a concurrent session, each time returning the file to its pre-edit
90// 10199B. knowledge/store/riskreg- is MIGRATED TO NXR1 on disk, so WITHOUT this block nx_info_registry
91// reads that live plane as rows=[] total=54 malformed=54 and nx_store_put load returns shredded garbage.
92// It is purely ADDITIVE: the render path is unreachable for any value not starting with the NXR1 magic,
93// so it is provably inert on every legacy plane and costs other lanes nothing.
94// ⚠Run nx_libcheck before building anything that imports this file -- the runtime/ and _hdl_build/ copies
95// are EACH OTHER'S CONTROL, and divergence means half the tree will silently build old behaviour.
96func sts_emit_row(src: *u8, vl: i64, out: *u8, off: i64, cap: i64) -> i64 {
97 var o: i64 = off
98 if vl >= STS_NXR_HDR {
99 if src[0] == (STS_NXR_N as u8) { if src[1] == (STS_NXR_X as u8) {
100 if src[2] == (STS_NXR_R as u8) { if src[3] == (STS_NXR_1 as u8) {
101 let cols: i64 = nxr_count(src)
102 let n2: i64 = rtv_to_tsv(src, vl, cols, (out as i64 + o) as *u8, cap - o)
103 if n2 >= 0 { return o + n2 }
104 return o
105 } } } }
106 }
107 var t2: i64 = 0
108 while t2 < vl { if o < cap { out[o] = src[t2]; o = o + 1 } t2 = t2 + 1 }
109 return o
110}
111
112func sts_atoi(b: *u8, n: i64) -> i64 {
113 var v: i64 = 0
114 var i: i64 = 0
115 var go: i64 = 1
116 while i < n {
117 if go == 1 {
118 let c: i64 = b[i] as i64
119 if c >= STS_ZERO { if c <= STS_NINE { v = v * STS_BASE10 + (c - STS_ZERO) } else { go = 0 } } else { go = 0 }
120 }
121 i = i + 1
122 }
123 return v
124}
125// ---- THE CAS / GENERATION GUARD (2026-08-06) ----------------------------------------------------
126// MEASURED by nx_sts_cas_gate on the pre-guard code: six unlocked writers, SIX told they succeeded,
127// ONE row present. Five callers were handed a row count for a write that does not exist.
128//
129// The lock cannot be moved inside sts_seed -- that argument is made twice above and it is correct:
130// the critical section is the whole load -> mutate -> seed, and only the caller can express it.
131// BUT SILENCE IS A SEPARATE DEFECT FROM LOSS, and this half CAN be fixed here. sts_seed cannot make
132// the conflicting writes both survive; it can refuse to LIE about the one it is destroying.
133//
134// THE RULE: remember, per process, the generation of the plane this process last LOADED. If sts_seed
135// is handed that same prefix and the plane has moved since, another writer committed inside our
136// read-modify-write, so seeding would overwrite them from a stale snapshot -> REFUSE.
137//
138// WHY THIS DOES NOT REPEAT THE 2026-08-02 REVERT. A shrink-refusal guard was built here and pulled
139// before promote because it broke LEGITIMATE whole-plane rewriters. This one cannot, because it is
140// keyed on THIS PROCESS HAVING LOADED THIS PREFIX, not on row counts:
141// * nx_plane_append ROLLBACK -- its first seed UPDATES the remembered generation, so the rollback
142// seed that follows matches and is ALLOWED. The failure mode that guard created is gone.
143// * nx_plane_repair / nx_store_put close/setcol -- load then seed with no other writer -> allowed.
144// * fresh seeders that never loaded, and nx_plane_append's T1 negative control that deliberately
145// raw-seeds to prove a raw seed destroys a plane -> no recorded generation for that prefix, so
146// NO CHECK RUNS and the honest gate stays honest.
147// It fires ONLY when this process loaded the plane and somebody else committed in between, which is
148// exactly and only the lost-update case.
149//
150// Two static SCALARS, deliberately not an array: a BSS static array crashes the module on startup in
151// this compiler, and scalars are the proven-safe shape. `static` (no initialiser) is zero-init and
152// persists for the process; a fork gives each child its own copy-on-write copy, which is what makes
153// this correct across the fork-per-worker shape every one of these writers uses.
154const STS_HASHMUL: i64 = 131
155const STS_ERR_STALE: i64 = 0 - 5
156static STS_GEN_KEY: i64
157static STS_GEN_VAL: i64
158
159// Never returns 0 -- 0 is the "nothing recorded" sentinel. A collision would only ever cause a
160// SPURIOUS REFUSAL of an unrelated prefix, never a missed one: it fails closed.
161func sts_pfxhash(prefix: *u8) -> i64 {
162 var h: i64 = 0
163 var i: i64 = 0
164 while prefix[i] != (0 as u8) {
165 h = h * STS_HASHMUL + (prefix[i] as i64)
166 i = i + 1
167 }
168 if h == 0 { h = 1 }
169 return h
170}
171
172func sts_gen_note(prefix: *u8) -> i64 {
173 STS_GEN_KEY = sts_pfxhash(prefix)
174 STS_GEN_VAL = ss_max_segid(prefix)
175 return 0
176}
177
178func sts_rowkey(seq: i64, out: *u8) -> i64 {
179 out[0] = STS_Q as u8
180 out[1] = STS_COLON as u8
181 var o: i64 = ss_catn(out, STS_KPFX, seq)
182 out[o] = 0 as u8
183 return o
184}
185// migrate a flat buffer into the store at `prefix`; ONE commit. returns row count or -1.
186func sts_seed(prefix: *u8, buf: *u8, n: i64) -> i64 {
187 // CAS GUARD -- see the block above sts_rowkey. Runs ONLY if THIS process loaded THIS prefix.
188 // Refusing costs the caller its own write; NOT refusing costs another writer theirs, silently,
189 // and hands this caller a row count for data that will never exist.
190 let gh: i64 = sts_pfxhash(prefix)
191 var expect: i64 = SS_CAS_ANY
192 if STS_GEN_KEY == gh {
193 expect = STS_GEN_VAL
194 }
195 // WRITER CAPACITY IS DATA-DRIVEN, NOT A CEILING (2026-07-30). This was ss_begin_cap(STS_WCAP)
196 // with STS_WCAP a fixed 1MiB. sts_seed rewrites the WHOLE plane on every write, so the moment a
197 // plane outgrew 1MiB the trailing ss_add calls failed -- and their return value was DISCARDED --
198 // while the q:n count row still recorded the INTENDED total. The plane then declared more rows
199 // than it contained: silent, unbounded data loss that only surfaced later as DEBT-REFUSED
200 // lossy-load, with the debt board (the ecosystem ledger) frozen read-only.
201 // Size from the actual payload the way reg_put and ss_compact_cap already do: every byte of
202 // input, plus per-row key+header overhead, plus the count row and slack. A plane can now grow
203 // to whatever it needs; there is no number here for a future plane to outgrow.
204 var rowcount: i64 = 0
205 var scan: i64 = 0
206 while scan < n { if buf[scan] == (STS_NL as u8) { rowcount = rowcount + 1 } scan = scan + 1 }
207 // ⚠A SHRINK-REFUSAL GUARD WAS ATTEMPTED HERE 2026-08-02 AND DELIBERATELY REVERTED BEFORE PROMOTE.
208 // It would have refused any sts_seed whose input holds fewer rows than the plane already has --
209 // correct for the clobber class (dedupq- seq756, commontask- 08-02) but WRONG HERE, because a
210 // blast-radius read of the 118 call sites found LEGITIMATE shrinking writers that the guard would
211 // have broken, some catastrophically:
212 // * nx_plane_append ROLLBACK -- sts_seed(prefix, oldb, oldn) restores the PRE-append buffer after a
213 // failed write; refusing that strands the plane in the failed state (the guard would cause the
214 // very loss it exists to prevent).
215 // * nx_plane_repair -- repairing a corrupted plane legitimately produces FEWER rows.
216 // * nx_plane_append's own T1 NEGATIVE CONTROL deliberately raw-seeds to PROVE a raw seed destroys a
217 // plane (2 rows -> 1); refusing it turns a healthy liar-killed gate RED.
218 // * nx_store_put close/setcol paths rewrite the whole plane by design.
219 // THE GUARD BELONGS AT THE PLANE-WRITER LAYER, NOT IN THE SHARED PRIMITIVE: see debt 1785710884 --
220 // either a checked twin (sts_seed_checked) that intentional shrinkers opt out of, or the guard inside
221 // nx_store_put's put path only. The primitive stays raw and DOCUMENTED-DANGEROUS; nx_plane_append is
222 // already the one correct append path.
223 let needed: i64 = n + (rowcount + 2) * (STS_KEYCAP + STS_ROWOVH) + STS_WSLACK
224 let w: *i64 = ss_begin_cap(needed)
225 let key: *u8 = sts_mm(STS_KEYCAP)
226 let base: i64 = buf as i64
227 var seq: i64 = 0
228 var i: i64 = 0
229 while i < n {
230 var le: i64 = i
231 var s: i64 = 1
232 while s == 1 { if le >= n { s = 0 } else { if buf[le] == (STS_NL as u8) { s = 0 } else { le = le + 1 } } }
233 if le > i { if buf[i] != (STS_HASH as u8) {
234 sts_rowkey(seq, key)
235 // CHECKED: a dropped row used to be invisible here, which is what let q:n over-declare.
236 if ss_add(w, STS_KIND_LIVE, key, (base + i) as *u8, le - i) < 0 { return 0 - 2 }
237 seq = seq + 1
238 } }
239 i = le + 1
240 }
241 let cb: *u8 = sts_mm(STS_NUMCAP)
242 let cl: i64 = ss_catn(cb, 0, seq)
243 if ss_add(w, STS_KIND_LIVE, "q:n" as *u8, cb, cl) < 0 { return 0 - 2 }
244 // CAS: the plane must still be at the generation this process loaded, checked UNDER THE PLANE
245 // LOCK inside ss_commit_cas. Checking it here instead is what the first attempt did, and it
246 // measured EXACTLY ZERO improvement -- see the note above ss_commit_cas.
247 let rc: i64 = ss_commit_cas(prefix, w, ss_next_segid(prefix), expect)
248 if rc == SS_ERR_STALE { return STS_ERR_STALE }
249 // Re-baseline ON SUCCESS ONLY. This is what keeps a legitimate second write from this same
250 // process -- nx_plane_append's rollback seed above all -- from being refused for the generation
251 // bump its OWN first seed just caused.
252 if rc == 0 { sts_gen_note(prefix) }
253 if rc != 0 { return 0 - 1 }
254 return seq
255}
256// ---------------------------------------------------------------------------------------------------
257// sts_append_fast -- O(1) APPEND OF ONE ROW. The seq724 amplification fix, living beside sts_seed so every
258// writer that already imports this lib can reach it without a new dependency.
259//
260// sts_seed REWRITES THE WHOLE PLANE. Measured 2026-07-30 on a 2000-row / 210,906-byte plane: appending one
261// row via re-seed wrote a 210,969-byte segment; this path wrote 47 BYTES. 4489x less. On dp-web-pub-
262// (1.5GB, 4,291,836 entries) that is 1.5GB rewritten versus about 50 bytes.
263//
264// IT IS NOT ONLY A SPEED FIX -- IT REMOVES TWO WHOLE DEFECT CLASSES BY CONSTRUCTION:
265// * PARTIAL-LOAD DROPS ROWS: a re-seed rebuilds the plane from whatever the loader could reach, so a
266// partial read silently deletes every row past the declared count (the lossy-plane class). An append
267// rewrites NOTHING, so an incomplete read cannot destroy a row it never saw.
268// * ORDINAL SHIFT: a re-seed RE-SEGMENTS rows (any row containing a newline splits), shifting every
269// ordinal after it -- which is how a positional seq issued before a re-seed later addresses a
270// DIFFERENT row. An append adds q:<n> and touches no existing key, so ordinals are stable.
271//
272// Correctness rests on properties the store already guarantees: segments are append-only and reads are
273// NEWEST-WINS per key; q:<n> is a key never written before; q:n is simply overwritten; and every reader
274// already walks q:0..q:n-1 ACROSS segments. NO READER CHANGES ARE REQUIRED.
275// Segment count grows by one per append BY DESIGN -- nx_store_fold_beat merges on the standing sweep and
276// nx_store_janitor_beat reclaims what folding supersedes. Cheap appends + background compaction is the LSM
277// shape this store was built for and that re-seeding defeats.
278// FAIL-CLOSED: a plane with no q:n is REFUSED (-1), never conjured. Returns the NEW row count, or -1/-2.
279func sts_append_fast(prefix: *u8, row: *u8, rowlen: i64) -> i64 {
280 if rowlen <= 0 { return 0 - 1 }
281 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
282 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
283 // CAS BASELINE, captured BEFORE the q:n read on purpose. Taking it after would leave a window in
284 // which a commit lands between the read and the baseline and is never noticed; taking it first can
285 // only ever over-refuse, which is the safe direction. Unlike sts_seed this needs no process-local
286 // state at all -- the read and the commit are both inside THIS function, so the generation is just
287 // a local. MEASURED before the fix by nx_sts_cas_gate T3: 6 writers told yes, 1 row present.
288 let gen0: i64 = ss_max_segid(prefix)
289 if ss_get(prefix, "q:n" as *u8, pq, lq) != 1 { return 0 - 1 }
290 let n: i64 = sts_atoi(pq[0] as *u8, lq[0])
291 let key: *u8 = sts_mm(STS_KEYCAP)
292 sts_rowkey(n, key)
293 let cb: *u8 = sts_mm(STS_NUMCAP)
294 let cl: i64 = ss_catn(cb, 0, n + 1)
295 let w: *i64 = ss_begin_cap(rowlen + STS_WSLACK)
296 if ss_add(w, STS_KIND_LIVE, key, row, rowlen) < 0 { return 0 - 2 }
297 if ss_add(w, STS_KIND_LIVE, "q:n" as *u8, cb, cl) < 0 { return 0 - 2 }
298 // If ANY writer committed since gen0, this appender's q:<n> would collide with theirs and the
299 // NEWEST-WINS read would silently discard one of the two rows. Refuse instead: the caller gets a
300 // negative return and can retry against the new n, which is the whole difference between
301 // backpressure and corruption.
302 let crc: i64 = ss_commit_cas(prefix, w, ss_next_segid(prefix), gen0)
303 if crc == SS_ERR_STALE { return STS_ERR_STALE }
304 if crc != 0 { return 0 - 2 }
305 return n + 1
306}
307
308// UPDATED 2026-08-06 -- THIS PARAGRAPH USED TO OPEN "sts_append_fast IS STILL A READ-MODIFY-WRITE
309// AND IT STILL LOSES ROWS UNDER CONCURRENCY". THAT IS NO LONGER TRUE OF THE CODE ABOVE, and leaving
310// it would have been worse than never writing it: a comment that contradicts its own function is read
311// as the specification by the next person, who then re-derives a defect that is already fixed.
312// IT IS STILL A READ-MODIFY-WRITE. It no longer loses rows SILENTLY.
313// The diagnosis below is preserved verbatim because it is exactly right about the MECHANISM -- it is
314// the WHY for the CAS baseline in the body above. Only its conclusion changed.
315// MEASURED both ways by nx_sts_cas_gate T3/T4: before, 6 concurrent appenders were ALL told they
316// succeeded while 1 row existed (5 silent losses); after, every writer told YES has written, and the
317// losers get STS_ERR_STALE and can retry against the new n.
318// Measured/reasoned 2026-07-30 (ws=sev-eater): it ss_get's q:n to learn n, then writes q:<n> and
319// q:n=n+1. Two concurrent appenders both read n, both write THE SAME q:<n> key -- and reads are
320// NEWEST-WINS per key, so one row does not merely fail to appear, it is silently OVERWRITTEN -- and
321// both then set q:n=n+1, so the count agrees with the loss and no guard ever notices. It is 4489x
322// cheaper than a re-seed and exactly as lossy; SPEED IS NOT SAFETY.
323//
324// THE LOCK IS DELIBERATELY *NOT* INSIDE sts_append_fast. Audited its callers first, and nx_debt
325// (nx_debt.nx:320) ALREADY HOLDS <prefix>plock via db_lock and then calls it on THAT SAME prefix --
326// flock is per open-file-description, so an internal lock would make nx_debt block against ITSELF
327// and hang the debt board for every seat. Same trap that rules out locking sts_seed.
328// ★LAW, twice proven in one file now: BEFORE LOCKING A SHARED PRIMITIVE, AUDIT WHO ALREADY HOLDS
329// THAT LOCK -- the callers doing it right are what the internal lock breaks first.
330//
331// So the safe variant is a WRAPPER. Callers that do NOT already hold the plane lock use this one;
332// callers that do (nx_debt, nx_frontier_put) keep calling the raw primitive and stay correct.
333// (the wrapper itself is defined at the END of this file, below sts_lock -- NishiLang resolves
334// identifiers in TEXTUAL order and a forward reference to sts_lock from here would not compile.)
335
336// read the store at `prefix` -> newline-joined row buffer. returns bytes.
337// seq356 (INCIDENT-0720 residual): the original body did one ss_get PER ROW, and every ss_get
338// re-opens + re-maps the whole seglist => O(rows x segments) file IO -- the amplification that
339// helped the reader family (nx_debt/nx_ws_cycle/...) OOM the host. NOW: ss_open ONCE ->
340// ss_hget per row (zero file IO per call; the proven WMS audit-scale pattern). Semantics
341// identical BY ORACLE: sts_load_slow below is the verbatim old body and the bulkload gate
342// proves byte-identical output on single-seg, multi-seg-supersede, and shrink planes.
343func sts_load(prefix: *u8, out: *u8, cap: i64) -> i64 {
344 // Record the generation we are ABOUT to read at. Deliberately before the read, not after: if a
345 // writer commits DURING our load our snapshot is already torn, and stamping the earlier
346 // generation means sts_seed will catch it. Conservative on purpose -- it can only over-refuse.
347 sts_gen_note(prefix)
348 // ss_open_cached, NOT ss_open (seq905/962 CLASS FIX, 2026-07-30). ss_open reads every live segment
349 // fully into anonymous RAM and nothing frees it, so a consumer that loads repeatedly leaks the WHOLE
350 // store per load -- the fingerprint behind ~23.6 GiB of anonymous address space across nine organs and
351 // the 92.3%-swap thrash. MEASURED 2026-07-30: 133 files reach ss_open but only 1 called ss_close, so
352 // the fix existed and was dark. This lib is a CHOKEPOINT -- 63 importers, and it is the exact reader
353 // family (nx_debt / nx_ws_cycle / ...) named above as having OOM'd the host -- so migrating the two
354 // opens here reaches far more consumers than migrating leaf call sites one at a time (rule 15).
355 // Cache is prefix-keyed with manifest (st_size, st_mtime) invalidation, so LIVE EDITS ARE STILL PICKED
356 // UP on the next call with no restart; you simply cannot leak what you never allocate twice.
357 // ⚠Safe here because these loaders are single-threaded and run to completion before the next call, so
358 // the handle's shared query-scratch arena is never re-entered. Do NOT blanket-alias ss_open itself.
359 let h: *i64 = ss_open_cached(prefix)
360 if (h as i64) == 0 { return 0 }
361 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
362 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
363 if ss_hget(h, "q:n" as *u8, pq, lq) != 1 { return 0 }
364 let cnt: i64 = sts_atoi(pq[0] as *u8, lq[0])
365 let key: *u8 = sts_mm(STS_KEYCAP)
366 let pr: *i64 = sts_mm(STS_OUTCAP) as *i64
367 let lr: *i64 = sts_mm(STS_OUTCAP) as *i64
368 var o: i64 = 0
369 var seq: i64 = 0
370 var lost: i64 = 0
371 while seq < cnt {
372 sts_rowkey(seq, key)
373 if ss_hget(h, key, pr, lr) == 1 {
374 let src: *u8 = pr[0] as *u8
375 let vl: i64 = lr[0]
376 o = sts_emit_row(src, vl, out, o, cap)
377 if o >= cap { lost = lost + 1 }
378 if o < cap { out[o] = STS_NL as u8; o = o + 1 }
379 if o >= cap { lost = lost + 1 }
380 }
381 seq = seq + 1
382 }
383 // ⚠TRUNCATION IS LOUD (ported from the authoring tree 2026-08-06 -- it was authored there on
384 // 2026-07-30 and NEVER REACHED THE TREE THAT COMPILES AND DEPLOYS, so every organ built here has
385 // been truncating silently ever since). The loop above drops bytes whenever o >= cap and returns a
386 // byte count that looks perfectly healthy, so a caller whose cap is smaller than the plane reads a
387 // PARTIAL board and reports on it as if complete.
388 // MEASURED SCOPE (authoring-tree note, preserved): 126 call sites use this plain loader against 15
389 // on sts_load_honest -- ~89% of all plane reads were silent; once the debt plane passed 1MB,
390 // nx_sheriff / nx_pm_board / nx_pm_cockpit / nx_law_warden / nx_dora / nx_debt_hygiene /
391 // nx_backlog_feeder were ALL reading a TRUNCATED board without knowing.
392 // ★WHY STDERR AND NOT A RETURN CODE: the return is a BYTE COUNT 126 callers already consume;
393 // changing that contract would be a silent semantic break across the estate -- the very failure
394 // being fixed. A diagnostic makes the condition VISIBLE without changing any contract.
395 // ★LAW: a reader that cannot fit its source must SAY SO. Under-reporting is indistinguishable from
396 // good news, which is what makes it dangerous.
397 // ⚠DELIBERATE SHAPE DIFFERENCE FROM THE AUTHORING COPY: that one counts DROPPED BYTES inside an
398 // inline byte loop; this tree emits rows through sts_emit_row (the NXR1 auto-detect the authoring
399 // copy does not have), so `lost` counts ROWS-at-the-boundary instead. The warning predicate is
400 // `lost > 0` in both, so the DIAGNOSTIC IS IDENTICAL; only the unit behind it differs.
401 if lost > 0 {
402 sts_werr("STS-LOAD TRUNCATED plane=" as *u8)
403 sts_werr(prefix)
404 sts_werr(" -- read cap too small; bytes DROPPED, the returned buffer is a PARTIAL board. Raise the caller's cap or use sts_load_honest.\n" as *u8)
405 }
406 return o
407}
408
409// ---- sts_load_fit -- A LOADER THAT CANNOT BE UNDER-CAPPED (2026-08-06) --------------------------
410// nx_debt's DB_CAP comment states the requirement exactly: "THIS IS THE THIRD RAISE, NOT A FIX: the
411// structural answer is to compare the cap against the actual plane size and REFUSE LOUDLY instead of
412// silently returning a prefix -- A CAP THAT CAN BE CROSSED IN SILENCE WILL BE CROSSED AGAIN."
413// Raising a constant buys time; it does not remove the class. This removes the class: the caller
414// stops choosing a number at all, and the loader sizes itself from the plane.
415//
416// ★THE TEST IS EXACT AND NEEDS NO STAT: sts_load truncates ONLY when its buffer fills, so a return
417// STRICTLY LESS THAN cap PROVES the read was complete. n == cap is the only ambiguous case -- it may
418// be an exact fit or a truncation -- so that is the single case we grow on. No sizing heuristic, no
419// estimate that can be wrong in the dangerous direction.
420//
421// ★STARTS ABOVE EVERY MEASURED PLANE ON PURPOSE. nx_planefit swept all 1,235 planes on 2026-08-06:
422// the largest was knowledge/store/debt- at 4,416,561B. An 8 MiB first attempt therefore completes in
423// ONE pass for every plane that exists today, so the common path costs one mmap and prints no
424// spurious truncation warning; growth is the rare fallback, not the norm.
425//
426// ★FAILURE IS LOUD AND BOUNDED. Doubling is capped, and exhausting it RETURNS NULL with a named
427// diagnostic rather than handing back a partial board -- the whole defect being closed here is a
428// short read that looks healthy, so this must never be able to produce one.
429// ⚠Each failed attempt is MUNMAPPED before growing: sys_mmap is page-granular with no allocator
430// behind it, and an unpaired scratch mmap leaks a full page per call (the 27.7GB class).
431// out_len[0] = bytes on success, -1 on refusal. Returns the buffer, or null on refusal.
432const STS_FIT_START: i64 = 8388608 // 8 MiB: ~1.9x the largest plane measured 2026-08-06
433const STS_FIT_MAXTRIES: i64 = 8 // 8 MiB .. 1 GiB, then REFUSE
434func sts_load_fit(prefix: *u8, out_len: *i64) -> *u8 {
435 var cap: i64 = STS_FIT_START
436 var tries: i64 = 0
437 while tries < STS_FIT_MAXTRIES {
438 let buf: *u8 = sts_mm(cap)
439 let n: i64 = sts_load(prefix, buf, cap)
440 // STRICTLY less than cap => the buffer never filled => nothing was dropped. Complete.
441 if n < cap {
442 out_len[0] = n
443 return buf
444 }
445 sys_munmap(buf, cap)
446 cap = cap * 2
447 tries = tries + 1
448 }
449 sts_werr("STS-LOAD-FIT REFUSED plane=" as *u8)
450 sts_werr(prefix)
451 sts_werr(" -- still filling the buffer at 1 GiB. REFUSING to return a partial board; shard the plane or raise STS_FIT_MAXTRIES deliberately.\n" as *u8)
452 out_len[0] = 0 - 1
453 return 0 as *u8
454}
455// HONEST LOADER (2026-07-25, ws=debt-instrument). sts_load trusts the q:n count key and stops
456// at it with NO error and NO flag, so a low/stale q:n SILENTLY truncates every reader that uses
457// it. MEASURED on the debt- plane: q:n resolved 125 while 629 segments held 734+ rows, and
458// nx_debt list reported total=125 AS FACT. Loads byte-identically to sts_load (which is left
459// UNTOUCHED for API-contract stability, rule 19) but additionally REPORTS what it could not
460// reach, so partial coverage can never again be presented as complete (honesty law L011).
461// flags[0]=declared q:n flags[1]=rows actually loaded flags[2]=rows reachable BEYOND q:n
462// DETECT-ONLY BY CONSTRUCTION: never loads a row past the declared count. sts_seed REASSIGNS
463// q:<i> on every commit, so rows past q:n belong to an OLDER seeding generation -- loading them
464// would duplicate live rows and revive eaten ones. Reporting the gap is safe; reconciling it is
465// a separate operation that must diff the generations.
466// SAFE ASYMMETRY it relies on: a too-LOW q:n silently truncates, a too-HIGH q:n is harmless on
467// read because ss_hget misses are skipped -- so probing past the count cannot corrupt.
468func sts_load_honest(prefix: *u8, out: *u8, cap: i64, flags: *i64) -> i64 {
469 sts_gen_note(prefix)
470 flags[0] = 0
471 flags[1] = 0
472 flags[2] = 0
473 // ss_open_cached -- same seq905/962 class fix and same single-threaded-loader reasoning as sts_load.
474 let h: *i64 = ss_open_cached(prefix)
475 if (h as i64) == 0 { return 0 }
476 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
477 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
478 if ss_hget(h, "q:n" as *u8, pq, lq) != 1 { return 0 }
479 let cnt: i64 = sts_atoi(pq[0] as *u8, lq[0])
480 flags[0] = cnt
481 let key: *u8 = sts_mm(STS_KEYCAP)
482 let pr: *i64 = sts_mm(STS_OUTCAP) as *i64
483 let lr: *i64 = sts_mm(STS_OUTCAP) as *i64
484 var o: i64 = 0
485 var seq: i64 = 0
486 while seq < cnt {
487 sts_rowkey(seq, key)
488 if ss_hget(h, key, pr, lr) == 1 {
489 let src: *u8 = pr[0] as *u8
490 let vl: i64 = lr[0]
491 o = sts_emit_row(src, vl, out, o, cap)
492 if o < cap { out[o] = STS_NL as u8; o = o + 1 }
493 flags[1] = flags[1] + 1
494 }
495 seq = seq + 1
496 }
497 var beyond: i64 = 0
498 var miss: i64 = 0
499 var p: i64 = cnt
500 let lim: i64 = cnt + STS_PROBE_WINDOW
501 while p < lim {
502 if miss < STS_PROBE_MISS_RUN {
503 sts_rowkey(p, key)
504 if ss_hget(h, key, pr, lr) == 1 { beyond = beyond + 1; miss = 0 } else { miss = miss + 1 }
505 }
506 p = p + 1
507 }
508 flags[2] = beyond
509 return o
510}
511// ---- ATOMIC PLANE APPEND (root fix for seq1559, ws=sev-eater 2026-07-30) ----------------------
512// 55 files call sts_seed(); only THREE take a lock. sts_seed REPLACES the whole plane from the
513// caller's buffer, and the universal call shape is READ-MODIFY-WRITE:
514// n = sts_load(prefix, buf, cap); ...append a row...; sts_seed(prefix, buf, n)
515// Two overlapping unlocked writers interleave as A-loads / B-loads / A-commits n+1 /
516// B-commits n+1-WITHOUT-A. A's row is gone, silently, and the next reader's declared-vs-found
517// mismatch blames a prior writer for dropping rows -- true, but the wrong cause.
518//
519// WHY THE OBVIOUS FIX IS WRONG AND IS NOT DONE HERE: putting the lock INSIDE sts_seed would
520// DEADLOCK the three callers that already do it right. flock(2) locks are per OPEN FILE
521// DESCRIPTION, not per process, so nx_debt -- which already holds <prefix>plock via db_lock and
522// then calls sts_seed -- would block against ITSELF on a second fd of the same file. That trades
523// silent data loss for a hard hang of the debt board for every seat, which is strictly worse.
524// ★LAW: A CHOKEPOINT FIX MUST NOT ASSUME ITS CALLERS ARE ALL WRONG -- the ones already doing it
525// right are exactly what a naive fix breaks first.
526//
527// So sts_seed is left UNLOCKED and this is added ALONGSIDE it: the whole critical section as ONE
528// call. ★LAW: THE RIGHT PRIMITIVE IS THE CRITICAL SECTION, NOT THE LOCK -- a lock 52 callers must
529// remember to take is the same class of defect as the missing lock. Callers migrate to
530// sts_append_row and become correct by construction; nothing has to be remembered.
531//
532// The lock file is <prefix>plock -- deliberately THE SAME PATH nx_debt/nx_ecomat_put/
533// nx_frontier_put already use, so migrated and unmigrated writers share ONE lock domain. A new
534// lock file would have been easier and would have protected nothing.
535const STS_LOCK_EX: i64 = 2
536const STS_LOCK_UN: i64 = 8
537const STS_LOCKMODE: i64 = 420
538const STS_LOCKPATHCAP: i64 = 256
539const STS_ERR_LOCK: i64 = 0 - 3
540const STS_ERR_CAP: i64 = 0 - 4
541
542// Take the plane's exclusive lock. Returns the held fd, or -1 (LOUD: names the path, because
543// "cannot lock" alone has historically blamed flock when the cause was an open failure).
544func sts_lock(prefix: *u8) -> i64 {
545 let p: *u8 = sts_mm(STS_LOCKPATHCAP)
546 var o: i64 = ss_cat(p, 0, prefix)
547 o = ss_cat(p, o, "plock" as *u8)
548 p[o] = 0 as u8
549 let fd: i64 = sys_openat_append(p, STS_LOCKMODE)
550 if fd < 0 {
551 sts_werr("STS-LOCK open-failed (not flock) path=" as *u8)
552 sts_werr(p)
553 sts_werr("\n" as *u8)
554 return 0 - 1
555 }
556 sys_flock(fd, STS_LOCK_EX)
557 return fd
558}
559
560func sts_unlock(fd: i64) -> i64 {
561 if fd < 0 { return 0 }
562 sys_flock(fd, STS_LOCK_UN)
563 sys_close(fd)
564 return 0
565}
566
567// ATOMIC ROW APPEND: lock -> load -> append -> commit -> unlock, with no window in which another
568// writer can load a snapshot this one is about to invalidate. Returns sts_seed's row count, or
569// STS_ERR_LOCK / STS_ERR_CAP. Fail-closed: if the buffer cannot hold the appended row the plane is
570// left EXACTLY as it was rather than committed short (a truncated commit is the very loss this
571// exists to prevent).
572func sts_append_row(prefix: *u8, row: *u8, rowlen: i64, cap: i64) -> i64 {
573 let fd: i64 = sts_lock(prefix)
574 if fd < 0 { return STS_ERR_LOCK }
575 let buf: *u8 = sts_mm(cap)
576 var n: i64 = sts_load(prefix, buf, cap)
577 if n < 0 { n = 0 }
578 if n + rowlen + 1 > cap { sts_unlock(fd); return STS_ERR_CAP }
579 var i: i64 = 0
580 while i < rowlen { buf[n] = row[i]; n = n + 1; i = i + 1 }
581 buf[n] = STS_NL as u8
582 n = n + 1
583 let rc: i64 = sts_seed(prefix, buf, n)
584 sts_unlock(fd)
585 return rc
586}
587
588// Locked form of sts_append_fast, defined HERE because it needs sts_lock above it (textual order).
589// Use this from any caller that does NOT already hold the plane lock; callers that DO (nx_debt,
590// nx_frontier_put) must keep calling the raw sts_append_fast or they will deadlock against
591// themselves -- see the audit note beside sts_append_fast.
592func sts_append_fast_locked(prefix: *u8, row: *u8, rowlen: i64) -> i64 {
593 let fd: i64 = sts_lock(prefix)
594 if fd < 0 { return STS_ERR_LOCK }
595 let rc: i64 = sts_append_fast(prefix, row, rowlen)
596 sts_unlock(fd)
597 return rc
598}
599
600// the pre-seq356 body VERBATIM (one ss_get per row) -- kept as the equivalence ORACLE for
601// nx_sts_bulkload_gate; not for production use (the amplification lives here).
602func sts_load_slow(prefix: *u8, out: *u8, cap: i64) -> i64 {
603 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
604 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
605 if ss_get(prefix, "q:n" as *u8, pq, lq) != 1 { return 0 }
606 let cnt: i64 = sts_atoi(pq[0] as *u8, lq[0])
607 let key: *u8 = sts_mm(STS_KEYCAP)
608 let pr: *i64 = sts_mm(STS_OUTCAP) as *i64
609 let lr: *i64 = sts_mm(STS_OUTCAP) as *i64
610 var o: i64 = 0
611 var seq: i64 = 0
612 while seq < cnt {
613 sts_rowkey(seq, key)
614 if ss_get(prefix, key, pr, lr) == 1 {
615 let src: *u8 = pr[0] as *u8
616 let vl: i64 = lr[0]
617 o = sts_emit_row(src, vl, out, o, cap)
618 if o < cap { out[o] = STS_NL as u8; o = o + 1 }
619 }
620 seq = seq + 1
621 }
622 return o
623}
624
625// ---- ROW-LEVEL WRITES WITHOUT A RESEED (2026-09-02, loadgov LV17 sts_put_append) -----------------------------
626// THE STORM, MEASURED: nx_store_put put/close/setcol reload the whole plane and hand it to sts_seed, so ONE row costs
627// ONE fsync'd rewrite of the WHOLE plane (the debt plane is 4.9 MB). Five such writers in flight held the RAID array in
628// D-state for minutes and every /api/build on the estate was refused for hours (nx_dstate roster, 2026-09-02). The store
629// already had the O(1) shape for NEW rows (sts_append_fast: one segment holding q:<n> + q:n). What it lacked was the
630// same shape for a MODIFIED row. These two functions supply it, and nx_store_put composes them.
631// sts_find_seq: the seq (0..q:n-1) whose row's FIRST column equals `id`, or -1. Walks the same q:0..q:n-1 order every
632// reader uses, on the cached handle (zero file IO per key), decoding NXR1 rows exactly as sts_load does so the id
633// comparison is on the tsv form every caller sees. -1 is also returned for an unseeded plane (no q:n).
634const STS_ROWTAB: i64 = 9
635const STS_FINDCAP: i64 = 65536 // one decoded row; the largest plane row measured is far below this, and a longer row
636 // simply fails to match (never a wrong match): sts_emit_row stops at the cap
637func sts_find_seq(prefix: *u8, id: *u8) -> i64 {
638 let h: *i64 = ss_open_cached(prefix)
639 if (h as i64) == 0 { return 0 - 1 }
640 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
641 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
642 if ss_hget(h, "q:n" as *u8, pq, lq) != 1 { return 0 - 1 }
643 let cnt: i64 = sts_atoi(pq[0] as *u8, lq[0])
644 let key: *u8 = sts_mm(STS_KEYCAP)
645 let pr: *i64 = sts_mm(STS_OUTCAP) as *i64
646 let lr: *i64 = sts_mm(STS_OUTCAP) as *i64
647 let tmp: *u8 = sts_mm(STS_FINDCAP)
648 var idl: i64 = 0
649 while id[idl] != (0 as u8) { idl = idl + 1 }
650 var seq: i64 = 0
651 var hit: i64 = 0 - 1
652 while seq < cnt {
653 if hit < 0 {
654 sts_rowkey(seq, key)
655 if ss_hget(h, key, pr, lr) == 1 {
656 let n2: i64 = sts_emit_row(pr[0] as *u8, lr[0], tmp, 0, STS_FINDCAP)
657 var c: i64 = 0
658 var go: i64 = 1
659 while go == 1 { if c >= n2 { go = 0 } else { if tmp[c] == (STS_ROWTAB as u8) { go = 0 } else { c = c + 1 } } }
660 if c == idl {
661 var same: i64 = 1
662 var k: i64 = 0
663 while k < idl { if tmp[k] != id[k] { same = 0; k = idl } else { k = k + 1 } }
664 if same == 1 { hit = seq }
665 }
666 }
667 }
668 seq = seq + 1
669 }
670 sys_munmap(tmp, STS_FINDCAP)
671 return hit
672}
673// sts_replace_fast: overwrite the row at `seq` in ONE new segment. NEWEST-WINS per key means every reader sees the new
674// bytes at the same position: row count and order are unchanged, q:n is untouched, NO READER CHANGES ARE REQUIRED.
675// FAIL-CLOSED: no q:n, or seq outside 0..q:n-1, is refused (-1) with the plane untouched. Same CAS discipline as
676// sts_append_fast (baseline segid taken BEFORE the q:n read; a commit that lands in between returns STS_ERR_STALE).
677// LOCKING: like sts_append_fast this is the RAW primitive -- the caller holds <prefix>plock (nx_store_put does, at main).
678// Returns q:n (the unchanged row count) on success, -1 refused, -2 write error, STS_ERR_STALE on a lost race.
679func sts_replace_fast(prefix: *u8, seq: i64, row: *u8, rowlen: i64) -> i64 {
680 if rowlen <= 0 { return 0 - 1 }
681 if seq < 0 { return 0 - 1 }
682 let pq: *i64 = sts_mm(STS_OUTCAP) as *i64
683 let lq: *i64 = sts_mm(STS_OUTCAP) as *i64
684 let gen0: i64 = ss_max_segid(prefix)
685 if ss_get(prefix, "q:n" as *u8, pq, lq) != 1 { return 0 - 1 }
686 let n: i64 = sts_atoi(pq[0] as *u8, lq[0])
687 if seq >= n { return 0 - 1 }
688 let key: *u8 = sts_mm(STS_KEYCAP)
689 sts_rowkey(seq, key)
690 let w: *i64 = ss_begin_cap(rowlen + STS_WSLACK)
691 if ss_add(w, STS_KIND_LIVE, key, row, rowlen) < 0 { return 0 - 2 }
692 let crc: i64 = ss_commit_cas(prefix, w, ss_next_segid(prefix), gen0)
693 if crc == SS_ERR_STALE { return STS_ERR_STALE }
694 if crc != 0 { return 0 - 2 }
695 return n
696}