code wiki / _hdl_build / nx_raci.nx

nx_raci.nx source

↩ module page · 128 lines · 7147 B

1// nx_raci.nx -- THE NISHI TEAM RACI validator + reporter (the "hammered out" coordination contract). 2// 3// Reads the data-driven registry (knowledge/registry/nishi_raci.tsv: role<TAB>activity<TAB>raci-letters) and 4// enforces the S-class RACI integrity rules (synthesized from the Nishi Researcher's team_*.raw corpus -- 5// responsibility-assignment-matrix + separation-of-duties): EVERY activity has EXACTLY ONE Accountable (A) and 6// AT LEAST ONE Responsible (R). One-A = no ambiguity about who owns it (= no competition); >=1-R = someone 7// actually does it. Prints the matrix (per activity: who is A / R / C / I) so the team contract is legible, 8// and exits non-zero if any activity violates -- so it IS its own gate / CI check. 9// 10// usage: nx_raci [registry-path] (default knowledge/registry/nishi_raci.tsv) 11// license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 14 15const RC_MAXROWS: i64 = 512 16const RC_STR: i64 = 40 17const RC_MAXACT: i64 = 48 18const RC_CAP: i64 = 262144 19const RC_DEFAULT: *u8 = "knowledge/registry/nishi_raci.tsv" 20 21func rc_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 22// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 23// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 24// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 25// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 26func rc_wn(v: i64) -> i64 { nxi_out(v); return 0 } 27func rc_read(path: *u8, buf: *u8, cap: i64) -> i64 { 28 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 } 29 var off: i64 = 0; var go: i64 = 1 30 while go == 1 { if off >= cap { go = 0 } else { let r: i64 = sys_read(fd, buf + off, cap - off); if r <= 0 { go = 0 } else { off = off + r } } } 31 sys_close(fd); return off 32} 33func rc_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 } 34func rc_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 } 35func rc_cpy(dst: *u8, src: *u8, max: i64) -> i64 { var i: i64=0; while src[i]!=(0 as u8) { if i<max-1 {dst[i]=src[i]} i=i+1 } dst[i]=0 as u8; return 0 } 36// idx-th tab/newline field of line[0..len) -> out (NUL-term). 1 if found. 37func rc_field(line: *u8, len: i64, idx: i64, out: *u8, outcap: i64) -> i64 { 38 var f: i64=0; var i: i64=0; var w: i64=0 39 while i < len { let c: i64=line[i] as i64 40 if c==9 { if f==idx { out[w]=0 as u8; return 1 } f=f+1 } else { if f==idx { if w<outcap-1 { out[w]=line[i]; w=w+1 } } } 41 i=i+1 } 42 if f==idx { out[w]=0 as u8; return 1 } 43 return 0 44} 45// list roles for activity `act` having letter `ch` -> printed inline. returns count. 46func rc_roles_with(roleS: *u8, actS: *u8, letS: *u8, nrows: i64, act: *u8, ch: i64, verbose: i64) -> i64 { 47 var c: i64=0; var i: i64=0 48 while i < nrows { 49 if rc_streq(actS + i*RC_STR, act) == 1 { if rc_has(letS + i*RC_STR, ch) == 1 { 50 if verbose == 1 { if c > 0 { rc_w("," as *u8) } rc_w(roleS + i*RC_STR) } 51 c = c + 1 52 } } 53 i = i + 1 54 } 55 return c 56} 57 58// validate registry. returns # of violations (0 = valid). verbose -> print the matrix. 59func raci_validate(path: *u8, verbose: i64) -> i64 { 60 let buf: *u8 = sys_mmap(RC_CAP); let n: i64 = rc_read(path, buf, RC_CAP) 61 if n <= 0 { if verbose==1 { rc_w("RACI: registry empty/unreadable\n" as *u8) } return 0 - 1 } 62 let roleS: *u8 = sys_mmap(RC_MAXROWS*RC_STR); let actS: *u8 = sys_mmap(RC_MAXROWS*RC_STR); let letS: *u8 = sys_mmap(RC_MAXROWS*RC_STR) 63 let f: *u8 = sys_mmap(RC_STR) 64 var nrows: i64 = 0; var ls: i64 = 0; var i: i64 = 0 65 while i <= n { 66 var nl: i64 = 0; if i>=n {nl=1} else { if buf[i]==(10 as u8) {nl=1} } 67 if nl == 1 { 68 let ll: i64 = i - ls 69 if ll > 0 { 70 let line: *u8 = ((buf as i64)+ls) as *u8 71 if line[0] != (35 as u8) { // skip '#' comments 72 if rc_field(line, ll, 0, f, RC_STR)==1 { if f[0]!=(0 as u8) { 73 if nrows < RC_MAXROWS { 74 rc_cpy(roleS + nrows*RC_STR, f, RC_STR) 75 rc_field(line, ll, 1, actS + nrows*RC_STR, RC_STR) 76 rc_field(line, ll, 2, letS + nrows*RC_STR, RC_STR) 77 nrows = nrows + 1 78 } 79 } } 80 } 81 } 82 ls = i + 1 83 } 84 i = i + 1 85 } 86 // distinct activities 87 let dact: *u8 = sys_mmap(RC_MAXACT*RC_STR); var ndact: i64 = 0 88 var r: i64 = 0 89 while r < nrows { 90 let a: *u8 = actS + r*RC_STR; var seen: i64 = 0; var d: i64 = 0 91 while d < ndact { if rc_streq(dact + d*RC_STR, a)==1 { seen=1 } d=d+1 } 92 if seen==0 { if ndact < RC_MAXACT { rc_cpy(dact + ndact*RC_STR, a, RC_STR); ndact=ndact+1 } } 93 r = r + 1 94 } 95 if verbose==1 { rc_w("=== NISHI TEAM RACI (" as *u8); rc_wn(nrows); rc_w(" cells, " as *u8); rc_wn(ndact); rc_w(" activities) ===\n" as *u8) } 96 var violations: i64 = 0 97 var k: i64 = 0 98 while k < ndact { 99 let a: *u8 = dact + k*RC_STR 100 // count A and R (without printing) for the integrity check 101 var ac: i64 = 0; var rcc: i64 = 0; var j: i64 = 0 102 while j < nrows { if rc_streq(actS + j*RC_STR, a)==1 { if rc_has(letS + j*RC_STR, 65)==1 {ac=ac+1} if rc_has(letS + j*RC_STR, 82)==1 {rcc=rcc+1} } j=j+1 } 103 var ok: i64 = 1; if ac != 1 { ok = 0 } if rcc < 1 { ok = 0 } 104 if ok == 0 { violations = violations + 1 } 105 if verbose == 1 { 106 if ok==1 { rc_w("[OK] " as *u8) } else { rc_w("[!!] " as *u8) } 107 var aw: i64=0; while a[aw]!=(0 as u8){aw=aw+1} sys_write(1, a, aw); var pad: i64=11-aw; while pad>0 {rc_w(" " as *u8);pad=pad-1} 108 rc_w(" A=" as *u8); rc_roles_with(roleS,actS,letS,nrows,a,65,1) 109 rc_w(" R=" as *u8); rc_roles_with(roleS,actS,letS,nrows,a,82,1) 110 rc_w(" C=" as *u8); let cc: i64=rc_roles_with(roleS,actS,letS,nrows,a,67,1); if cc==0 {rc_w("-" as *u8)} 111 rc_w(" I=" as *u8); let ic: i64=rc_roles_with(roleS,actS,letS,nrows,a,73,1); if ic==0 {rc_w("-" as *u8)} 112 if ac != 1 { rc_w(" <-- VIOLATION: A-count=" as *u8); rc_wn(ac) } 113 if rcc < 1 { rc_w(" <-- VIOLATION: no Responsible" as *u8) } 114 rc_w("\n" as *u8) 115 } 116 k = k + 1 117 } 118 return violations 119} 120 121func main(argc: i64, argv: *i64) -> i64 { 122 var path: *u8 = RC_DEFAULT; if argc >= 2 { path = argv[1] as *u8 } 123 let v: i64 = raci_validate(path, 1) 124 if v < 0 { rc_w("RACI: ERROR (no registry)\n" as *u8); return 2 } 125 if v == 0 { rc_w("=== RACI VALID (every activity has exactly 1 Accountable + >=1 Responsible) ===\n" as *u8); return 0 } 126 rc_w("=== RACI INVALID: " as *u8); rc_wn(v); rc_w(" activity violation(s) ===\n" as *u8) 127 return 1 128}