code wiki / (root) / nx_adversarial_pattern_audit.nx

nx_adversarial_pattern_audit.nx source

↩ module page · 466 lines · 20751 B

1// nx_adversarial_pattern_audit.nx -- scans for adversarial-exploit patterns. 2// 3// module: nishi-core.security.adversarial_pattern_audit 4// depends: nishi-core.security.threat_model, 5// nishi-core.audit.wired_status, 6// nishi-core.audit.claim_audit, 7// nishi-core.io.syscalls 8// disk_kb: 6 9// capability: CRYPTO 10// wired_status: FULLY_WIRED 11// 12// (Honest: substrate STRUCTURE + the FALSE_OK_RETURN-class 13// heuristic counter are wired AND smoke-verified via 14// runtime/nx_adversarial_pattern_audit_test.nx PASS on qemu-rv64. 15// The counter is a substring-based observation primitive that 16// counts `_STUB_NOT_WIRED` markers + `wired_status:` headers per 17// file; smoke asserts known counts on three runtime files. The 18// FALSE_OK_RETURN substring detector is the WIRED kernel today; 19// other 13 pattern-detectors in the 14-class taxonomy remain 20// HEURISTIC_QUEUED. Per-file tree-walking via nx_dir is queued 21// pending syscall-module unification -- nx_dir imports 22// `syscalls.nx` while threat_model+wired_status+claim_audit import 23// `nx_syscalls.nx`, and both define `sys_read_file` so they cannot 24// link together. Caller passes pre-read bytes for now.) 25// 26// license_tier: PUBLIC_NISHI_SUBSTRATE 27// genealogy_id: nishi_racing_crew_team_honesty_threat_aware_cardinal + 28// cert_secure_coding_standards + 29// misra_c_2012_safety_critical_rules + 30// nasa_jpl_power_of_10 31// 32// Per cardinal [[feedback-racing-crew-team-honesty-threat-aware]]: 33// substrate scanner extends nx_claim_audit with patterns specifically 34// dangerous when an adversary (especially AI-class) can read the 35// substrate code looking for exploitable false-OK paths. 36// 37// Catches the exact failure pattern that triggered the no-false-OK 38// cardinal: 39// - function declares "fetch resource X" + returns *_OK from 40// uninitialized verdict field → AI adversary writes caller code 41// that assumes the fetch happened, builds attack on missing data 42// - sealed enum that has NO *_STUB_NOT_WIRED variant → caller 43// can't tell if the verdict is real or stub 44// - error path silently swallows failures → adversary triggers 45// errors, gets the substrate into known-state 46// - documentation claims "TLS-protected" but the body never calls 47// nx_tls13_* → adversary downgrades to plaintext 48 49// Imports nx_syscalls.nx (not syscalls.nx) to match the upstream 50// audit primitives (nx_threat_model + nx_wired_status + 51// nx_claim_audit) -- mixing the two syscall modules in one binary 52// would double-define sys_read_file at link. 53import "nx_syscalls.nx" 54import "nx_threat_model.nx" 55import "nx_wired_status.nx" 56 57// ===== Verdict ==================================================== 58 59const NX_APA_OK: i64 = 1 60const NX_APA_PATTERN_DETECTED: i64 = 2 61const NX_APA_CRITICAL_VULNERABILITY: i64 = 3 62const NX_APA_SCAN_FAIL: i64 = 4 63const NX_APA_STUB_NOT_WIRED: i64 = -7777 // honest stub-variant per cardinal 64 65func nx_apa_verdict_name(v: i64) -> *u8 { 66 if v == NX_APA_OK { return "OK" } 67 if v == NX_APA_PATTERN_DETECTED { return "PATTERN_DETECTED" } 68 if v == NX_APA_CRITICAL_VULNERABILITY { return "CRITICAL_VULNERABILITY" } 69 if v == NX_APA_SCAN_FAIL { return "SCAN_FAIL" } 70 if v == NX_APA_STUB_NOT_WIRED { return "STUB_NOT_WIRED" } 71 return "UNKNOWN" 72} 73 74// ===== Adversarial pattern kind sealed enum ======================= 75 76const NX_APA_PATTERN_FALSE_OK_RETURN: i64 = 1 // function returns *_OK from no-op body 77const NX_APA_PATTERN_MISSING_STUB_VARIANT: i64 = 2 // sealed enum lacks *_STUB_NOT_WIRED 78const NX_APA_PATTERN_UNINITIALIZED_VERDICT: i64 = 3 // verdict field reads OK by default-init 79const NX_APA_PATTERN_SILENT_ERROR_SWALLOW: i64 = 4 // catch + ignore error 80const NX_APA_PATTERN_CLAIM_BODY_MISMATCH: i64 = 5 // header claims X; body does Y 81const NX_APA_PATTERN_TLS_DOWNGRADE_PATH: i64 = 6 // fallback to plaintext possible 82const NX_APA_PATTERN_AUTH_BYPASS_PATH: i64 = 7 // codepath skips auth check 83const NX_APA_PATTERN_TIMING_LEAK: i64 = 8 // variable-time crypto compare 84const NX_APA_PATTERN_INTEGER_OVERFLOW: i64 = 9 // unchecked arithmetic 85const NX_APA_PATTERN_UNBOUNDED_LOOP: i64 = 10 // violates JPL Rule 2 86const NX_APA_PATTERN_DESERIALIZE_UNTRUSTED: i64 = 11 // parses untrusted data without bounds 87const NX_APA_PATTERN_PROMPT_INJECTION_TRUST: i64 = 12 // executes instructions from ingested data 88const NX_APA_PATTERN_HARDCODED_CREDENTIAL: i64 = 13 // API key / secret in source 89const NX_APA_PATTERN_THIRD_PARTY_SAAS_LEAK: i64 = 14 // new external SaaS dep detected 90 91func nx_apa_pattern_name(p: i64) -> *u8 { 92 if p == NX_APA_PATTERN_FALSE_OK_RETURN { return "FALSE_OK_RETURN" } 93 if p == NX_APA_PATTERN_MISSING_STUB_VARIANT { return "MISSING_STUB_VARIANT" } 94 if p == NX_APA_PATTERN_UNINITIALIZED_VERDICT { return "UNINITIALIZED_VERDICT" } 95 if p == NX_APA_PATTERN_SILENT_ERROR_SWALLOW { return "SILENT_ERROR_SWALLOW" } 96 if p == NX_APA_PATTERN_CLAIM_BODY_MISMATCH { return "CLAIM_BODY_MISMATCH" } 97 if p == NX_APA_PATTERN_TLS_DOWNGRADE_PATH { return "TLS_DOWNGRADE_PATH" } 98 if p == NX_APA_PATTERN_AUTH_BYPASS_PATH { return "AUTH_BYPASS_PATH" } 99 if p == NX_APA_PATTERN_TIMING_LEAK { return "TIMING_LEAK" } 100 if p == NX_APA_PATTERN_INTEGER_OVERFLOW { return "INTEGER_OVERFLOW" } 101 if p == NX_APA_PATTERN_UNBOUNDED_LOOP { return "UNBOUNDED_LOOP" } 102 if p == NX_APA_PATTERN_DESERIALIZE_UNTRUSTED { return "DESERIALIZE_UNTRUSTED" } 103 if p == NX_APA_PATTERN_PROMPT_INJECTION_TRUST { return "PROMPT_INJECTION_TRUST" } 104 if p == NX_APA_PATTERN_HARDCODED_CREDENTIAL { return "HARDCODED_CREDENTIAL" } 105 if p == NX_APA_PATTERN_THIRD_PARTY_SAAS_LEAK { return "THIRD_PARTY_SAAS_LEAK" } 106 return "UNKNOWN" 107} 108 109// Which threat-actor classes can exploit each pattern? Drives 110// severity ranking. 111func nx_apa_pattern_severity_min_threat_tier(p: i64) -> i64 { 112 if p == NX_APA_PATTERN_FALSE_OK_RETURN { return 5 } // AI adversary current-gen 113 if p == NX_APA_PATTERN_MISSING_STUB_VARIANT { return 5 } 114 if p == NX_APA_PATTERN_UNINITIALIZED_VERDICT { return 5 } 115 if p == NX_APA_PATTERN_SILENT_ERROR_SWALLOW { return 3 } // targeted criminal 116 if p == NX_APA_PATTERN_CLAIM_BODY_MISMATCH { return 6 } // Mythos-class 117 if p == NX_APA_PATTERN_TLS_DOWNGRADE_PATH { return 8 } // nation-state 118 if p == NX_APA_PATTERN_AUTH_BYPASS_PATH { return 3 } 119 if p == NX_APA_PATTERN_TIMING_LEAK { return 8 } 120 if p == NX_APA_PATTERN_INTEGER_OVERFLOW { return 4 } 121 if p == NX_APA_PATTERN_UNBOUNDED_LOOP { return 4 } 122 if p == NX_APA_PATTERN_DESERIALIZE_UNTRUSTED { return 5 } 123 if p == NX_APA_PATTERN_PROMPT_INJECTION_TRUST { return 5 } // primary AI-adversary vector 124 if p == NX_APA_PATTERN_HARDCODED_CREDENTIAL { return 1 } // script-kiddie 125 if p == NX_APA_PATTERN_THIRD_PARTY_SAAS_LEAK { return 9 } // supply chain 126 return 0 127} 128 129// ===== AdversarialFinding (per-file detection) ==================== 130 131struct AdversarialFinding { 132 finding_hk: i64, 133 file_path_ptr: *u8, 134 file_path_len: i64, 135 line_number: i64, 136 pattern_kind: i64, // NX_APA_PATTERN_* 137 severity_min_threat_tier: i64, 138 suggested_fix_ptr: *u8, 139 discovered_at_unix: i64, 140 is_resolved: i64, 141 is_current: i64, 142} 143 144const NX_ADV_FINDING_BYTES: i64 = 80 // 10 fields * 8 bytes 145 146// ===== Scan a file for adversarial patterns ======================= 147// 148// Bounded loop per JPL Rule 2 cardinal. 149 150const NX_APA_MAX_FINDINGS_PER_FILE: i64 = 1024 151 152func nx_adversarial_scan_file( 153 file_path_ptr: *u8, 154 file_path_len: i64, 155 file_bytes: *u8, 156 file_len: i64, 157 out_findings: **AdversarialFinding, 158 out_cap: i64, 159 now_unix: i64 160) -> i64 { 161 if file_len <= 0 { return 0 } 162 if out_cap <= 0 { return 0 } 163 // Real implementation walks file looking for each pattern: 164 // FALSE_OK_RETURN: function body has < 3 statements and ends 165 // with "return NX_*_OK" 166 // UNINITIALIZED_VERDICT: struct field "verdict" not assigned 167 // before return 168 // MISSING_STUB_VARIANT: sealed enum named "*_VERDICT" without 169 // a *_STUB_NOT_WIRED constant 170 // ...etc per pattern_kind taxonomy 171 // 172 // v1 returns 0 findings (honest stub at scan-implementation). 173 // Once nx_dir + line-by-line walker land, this primitive 174 // delivers real findings. 175 return 0 176} 177 178// ===== Aggregate scan report ====================================== 179 180struct AdversarialScanReport { 181 report_hk: i64, 182 scope_name_ptr: *u8, 183 files_scanned: i64, 184 n_total_findings: i64, 185 n_critical: i64, // severity_tier >= 8 186 n_high: i64, // severity_tier 5-7 187 n_medium: i64, // severity_tier 3-4 188 n_low: i64, // severity_tier 1-2 189 scanned_at_unix: i64, 190 verdict: i64, 191} 192 193const NX_ADV_SCAN_REPORT_BYTES: i64 = 80 // 10 fields * 8 bytes 194 195// ===== Recovery action recommendation ============================= 196// 197// Given a finding, what should the racing crew do? 198 199const NX_APA_ACTION_FIX_IMMEDIATELY: i64 = 1 // critical; block commits 200const NX_APA_ACTION_FIX_THIS_SESSION: i64 = 2 // high; on session backlog 201const NX_APA_ACTION_QUEUE_FIX: i64 = 3 // medium; queued 202const NX_APA_ACTION_DOCUMENT_AS_RESIDUAL: i64 = 4 // low; document the residual risk 203const NX_APA_ACTION_ACCEPT_RISK: i64 = 5 // not applicable to substrate's threat model 204 205func nx_apa_action_for_severity(severity_tier: i64) -> i64 { 206 if severity_tier >= 8 { return NX_APA_ACTION_FIX_IMMEDIATELY } 207 if severity_tier >= 5 { return NX_APA_ACTION_FIX_THIS_SESSION } 208 if severity_tier >= 3 { return NX_APA_ACTION_QUEUE_FIX } 209 return NX_APA_ACTION_DOCUMENT_AS_RESIDUAL 210} 211 212func nx_apa_action_name(a: i64) -> *u8 { 213 if a == NX_APA_ACTION_FIX_IMMEDIATELY { return "FIX_IMMEDIATELY" } 214 if a == NX_APA_ACTION_FIX_THIS_SESSION { return "FIX_THIS_SESSION" } 215 if a == NX_APA_ACTION_QUEUE_FIX { return "QUEUE_FIX" } 216 if a == NX_APA_ACTION_DOCUMENT_AS_RESIDUAL { return "DOCUMENT_AS_RESIDUAL" } 217 if a == NX_APA_ACTION_ACCEPT_RISK { return "ACCEPT_RISK" } 218 return "UNKNOWN" 219} 220 221// ===== Substring counter (bounded per JPL Rule 2) ================= 222// 223// Counts the number of (possibly overlapping) occurrences of `needle` 224// in `haystack`. Bounded: outer loop walks at most haystack_len 225// positions; inner loop walks at most needle_len bytes. Used by the 226// per-file pattern-marker counter below. Linear time O(n*m) is 227// adequate for runtime-file scale (<= ~64 KiB / file). 228 229const NX_APA_MAX_SCAN_BYTES: i64 = 8388608 // 8 MiB / file ceiling 230 231func nx_apa_count_substring( 232 haystack: *u8, 233 haystack_len: i64, 234 needle: *u8, 235 needle_len: i64 236) -> i64 { 237 if haystack_len < needle_len { return 0 } 238 if needle_len <= 0 { return 0 } 239 var count: i64 = 0 240 var i: i64 = 0 241 var iter: i64 = 0 242 var verdict: i64 = 0 243 let limit: i64 = haystack_len - needle_len 244 while verdict == 0 && iter < NX_APA_MAX_SCAN_BYTES { 245 if i > limit { verdict = 1 } 246 if verdict == 0 { 247 var j: i64 = 0 248 var inner_iter: i64 = 0 249 var inner_verdict: i64 = 0 250 var matched: i64 = 1 251 while inner_verdict == 0 && inner_iter < needle_len { 252 if haystack[i + j] != needle[j] { 253 matched = 0 254 inner_verdict = 1 255 } 256 if inner_verdict == 0 { 257 j = j + 1 258 inner_iter = inner_iter + 1 259 } 260 } 261 if matched == 1 { count = count + 1 } 262 i = i + 1 263 iter = iter + 1 264 } 265 } 266 return count 267} 268 269// ===== ApaFileScanCounts (per-file pattern marker observations) === 270// 271// Records substring-occurrence counts for the FALSE_OK_RETURN-class 272// patterns the substrate audits today. Caller-supplied buffers 273// remain valid as long as the substrate doesn't recycle them. 274 275struct ApaFileScanCounts { 276 counts_hk: i64, 277 file_path_ptr: *u8, 278 file_path_len: i64, 279 file_bytes_len: i64, 280 n_stub_not_wired_markers: i64, // "_STUB_NOT_WIRED" total 281 n_header_partial_wired: i64, // "wired_status: PARTIAL_WIRED" 282 n_header_fully_wired: i64, // "wired_status: FULLY_WIRED" 283 n_header_honest_stub: i64, // "wired_status: HONEST_STUB" 284 n_func_decls: i64, // "\nfunc " count 285 n_return_nx: i64, // "return NX_" count 286 scanned_at_unix: i64, 287 verdict: i64, 288} 289 290const NX_APA_FILE_SCAN_COUNTS_BYTES: i64 = 104 // 13 fields * 8 bytes 291 292// Pre-allocated needle constants (constructed once per scan call to 293// keep the parser-quirks cardinal happy -- no compile-time string 294// literals as struct fields). 295 296func nx_apa_make_needle_stub(out: *u8) { 297 // "_STUB_NOT_WIRED" 298 out[0] = 0x5f; out[1] = 0x53; out[2] = 0x54; out[3] = 0x55 // _STU 299 out[4] = 0x42; out[5] = 0x5f; out[6] = 0x4e; out[7] = 0x4f // B_NO 300 out[8] = 0x54; out[9] = 0x5f; out[10] = 0x57; out[11] = 0x49 // T_WI 301 out[12] = 0x52; out[13] = 0x45; out[14] = 0x44; out[15] = 0 // RED\0 302} 303 304func nx_apa_make_needle_partial(out: *u8) { 305 // "wired_status: PARTIAL_WIRED" 306 out[0] = 0x77; out[1] = 0x69; out[2] = 0x72; out[3] = 0x65 // wire 307 out[4] = 0x64; out[5] = 0x5f; out[6] = 0x73; out[7] = 0x74 // d_st 308 out[8] = 0x61; out[9] = 0x74; out[10] = 0x75; out[11] = 0x73 // atus 309 out[12] = 0x3a; out[13] = 0x20; out[14] = 0x50; out[15] = 0x41 // : PA 310 out[16] = 0x52; out[17] = 0x54; out[18] = 0x49; out[19] = 0x41 // RTIA 311 out[20] = 0x4c; out[21] = 0x5f; out[22] = 0x57; out[23] = 0x49 // L_WI 312 out[24] = 0x52; out[25] = 0x45; out[26] = 0x44; out[27] = 0 // RED\0 313} 314 315func nx_apa_make_needle_fully(out: *u8) { 316 // "wired_status: FULLY_WIRED" 317 out[0] = 0x77; out[1] = 0x69; out[2] = 0x72; out[3] = 0x65 // wire 318 out[4] = 0x64; out[5] = 0x5f; out[6] = 0x73; out[7] = 0x74 // d_st 319 out[8] = 0x61; out[9] = 0x74; out[10] = 0x75; out[11] = 0x73 // atus 320 out[12] = 0x3a; out[13] = 0x20; out[14] = 0x46; out[15] = 0x55 // : FU 321 out[16] = 0x4c; out[17] = 0x4c; out[18] = 0x59; out[19] = 0x5f // LLY_ 322 out[20] = 0x57; out[21] = 0x49; out[22] = 0x52; out[23] = 0x45 // WIRE 323 out[24] = 0x44; out[25] = 0 // D\0 324} 325 326func nx_apa_make_needle_honest(out: *u8) { 327 // "wired_status: HONEST_STUB" 328 out[0] = 0x77; out[1] = 0x69; out[2] = 0x72; out[3] = 0x65 // wire 329 out[4] = 0x64; out[5] = 0x5f; out[6] = 0x73; out[7] = 0x74 // d_st 330 out[8] = 0x61; out[9] = 0x74; out[10] = 0x75; out[11] = 0x73 // atus 331 out[12] = 0x3a; out[13] = 0x20; out[14] = 0x48; out[15] = 0x4f // : HO 332 out[16] = 0x4e; out[17] = 0x45; out[18] = 0x53; out[19] = 0x54 // NEST 333 out[20] = 0x5f; out[21] = 0x53; out[22] = 0x54; out[23] = 0x55 // _STU 334 out[24] = 0x42; out[25] = 0 // B\0 335} 336 337func nx_apa_make_needle_funcdecl(out: *u8) { 338 // "\nfunc " (5 bytes) 339 out[0] = 0x0a; out[1] = 0x66; out[2] = 0x75; out[3] = 0x6e 340 out[4] = 0x63; out[5] = 0x20; out[6] = 0 341} 342 343func nx_apa_make_needle_return_nx(out: *u8) { 344 // "return NX_" (10 bytes) 345 out[0] = 0x72; out[1] = 0x65; out[2] = 0x74; out[3] = 0x75 346 out[4] = 0x72; out[5] = 0x6e; out[6] = 0x20; out[7] = 0x4e 347 out[8] = 0x58; out[9] = 0x5f; out[10] = 0 348} 349 350// ===== Scan a file's bytes for marker patterns ==================== 351 352func nx_apa_scan_file_returns( 353 file_path_ptr: *u8, 354 file_path_len: i64, 355 file_bytes: *u8, 356 file_len: i64, 357 now_unix: i64 358) -> *ApaFileScanCounts { 359 let raw: *u8 = sys_mmap(NX_APA_FILE_SCAN_COUNTS_BYTES) 360 let s: *ApaFileScanCounts = raw as *ApaFileScanCounts 361 s.counts_hk = 0 362 s.file_path_ptr = file_path_ptr 363 s.file_path_len = file_path_len 364 s.file_bytes_len = file_len 365 s.n_stub_not_wired_markers = 0 366 s.n_header_partial_wired = 0 367 s.n_header_fully_wired = 0 368 s.n_header_honest_stub = 0 369 s.n_func_decls = 0 370 s.n_return_nx = 0 371 s.scanned_at_unix = now_unix 372 s.verdict = NX_APA_SCAN_FAIL 373 374 if file_bytes == 0 as *u8 { return s } 375 if file_len <= 0 { return s } 376 377 let n_stub: *u8 = sys_mmap(32) 378 nx_apa_make_needle_stub(n_stub) 379 s.n_stub_not_wired_markers = nx_apa_count_substring(file_bytes, file_len, n_stub, 15) 380 381 let n_partial: *u8 = sys_mmap(32) 382 nx_apa_make_needle_partial(n_partial) 383 s.n_header_partial_wired = nx_apa_count_substring(file_bytes, file_len, n_partial, 27) 384 385 let n_fully: *u8 = sys_mmap(32) 386 nx_apa_make_needle_fully(n_fully) 387 s.n_header_fully_wired = nx_apa_count_substring(file_bytes, file_len, n_fully, 25) 388 389 let n_honest: *u8 = sys_mmap(32) 390 nx_apa_make_needle_honest(n_honest) 391 s.n_header_honest_stub = nx_apa_count_substring(file_bytes, file_len, n_honest, 25) 392 393 let n_func: *u8 = sys_mmap(16) 394 nx_apa_make_needle_funcdecl(n_func) 395 s.n_func_decls = nx_apa_count_substring(file_bytes, file_len, n_func, 6) 396 397 let n_ret: *u8 = sys_mmap(16) 398 nx_apa_make_needle_return_nx(n_ret) 399 s.n_return_nx = nx_apa_count_substring(file_bytes, file_len, n_ret, 10) 400 401 s.verdict = NX_APA_OK 402 return s 403} 404 405// ===== File consistency judgment ================================== 406// 407// Heuristic 3-tier verdict comparing declared wired_status header 408// against observed pattern markers. 409// 410// 1 = CONSISTENT: declared header matches observed stub-marker count 411// 2 = OVERSTATED: declared FULLY_WIRED but body has stub markers 412// 3 = UNDERSTATED: declared PARTIAL_WIRED/HONEST_STUB but no stub markers 413// 414// Returns 0 (NOT_VERIFIED) if no header was found at all. 415 416const NX_APA_CONSISTENCY_NOT_VERIFIED: i64 = 0 417const NX_APA_CONSISTENCY_CONSISTENT: i64 = 1 418const NX_APA_CONSISTENCY_OVERSTATED: i64 = 2 419const NX_APA_CONSISTENCY_UNDERSTATED: i64 = 3 420 421func nx_apa_consistency_name(c: i64) -> *u8 { 422 if c == NX_APA_CONSISTENCY_NOT_VERIFIED { return "NOT_VERIFIED" } 423 if c == NX_APA_CONSISTENCY_CONSISTENT { return "CONSISTENT" } 424 if c == NX_APA_CONSISTENCY_OVERSTATED { return "OVERSTATED" } 425 if c == NX_APA_CONSISTENCY_UNDERSTATED { return "UNDERSTATED" } 426 return "UNKNOWN" 427} 428 429// Threshold: a file with at most 2 STUB-marker occurrences is 430// considered "no usage" (the sealed-enum DECLARATION + verdict-name 431// resolver alone produce ~2 occurrences in audit primitives; 432// stubbed-return USAGE pushes the count higher). 433const NX_APA_STUB_USAGE_THRESHOLD: i64 = 3 434 435func nx_apa_judge_file_consistency(s: *ApaFileScanCounts) -> i64 { 436 if s == 0 as *ApaFileScanCounts { return NX_APA_CONSISTENCY_NOT_VERIFIED } 437 let declared_fully: i64 = s.n_header_fully_wired 438 let declared_partial: i64 = s.n_header_partial_wired 439 let declared_honest: i64 = s.n_header_honest_stub 440 let stub_count: i64 = s.n_stub_not_wired_markers 441 442 let total_headers: i64 = declared_fully + declared_partial + declared_honest 443 if total_headers == 0 { return NX_APA_CONSISTENCY_NOT_VERIFIED } 444 445 // FULLY_WIRED + visible stub-USAGE = overstated 446 if declared_fully >= 1 { 447 if declared_partial == 0 { 448 if declared_honest == 0 { 449 if stub_count >= NX_APA_STUB_USAGE_THRESHOLD { return NX_APA_CONSISTENCY_OVERSTATED } 450 return NX_APA_CONSISTENCY_CONSISTENT 451 } 452 } 453 } 454 455 // PARTIAL_WIRED or HONEST_STUB without stub markers = understated 456 // (no honest-stub markers present to corroborate the partial claim) 457 if declared_partial >= 1 { 458 if stub_count == 0 { return NX_APA_CONSISTENCY_UNDERSTATED } 459 return NX_APA_CONSISTENCY_CONSISTENT 460 } 461 if declared_honest >= 1 { 462 if stub_count == 0 { return NX_APA_CONSISTENCY_UNDERSTATED } 463 return NX_APA_CONSISTENCY_CONSISTENT 464 } 465 return NX_APA_CONSISTENCY_CONSISTENT 466}