code wiki / (root) / nx_organkind.nx

nx_organkind.nx source

↩ module page · 225 lines · 12430 B

1// nx_organkind.nx -- WHAT KIND OF THING IS THIS ORGAN? The classifier seq1492 says both ship verbs need. 2// 3// THE DEFECT IT FIXES: `/api/promote target=nx_torrent_get` -> 400 'daemon/oracle names are never 4// promotable (use /api/deploy)'; `/api/deploy target=nx_torrent_get` -> 400 'unknown target'. Promote 5// calls it a DAEMON, deploy has never heard of it, so a gate-proven binary (nx_poolgov_gate 21/21, 6// deleting a hardcoded MAXP=32) cannot ship by ANY sanctioned route. Both verdicts come from matching 7// NAMES -- a `torrent`/daemon-ish substring -- rather than from what the organ IS. 8// LAW: TWO VERBS THAT DISAGREE ABOUT AN ARTEFACT'S KIND LEAVE IT UNSHIPPABLE -- the classifier, not the 9// allowlist, is the defect. 10// 11// WHY A DECLARED KIND AND NOT A BETTER HEURISTIC: a smarter name rule is still a guess, and the cost of 12// guessing is asymmetric -- misfiling a DAEMON as a one-shot lets promote swap a binary underneath a 13// running process with no health check and no rollback (a rule-26 hazard), while misfiling a one-shot as 14// a daemon merely makes it unshippable. So the kind must be DECLARED DATA (rule 11/17), and anything 15// undeclared must be REFUSED BY BOTH VERBS rather than fall through to a name guess. 16// 17// THE ASYMMETRY IS THE WHOLE POLICY: 18// deploy = for things with a HEALTH SURFACE (a port to probe, so never-brick rollback is meaningful). 19// promote = for one-shots/oracles: atomic rename + .prev backup, no probe needed because nothing is 20// holding the old binary open -- its 'health' is that the NEXT invocation succeeds. 21// A one-shot handed to deploy would have a port-based health check run against a target with no port, 22// making the never-brick verdict meaningless-or-wrong BY CONSTRUCTION. 23// 24// Lives in runtime/ (PRIMITIVE layer, seq1450) so BOTH mgmt handlers can reach it; imports nothing above. 25// license_tier: ORIGINAL Pure + read-only. No hw writes (Rule 26). 26import "nx_syscalls.nx" 27 28const OK_UNKNOWN: i64 = 0 29const OK_DAEMON: i64 = 1 30const OK_ONESHOT: i64 = 2 31const OK_ORACLE: i64 = 3 32const OK_LIB: i64 = 4 33// FIXTURE (2026-09-02): a RUNNABLE WITNESS -- a source with a main that a GATE compiles per run under the 34// declared mode it proves (--chkarith, --optenforce, --ptrprov, --ownership ...) and then asserts the trap or 35// the refusal. A promoted binary of it would prove nothing (the mode flag is the subject, not the program), 36// so BOTH ship verbs refuse it, exactly like a lib. Undeclared, the adoption ladder read every one of them 37// SOURCE-ONLY 'never compiled: /api/build it' and the ranker published DONE rungs as done-but-partially- 38// adopted -- five on /compare/lang alone. The remedy is a DECLARED kind, never a smarter guess (see above). 39const OK_FIXTURE: i64 = 5 40const OK_NL: i64 = 10 41const OK_SP: i64 = 32 42const OK_TAB: i64 = 9 43 44func ok_is_sep(c: i64) -> i64 { 45 if c == OK_SP { return 1 } 46 if c == OK_TAB { return 1 } 47 return 0 48} 49 50func ok_kind_code(buf: *u8, s: i64, e: i64) -> i64 { 51 let n: i64 = e - s 52 if n == 6 { if buf[s] == (100 as u8) { return OK_DAEMON } } 53 if n == 7 { if buf[s] == (111 as u8) { if buf[s+1] == (110 as u8) { return OK_ONESHOT } } } 54 if n == 6 { if buf[s] == (111 as u8) { return OK_ORACLE } } 55 if n == 3 { if buf[s] == (108 as u8) { return OK_LIB } } 56 if n == 7 { if buf[s] == (102 as u8) { return OK_FIXTURE } } // 'fixture': 7 letters, leading f (oneshot is 7, leading o) 57 return OK_UNKNOWN 58} 59 60// Look up <name> in a declared-kind table: one `<name> <kind>` row per line. 61// FAIL-CLOSED: an absent name is OK_UNKNOWN, never a guessed default -- that refusal is the point. 62// Match is WHOLE-FIELD (name must be followed by a separator), so `nx_torrent` can never match 63// `nx_torrent_get` -- the substring lie that produced this defect in the first place. 64func ok_kind_of(buf: *u8, n: i64, name: *u8) -> i64 { 65 var nl: i64 = 0 66 while name[nl] != (0 as u8) { nl = nl + 1 } 67 if nl == 0 { return OK_UNKNOWN } 68 var i: i64 = 0 69 while i < n { 70 var bol: i64 = 0 71 if i == 0 { bol = 1 } 72 if i > 0 { if buf[i-1] == (OK_NL as u8) { bol = 1 } } 73 if bol == 1 { 74 var j: i64 = 0 75 var m: i64 = 1 76 while j < nl { 77 if i + j >= n { m = 0; j = nl } else { 78 if buf[i + j] != name[j] { m = 0; j = nl } else { j = j + 1 } 79 } 80 } 81 if m == 1 { 82 var after: i64 = i + nl 83 var whole: i64 = 0 84 if after < n { if ok_is_sep(buf[after] as i64) == 1 { whole = 1 } } 85 if whole == 1 { 86 // skip the separator run after the name (clean sentinel-free idiom: a flag, not an 87 // out-of-range index -- the k=n+1 / k-1 trick I first wrote collapsed to k=n and made 88 // EVERY lookup return UNKNOWN; the gate caught it at 2/11 before it reached mgmt) 89 var k: i64 = after 90 var r1: i64 = 1 91 while r1 == 1 { 92 if k >= n { r1 = 0 } else { 93 if ok_is_sep(buf[k] as i64) == 1 { k = k + 1 } else { r1 = 0 } 94 } 95 } 96 // the kind token ends at the first separator or newline 97 var kend: i64 = k 98 var r2: i64 = 1 99 while r2 == 1 { 100 if kend >= n { r2 = 0 } else { 101 if ok_is_sep(buf[kend] as i64) == 1 { r2 = 0 } else { 102 if buf[kend] == (OK_NL as u8) { r2 = 0 } else { kend = kend + 1 } 103 } 104 } 105 } 106 return ok_kind_code(buf, k, kend) 107 } 108 } 109 } 110 i = i + 1 111 } 112 return OK_UNKNOWN 113} 114 115const OK_CONFBUF: i64 = 65536 116const OK_CONF_PATH_LEN: i64 = 256 117 118// Self-contained lookup: open the declared-kind table and classify <name>. Returns OK_UNKNOWN when the 119// file is absent or the name is undeclared -- callers then fall back to their legacy policy, so adopting 120// this is ADDITIVE and inert until the conf exists. 121// The file read lives HERE, not in the caller, so a consumer's adoption is ONE LINE. That is deliberate: 122// seq1410 measured that primitives fail to get adopted, and the cost of adoption is the main reason -- 123// a primitive that makes its consumer do the plumbing is a primitive that stays dark. 124func ok_kind_of_path(path: *u8, name: *u8) -> i64 { 125 // NO FIXED CAP (2026-08-28). The previous body read at most OK_CONFBUF-1 = 65535 bytes with NO 126 // truncation check, while knowledge/status/organ_kind.conf had reached 62467 -- 3068 bytes of headroom, 127 // 95 pct of the cap consumed, on a file that only ever grows. nx_organkind_gate's T24 states the 128 // consequence exactly: past that cap a DECLARED DAEMON reads as UNDECLARED, and the caller's 129 // terminal-suffix fallback then makes a *_gate name PROMOTABLE -- the one misfile rule 26 forbids. 130 // nx_mgmt_api.nx:3458 is the live ship path that calls this, so the blast radius is /api/promote itself. 131 // MEASURED THE SAME DAY: `nx_wirecensus e` proposes 718 evidence-backed rows totalling 18074 bytes 132 // (/tmp/okemit.txt), which would land the file 15006 bytes PAST the cap -- so the declaration backfill 133 // everybody wants would have silently disarmed both ship verbs on the rows it added, in the flattering 134 // direction, with no error anywhere. 135 // sys_read_file sizes its buffer from the file itself (lseek END) and CANNOT short-read, so the cap is 136 // REMOVED rather than raised: raising it only moves the guess to the next growth spurt. 137 // OK_CONFBUF is deliberately KEPT: nx_organkind_gate's T24 still reads it as its bound, so a revert of 138 // this function re-arms that tooth instead of leaving it dangling. 139 let lp: *i64 = sys_mmap(16) as *i64 140 lp[0] = 0 141 let b: *u8 = sys_read_file(path, lp) 142 let tot: i64 = lp[0] 143 if tot <= 0 { return OK_UNKNOWN } 144 let k: i64 = ok_kind_of(b, tot, name) 145 sys_free_file(b, tot) 146 return k 147} 148 149// deploy is ONLY for things with a health surface to probe. 150func ok_may_deploy(kind: i64) -> i64 { 151 if kind == OK_DAEMON { return 1 } 152 return 0 153} 154 155// promote is for one-shots and oracles: atomic rename + .prev, nothing holds the old binary open. 156// A LIB is neither -- it is compiled INTO consumers, so shipping one means rebuilding them. 157// A FIXTURE is neither -- its gate compiles it per run; a promoted copy would be a binary nobody forks. 158func ok_may_promote(kind: i64) -> i64 { 159 if kind == OK_ONESHOT { return 1 } 160 if kind == OK_ORACLE { return 1 } 161 return 0 162} 163 164// The honest end state: an UNDECLARED organ is refused by BOTH verbs, loudly, instead of being 165// name-guessed into the wrong one. Returns 1 when the kind is declared and at least one verb accepts it. 166func ok_is_shippable(kind: i64) -> i64 { 167 if ok_may_deploy(kind) == 1 { return 1 } 168 if ok_may_promote(kind) == 1 { return 1 } 169 return 0 170} 171 172// ---- seq1789: A TERMINAL SUFFIX IS A DECLARATION, A SUBSTRING IS A GUESS -------------------------- 173// THE DEFECT THIS FIXES (measured 2026-07-30): /api/promote refused nx_survey_serve_gate because the 174// legacy shape heuristic md_promote_deny asks `does the name CONTAIN "serve"`. It does -- inside the 175// word `survey_serve` -- so an ORACLE that runs to completion was classified as a long-lived DAEMON and 176// became unshippable by every sanctioned route. Its gate then read exit=127 (binary absent) and that one 177// RED was the only thing holding an otherwise 35/35-grounded, 3/4-green domain off MEASURED-HONEST. 178// LAW: A SUBSTRING CANNOT TELL A ROLE FROM A WORD THAT MERELY APPEARS IN ONE. Position is meaning. 179// 180// WHY THIS IS NOT THE NAME-GUESSING THIS FILE EXISTS TO FORBID. The policy above refuses inference 181// because the cost is ASYMMETRIC: misfiling a DAEMON as a one-shot lets promote swap a binary under a 182// live process with no probe and no rollback (rule 26), while the reverse merely blocks a build. That 183// same asymmetry is what makes a TERMINAL suffix safe where a substring is not: 184// - it is a CONVENTION ENFORCED AT CREATION, not an inference about runtime behaviour; 185// - it is ONE-DIRECTIONAL -- it can only ever yield OK_ORACLE, the SAFE side of the asymmetry, so this 186// rule is INCAPABLE BY CONSTRUCTION of producing the dangerous misfile; 187// - the claim is MECHANICALLY CHECKED, not asserted: nx_organkind_gate proves that no name carrying 188// one of these suffixes can classify as a daemon, and that a DECLARED daemon still wins if one ever 189// did. A guarantee that is only promised is the failure mode this ecosystem keeps paying for. 190// A DECLARED kind always wins -- see ok_kind_or_suffix. This is strictly a floor under UNDECLARED names, 191// which previously fell through to the substring lie. 192func ok_ends_with(name: *u8, sfx: *u8) -> i64 { 193 var nl: i64 = 0 194 while name[nl] != (0 as u8) { nl = nl + 1 } 195 var sl: i64 = 0 196 while sfx[sl] != (0 as u8) { sl = sl + 1 } 197 if sl == 0 { return 0 } 198 if nl < sl { return 0 } 199 var i: i64 = 0 200 var m: i64 = 1 201 while i < sl { 202 if name[nl - sl + i] != sfx[i] { m = 0; i = sl } else { i = i + 1 } 203 } 204 return m 205} 206 207// The oracle-shaped suffixes. Kept in ONE function so the rule and its proof cannot drift apart: the 208// gate exercises this same entry point, so a suffix added here without a daemon-free proof fails there. 209func ok_suffix_kind(name: *u8) -> i64 { 210 if ok_ends_with(name, "_gate" as *u8) == 1 { return OK_ORACLE } 211 if ok_ends_with(name, "_test" as *u8) == 1 { return OK_ORACLE } 212 if ok_ends_with(name, "_kat" as *u8) == 1 { return OK_ORACLE } 213 return OK_UNKNOWN 214} 215 216// THE PRECEDENCE, IN ONE PLACE so no consumer re-implements it (and re-implements it differently, which 217// is how this concern grew two confs and two readers already): a DECLARED kind always wins; only an 218// UNDECLARED name falls back to the terminal-suffix rule; anything else stays UNKNOWN and is refused by 219// both verbs exactly as before. Passing the declared kind IN rather than re-reading the conf keeps this 220// pure and lets the caller pay for the file read once. 221func ok_kind_or_suffix(declared: i64, name: *u8) -> i64 { 222 if declared != OK_UNKNOWN { return declared } 223 return ok_suffix_kind(name) 224} 225