code wiki / (root) / nx_http_health_emit.nx

nx_http_health_emit.nx source

↩ module page · 258 lines · 9686 B

1// nx_http_health_emit.nx -- /health and /ready endpoint emitter. 2// 3// RESTORED 2026-07-31. This code was NOT unwritten -- it was OVERWRITTEN. A dedupe/reconcile on 4// 2026-07-21 found two files named nx_http_health.nx and treated a NAME COLLISION as a COPY. They are 5// different organs on OPPOSITE sides of HTTP health: one PROBES a remote URL (a CLI with main()), this 6// one EMITS a /health response (a library). The reconcile kept the prober and renamed this to 7// nx_http_health.nx.dupe-reconciled, silently deleting the emit capability and darkening every consumer: 8// nx_http_health_test.nx, nx_audit_server_routed.nx, and wiki/nx_wiki_routes.nx (2 call sites). 9// 10// THE LAW IT PROVES, already in the corpus and violated anyway: a duplicate-basename detector cannot tell 11// a COPY from a COLLISION, and the remedies are OPPOSITE -- retire vs RENAME. Canonical must be chosen by 12// WHO IMPORTS IT, not by directory convention: this file had 3 importers, the prober had zero. 13// 14// Restored under a DISTINCT name rather than by taking the old one back, so the running prober binary is 15// untouched and the collision can never be load-bearing again. Probe and emit are different jobs and now 16// have different names (rule 9). 17// 18// Standard S-class hosting observability: 19// - /health => liveness probe (process is alive + responding) 20// - /ready => readiness probe (process is ready to serve) 21// 22// Per cardinal feedback-no-third-party-trust-native-or-nothing: 23// substrate's own probe handlers; no Prometheus SDK, no /healthz 24// framework, no liveness-probe-via-CRD. 25// 26// Per cardinal feedback-defensive-at-boundaries-trusting-internally: 27// these emitters never read external input; they emit a fixed 28// shape with caller-provided stats (uptime, request count, etc.). 29// 30// nx_capability_claims: 31// needs: [sealed_enum, bounded_buffer] 32// provides: [http_health_emit, http_ready_emit] 33// safety: [no_unchecked_deref, no_floating_point, no_syscall, 34// bounded_iteration, bit_equal_reproducible, 35// target_agnostic] 36// verdict: [sealed_enum_4_state] 37// license: ORIGINAL 38// kind: racing_crew_specialist 39// layer: L3 (algorithm: response shape emitter) 40 41// ---- Sealed enum: health-emit verdict ---------------------------- 42 43const NXHL_OK: i64 = 0 44const NXHL_OOM_BUFFER: i64 = 1 45const NXHL_BAD_ARG: i64 = 2 46const NXHL_VERDICT_N: i64 = 3 47 48func nxhl_verdict_is_valid(v: i64) -> i64 { 49 if v < 0 { return 0 } 50 if v >= NXHL_VERDICT_N { return 0 } 51 return 1 52} 53 54func nxhl_verdict_name(v: i64) -> *u8 { 55 if v == NXHL_OK { return "OK" as *u8 } 56 if v == NXHL_OOM_BUFFER { return "OOM_BUFFER" as *u8 } 57 if v == NXHL_BAD_ARG { return "BAD_ARG" as *u8 } 58 return "INVALID" as *u8 59} 60 61// ---- Sealed enum: health status ---------------------------------- 62// 63// Mirrors the convention from kubernetes / docker / consul health 64// checks. Substrate emits PASS / WARN / FAIL. Caller picks which 65// based on their own predicates. 66 67const NXHL_STATUS_PASS: i64 = 0 68const NXHL_STATUS_WARN: i64 = 1 69const NXHL_STATUS_FAIL: i64 = 2 70const NXHL_STATUS_N: i64 = 3 71 72func nxhl_status_is_valid(s: i64) -> i64 { 73 if s < 0 { return 0 } 74 if s >= NXHL_STATUS_N { return 0 } 75 return 1 76} 77 78func nxhl_status_name(s: i64) -> *u8 { 79 if s == NXHL_STATUS_PASS { return "pass" as *u8 } 80 if s == NXHL_STATUS_WARN { return "warn" as *u8 } 81 if s == NXHL_STATUS_FAIL { return "fail" as *u8 } 82 return "invalid" as *u8 83} 84 85// HTTP status code for each health status. 86// PASS -> 200 OK 87// WARN -> 200 OK (still healthy enough; consumers can filter) 88// FAIL -> 503 Service Unavailable 89func nxhl_status_http_code(s: i64) -> i64 { 90 if s == NXHL_STATUS_PASS { return 200 } 91 if s == NXHL_STATUS_WARN { return 200 } 92 if s == NXHL_STATUS_FAIL { return 503 } 93 return 500 94} 95 96// ---- Byte emit helpers (sealed-enum verdict) --------------------- 97 98func nxhl_put(out: *u8, off: *i64, cap: i64, b: i64) -> i64 { 99 if *off >= cap { return NXHL_OOM_BUFFER } 100 out[*off] = b as u8 101 *off = *off + 1 102 return NXHL_OK 103} 104 105func nxhl_put_cstr(out: *u8, off: *i64, cap: i64, s: *u8) -> i64 { 106 var i: i64 = 0 107 while s[i] != 0 { 108 let rc: i64 = nxhl_put(out, off, cap, s[i] as i64) 109 if rc != NXHL_OK { return rc } 110 i = i + 1 111 } 112 return NXHL_OK 113} 114 115func nxhl_put_bytes(out: *u8, off: *i64, cap: i64, src: *u8, n: i64) -> i64 { 116 var i: i64 = 0 117 while i < n { 118 let rc: i64 = nxhl_put(out, off, cap, src[i] as i64) 119 if rc != NXHL_OK { return rc } 120 i = i + 1 121 } 122 return NXHL_OK 123} 124 125// ---- i64 -> ASCII decimal (no syscalls; uses caller-provided scratch) ---- 126// 127// Caller provides a 24-byte scratch buffer (enough for any i64 in 128// decimal: max 20 digits + sign + NUL). Emits the digits forward 129// into out_buf via nxhl_put. 130 131func nxhl_put_dec(out: *u8, off: *i64, cap: i64, 132 scratch: *u8, v: i64) -> i64 { 133 if v == 0 { return nxhl_put(out, off, cap, 0x30) } 134 var n: i64 = v 135 var sign: i64 = 0 136 if n < 0 { sign = 1; n = 0 - n } 137 var k: i64 = 0 138 while n > 0 { 139 scratch[k] = (0x30 + (n - (n / 10) * 10)) as u8 140 n = n / 10 141 k = k + 1 142 } 143 if sign == 1 { 144 let rcs: i64 = nxhl_put(out, off, cap, 0x2d) 145 if rcs != NXHL_OK { return rcs } 146 } 147 var ri: i64 = k - 1 148 while ri >= 0 { 149 let rc: i64 = nxhl_put(out, off, cap, scratch[ri] as i64) 150 if rc != NXHL_OK { return rc } 151 ri = ri - 1 152 } 153 return NXHL_OK 154} 155 156// ---- /health response emitter ----------------------------------- 157// 158// Emits a full HTTP response: 159// 160// HTTP/1.1 <code> <reason>\r\n 161// Content-Type: application/health+json\r\n 162// Content-Length: <N>\r\n 163// \r\n 164// {"status":"pass","uptime_ms":12345,"checks":N} 165// 166// The Content-Type follows draft-inadarei-api-health-check-06 167// ("application/health+json"). Substrate uses this; consumers 168// that don't recognize it MIME-fallback to application/json. 169// 170// Caller supplies: 171// status sealed-enum NXHL_STATUS_* 172// uptime_ms monotonic uptime (caller computes; substrate 173// doesn't read sys_clock here) 174// n_checks number of internal checks aggregated into status 175// scratch 24-byte buffer for decimal conversion 176// out response buffer + cap 177// Returns sealed-enum verdict + writes total bytes to *out_n. 178 179func nx_http_emit_health( 180 out: *u8, cap: i64, out_n: *i64, 181 status: i64, uptime_ms: i64, n_checks: i64, 182 scratch: *u8) -> i64 { 183 if out == (0 as *u8) { return NXHL_BAD_ARG } 184 if out_n == (0 as *i64) { return NXHL_BAD_ARG } 185 if scratch == (0 as *u8) { return NXHL_BAD_ARG } 186 if cap <= 0 { return NXHL_BAD_ARG } 187 if nxhl_status_is_valid(status) != 1 { return NXHL_BAD_ARG } 188 189 // Body is variable-width (uptime_ms + n_checks), but Content-Length must be known BEFORE the headers 190 // are written. So: build the body at a reserved offset, measure it, emit headers at 0, then move the 191 // body down to sit immediately after them. 192 let body_start: i64 = 256 193 if cap < body_start + 128 { return NXHL_OOM_BUFFER } 194 195 var body_off: i64 = body_start 196 let r_body_start: i64 = nxhl_put_cstr(out, &body_off, cap, 197 "{\"status\":\"" as *u8) 198 if r_body_start != NXHL_OK { return r_body_start } 199 let r_status: i64 = nxhl_put_cstr(out, &body_off, cap, 200 nxhl_status_name(status)) 201 if r_status != NXHL_OK { return r_status } 202 let r_up_pre: i64 = nxhl_put_cstr(out, &body_off, cap, 203 "\",\"uptime_ms\":" as *u8) 204 if r_up_pre != NXHL_OK { return r_up_pre } 205 let r_up: i64 = nxhl_put_dec(out, &body_off, cap, scratch, uptime_ms) 206 if r_up != NXHL_OK { return r_up } 207 let r_chk_pre: i64 = nxhl_put_cstr(out, &body_off, cap, 208 ",\"checks\":" as *u8) 209 if r_chk_pre != NXHL_OK { return r_chk_pre } 210 let r_chk: i64 = nxhl_put_dec(out, &body_off, cap, scratch, n_checks) 211 if r_chk != NXHL_OK { return r_chk } 212 let r_body_end: i64 = nxhl_put(out, &body_off, cap, 0x7d) // } 213 if r_body_end != NXHL_OK { return r_body_end } 214 215 let body_n: i64 = body_off - body_start 216 217 var h_off: i64 = 0 218 let http_code: i64 = nxhl_status_http_code(status) 219 220 if http_code == 200 { 221 let rh: i64 = nxhl_put_cstr(out, &h_off, body_start, 222 "HTTP/1.1 200 OK\r\nContent-Type: application/health+json\r\nContent-Length: " as *u8) 223 if rh != NXHL_OK { return rh } 224 } else { 225 let rh: i64 = nxhl_put_cstr(out, &h_off, body_start, 226 "HTTP/1.1 503 Service Unavailable\r\nContent-Type: application/health+json\r\nContent-Length: " as *u8) 227 if rh != NXHL_OK { return rh } 228 } 229 let r_clen: i64 = nxhl_put_dec(out, &h_off, body_start, scratch, body_n) 230 if r_clen != NXHL_OK { return r_clen } 231 let r_blank: i64 = nxhl_put_cstr(out, &h_off, body_start, 232 "\r\n\r\n" as *u8) 233 if r_blank != NXHL_OK { return r_blank } 234 235 let move_n: i64 = body_n 236 var mi: i64 = 0 237 while mi < move_n { 238 out[h_off + mi] = out[body_start + mi] 239 mi = mi + 1 240 } 241 242 *out_n = h_off + move_n 243 return NXHL_OK 244} 245 246// ---- /ready response emitter (alias to /health for v1) ---------- 247// 248// Future: /ready may differ from /health by requiring stricter 249// preconditions (e.g., "database connection established"). For 250// v1 we share the same emitter. 251 252func nx_http_emit_ready( 253 out: *u8, cap: i64, out_n: *i64, 254 status: i64, uptime_ms: i64, n_checks: i64, 255 scratch: *u8) -> i64 { 256 return nx_http_emit_health(out, cap, out_n, 257 status, uptime_ms, n_checks, scratch) 258}