code wiki / (root) / nx_srcfresh.nx

nx_srcfresh.nx source

↩ module page · 162 lines · 7700 B

1// nx_srcfresh.nx -- LIB: IS THIS ARTIFACT BUILT FROM THIS SOURCE? The canonical source-vs-artifact 2// staleness predicate, extracted 2026-08-07 so callers that are not installers can ask the question. 3// 4// WHY IT EXISTS AS A LIB. The predicate already existed and was already PROVEN -- oi_src_stale in 5// nx_offc_install.nx, locked by _freshness_gate.nx (T1 stale / T2 neg-control fresh / T3 artifact-absent / 6// T4 source-absent / T5 mtime round-trip). But it lives inside an INSTALLER that owns main(), so no other 7// organ can import it, and the mtime-stat idiom is consequently open-coded in 10+ places (gv_mtime in 8// nx_gate_verdict_lib, gb_mtime in nx_gatebuilt_gate, nx_pipeline_census, nx_datacurator x3, nx_netobs, 9// nx_imgbook_promote, nx_janitor_sprawl, nx_sov_tree_audit, nx_eff_lib, nx_mem_healer) -- and those copies 10// do NOT agree: several read only st_mtim.tv_sec, so two writes in the same second compare EQUAL and a 11// rebuild-within-a-second reads FRESH when it is stale. 12// A PROVEN PREDICATE TRAPPED INSIDE AN ORGAN THAT OWNS main() IS NOT A SHARED CAPABILITY, IT IS A COPY 13// WAITING TO BE MADE -- AND EVERY COPY IS FREE TO DISAGREE WITH THE ONE THE GATE PROVED. 14// 15// SEMANTICS ARE LIFTED VERBATIM from oi_src_stale rather than re-derived, so the behaviour _freshness_gate 16// already locked carries over unchanged; nx_srcfresh_gate re-asserts all five of its cases against THIS 17// copy (equivalence is asserted, not assumed) and adds the same-second case the second-granularity copies 18// silently fail. 19// Imports ONLY nx_syscalls.nx -- a lib that drags a dependency tree behind it does not get adopted. 20// license_tier: ORIGINAL No hw writes (Rule 26). 21import "nx_syscalls.nx" 22import "nx_sha256.nx" // CONTENT identity -- the only thing a clock cannot establish 23const SF_MAGIC_4194304: i64 = 4194304 24 25const SF_STATBUF: i64 = 256 26const SF_MTIME_SEC_OFF: i64 = 88 27const SF_MTIME_NSEC_OFF: i64 = 96 28const SF_NS_PER_SEC: i64 = 1000000000 29 30// mtime in NANOSECONDS, or -1 if the path cannot be stat'd. Nanoseconds, not seconds, because the whole 31// point of this predicate is ordering two writes that are often seconds apart -- and sometimes less. 32func sf_mtime_ns(path: *u8) -> i64 { 33 let sb: *u8 = sys_mmap(SF_STATBUF) 34 if sys_fstatat(path, sb) < 0 { sys_munmap(sb, SF_STATBUF); return 0 - 1 } 35 let secp: *i64 = ((sb as i64) + SF_MTIME_SEC_OFF) as *i64 36 let nsecp: *i64 = ((sb as i64) + SF_MTIME_NSEC_OFF) as *i64 37 let v: i64 = secp[0] * SF_NS_PER_SEC + nsecp[0] 38 sys_munmap(sb, SF_STATBUF) 39 return v 40} 41 42// 1 if `artifact` is STALE vs `source`; 0 if fresh or there is no source to be stale against. 43// The four cases, verbatim from the proven oi_src_stale: 44// source absent -> 0 nothing to be stale against 45// artifact absent -> 1 never built (and the source exists) 46// artifact older -> 1 stale 47// otherwise -> 0 fresh 48// The asymmetry is deliberate and load-bearing: absent-source is NOT stale, absent-artifact IS. 49func sf_src_stale(artifact: *u8, source: *u8) -> i64 { 50 let sm: i64 = sf_mtime_ns(source) 51 if sm < 0 { return 0 } 52 let am: i64 = sf_mtime_ns(artifact) 53 if am < 0 { return 1 } 54 if am < sm { return 1 } 55 return 0 56} 57 58// SECONDS the artifact is behind the source: 0 when fresh, -1 when the artifact is ABSENT (no measurable 59// lag, a different fact from "no lag") and -1 when there is no source. 60// WHY A MAGNITUDE AND NOT ONLY A FLAG: a boolean forces every caller to re-derive "how far behind", and the 61// decisions differ -- a 74-second lag is a sibling mid-edit, a 9885-minute lag is abandoned. Measured 62// 2026-08-07: the gate census showed both clusters in one run and the flag alone could not separate them. 63// A DETECTOR THAT REPORTS ONLY A BOOLEAN MAKES THE OPERATOR REDO THE MEASUREMENT IT ALREADY HAD. 64func sf_lag_sec(artifact: *u8, source: *u8) -> i64 { 65 let sm: i64 = sf_mtime_ns(source) 66 if sm < 0 { return 0 - 1 } 67 let am: i64 = sf_mtime_ns(artifact) 68 if am < 0 { return 0 - 1 } 69 if am >= sm { return 0 } 70 return (sm - am) / SF_NS_PER_SEC 71} 72 73// ============ PROVENANCE: what a clock cannot tell you (2026-08-07, debt 1786113214) ================== 74// EVERYTHING ABOVE ORDERS TWO WRITES. None of it can say that one was MADE FROM the other, and that gap has 75// a FALSE-FRESH direction: any promote by any seat resets an artifact mtime and erases the evidence of an 76// unadopted source edit. FRESH is the answer that stops you looking, so a false FRESH is the dangerous one. 77// PROVEN ON THIS ORGAN THE DAY IT SHIPPED: nx_gatefresh answered FRESH lag_sec=0 for nx_mgmt_api while its 78// source carried an edit no binary had ever been built from -- a concurrent promote had reset the mtime. 79// /api/build now records src_sha256 at the moment of production into <target>.provenance, so freshness can 80// be an EXACT identity comparison with no clock in it. 81// A CLOCK CAN ORDER TWO WRITES BUT NOT ESTABLISH THAT ONE WAS MADE FROM THE OTHER. 82const SF_PROV_CAP: i64 = 4096 83const SF_HEXLEN: i64 = 64 84const SF_HEXBUF: i64 = 80 85 86func sf_hex32(dig: *u8, out: *u8) -> i64 { 87 let tab: *u8 = "0123456789abcdef" as *u8 88 var i: i64 = 0 89 while i < 32 { 90 let v: i64 = dig[i] as i64 91 out[i * 2] = tab[v / 16] 92 out[i * 2 + 1] = tab[v % 16] 93 i = i + 1 94 } 95 out[64] = 0 as u8 96 return 64 97} 98// sha256 of a file, hex into `out` (needs SF_HEXBUF). 1 = ok, 0 = unreadable/empty. 99func sf_file_sha_hex(path: *u8, out: *u8) -> i64 { 100 let fd: i64 = sys_openat_rd(path) 101 if fd < 0 { return 0 } 102 let cap: i64 = SF_MAGIC_4194304 103 let buf: *u8 = sys_mmap(cap + 1) 104 var total: i64 = 0 105 var nrd: i64 = sys_read(fd, buf, cap) 106 while nrd > 0 { 107 total = total + nrd 108 if total >= cap { nrd = 0 } 109 else { nrd = sys_read(fd, ((buf as i64) + total) as *u8, cap - total) } 110 } 111 sys_close(fd) 112 if total <= 0 { return 0 } 113 let dig: *u8 = sys_mmap(32) 114 sha256_digest(buf, total, dig) 115 sf_hex32(dig, out) 116 return 1 117} 118// extract the src_sha256=<64hex> field from a sidecar. 1 = found, 0 = absent/malformed. 119// FAIL CLOSED ON A MALFORMED SIDECAR: a half-written receipt must read as UNKNOWN, never as agreement. 120func sf_prov_src_sha(provpath: *u8, out: *u8) -> i64 { 121 let fd: i64 = sys_openat_rd(provpath) 122 if fd < 0 { return 0 } 123 let buf: *u8 = sys_mmap(SF_PROV_CAP + 1) 124 let n: i64 = sys_read(fd, buf, SF_PROV_CAP) 125 sys_close(fd) 126 if n <= 0 { return 0 } 127 let key: *u8 = "src_sha256=" as *u8 128 var i: i64 = 0 129 while i < n { 130 var k: i64 = 0 131 var hit: i64 = 1 132 while key[k] != (0 as u8) { 133 if i + k >= n { hit = 0 } 134 if hit == 1 { if buf[i + k] != key[k] { hit = 0 } } 135 k = k + 1 136 } 137 if hit == 1 { 138 let s: i64 = i + k 139 if s + SF_HEXLEN > n { return 0 } 140 var j: i64 = 0 141 while j < SF_HEXLEN { out[j] = buf[s + j]; j = j + 1 } 142 out[SF_HEXLEN] = 0 as u8 143 return 1 144 } 145 i = i + 1 146 } 147 return 0 148} 149// PROVENANCE verdict: 1 STALE (recorded digest != current source digest), 0 FRESH (exact match), 150// -1 UNKNOWN (no sidecar, malformed sidecar, or unreadable source). 151// -1 MUST NOT BE READ AS FRESH by any caller -- that is the whole defect this replaces. 152func sf_prov_stale(provpath: *u8, srcpath: *u8) -> i64 { 153 let rec: *u8 = sys_mmap(SF_HEXBUF) 154 if sf_prov_src_sha(provpath, rec) == 0 { return 0 - 1 } 155 let cur: *u8 = sys_mmap(SF_HEXBUF) 156 if sf_file_sha_hex(srcpath, cur) == 0 { return 0 - 1 } 157 var i: i64 = 0 158 while i < SF_HEXLEN { 159 if rec[i] != cur[i] { return 1 } 160 i = i + 1 161 } 162 return 0 163}