code wiki / (root) / nx_acquire_gate.nx

nx_acquire_gate.nx source

↩ module page · 161 lines · 11575 B

1// nx_acquire_gate.nx -- GATE for nx_acquire_lib, the librarian's door. 2// 3// The subject is a PURE function: aq_decide reads no file and no clock, so this gate needs NO fixture 4// on disk. That matters more than it sounds -- the estate's measured gate-failure modes are dominated 5// by fixtures (a gate sharing scratch with a production beat, a fixture the defect cannot fail, a 6// snapshot gone stale silencing the teeth). A subject with no inputs but its arguments cannot suffer 7// any of them, and every tooth below is decidable from arithmetic alone. 8// 9// THREE BITE-PROVEN NEGATIVE CONTROLS. A rule that has only ever passed is unverified, so each bite 10// pairs an input the rule MUST fire on with one it MUST stay silent on. gv_bite prints VACUOUS when 11// the bad input did not fire and FALSE-POSITIVE when the good one did, so vacuity is SEEN, not counted. 12// license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_gate_verdict.nx" 15import "nx_acquire_lib.nx" 16 17func main(argc: i64, argv: *i64) -> i64 { 18 let ctr: *i64 = gv_ctr() 19 gv_head("=== nx_acquire_gate: the librarian's door -- evidence, rights and obligations ===" as *u8) 20 21 // ---- NO EVIDENCE: the 24-of-26 case measured on the NAVER Labs listing ---- 22 let n0: *i64 = aq_res() 23 let rc0: i64 = aq_decide(AQ_EV_NONE, AQ_YES, 1, n0) 24 gv_check("no-evidence-mirror-abstains-REVIEW" as *u8, (n0[AQ_R_MIRROR] == AQ_REVIEW) as i64, ctr) 25 gv_check("no-evidence-redistribute-abstains-REVIEW" as *u8, (n0[AQ_R_REDIST] == AQ_REVIEW) as i64, ctr) 26 gv_check("no-evidence-overall-is-REVIEW-not-CLEAR" as *u8, (rc0 == AQ_RC_REVIEW) as i64, ctr) 27 // THE OBLIGATION MUST NOT ABSTAIN. "I could not look" may never lighten a duty, so attribution 28 // stays YES precisely where every right went to REVIEW. This tooth is the one that separates an 29 // obligation from a right, and it is the one a careless refactor collapses. 30 gv_check("no-evidence-attribution-STAYS-YES-obligations-do-not-abstain" as *u8, (n0[AQ_R_ATTRIB] == AQ_YES) as i64, ctr) 31 // Learning from published work is not the act a copyright licence governs; if this went to REVIEW 32 // the whole oracle/benchmark purpose of the library would be gated on paperwork it does not need. 33 gv_check("no-evidence-learn-from-published-work-stays-YES" as *u8, (n0[AQ_R_LEARN] == AQ_YES) as i64, ctr) 34 35 // ---- DECLARED BUT UNREAD: an upstream page asserted a permissive licence ---- 36 let d0: *i64 = aq_res() 37 let rcd: i64 = aq_decide(AQ_EV_DECLARED, AQ_YES, 1, d0) 38 // The declared right here is the MOST permissive value the table can hold, and verified is 1. 39 // If evidence were being ignored this would come back YES. It must not. 40 gv_check("declared-unread-cannot-grant-mirror-even-when-permissive" as *u8, (d0[AQ_R_MIRROR] == AQ_REVIEW) as i64, ctr) 41 gv_check("declared-unread-cannot-grant-redistribute" as *u8, (d0[AQ_R_REDIST] == AQ_REVIEW) as i64, ctr) 42 gv_check("declared-unread-overall-is-REVIEW" as *u8, (rcd == AQ_RC_REVIEW) as i64, ctr) 43 44 // ---- READ, BUT THE RIGHTS ROW ITSELF IS UNCONFIRMED ---- 45 // This is the exact defect found live in nx_licgate_lib on 2026-08-25: verified was parsed, 46 // printed by `list`, and never consulted, so sdxl-base-1.0 / openrail-pp returned SHIP_OK. 47 let u0: *i64 = aq_res() 48 let rcu: i64 = aq_decide(AQ_EV_READ, AQ_YES, 0, u0) 49 gv_check("read-but-row-unverified-cannot-grant-mirror" as *u8, (u0[AQ_R_MIRROR] == AQ_REVIEW) as i64, ctr) 50 gv_check("read-but-row-unverified-overall-is-REVIEW" as *u8, (rcu == AQ_RC_REVIEW) as i64, ctr) 51 52 // ---- READ AND VERIFIED: the only state that may grant ---- 53 let g0: *i64 = aq_res() 54 let rcg: i64 = aq_decide(AQ_EV_READ, AQ_YES, 1, g0) 55 gv_check("read-and-verified-permissive-grants-mirror" as *u8, (g0[AQ_R_MIRROR] == AQ_YES) as i64, ctr) 56 gv_check("read-and-verified-permissive-grants-redistribute" as *u8, (g0[AQ_R_REDIST] == AQ_YES) as i64, ctr) 57 gv_check("read-and-verified-permissive-overall-is-CLEAR" as *u8, (rcg == AQ_RC_OK) as i64, ctr) 58 gv_check("attribution-is-YES-even-on-the-fully-cleared-path" as *u8, (g0[AQ_R_ATTRIB] == AQ_YES) as i64, ctr) 59 60 // ---- READ AND VERIFIED AND FORBIDDEN: a real finding, never softened ---- 61 // "I looked and it is forbidden" must not arrive in the same word as "I could not look". 62 let f0: *i64 = aq_res() 63 let rcf: i64 = aq_decide(AQ_EV_READ, AQ_NO, 1, f0) 64 gv_check("read-verified-forbidden-redistribute-is-NO-not-REVIEW" as *u8, (f0[AQ_R_REDIST] == AQ_NO) as i64, ctr) 65 gv_check("read-verified-forbidden-overall-is-REFUSE-not-REVIEW" as *u8, (rcf == AQ_RC_REFUSE) as i64, ctr) 66 // Even a forbidding licence still lets us keep the copy we lawfully hold; only passing it on is barred. 67 gv_check("forbidding-redistribution-still-permits-keeping-our-copy" as *u8, (f0[AQ_R_MIRROR] == AQ_YES) as i64, ctr) 68 69 // ---- READ AND VERIFIED AND CONDITIONAL ---- 70 let c0: *i64 = aq_res() 71 let rcc: i64 = aq_decide(AQ_EV_READ, AQ_REVIEW, 1, c0) 72 gv_check("read-verified-conditional-overall-is-REVIEW" as *u8, (rcc == AQ_RC_REVIEW) as i64, ctr) 73 74 // ---- MALFORMED EVIDENCE WORD ---- 75 gv_check("evidence-word-READ-parses" as *u8, (aq_ev_parse("READ" as *u8) == AQ_EV_READ) as i64, ctr) 76 gv_check("evidence-word-DECLARED-parses" as *u8, (aq_ev_parse("DECLARED" as *u8) == AQ_EV_DECLARED) as i64, ctr) 77 gv_check("evidence-word-NONE-parses" as *u8, (aq_ev_parse("NONE" as *u8) == AQ_EV_NONE) as i64, ctr) 78 // A prefix must NOT match: READX is not READ. A parser that accepts a prefix silently admits a 79 // truncated row, which is the class that produces confident wrong answers from good-looking data. 80 gv_check("evidence-word-prefix-READX-is-rejected" as *u8, (aq_ev_parse("READX" as *u8) == (0 - 1)) as i64, ctr) 81 82 // ================= BITE-PROVEN NEGATIVE CONTROLS ================= 83 // B1: does the evidence axis actually DO anything, or is it decoration? Fire on unread; silent on read. 84 var b1_bad: i64 = 0 85 var b1_good: i64 = 0 86 if d0[AQ_R_MIRROR] != AQ_YES { b1_bad = 1 } 87 if g0[AQ_R_MIRROR] != AQ_YES { b1_good = 1 } 88 gv_bite("neg-control-unread-licence-cannot-grant-mirror-but-read-one-can" as *u8, b1_bad, b1_good, ctr) 89 90 // B2: does a forbidding licence actually refuse, while a permissive one does not? 91 var b2_bad: i64 = 0 92 var b2_good: i64 = 0 93 if rcf == AQ_RC_REFUSE { b2_bad = 1 } 94 if rcg == AQ_RC_REFUSE { b2_good = 1 } 95 gv_bite("neg-control-forbidding-licence-REFUSES-and-permissive-one-does-not" as *u8, b2_bad, b2_good, ctr) 96 97 // B3: does the evidence parser reject nonsense rather than defaulting it to the abstaining case? 98 // Defaulting garbage to NONE would read as an honest abstention and hide a broken producer. 99 var b3_bad: i64 = 0 100 var b3_good: i64 = 0 101 if aq_ev_parse("APACHE-2.0" as *u8) == (0 - 1) { b3_bad = 1 } 102 if aq_ev_parse("NONE" as *u8) == (0 - 1) { b3_good = 1 } 103 gv_bite("neg-control-malformed-evidence-word-refused-not-defaulted-to-NONE" as *u8, b3_bad, b3_good, ctr) 104 105 // ==================== FIXITY: IS THIS ALL OF THE BYTES? ==================== 106 // Digest shape is DERIVED from the algorithm, never a constant. 107 gv_check("sha256-expects-64-hex" as *u8, (aq_alg_hexlen(AQ_ALG_SHA256) == 64) as i64, ctr) 108 gv_check("sha1-expects-40-hex" as *u8, (aq_alg_hexlen(AQ_ALG_SHA1) == 40) as i64, ctr) 109 gv_check("md5-expects-32-hex" as *u8, (aq_alg_hexlen(AQ_ALG_MD5) == 32) as i64, ctr) 110 // An algorithm we have no expected length for cannot be certified. Guessing one would be a 111 // fabricated fact wearing a checksum. 112 gv_check("unknown-algorithm-cannot-certify-a-shape" as *u8, (aq_digest_shape_ok(AQ_ALG_UNKNOWN, 64) == 0) as i64, ctr) 113 114 // THE FIELD'S OWN DOCUMENTED FAILURE, USED AS A TEST CASE. The Croissant specification's canonical 115 // FileObject examples put SIX values in a property named `sha256`, FOUR of them 32 hex characters 116 // (an MD5 length) and one 40 (SHA-1). A field named for one hash carrying another must be caught 117 // by LENGTH, because the NAME is only a claim. 118 gv_check("a-32-hex-value-in-a-sha256-field-is-refused" as *u8, (aq_digest_shape_ok(AQ_ALG_SHA256, 32) == 0) as i64, ctr) 119 gv_check("a-40-hex-value-in-a-sha256-field-is-refused" as *u8, (aq_digest_shape_ok(AQ_ALG_SHA1, 32) == 0) as i64, ctr) 120 // ...and a malformed digest is a MISMATCH, not an abstention: the record HAS a value and it is 121 // wrong, which is a different situation from the record never carrying one. 122 gv_check("malformed-digest-is-MISMATCH-not-UNAVAILABLE" as *u8, (aq_fixity(AQ_ALG_SHA256, 100, 100, 32, 1) == AQ_FIX_MISMATCH) as i64, ctr) 123 124 // A whole, correctly-shaped, digest-equal artifact. 125 gv_check("complete-artifact-with-matching-digest-and-length-MATCHES" as *u8, (aq_fixity(AQ_ALG_SHA256, 1000, 1000, 64, 1) == AQ_FIX_MATCH) as i64, ctr) 126 127 // ★ THE CASE THE FIELD CANNOT SEE. A body truncated in transit, whose digest was then computed on 128 // WHAT ARRIVED, so the digest COMPARES EQUAL. in-toto's DigestSet and SPDX's verifiedUsing carry 129 // no byte length, so both verify this clean. The length is the only witness. 130 gv_check("truncated-body-with-a-MATCHING-digest-is-still-MISMATCH" as *u8, (aq_fixity(AQ_ALG_SHA256, 1000, 400, 64, 1) == AQ_FIX_MISMATCH) as i64, ctr) 131 gv_check("digest-inequality-alone-is-MISMATCH" as *u8, (aq_fixity(AQ_ALG_SHA256, 1000, 1000, 64, 0) == AQ_FIX_MISMATCH) as i64, ctr) 132 133 // NO LENGTH RECORDED IS UNAVAILABLE, NEVER A PASS -- this is exactly the in-toto / SPDX state, and 134 // it is precisely the state in which a truncated body verifies clean. 135 gv_check("absent-declared-length-is-UNAVAILABLE-not-MATCH" as *u8, (aq_fixity(AQ_ALG_SHA256, 0 - 1, 400, 64, 1) == AQ_FIX_UNAVAILABLE) as i64, ctr) 136 gv_check("absent-declared-digest-shape-is-UNAVAILABLE-not-MATCH" as *u8, (aq_fixity(AQ_ALG_SHA256, 1000, 1000, 0 - 1, 1) == AQ_FIX_UNAVAILABLE) as i64, ctr) 137 138 // B4: does the LENGTH leg do work the digest leg cannot? Fire on the truncation-with-matching-pin 139 // case; stay silent on the same artifact complete. If this ever goes VACUOUS the whole exceed is gone. 140 var b4_bad: i64 = 0 141 var b4_good: i64 = 0 142 if aq_fixity(AQ_ALG_SHA256, 1000, 400, 64, 1) == AQ_FIX_MISMATCH { b4_bad = 1 } 143 if aq_fixity(AQ_ALG_SHA256, 1000, 1000, 64, 1) == AQ_FIX_MISMATCH { b4_good = 1 } 144 gv_bite("neg-control-length-catches-a-truncation-the-digest-alone-calls-clean" as *u8, b4_bad, b4_good, ctr) 145 146 // B5: does the SHAPE leg do work? Fire on an md5-length value in a sha256 field; silent on a real one. 147 var b5_bad: i64 = 0 148 var b5_good: i64 = 0 149 if aq_digest_shape_ok(AQ_ALG_SHA256, 32) == 0 { b5_bad = 1 } 150 if aq_digest_shape_ok(AQ_ALG_SHA256, 64) == 0 { b5_good = 1 } 151 gv_bite("neg-control-shape-refuses-an-md5-length-in-a-sha256-field-and-passes-a-real-one" as *u8, b5_bad, b5_good, ctr) 152 153 // B6: is UNAVAILABLE genuinely distinct from MATCH, or does a missing record quietly pass? 154 var b6_bad: i64 = 0 155 var b6_good: i64 = 0 156 if aq_fixity(AQ_ALG_SHA256, 0 - 1, 400, 64, 1) != AQ_FIX_MATCH { b6_bad = 1 } 157 if aq_fixity(AQ_ALG_SHA256, 1000, 1000, 64, 1) != AQ_FIX_MATCH { b6_good = 1 } 158 gv_bite("neg-control-an-unrecorded-length-never-reports-MATCH-but-a-recorded-one-does" as *u8, b6_bad, b6_good, ctr) 159 160 return gv_verdict("ACQUIRE-GATE" as *u8, ctr, "evidence gates rights, obligations never abstain, a read refusal outranks an abstention, and a length catches the truncation a digest calls clean" as *u8) 161}