nx_stubmain_lib.nx
buildroot/runtime/nx_stubmain_lib.nx
about
nx_stubmain_lib.nx -- THE STUB-MAIN RULER. One predicate, so the writer and the reader of this
classification cannot drift apart.
THE DEFECT IT NAMES, MEASURED 2026-09-03. buildroot/runtime/nx_https_get.nx ends with
`// Compile-only smoke.` and `func main() -> i64 { return 0 }`. Nothing is reachable from that main,
so the compiler DEAD-STRIPS the entire TLS closure: /api/build returns action=BUILT src_stable=1 with
no error and stages 14,880 bytes against a LIVE 468,929-byte binary. Any seat running the ordinary
build-then-promote loop replaces the estate's sovereign HTTPS client with a binary that returns 0 --
silently, off a GREEN receipt.
★THE SHARP PART, AND THE REASON THIS NEEDS ITS OWN RULER: nx_catalog ALREADY detects libraries, by
"no top-level main()" -- nx_https_fetch reads `KIND LIB (a binary is NOT expected for this one)` and
is therefore safe from this whole class. nx_https_get EVADES that detector PRECISELY BECAUSE IT HAS
A MAIN. A stub one. So the lib detector is defeated by the very convention that lets a library
compile standalone, and the catalogue then reports the name as LIVE because an .elf sits beside it.
THREE STATES, NEVER TWO -- collapsing them is the whole bug:
SM_NO_MAIN a library by construction. nx_catalog already handles it. NOT this ruler's subject.
SM_STUB_MAIN a main that returns a constant and calls nothing. Compiles, links nothing, ships a no-op.
SM_REAL_MAIN a program.
WHAT IT DELIBERATELY DOES NOT DECIDE. Being SM_STUB_MAIN is NOT by itself a defect: it is a deliberate
estate convention ("compile-only smoke") and a census over 12,067 sources found 114 of them, of which
every one checked was correctly unpromoted. The ARMED condition is the CONJUNCTION -- stub main AND a
promoted binary somebody calls -- and the promoted half is nx_artifactdrift's to answer, because that
organ already walks the serving root and already resolves sources through PS_SRCROOT_A then
PS_SRCROOT_B in builder order. This lib exists so that adoption is one predicate call and NOT a second
tree walker: the estate has one drift census and must keep having one.
NO SIZE THRESHOLD, ON PURPOSE. The tempting rule is "refuse a candidate much smaller than live", but
that is a magic number (rule 11) and it fails in both directions -- a legitimate toolchain shrink of
304 permil is on record, and a stub of a SMALL program is not much smaller than the real thing. The
structural fact (main calls nothing) is the signal; size is at most a triage hint.
license_tier: ORIGINAL
dependencies 1 imports · 2 importers
imports: nx_syscalls.nx
imported by: nx_artifactdrift.nxnx_stubmain_gate.nx
structs
| none |
consts
| 37 | const SM_NO_MAIN: i64 = 0 |
| 38 | const SM_STUB_MAIN: i64 = 1 |
| 39 | const SM_REAL_MAIN: i64 = 2 |
| 40 | const SM_UNREADABLE: i64 = 0 - 1 |
| 42 | const SM_NL: i64 = 10 |
| 43 | const SM_CR: i64 = 13 |
| 44 | const SM_SP: i64 = 32 |
| 45 | const SM_TAB: i64 = 9 |
| 46 | const SM_SLASH: i64 = 47 |
| 47 | const SM_LBRACE: i64 = 123 |
| 48 | const SM_RBRACE: i64 = 125 |
| 49 | const SM_MINUS: i64 = 45 |
| 50 | const SM_D0: i64 = 48 |
| 51 | const SM_D9: i64 = 57 |
functions
| 53 | func sm_is_space(c: i64) -> i64 called by 1: sm_body_is_stub |
| 59 | func sm_streq_at(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 |
| 69 | func sm_find(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 calls 1: sm_streq_at |
| 92 | func sm_find_line_start(buf: *u8, n: i64, lit: *u8) -> i64 |
| 108 | func sm_open_brace(buf: *u8, s: i64, e: i64) -> i64 called by 1: sm_classify |
| 120 | func sm_close_brace(buf: *u8, s: i64, e: i64) -> i64 called by 1: sm_classify |
| 137 | func sm_body_is_stub(buf: *u8, s: i64, e: i64) -> i64 |
| 181 | func sm_classify(buf: *u8, n: i64) -> i64 called by 2: mainsm_classify_path calls 4: sm_find_line_startsm_open_bracesm_close_bracesm_body_is_stub |
| 195 | func sm_classify_path(path: *u8) -> i64 |
| 206 | func sm_is_armed(cls: i64, promoted_exists: i64) -> i64 |