nx_raci_sov.nx source
↩ module page · 215 lines · 11367 B
1// nx_raci_sov.nx -- get the conductor's RACI OFF the TSV into the SOVEREIGN seg_store (operator: "get us off
2// tsv and all the other third party bullshit"). The conductor (nx_harmony_conduct) + the pulse governance
3// read role accountability from knowledge/registry/nishi_raci.tsv -- a third-party flat TSV. This migrates
4// those rows into knowledge/store/raci (sovereign seg_store) via the PROVEN nx_role_store_migrate pattern
5// (read -> seed -> byte-verify every row), and answers `raci_is_accountable(role)` FROM THE STORE -- no TSV.
6// It also FIXES a latent bug: the hardcoded owner list said {engineer,doctor,researcher,adversarial,pm} but
7// the real contract's Accountable roles are {researcher,workstream,doctor,engineer,publisher,supervisor,pm,
8// warden} -- "adversarial" is NOT a RACI role, and workstream/publisher/supervisor/warden were missing.
9// Sovereign. license_tier: ORIGINAL
10import "nx_seg_store.nx"
11import "nx_syscalls.nx"
12
13const RACI_TSV: *u8 = "knowledge/registry/nishi_raci.tsv"
14const RACI_STORE: *u8 = "knowledge/store/raci"
15
16// key "raci:row:K" -> out
17func rsv_key(k: i64, out: *u8) -> i64 {
18 var o: i64=0; let p: *u8="raci:row:" as *u8; var i: i64=0
19 while p[i]!=(0 as u8){ out[o]=p[i]; o=o+1; i=i+1 }
20 // ★★★THE CHOKEPOINT, AND THE REASON THE FIRST FIX WAS NOT ENOUGH. This built its digits in a
21 // sys_mmap(24) scratch buffer -- and rsv_key is called ONCE PER ROW by every scan in this file. So even
22 // after hoisting the callers' own per-row mmap, each iteration STILL burned a page here: 2 allocations
23 // per row became 1, and nx_orchestrate_gate went from 2 PASS lines to 4 and then timed out again.
24 // MIGRATE THE CHOKEPOINT, NOT THE LEAF -- one allocation-free key builder fixes every caller at once.
25 // Digits are counted first and written in place, which needs no scratch and is exactly equivalent.
26 if k==0 { out[o]=48 as u8; o=o+1 } else {
27 var nd: i64=0; var m: i64=k
28 while m>0 { nd=nd+1; m=m/10 }
29 m=k
30 var j: i64=nd-1
31 while j>=0 { out[o+j]=(48+(m%10)) as u8; m=m/10; j=j-1 }
32 o=o+nd
33 }
34 out[o]=0 as u8; return 0
35}
36
37// MIGRATE the RACI rows into the store (skip '#' comments + empty), then byte-verify each row reads back.
38// Re-migrates each run (the RACI is the static coordination contract until the TSV is retired). Returns
39// verified-row-count via verp[0]; total source rows via totp[0]. GREEN when verp==totp.
40func raci_migrate(totp: *i64, verp: *i64) -> i64 {
41 let szp: *i64 = sys_mmap(16) as *i64
42 let buf: *u8 = ss_readall(RACI_TSV, szp)
43 let sz: i64 = szp[0]
44 if sz <= 0 { totp[0]=0; verp[0]=0; return 0 }
45 let lp: *i64 = sys_mmap(8*512) as *i64; let ll: *i64 = sys_mmap(8*512) as *i64
46 var k: i64 = 0; var i: i64 = 0; var ls: i64 = 0
47 while i <= sz {
48 var nl: i64 = 0; if i>=sz { nl=1 } else { if buf[i]==(10 as u8) { nl=1 } }
49 if nl==1 {
50 let len: i64 = i - ls
51 if len>0 { if (buf[ls] as i64) != 35 { if k<512 { lp[k]=(buf as i64)+ls; ll[k]=len; k=k+1 } } } // skip '#'
52 ls = i+1
53 }
54 i=i+1
55 }
56 totp[0]=k
57 // seed every data row keyed by index, in one commit
58 let w: *i64 = ss_begin()
59 var j: i64 = 0
60 while j<k { let rk: *u8=sys_mmap(64); rsv_key(j, rk); ss_add(w, 1, rk, lp[j] as *u8, ll[j]); j=j+1 }
61 ss_commit(RACI_STORE, w, sys_now_realtime_sec())
62 // verify each row reads back byte-exact from the store
63 let h: *i64 = ss_open(RACI_STORE)
64 let pq: *i64=sys_mmap(16) as *i64; let lq: *i64=sys_mmap(16) as *i64
65 var ver: i64 = 0; var j2: i64 = 0
66 while j2<k {
67 let rk: *u8=sys_mmap(64); rsv_key(j2, rk)
68 if ss_hget(h, rk, pq, lq)==1 { if lq[0]==ll[j2] { let a: *u8=pq[0] as *u8; let b: *u8=lp[j2] as *u8; var eq: i64=1; var x: i64=0; while x<lq[0] { if a[x]!=b[x] { eq=0 } x=x+1 } if eq==1 { ver=ver+1 } } }
69 j2=j2+1
70 }
71 verp[0]=ver
72 return ver
73}
74
75func rsv_field(line: *u8, len: i64, idx: i64, out: *u8) -> i64 {
76 var f: i64=0; var i: i64=0; var w: i64=0
77 while i<len { let c: i64=line[i] as i64
78 if c==9 { if f==idx { out[w]=0 as u8; return 1 } f=f+1 } else { if f==idx { out[w]=line[i]; w=w+1 } }
79 i=i+1 }
80 if f==idx { out[w]=0 as u8; return 1 }
81 return 0
82}
83func rsv_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8){ if a[i]!=b[i]{return 0} i=i+1 } if b[i]!=(0 as u8){return 0} return 1 }
84func rsv_has(s: *u8, ch: i64) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ if (s[i] as i64)==ch {return 1} i=i+1 } return 0 }
85
86// SOVEREIGN ownership: is `role` Accountable ('A') for ANY activity? reads the STORE, not the TSV. Iterates
87// raci:row:0.. until a gap. The grounded replacement for the hardcoded owner list.
88func raci_is_accountable(role: *u8) -> i64 {
89 let h: *i64 = ss_open(RACI_STORE)
90 if (h as i64)==0 { return 0 }
91 let pq: *i64=sys_mmap(16) as *i64; let lq: *i64=sys_mmap(16) as *i64
92 let rolef: *u8=sys_mmap(64); let letf: *u8=sys_mmap(64)
93 var k: i64=0; var go: i64=1
94 let rk: *u8=sys_mmap(64) // hoisted: same per-row page burn as raci_accountable_for had
95 while go==1 {
96 rsv_key(k, rk)
97 if ss_hget(h, rk, pq, lq)==1 {
98 let line: *u8=pq[0] as *u8; let ln: i64=lq[0]
99 rsv_field(line, ln, 0, rolef); rsv_field(line, ln, 2, letf)
100 if rsv_streq(rolef, role)==1 { if rsv_has(letf, 65)==1 { ss_close(h); return 1 } } // 'A' = Accountable
101 k=k+1
102 } else { go=0 }
103 }
104 ss_close(h)
105 return 0
106}
107
108// PUBLIC row accessor (reader-flip export, 2026-07-16): row k's bytes into out (NUL-terminated,
109// capped), from the STORE. Returns len, or -1 when k is past the last row (the iteration sentinel).
110// ---- seq1789: THE HANDLE IS HOISTED, AND EVERY OPEN IS CLOSED -------------------------------------
111// THE DEFECT (measured 2026-07-30): raci_row opened the seg-store ON EVERY ROW and never closed it, and
112// raci_read_all called raci_row once per row -- so ONE full-contract read cost N opens, each mapping every
113// live segment, none released. nx_orchestrate_gate calls it 5+ times and HUNG; that hang propagated up
114// through nx_swcompare_evidence (which forks domain gates with no deadline) until the whole `librarian`
115// domain was unmeasurable and the symptom presented as an MCP transport error.
116// ss_close's own header predicted this exactly: the leak parks a process in uninterruptible sleep, so it
117// "presents as a HANG, not as an OOM". This file was one of the ~133 openers with no matching closer.
118// LAW: AN UNCLOSED RESOURCE INSIDE A LOOP IS NOT A LEAK, IT IS A CLOCK -- it fails at a size, not at a
119// line, so it looks like a hang in whoever calls you rather than a bug where it is written.
120// SHAPE OF THE FIX (the reason there are now two functions): the handle-taking core does the work, the
121// convenience wrapper owns the lifetime. Any caller that needs MANY rows takes the handle once instead of
122// paying an open per row -- which is the difference between O(1) and O(N) mappings for the same answer.
123
124// CORE: row k's bytes into out (NUL-terminated, capped) from an ALREADY-OPEN store. Opens nothing and
125// closes nothing -- the caller owns the handle. Returns len, or -1 when k is past the last row.
126func raci_row_h(h: *i64, k: i64, out: *u8, cap: i64) -> i64 {
127 if (h as i64)==0 { return 0 - 1 }
128 let pq: *i64=sys_mmap(16) as *i64
129 let lq: *i64=sys_mmap(16) as *i64
130 let rk: *u8=sys_mmap(64)
131 rsv_key(k, rk)
132 if ss_hget(h, rk, pq, lq)!=1 { return 0 - 1 }
133 var n: i64 = lq[0]
134 if n > cap - 1 { n = cap - 1 }
135 let src: *u8 = pq[0] as *u8
136 var i: i64=0
137 while i<n { out[i]=src[i]; i=i+1 }
138 out[n]=0 as u8
139 return n
140}
141
142// PUBLIC row accessor (reader-flip export, 2026-07-16): unchanged contract for single-row callers --
143// same arguments, same return, same sentinel -- but it now RELEASES what it maps. Callers wanting more
144// than one row should open once and use raci_row_h.
145func raci_row(k: i64, out: *u8, cap: i64) -> i64 {
146 let h: *i64 = ss_open(RACI_STORE)
147 if (h as i64)==0 { return 0 - 1 }
148 let n: i64 = raci_row_h(h, k, out, cap)
149 ss_close(h)
150 return n
151}
152
153// PM/routing export (reader-flip, 2026-07-16): the Accountable role for `activity`, FROM THE STORE
154// (single-A invariant validated by nx_raci_gate, so the first 'A' match is THE owner). 1 = found
155// (out_role NUL-terminated), 0 = no accountable row. Replaces every TSV activity-lookup.
156func raci_accountable_for(activity: *u8, out_role: *u8) -> i64 {
157 let h: *i64 = ss_open(RACI_STORE)
158 if (h as i64)==0 { return 0 }
159 let pq: *i64=sys_mmap(16) as *i64
160 let lq: *i64=sys_mmap(16) as *i64
161 let actf: *u8=sys_mmap(64)
162 let letf: *u8=sys_mmap(64)
163 var k: i64=0
164 var go: i64=1
165 // ★MEASURED 2026-07-30: this mmap was INSIDE the loop -- one fresh 64-byte mapping PER ROW. mmap is
166 // page-granular, so every iteration burned a whole 4KiB page plus a syscall, and nothing ever unmapped
167 // them. A lookup that MISSES walks the entire plane, so the cost is O(rows) pages for a single failed
168 // question. LIVE EFFECT: nx_orchestrate_gate printed 2 PASS lines and then TIMED OUT at the 12s deadline
169 // on its THIRD lookup -- the first two matched early rows, the third scanned to the end -- which made the
170 // whole `librarian` domain read RED in nx_sota_status, which is the single BLOCK in nx_deploy_ready.
171 // ★★★ONE ALLOCATION IN A HOT LOOP IS A SCALE BUG WEARING A CORRECTNESS COSTUME: it is invisible on a
172 // small plane, it never returns a wrong answer, and it takes down a domain's evidence once the data grows.
173 // rsv_key overwrites the buffer every pass, so a single hoisted allocation is exactly equivalent.
174 let rk: *u8=sys_mmap(64)
175 while go==1 {
176 rsv_key(k, rk)
177 if ss_hget(h, rk, pq, lq)==1 {
178 let line: *u8=pq[0] as *u8
179 let ln: i64=lq[0]
180 rsv_field(line, ln, 1, actf)
181 rsv_field(line, ln, 2, letf)
182 if rsv_streq(actf, activity)==1 { if rsv_has(letf, 65)==1 { rsv_field(line, ln, 0, out_role); ss_close(h); return 1 } }
183 k=k+1
184 } else { go=0 }
185 }
186 ss_close(h)
187 return 0
188}
189
190// FULL-CONTRACT reader (reader-flip export, 2026-07-16): every row from the STORE, newline-joined,
191// byte-compatible with the old TSV data rows -- so full-matrix consumers (dashboard/harmony/roster)
192// flip with a ONE-LINE swap of their file-read call. Returns total bytes (0 if store empty).
193func raci_read_all(out: *u8, cap: i64) -> i64 {
194 // ONE open for the whole contract (seq1789). This used to reach the store through raci_row, which
195 // opened it PER ROW and never released it -- same answer, N mappings, and the process eventually
196 // parked in uninterruptible sleep. Behaviour on a missing store is preserved exactly: empty, 0.
197 let h: *i64 = ss_open(RACI_STORE)
198 if (h as i64) == 0 { out[0] = 0 as u8; return 0 }
199 var o: i64 = 0
200 var k: i64 = 0
201 var go: i64 = 1
202 while go == 1 {
203 let n: i64 = raci_row_h(h, k, ((out as i64) + o) as *u8, cap - o - 1)
204 if n < 0 { go = 0 } else {
205 o = o + n
206 out[o] = 10 as u8
207 o = o + 1
208 k = k + 1
209 if o >= cap - 2 { go = 0 }
210 }
211 }
212 out[o] = 0 as u8
213 ss_close(h)
214 return o
215}