code wiki / (root) / nx_cite_lib.nx

nx_cite_lib.nx source

↩ module page · 159 lines · 8020 B

1// nx_cite_lib.nx -- F993 CITE-OR-ABSTAIN: deterministic citation verification, the legal flagship. 2// 3// THE 2026 WALL (measured, not rhetorical): independent benchmarks show ~24% of graded legal answers 4// cite or misapply law that does NOT support the claim, and every model tested fabricated at least one 5// citation. The sovereign answer is not a better-behaved chatbot -- it is a VERIFIER that structurally 6// cannot pass a citation whose quoted text is not BYTE-PRESENT in the cited source. No LLM sits in the 7// trust path: a citation is verified by exact substring containment against a stored, content-addressed 8// source, so a fabricated or subtly-altered quote is caught by construction. 9// 10// FAIL-CLOSED, three honest outcomes: 11// CITED (1) the quote is an exact span of a real source -> show the source 12// ABSTAIN_NO_SOURCE (-1) the cited source does not exist (the "made-up case" failure) 13// ABSTAIN_NO_SPAN (-2) the source exists but the quote is not in it (fabricated/altered/empty) 14// An empty quote is ABSTAIN, never CITED -- "the empty string is a substring of everything" is exactly 15// the hole a fabricator would drive through, so it is closed explicitly. 16// 17// BYTE-EXACT is the honest floor. Normalization (whitespace collapse, case-fold, smart-quote unify) is 18// a DECLARED follow-on, not silently applied -- a verifier that quietly normalizes can be tricked into 19// accepting a materially altered quote, so the strict floor ships first and any loosening is opt-in. 20// 21// SCALE ENVELOPE (declared): cite_verify is O(source-length) substring scan per call (Rabin-Karp/KMP is 22// the speed rung); source retrieval inherits the seg-store read cost (see the finance-spine scale note). 23// DRY: composes nx_matter_lib (reg_put/reg_get/mt_field/canon_encode). license_tier: ORIGINAL LIB. 24 25import "nx_matter_lib.nx" 26 27const CITE_CITED: i64 = 1 28const CITE_ABSTAIN_NO_SOURCE: i64 = 0 - 1 29const CITE_ABSTAIN_NO_SPAN: i64 = 0 - 2 30const CITE_SRC_CAP: i64 = 65536 // max stored source length (declared) 31 32func cite_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 33 34// exact byte-substring: 1 if needle[0..nl) occurs in hay[0..hl), else 0. No break keyword: a mismatch 35// jumps the inner cursor PAST nl so only a full run leaves j==nl. 36func cite_contains(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 { 37 if nl == 0 { return 0 } 38 if nl > hl { return 0 } 39 var i: i64 = 0 40 while i + nl <= hl { 41 var j: i64 = 0 42 while j < nl { 43 if hay[i + j] == needle[j] { j = j + 1 } else { j = nl + 1 } 44 } 45 if j == nl { return 1 } 46 i = i + 1 47 } 48 return 0 49} 50 51// store a source document (statute, case, contract clause) on the content-addressed plane. 52func cite_source_put(prefix: *u8, source_id: *u8, text: *u8) -> i64 { 53 let k: *i64 = sys_mmap(8 * 1) as *i64 54 let v: *i64 = sys_mmap(8 * 1) as *i64 55 k[0] = ("text" as *u8) as i64 56 v[0] = text as i64 57 let rec: *u8 = sys_mmap(CITE_SRC_CAP) 58 let rl: i64 = canon_encode(k, v, 1, rec) 59 return reg_put(prefix, "cite:" as *u8, "cite:__idx__" as *u8, source_id, rec, rl) 60} 61 62// retrieve a source's text into out (<= CITE_SRC_CAP); returns length, or -1 if the source is absent. 63func cite_source_text(prefix: *u8, source_id: *u8, out: *u8) -> i64 { 64 let po: *i64 = sys_mmap(16) as *i64 65 let lo: *i64 = sys_mmap(16) as *i64 66 if reg_get(prefix, "cite:" as *u8, source_id, po, lo) != 1 { return 0 - 1 } 67 mt_field(po[0] as *u8, lo[0], "text" as *u8, 4, out) 68 return cite_len(out) 69} 70 71// ★THE VERIFIER. CITED only if `quoted` is an exact byte-span of source_id's stored text. 72// -1 = ABSTAIN, the source does not exist 73// -2 = ABSTAIN, the source exists but the quote is not in it (fabricated / altered / empty) 74func cite_verify(prefix: *u8, source_id: *u8, quoted: *u8) -> i64 { 75 let txt: *u8 = sys_mmap(CITE_SRC_CAP) 76 let tl: i64 = cite_source_text(prefix, source_id, txt) 77 if tl < 0 { return CITE_ABSTAIN_NO_SOURCE } 78 let ql: i64 = cite_len(quoted) 79 if ql == 0 { return CITE_ABSTAIN_NO_SPAN } 80 if cite_contains(txt, tl, quoted, ql) == 1 { return CITE_CITED } 81 return CITE_ABSTAIN_NO_SPAN 82} 83 84// 1 only if a citation is safe to surface. Any ABSTAIN code -> 0. This is the gate a drafting tool 85// calls before it is allowed to print a citation: no green light, no cite. 86func cite_ok(prefix: *u8, source_id: *u8, quoted: *u8) -> i64 { 87 if cite_verify(prefix, source_id, quoted) == CITE_CITED { return 1 } 88 return 0 89} 90 91// ★DOCUMENT REDLINE -- the product surface. A whole drafted paragraph carries inline citations in the 92// convention <<source_id|quoted span>>. This scans EVERY one, verifies it, and writes a human report: 93// [VERIFIED] or [STRUCK ...] per citation. Returns the number of STRUCK (unverifiable) citations; a 94// document is safe to file ONLY when the return is 0. Because the count is what gates the document, a 95// tool physically cannot emit a paragraph with an unverified citation passed off as verified. 96// 97// FAIL-CLOSED ON MALFORMED (the dodge a fabricator would try): an UNTERMINATED citation -- a << with no 98// matching >> -- is counted STRUCK, not silently dropped. Skipping verification by omitting the close 99// is exactly the hole that has to be closed, so an open citation at end-of-document is a strike. 100func cite_scan_doc(prefix: *u8, doc: *u8, report: *u8) -> i64 { 101 let dl: i64 = cite_len(doc) 102 let id: *u8 = sys_mmap(256) 103 let quote: *u8 = sys_mmap(4096) 104 var ro: i64 = 0 105 var struck: i64 = 0 106 var mode: i64 = 0 // 0 outside, 1 reading id, 2 reading quote 107 var ii: i64 = 0 108 var qi: i64 = 0 109 var i: i64 = 0 110 while i < dl { 111 if mode == 0 { 112 var op: i64 = 0 113 if doc[i] == (60 as u8) { if i + 1 < dl { if doc[i+1] == (60 as u8) { op = 1 } } } 114 if op == 1 { mode = 1; ii = 0; i = i + 2 } else { i = i + 1 } 115 } else { 116 if mode == 1 { 117 if doc[i] == (124 as u8) { mode = 2; qi = 0; i = i + 1 } 118 else { if ii < 255 { id[ii] = doc[i]; ii = ii + 1 } i = i + 1 } 119 } else { 120 var cl: i64 = 0 121 if doc[i] == (62 as u8) { if i + 1 < dl { if doc[i+1] == (62 as u8) { cl = 1 } } } 122 if cl == 1 { 123 id[ii] = 0 as u8 124 quote[qi] = 0 as u8 125 let v: i64 = cite_verify(prefix, id, quote) 126 if v == CITE_CITED { 127 ro = mt_catcopy(report, ro, "[VERIFIED] " as *u8) 128 ro = mt_catcopy(report, ro, id) 129 report[ro] = 10 as u8; ro = ro + 1 130 } else { 131 struck = struck + 1 132 ro = mt_catcopy(report, ro, "[STRUCK] " as *u8) 133 ro = mt_catcopy(report, ro, id) 134 if v == CITE_ABSTAIN_NO_SOURCE { ro = mt_catcopy(report, ro, " (source not found)" as *u8) } 135 if v == CITE_ABSTAIN_NO_SPAN { ro = mt_catcopy(report, ro, " (quote not in source)" as *u8) } 136 report[ro] = 10 as u8; ro = ro + 1 137 } 138 mode = 0; i = i + 2 139 } else { if qi < 4095 { quote[qi] = doc[i]; qi = qi + 1 } i = i + 1 } 140 } 141 } 142 } 143 // fail-closed: an unterminated citation at end-of-document is a STRIKE, never a silent skip 144 if mode != 0 { 145 struck = struck + 1 146 ro = mt_catcopy(report, ro, "[STRUCK] <unterminated citation> (malformed, no closing marker)" as *u8) 147 report[ro] = 10 as u8; ro = ro + 1 148 } 149 report[ro] = 0 as u8 150 return struck 151} 152 153// 1 only if EVERY citation in the document verified (and none was malformed). The document-level 154// green light: no clean scan, no filing. 155func cite_doc_clean(prefix: *u8, doc: *u8) -> i64 { 156 let rep: *u8 = sys_mmap(65536) 157 if cite_scan_doc(prefix, doc, rep) == 0 { return 1 } 158 return 0 159}