code wiki / _hdl_build / nx_deploy_ready.nx
nx_deploy_ready.nx source
↩ module page · 270 lines · 15934 B
1// nx_deploy_ready.nx -- PRE-DEPLOY SAFETY GATE (operator: "prevent things like this... deploy... managed").
2// The capstone of the deploy-reliability trilogy: an agent/session calls this BEFORE deploying an organ to
3// learn if it is SAFE. Aggregates the supervised signals into ONE actionable verdict instead of 3 separate
4// checks -- proactive prevention (won't deploy into a drifted buildroot or after a contract regression).
5// Data-driven (rule 11): knowledge/registry/deploy_checks.tsv rows = name<TAB>file<TAB>marker<TAB>severity<TAB>remediation.
6// A check PASSES if <file> contains <marker>. severity BLOCK -> a fail makes deploy UNSAFE; WARN -> advisory.
7// nx_deploy_ready check [manifest] [target] (JSON: deploy_safe + per-check pass/severity + blockers + remediations)
8//
9// LOOSE COUPLING (operator 2026-09-02: "a supervisor deploy has no business being blocked by a search domain's
10// RED ... estate wide loose coupling small sharp intelligent pieces"). The evidence-honesty row used to be a
11// GLOBAL conjunction: any RED compare domain blocked EVERY deploy, so two content domains blocked a fleet-
12// supervisor memory-leak fix and the gate got overridden -- a gate that blocks too broadly is disabled in
13// practice and protects nothing. Now, when the caller names the deploy TARGET (a deploy_targets.conf row
14// name), that ONE row is SCOPED to the target's blast radius: it blocks iff the target's OWN domain, or a
15// SHARED-FATE domain (the deploy machinery itself), is named on the RED_DOMAINS= line nx_sota_status emits.
16// Every other row is unchanged. With no target, or an unmapped target, or an evidence log that carries no
17// RED_DOMAINS= line (an older producer), the row keeps its GLOBAL marker check -- the fallback fails in the
18// direction of REFUSING, never of acquitting, and the JSON names which scope applied so the audit is visible.
19// Data-driven (rule 11): knowledge/registry/deploy_domain.conf rows = <target> <domain>;
20// knowledge/registry/deploy_sharedfate.conf rows = one shared-fate domain per line.
21// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
22import "nx_syscalls.nx"
23
24const DR_CAP: i64 = 262144
25const DR_TAB: i64 = 9
26const DR_NL: i64 = 10
27const DR_HASH: i64 = 35
28const DR_SPACE: i64 = 32
29const DR_STDERR: i64 = 2
30const DR_SPAN: i64 = 16
31const DR_EXIT_USAGE: i64 = 2
32const DR_NAMECAP: i64 = 256
33const DR_DOMAIN_CONF: *u8 = "knowledge/registry/deploy_domain.conf"
34const DR_SHAREDFATE_CONF: *u8 = "knowledge/registry/deploy_sharedfate.conf"
35const DR_RED_KEY: *u8 = "RED_DOMAINS="
36const DR_SCOPED_ROW: *u8 = "evidence-honesty"
37
38func dr_werr(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(DR_STDERR, s, n); return 0 }
39func dr_vlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
40func dr_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o] = s[i]; o = o + 1; i = i + 1 } return o }
41func dr_catn(d: *u8, o: i64, v: i64) -> i64 { let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { d[o] = 45 as u8; o = o + 1; m = 0 - m } var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { d[o] = t[k-1-i]; o = o + 1; i = i + 1 } return o }
42func dr_cat_esc(d: *u8, o: i64, q: *u8, s: i64, e: i64) -> i64 { var i: i64 = s; while i < e { var c: i64 = q[i] as i64; if c == 34 { c = 39 } if c == 92 { c = 47 } if c < 32 { c = 32 } d[o] = c as u8; o = o + 1; i = i + 1 } return o }
43func dr_read(path: *u8, buf: *u8, cap: i64) -> i64 {
44 let fd: i64 = sys_openat_rd(path)
45 if fd < 0 { return 0 - 1 }
46 var n: i64 = 0
47 var go: i64 = 1
48 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
49 sys_close(fd)
50 return n
51}
52func dr_contains(buf: *u8, n: i64, lit: *u8) -> i64 {
53 var ll: i64 = 0
54 while lit[ll] != (0 as u8) { ll = ll + 1 }
55 if ll == 0 { return 1 }
56 var i: i64 = 0
57 while i + ll <= n {
58 var j: i64 = 0
59 var ok: i64 = 1
60 while j < ll { if buf[i+j] != lit[j] { ok = 0; j = ll } else { j = j + 1 } }
61 if ok == 1 { return 1 }
62 i = i + 1
63 }
64 return 0
65}
66func dr_le(q: *u8, i: i64, n: i64) -> i64 { var e: i64 = i; var s: i64 = 1; while s == 1 { if e >= n { s = 0 } else { if q[e] == (DR_NL as u8) { s = 0 } else { e = e + 1 } } } return e }
67func dr_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 {
68 var col: i64 = 0
69 var p: i64 = ls
70 while col < c {
71 var s: i64 = 1
72 while s == 1 { if p >= le { return 0 } if q[p] == (DR_TAB as u8) { s = 0 } else { p = p + 1 } }
73 p = p + 1
74 col = col + 1
75 }
76 var e: i64 = p
77 var s2: i64 = 1
78 while s2 == 1 { if e >= le { s2 = 0 } else { if q[e] == (DR_TAB as u8) { s2 = 0 } else { e = e + 1 } } }
79 out[0] = p
80 out[1] = e
81 return 1
82}
83func dr_cstr(q: *u8, s: i64, e: i64, dst: *u8) -> i64 { var i: i64 = 0; while s + i < e { dst[i] = q[s+i]; i = i + 1 } dst[i] = 0 as u8; return i }
84func dr_span_is(q: *u8, s: i64, e: i64, lit: *u8) -> i64 { var i: i64 = 0; while s + i < e { if lit[i] == (0 as u8) { return 0 } if q[s+i] != lit[i] { return 0 } i = i + 1 } if lit[i] != (0 as u8) { return 0 } return 1 }
85
86// ---- SCOPING HELPERS (2026-09-02) -------------------------------------------------------------------------
87// The RED_DOMAINS= line is " a b c " -- every name wrapped in spaces -- so the needle " <domain> " is an EXACT
88// token match: "search" can never match "performersearch". Returns 1 iff the evidence buffer carries a
89// RED_DOMAINS= line at all (out[0]=1) AND names <domain> (return 1). out[0]=0 means NO such line: an older
90// producer wrote this log, and the caller must fall back to the global marker rather than acquit.
91func dr_red_names(buf: *u8, n: i64, domain: *u8, out: *i64) -> i64 {
92 out[0] = 0
93 if dr_contains(buf, n, DR_RED_KEY) == 0 { return 0 }
94 out[0] = 1
95 let needle: *u8 = sys_mmap(DR_NAMECAP + 4)
96 var o: i64 = 0
97 needle[o] = DR_SPACE as u8; o = o + 1
98 var i: i64 = 0
99 while domain[i] != (0 as u8) { if i < DR_NAMECAP { needle[o] = domain[i]; o = o + 1 } i = i + 1 }
100 needle[o] = DR_SPACE as u8; o = o + 1
101 needle[o] = 0 as u8
102 return dr_contains(buf, n, needle)
103}
104// deploy_domain.conf: one row per deployable, "<target> <domain>" separated by a SPACE, hash-comment lines.
105// Copies the domain into dst and returns 1; 0 = target has no row (the caller treats that as GLOBAL scope).
106func dr_lookup_domain(conf: *u8, n: i64, target: *u8, dst: *u8) -> i64 {
107 var i: i64 = 0
108 while i < n {
109 let le: i64 = dr_le(conf, i, n)
110 if le > i { if (conf[i] as i64) != DR_HASH {
111 var p: i64 = i
112 var k: i64 = 0
113 var same: i64 = 1
114 while p < le { if conf[p] == (DR_SPACE as u8) { p = le + 1 } else { if target[k] == (0 as u8) { same = 0; p = le + 1 } else { if conf[p] != target[k] { same = 0; p = le + 1 } else { p = p + 1; k = k + 1 } } } }
115 if same == 1 { if target[k] == (0 as u8) {
116 var q: i64 = i + k
117 if q < le { if conf[q] == (DR_SPACE as u8) {
118 q = q + 1
119 var w: i64 = 0
120 while q < le { if conf[q] == (DR_SPACE as u8) { q = le } else { if w < DR_NAMECAP - 1 { dst[w] = conf[q]; w = w + 1 } q = q + 1 } }
121 dst[w] = 0 as u8
122 if w > 0 { return 1 }
123 } }
124 } }
125 } }
126 i = le + 1
127 }
128 return 0
129}
130// deploy_sharedfate.conf: one domain per line. Returns 1 iff ANY listed domain is on the RED_DOMAINS= line:
131// a RED in the deploy machinery itself is shared fate and blocks every target, exactly as before.
132func dr_sharedfate_red(sf: *u8, sfn: i64, ev: *u8, evn: i64) -> i64 {
133 let name: *u8 = sys_mmap(DR_NAMECAP)
134 let flag: *i64 = sys_mmap(8) as *i64
135 var i: i64 = 0
136 while i < sfn {
137 let le: i64 = dr_le(sf, i, sfn)
138 if le > i { if (sf[i] as i64) != DR_HASH {
139 var w: i64 = 0
140 var p: i64 = i
141 while p < le { if sf[p] == (DR_SPACE as u8) { p = le } else { if w < DR_NAMECAP - 1 { name[w] = sf[p]; w = w + 1 } p = p + 1 } }
142 name[w] = 0 as u8
143 if w > 0 { if dr_red_names(ev, evn, name, flag) == 1 { return 1 } }
144 } }
145 i = le + 1
146 }
147 return 0
148}
149
150func main(argc: i64, argv: *i64) -> i64 {
151 var verb: *u8 = "check" as *u8
152 if argc > 1 { verb = argv[1] as *u8 }
153 if dr_contains(verb, dr_vlen(verb), "check" as *u8) == 0 { dr_werr("usage: nx_deploy_ready check [manifest] [target]\n" as *u8); sys_exit(DR_EXIT_USAGE); return DR_EXIT_USAGE }
154 var mpath: *u8 = "knowledge/registry/deploy_checks.tsv" as *u8
155 if argc > 2 { mpath = argv[2] as *u8 }
156 // ---- the deploy TARGET (optional argv[3]) resolves to ONE compare domain = the blast radius ----
157 var have_target: i64 = 0
158 var target: *u8 = "" as *u8
159 if argc > 3 { target = argv[3] as *u8; if target[0] != (0 as u8) { have_target = 1 } }
160 let tdomain: *u8 = sys_mmap(DR_NAMECAP)
161 tdomain[0] = 0 as u8
162 var mapped: i64 = 0
163 let dconf: *u8 = sys_mmap(DR_CAP)
164 var dcn: i64 = 0
165 let sfconf: *u8 = sys_mmap(DR_CAP)
166 var sfn: i64 = 0
167 if have_target == 1 {
168 dcn = dr_read(DR_DOMAIN_CONF, dconf, DR_CAP)
169 if dcn > 0 { mapped = dr_lookup_domain(dconf, dcn, target, tdomain) }
170 sfn = dr_read(DR_SHAREDFATE_CONF, sfconf, DR_CAP)
171 if sfn < 0 { sfn = 0 }
172 }
173 let man: *u8 = sys_mmap(DR_CAP)
174 let mn: i64 = dr_read(mpath, man, DR_CAP)
175 if mn <= 0 { dr_werr("DR-FAIL manifest empty or unreadable\n" as *u8); sys_exit(1); return 1 }
176 let fbuf: *u8 = sys_mmap(DR_CAP)
177 let fpath: *u8 = sys_mmap(512)
178 let mark: *u8 = sys_mmap(512)
179 let c0: *i64 = sys_mmap(DR_SPAN) as *i64
180 let c1: *i64 = sys_mmap(DR_SPAN) as *i64
181 let c2: *i64 = sys_mmap(DR_SPAN) as *i64
182 let c3: *i64 = sys_mmap(DR_SPAN) as *i64
183 let c4: *i64 = sys_mmap(DR_SPAN) as *i64
184 let redflag: *i64 = sys_mmap(8) as *i64
185 let out: *u8 = sys_mmap(DR_CAP)
186 var o: i64 = 0
187 o = dr_cat(out, o, "{\"verb\":\"check\",\"checks\":[" as *u8)
188 var total: i64 = 0
189 var blockers: i64 = 0
190 var warns: i64 = 0
191 var emitted: i64 = 0
192 // scope_kind: 0 global (no target) | 1 domain-scoped | 2 global-unmapped-target | 3 global-no-RED_DOMAINS-line
193 var scope_kind: i64 = 0
194 if have_target == 1 { if mapped == 1 { scope_kind = 1 } else { scope_kind = 2 } }
195 var i: i64 = 0
196 while i < mn {
197 let le: i64 = dr_le(man, i, mn)
198 if le > i { if (man[i] as i64) != DR_HASH {
199 if dr_col(man, i, le, 0, c0) == 1 { if dr_col(man, i, le, 1, c1) == 1 { if dr_col(man, i, le, 2, c2) == 1 { if dr_col(man, i, le, 3, c3) == 1 {
200 dr_cstr(man, c1[0], c1[1], fpath)
201 dr_cstr(man, c2[0], c2[1], mark)
202 total = total + 1
203 let fn: i64 = dr_read(fpath, fbuf, DR_CAP)
204 var pass: i64 = 0
205 var scoped_here: i64 = 0
206 if scope_kind == 1 { if dr_span_is(man, c0[0], c0[1], DR_SCOPED_ROW) == 1 {
207 // THE SCOPED ROW: block iff the target's OWN domain or a SHARED-FATE domain is RED.
208 // An evidence log with no RED_DOMAINS= line cannot be scoped -> global marker (refuse-side).
209 if fn > 0 {
210 let own_red: i64 = dr_red_names(fbuf, fn, tdomain, redflag)
211 if redflag[0] == 1 {
212 scoped_here = 1
213 pass = 1
214 if own_red == 1 { pass = 0 }
215 if pass == 1 { if sfn > 0 { if dr_sharedfate_red(sfconf, sfn, fbuf, fn) == 1 { pass = 0 } } }
216 } else { scope_kind = 3 }
217 }
218 } }
219 if scoped_here == 0 { if fn > 0 { if dr_contains(fbuf, fn, mark) == 1 { pass = 1 } } }
220 var is_block: i64 = 0
221 if dr_span_is(man, c3[0], c3[1], "BLOCK" as *u8) == 1 { is_block = 1 }
222 if pass == 0 { if is_block == 1 { blockers = blockers + 1 } else { warns = warns + 1 } }
223 if emitted > 0 { o = dr_cat(out, o, "," as *u8) }
224 o = dr_cat(out, o, "{\"name\":\"" as *u8)
225 o = dr_cat_esc(out, o, man, c0[0], c0[1])
226 o = dr_cat(out, o, "\",\"pass\":" as *u8)
227 o = dr_catn(out, o, pass)
228 o = dr_cat(out, o, ",\"severity\":\"" as *u8)
229 o = dr_cat_esc(out, o, man, c3[0], c3[1])
230 o = dr_cat(out, o, "\"" as *u8)
231 if scoped_here == 1 { o = dr_cat(out, o, ",\"scope\":\"domain:" as *u8); o = dr_cat(out, o, tdomain); o = dr_cat(out, o, "\"" as *u8) }
232 if pass == 0 { if dr_col(man, i, le, 4, c4) == 1 { o = dr_cat(out, o, ",\"remediation\":\"" as *u8); o = dr_cat_esc(out, o, man, c4[0], c4[1]); o = dr_cat(out, o, "\"" as *u8) } }
233 o = dr_cat(out, o, "}" as *u8)
234 emitted = emitted + 1
235 } } } }
236 } }
237 i = le + 1
238 }
239 o = dr_cat(out, o, "],\"total\":" as *u8)
240 o = dr_catn(out, o, total)
241 o = dr_cat(out, o, ",\"blockers\":" as *u8)
242 o = dr_catn(out, o, blockers)
243 o = dr_cat(out, o, ",\"warnings\":" as *u8)
244 o = dr_catn(out, o, warns)
245 o = dr_cat(out, o, ",\"deploy_safe\":" as *u8)
246 if blockers == 0 { o = dr_cat(out, o, "true" as *u8) } else { o = dr_cat(out, o, "false" as *u8) }
247 o = dr_cat(out, o, ",\"scope\":\"" as *u8)
248 if scope_kind == 0 { o = dr_cat(out, o, "global" as *u8) }
249 if scope_kind == 1 { o = dr_cat(out, o, "domain:" as *u8); o = dr_cat(out, o, tdomain) }
250 if scope_kind == 2 { o = dr_cat(out, o, "global-unmapped-target:" as *u8); o = dr_cat(out, o, target) }
251 if scope_kind == 3 { o = dr_cat(out, o, "global-no-RED_DOMAINS-line" as *u8) }
252 o = dr_cat(out, o, "\",\"verdict\":\"" as *u8)
253 if blockers > 0 { o = dr_cat(out, o, "DEPLOY-BLOCKED" as *u8) } else { if warns > 0 { o = dr_cat(out, o, "DEPLOY-SAFE-WITH-WARNINGS" as *u8) } else { o = dr_cat(out, o, "DEPLOY-SAFE" as *u8) } }
254 o = dr_cat(out, o, "\",\"envelope\":\"manifest knowledge/registry/deploy_checks.tsv + each evidence file read bounded per DR_CAP; a check whose evidence file exceeds the cap reads TRUNCATED and its marker may be missed -- declared per the scale-law (F846), never silent. evidence-honesty is SCOPED to the target domain + shared-fate domains when a target is named and the log carries RED_DOMAINS=, else GLOBAL (refuse-side fallback)\"}\n" as *u8)
255 sys_write(1, out, o)
256 // ---- EXIT CODE NOW CARRIES THE VERDICT (2026-07-30) ------------------------------------------------
257 // This was sys_exit(0) UNCONDITIONALLY -- even when the verdict is DEPLOY-BLOCKED. So `nx_deploy_ready
258 // check && deploy` sailed straight through a blocking verdict, and NO caller checking $? could ever act
259 // on this gate. A gate whose exit code is constant cannot gate anything; it can only be read by something
260 // that already knows to parse its JSON. 0 = safe, 3 = DEPLOY-BLOCKED.
261 // WARNINGS DELIBERATELY STILL EXIT 0: warnings here are evidence DEBT, not a stop. A gate that exits
262 // nonzero on every warning gets wrapped in `|| true` and then protects nothing -- this file's own
263 // manifest makes that argument, and it is right.
264 // BLAST RADIUS MEASURED, NOT ASSUMED: grep across 19951 files found exactly ONE in-tree caller of
265 // nx_deploy_ready.elf (md_exec_deploy_ready), and it ignores the exit code and parses the JSON. So no
266 // existing in-tree behaviour changes; this only stops the gate from lying to future callers.
267 if blockers > 0 { sys_exit(3); return 3 }
268 sys_exit(0)
269 return 0
270}