code wiki / (root) / nx_staging_guard_candidate_t296.nx

nx_staging_guard_candidate_t296.nx

buildroot/runtime/nx_staging_guard_candidate_t296.nx

18458 B415 linesdepth 5pulls 5 transitivereach 0 importersview sourcekind orphan library
docsdependenciesstructsconstsfunctions

about

nx_staging_guard.nx -- REFUSE A PROMOTE THAT WOULD WALK A TARGET BACKWARDS. WHY (measured 2026-08-06): the deploy queue is armed to destroy work. md_promote_staged already carries md_prov_ok, which refuses a promote whose CONTENT this target ALREADY HELD (seq1484). That guard is blind to the COMMON CASE: a staged .new that was never itself promoted is a FIRST SIGHTING, so md_prov_ok records it as the baseline and returns ALLOW -- even when the staged file PREDATES the live binary it would replace. A .new older than its live .elf is not a pending upgrade, it is A ROLLBACK WEARING AN UPGRADE FILENAME, and nothing in the staging area marks it as one. It sits there looking deployable forever. *SIZE IS A SCREEN, NOT PROOF (nx_treecanon_gate:15, and the banked law: a byte DECREASE after an addition is a REVERT). A legitimate refactor can shrink a binary, and an operator-swap fix is BYTE-IDENTICAL. So this module never decides on size alone: it also measures CAPABILITY-TOKEN LOSS -- how many long printable tokens present in the LIVE binary are ABSENT from the staged one. That is the honest reading of would-lose-capability; size is only the cheap first screen. (2026-08-18: that sentence became TRUE IN CODE, not only in prose -- see the SHRINK note in sg_classify. Whole-program DCE in nx_cc made "smaller" the normal direction of every rebuild.) *IT REFUSES, IT NEVER DELETES. Every verdict is fail-closed and reversible: a refusal leaves live, .prev and the staged file untouched (Rule 13 additive-only, Rule 26 never-brick). Nothing in this module writes persistent state of any kind. *THRESHOLDS ARE DATA (Rule 11), read from knowledge/staging_hygiene.conf; the consts below are bootstrap defaults only, and every one of them is overridable without a rebuild (Rule 17). DIALECT: this module is IMPORTED by nx_mgmt_data -> nx_mgmt_api, so it must compile under today's hub compiler: plain-if (NO else -- seq533 desyncs the imported parser), no empty string literals (seq907 aliases the next literal), <=6 params (seq239). ONE implementation, every consumer (Rule 15) -- a guard that only the CLI imports is not a guard the deploy plane has. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 2 imports · 0 importers

nx_syscalls.nx nx_contentdiff_lib.nx nx_staging_guard_candidate_t29

imports: nx_syscalls.nxnx_contentdiff_lib.nx

imported by: nobody (leaf or entry point)

structs

256struct SgContentEvidence { state:i64, checked:i64, missing:i64, gained:i64, live_runs:i64, candidate_runs:i64, source_removed:i64, permil:i64 }
310struct SgFileEvidence { state:i64,size:i64,mtime:i64 }

consts

34const SG_STAT_SIZE_OFF: i64 = 48
35const SG_STAT_MTIME_OFF: i64 = 88
36const SG_STATBUF: i64 = 256
37const SG_DAY: i64 = 86400
38const SG_FILECAP: i64 = 8388608
39const SG_CONFCAP: i64 = 8192
42const SG_NONE: i64 = 0
43const SG_FORWARD: i64 = 1
44const SG_ORPHAN: i64 = 2
45const SG_BACKDATE: i64 = 3
46const SG_EXPIRED: i64 = 4
47const SG_SHRINK: i64 = 5
48const SG_CAPLOSS: i64 = 6
49const SG_UNQUALIFIED:i64=7
52const SG_O_LIVESZ: i64 = 0
53const SG_O_NEWSZ: i64 = 1
54const SG_O_LIVEMT: i64 = 2
55const SG_O_NEWMT: i64 = 3
56const SG_O_LOSTPERMIL: i64 = 4
57const SG_O_AGEDAYS: i64 = 5
58const SG_O_FLAGS: i64 = 6
59const SG_O_CHECKED: i64 = 7
60const SG_O_MISSING: i64 = 8
61const SG_O_SHRINKPERMIL: i64 = 9
64const SG_O_IDENTICAL: i64 = 10
65const SG_O_GAINED: i64 = 11 // tokens staged has that live lacks -- the half a loss detector cannot see
66const SG_O_LIVERUNS: i64 = 12 // qualifying runs in live
67const SG_O_CANDRUNS: i64 = 13 // qualifying runs in staged; >= liveruns means nothing was net-removed
68const SG_O_CONTENT_STATE:i64=14
69const SG_O_SOURCE_REMOVED:i64=15
70const SG_OUT_SLOTS: i64 = 16
73const SG_C_MAXAGE: i64 = 0
74const SG_C_SHRINKTOL: i64 = 1
75const SG_C_CAPLOSS: i64 = 2
76const SG_C_MINTOK: i64 = 3
77const SG_C_MAXTOK: i64 = 4
78const SG_C_CAPLOSSABS: i64 = 5
79const SG_C_CAPLOSSMIN: i64 = 6
80const SG_C_SLOTS: i64 = 8
83const SG_D_MAXAGE: i64 = 14
84const SG_D_SHRINKTOL: i64 = 20
88const SG_D_CAPLOSS: i64 = 25
96const SG_D_CAPLOSSABS: i64 = 5
103const SG_D_CAPLOSSMIN: i64 = 2
104const SG_D_MINTOK: i64 = 12
105const SG_D_MAXTOK: i64 = 256
108const SG_MAXTOKLEN: i64 = 255
308const SG_ERR_NOENT:i64=-2
309const SG_IO:i64=-204

functions

110func sg_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 1: sg_conf_get
113func sg_size(path: *u8) -> i64
123func sg_mtime(path: *u8) -> i64
132func sg_slurp(path: *u8, buf: *u8, cap: i64) -> i64
154func sg_contains(b: *u8, bn: i64, nd: *u8, nl: i64) -> i64
175func sg_eq_at(b: *u8, pos: i64, key: *u8, kl: i64) -> i64
called by 1: sg_conf_get
184func sg_parse_int_at(b: *u8, n: i64, pos: i64) -> i64
called by 1: sg_conf_get
203func sg_conf_get(b: *u8, n: i64, key: *u8) -> i64
226func sg_conf_load(cfg: *i64) -> i64
257func sg_measure_bytes(lb:*u8,ln:i64,nb:*u8,nn:i64,cfg:*i64,e:*SgContentEvidence)->i64
278func sg_caploss(lb: *u8, ln: i64, nb: *u8, nn: i64, cfg: *i64, out2: *i64) -> i64
311func sg_file_evidence(path:*u8,e:*SgFileEvidence)->i64
319func sg_content_paths(livep:*u8,newp:*u8,lsz:i64,nsz:i64,cfg:*i64,out:*i64)->i64
343func sg_classify(livep:*u8,newp:*u8,now:i64,cfg:*i64,out:*i64)->i64
379func sg_allows(c: i64) -> i64
called by 1: sg_allows_override
385func sg_class_name(c: i64) -> *u8
396func sg_allows_override(c:i64,explicitApproval:i64)->i64
calls 1: sg_allows
410func sg_scratch() -> i64
calls 1: sys_mmap