nx_swarm_endpoint_lib.nx source
↩ module page · 245 lines · 8952 B
1// nx_swarm_endpoint_lib.nx -- THE one act every swarm caller performs: resolve a ROLE to an ADDRESS.
2//
3// WHY (a live outage, measured 2026-07-30): the laptop GPU endpoint was a hardcoded string literal in
4// FIVE files -- nx_mesh_lb:42, nx_swarm_coord:66, nx_worker_dispatch:67, nx_hostctl:268,
5// nx_mgmt_api:456. DHCP moved the box from .193 to .192 and all five went stale in the same instant.
6// nx_swarm_coord:66 even carried the comment "worker_dispatch SSOT" while COPYING the value -- a
7// claimed single source of truth that was really a fifth duplicate. Meanwhile sd-server sat HEALTHY
8// on the 5080 and all four swarm gates read GREEN, because a gate that measures the PLAN does not
9// measure the REACHABILITY.
10//
11// LAW APPLIED: a fix that must be remembered at N sites has to bind to the ONE act all N perform.
12// That act is this function. Callers ask for a role; nobody spells an address again.
13//
14// LAYER: lives in runtime/ (the PRIMITIVE layer) precisely so BOTH runtime/ organs and
15// _hdl_build/ organs can import it -- the import edge is directed and primitives may not depend on
16// tools (seq1450). Library only: NO main(), so any organ can import it without a duplicate entry.
17//
18// FAIL-CLOSED: unknown role or unreadable table returns 0, never a fabricated address. A wrong
19// endpoint fails SILENTLY at dispatch; a missing one fails LOUDLY at resolve. Prefer loud.
20//
21// The table is re-read on every call (~1KB), so an address edit takes effect with no restart.
22// license_tier: ORIGINAL
23import "nx_syscalls.nx"
24const K_MAGIC_65536: i64 = 65536
25const K_MAGIC_65535: i64 = 65535
26
27func se_len(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i }
28
29func se_put(o: *u8, at: i64, s: *u8) -> i64 {
30 var i: i64 = 0
31 var a: i64 = at
32 while s[i] != (0 as u8) { o[a] = s[i]; a = a + 1; i = i + 1 }
33 return a
34}
35
36func se_putn(o: *u8, at: i64, buf: *u8, off: i64, n: i64) -> i64 {
37 var i: i64 = 0
38 var a: i64 = at
39 while i < n { o[a] = buf[off + i]; a = a + 1; i = i + 1 }
40 return a
41}
42
43func se_putd(o: *u8, at: i64, v: i64) -> i64 {
44 if v == 0 { o[at] = (48 as u8); return at + 1 }
45 let tmp: *u8 = sys_mmap(32)
46 var x: i64 = v
47 var k: i64 = 0
48 while x > 0 { tmp[k] = ((48 + (x - ((x / 10) * 10))) as u8); x = x / 10; k = k + 1 }
49 var a: i64 = at
50 var j: i64 = k - 1
51 while j >= 0 { o[a] = tmp[j]; a = a + 1; j = j - 1 }
52 return a
53}
54
55func se_ceq(a: *u8, b: *u8) -> i64 {
56 var i: i64 = 0
57 var ok: i64 = 1
58 var go: i64 = 1
59 while go == 1 {
60 if a[i] != b[i] { ok = 0; go = 0 }
61 else { if a[i] == (0 as u8) { go = 0 } else { i = i + 1 } }
62 }
63 return ok
64}
65
66func se_seq(buf: *u8, off: i64, n: i64, s: *u8) -> i64 {
67 if se_len(s) != n { return 0 }
68 var i: i64 = 0
69 var ok: i64 = 1
70 while i < n { if buf[off + i] != s[i] { ok = 0; i = n } else { i = i + 1 } }
71 return ok
72}
73
74func se_has(buf: *u8, off: i64, n: i64, needle: *u8) -> i64 {
75 let m: i64 = se_len(needle)
76 if m == 0 { return 0 }
77 if m > n { return 0 }
78 var i: i64 = 0
79 var hit: i64 = 0
80 while i <= n - m {
81 var j: i64 = 0
82 var same: i64 = 1
83 while j < m { if buf[off + i + j] != needle[j] { same = 0; j = m } else { j = j + 1 } }
84 if same == 1 { hit = 1; i = n - m + 1 } else { i = i + 1 }
85 }
86 return hit
87}
88
89func se_field(buf: *u8, s: i64, e: i64, idx: i64, box: *i64) -> i64 {
90 var p: i64 = s
91 var f: i64 = 0
92 while f < idx {
93 var go: i64 = 1
94 while go == 1 {
95 if p >= e { go = 0 }
96 else { if buf[p] == (9 as u8) { p = p + 1; go = 0 } else { p = p + 1 } }
97 }
98 f = f + 1
99 }
100 if p >= e { box[0] = 0; box[1] = 0; return 0 }
101 var q: i64 = p
102 var g2: i64 = 1
103 while g2 == 1 {
104 if q >= e { g2 = 0 }
105 else { if buf[q] == (9 as u8) { g2 = 0 } else { q = q + 1 } }
106 }
107 box[0] = p
108 box[1] = q - p
109 return 1
110}
111
112func se_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
113 let fd: i64 = sys_openat_rd(path)
114 if fd < 0 { return 0 - 1 }
115 var t: i64 = 0
116 var r: i64 = 1
117 while r > 0 {
118 r = sys_read(fd, (((buf as i64) + t) as *u8), cap - t)
119 if r > 0 { t = t + r }
120 }
121 sys_close(fd)
122 return t
123}
124
125// ctx layout (plain i64 slots -- never struct fields, per the house build rules):
126// ctx[0]=buf ptr ctx[1]=byte count ctx[2]=rows ptr ctx[3]=row count (0-1 = unreadable table)
127// rows stride 8: role_off,role_len,node_off,node_len,addr_off,addr_len,desc_off,desc_len
128func se_ctx() -> *i64 {
129 let ctx: *i64 = sys_mmap(64) as *i64
130 let buf: *u8 = sys_mmap(K_MAGIC_65536)
131 // CWD-PROOF (2026-08-04): the gen daemon runs with CWD=/volume1/ai/gen (its batchjob-*.json are
132 // CWD-relative there), where the relative read misses and every consumer silently fell back to
133 // stale argv endpoints -- the exact outage this lib exists to end, reintroduced by a CWD. A
134 // consumer's working directory must not decide whether the SSOT resolves: try relative (local
135 // buildroot/gate runs), then the estate-canonical absolute path. Fail-closed only if BOTH miss.
136 var n: i64 = se_slurp("knowledge/swarm_nodes.conf" as *u8, buf, K_MAGIC_65535)
137 if n <= 0 { n = se_slurp("/volume1/homes/elderwesto/nishihost/knowledge/swarm_nodes.conf" as *u8, buf, K_MAGIC_65535) }
138 ctx[0] = buf as i64
139 ctx[1] = n
140 ctx[2] = 0
141 ctx[3] = 0 - 1
142 if n <= 0 { return ctx }
143 let rows: *i64 = sys_mmap(64 * 8 * 8) as *i64
144 let box: *i64 = sys_mmap(32) as *i64
145 var nr: i64 = 0
146 var p: i64 = 0
147 while p < n {
148 var q: i64 = p
149 var g: i64 = 1
150 while g == 1 {
151 if q >= n { g = 0 }
152 else { if buf[q] == (10 as u8) { g = 0 } else { q = q + 1 } }
153 }
154 if q > p + 1 {
155 if buf[p] == (82 as u8) {
156 if buf[p + 1] == (9 as u8) {
157 if nr < 64 {
158 se_field(buf, p, q, 1, box); rows[nr * 8 + 0] = box[0]; rows[nr * 8 + 1] = box[1]
159 se_field(buf, p, q, 2, box); rows[nr * 8 + 2] = box[0]; rows[nr * 8 + 3] = box[1]
160 se_field(buf, p, q, 3, box); rows[nr * 8 + 4] = box[0]; rows[nr * 8 + 5] = box[1]
161 se_field(buf, p, q, 4, box); rows[nr * 8 + 6] = box[0]; rows[nr * 8 + 7] = box[1]
162 nr = nr + 1
163 }
164 }
165 }
166 }
167 p = q + 1
168 }
169 ctx[2] = rows as i64
170 ctx[3] = nr
171 return ctx
172}
173
174func se_find(ctx: *i64, role: *u8) -> i64 {
175 if ctx[3] < 0 { return 0 - 1 }
176 let buf: *u8 = ctx[0] as *u8
177 let rows: *i64 = ctx[2] as *i64
178 let nr: i64 = ctx[3]
179 var i: i64 = 0
180 var hit: i64 = 0 - 1
181 while i < nr {
182 if se_seq(buf, rows[i * 8 + 0], rows[i * 8 + 1], role) == 1 { hit = i; i = nr }
183 else { i = i + 1 }
184 }
185 return hit
186}
187
188// role -> "ip:port" (fresh NUL-terminated buffer), or 0 as *u8 when unknown. NEVER fabricates.
189func se_addr(role: *u8) -> *u8 {
190 let ctx: *i64 = se_ctx()
191 let idx: i64 = se_find(ctx, role)
192 if idx < 0 { return 0 as *u8 }
193 let buf: *u8 = ctx[0] as *u8
194 let rows: *i64 = ctx[2] as *i64
195 let out: *u8 = sys_mmap(256)
196 var o: i64 = se_putn(out, 0, buf, rows[idx * 8 + 4], rows[idx * 8 + 5])
197 out[o] = 0 as u8
198 return out
199}
200
201// role -> just the HOST (address with the :port stripped), or 0 as *u8.
202// Exists because nx_mesh_lb renders "name @ ip" with no port -- a consumer that needs a narrower
203// slice of the truth must still take it FROM the truth, never re-spell it.
204func se_host(role: *u8) -> *u8 {
205 let a: *u8 = se_addr(role)
206 if (a as i64) == 0 { return 0 as *u8 }
207 let out: *u8 = sys_mmap(256)
208 var i: i64 = 0
209 var go: i64 = 1
210 while go == 1 {
211 if a[i] == (0 as u8) { go = 0 }
212 else { if a[i] == (58 as u8) { go = 0 } else { out[i] = a[i]; i = i + 1 } }
213 }
214 out[i] = 0 as u8
215 return out
216}
217
218// role -> the short human label, or 0 as *u8.
219func se_desc(role: *u8) -> *u8 {
220 let ctx: *i64 = se_ctx()
221 let idx: i64 = se_find(ctx, role)
222 if idx < 0 { return 0 as *u8 }
223 let buf: *u8 = ctx[0] as *u8
224 let rows: *i64 = ctx[2] as *i64
225 let out: *u8 = sys_mmap(256)
226 var o: i64 = se_putn(out, 0, buf, rows[idx * 8 + 6], rows[idx * 8 + 7])
227 out[o] = 0 as u8
228 return out
229}
230
231// role -> "ip:port (short label)" = the display form the five old literals spelled by hand.
232func se_addr_desc(role: *u8) -> *u8 {
233 let ctx: *i64 = se_ctx()
234 let idx: i64 = se_find(ctx, role)
235 if idx < 0 { return 0 as *u8 }
236 let buf: *u8 = ctx[0] as *u8
237 let rows: *i64 = ctx[2] as *i64
238 let out: *u8 = sys_mmap(512)
239 var o: i64 = se_putn(out, 0, buf, rows[idx * 8 + 4], rows[idx * 8 + 5])
240 o = se_put(out, o, " (" as *u8)
241 o = se_putn(out, o, buf, rows[idx * 8 + 6], rows[idx * 8 + 7])
242 o = se_put(out, o, ")" as *u8)
243 out[o] = 0 as u8
244 return out
245}