code wiki / (root) / nx_log_category.nx

nx_log_category.nx source

↩ module page · 236 lines · 9016 B

1// nx_log_category.nx -- sealed-enum log-field classification with 2// structural people-data refusal. 3// 4// User directive 2026-05-17: "yes we want logs for systems not 5// people and s class". 6// 7// The sealed enum makes the system/people distinction LOAD-BEARING: 8// every log call declares its category; the emitter refuses to 9// transmit PEOPLE_* categories without an explicit caller-supplied 10// override token. This is structural prevention, not policy hope. 11// 12// Sealed-enum NxLogCategory (8 states): 13// 14// SYSTEM categories (default-allowed): 15// SYSTEM_STATE daemon uptime, state transitions, version 16// SYSTEM_PERF latency p50/p95, throughput, queue depths 17// SYSTEM_ERROR errno, crash dumps, aggregate error counts 18// SYSTEM_CONFIG config loaded, env var set, capability flag 19// SYSTEM_SECURITY auth failure AGGREGATE COUNT (not per-user) 20// 21// PEOPLE categories (refused by default; require override): 22// PEOPLE_PII IP, UA, cookie, fingerprint, email, name 23// PEOPLE_BEHAVIOR per-user click path, dwell time, navigation 24// PEOPLE_LOCATION geo-IP, coarse city, precise GPS 25// 26// Per cardinal feedback-privacy-by-default-no-tracking: 27// - SYSTEM categories serve operations: capacity planning, alert 28// thresholds, crash diagnosis, performance regressions 29// - PEOPLE categories enable surveillance: subpoena targets, 30// advertising profiles, behavioral manipulation 31// 32// Substrate's structural enforcement: 33// Default emit accepts ONLY SYSTEM categories. 34// PEOPLE category emit requires an explicit override token whose 35// value carries a citation (legal requirement / regulated industry 36// carve-out / user-explicit-consent flow). The grader scans for 37// override tokens + ensures each has a justification annotation. 38// 39// nx_capability_claims: 40// needs: [sealed_enum, byte_ops] 41// provides: [log_category_enum, system_vs_people_distinction, 42// structural_people_data_refusal] 43// safety: [no_unchecked_deref, no_floating_point, no_syscall, 44// bit_equal_reproducible, default_refuses_pii] 45// verdict: [sealed_enum_9_state] 46// license: ORIGINAL 47// kind: racing_crew_specialist 48// layer: L2 (transform: log call -> structural verdict) 49 50// ---- Sealed enum: log category ----------------------------------- 51 52const NXLC_SYSTEM_STATE: i64 = 0 53const NXLC_SYSTEM_PERF: i64 = 1 54const NXLC_SYSTEM_ERROR: i64 = 2 55const NXLC_SYSTEM_CONFIG: i64 = 3 56const NXLC_SYSTEM_SECURITY: i64 = 4 57const NXLC_PEOPLE_PII: i64 = 5 58const NXLC_PEOPLE_BEHAVIOR: i64 = 6 59const NXLC_PEOPLE_LOCATION: i64 = 7 60const NXLC_CATEGORY_N: i64 = 8 61 62func nxlc_category_is_valid(c: i64) -> i64 { 63 if c < 0 { return 0 } 64 if c >= NXLC_CATEGORY_N { return 0 } 65 return 1 66} 67 68func nxlc_category_name(c: i64) -> *u8 { 69 if c == NXLC_SYSTEM_STATE { return "SYSTEM_STATE" as *u8 } 70 if c == NXLC_SYSTEM_PERF { return "SYSTEM_PERF" as *u8 } 71 if c == NXLC_SYSTEM_ERROR { return "SYSTEM_ERROR" as *u8 } 72 if c == NXLC_SYSTEM_CONFIG { return "SYSTEM_CONFIG" as *u8 } 73 if c == NXLC_SYSTEM_SECURITY { return "SYSTEM_SECURITY" as *u8 } 74 if c == NXLC_PEOPLE_PII { return "PEOPLE_PII" as *u8 } 75 if c == NXLC_PEOPLE_BEHAVIOR { return "PEOPLE_BEHAVIOR" as *u8 } 76 if c == NXLC_PEOPLE_LOCATION { return "PEOPLE_LOCATION" as *u8 } 77 return "INVALID" as *u8 78} 79 80func nxlc_category_name_len(c: i64) -> i64 { 81 if c == NXLC_SYSTEM_STATE { return 12 } 82 if c == NXLC_SYSTEM_PERF { return 11 } 83 if c == NXLC_SYSTEM_ERROR { return 12 } 84 if c == NXLC_SYSTEM_CONFIG { return 13 } 85 if c == NXLC_SYSTEM_SECURITY { return 15 } 86 if c == NXLC_PEOPLE_PII { return 10 } 87 if c == NXLC_PEOPLE_BEHAVIOR { return 15 } 88 if c == NXLC_PEOPLE_LOCATION { return 15 } 89 return 7 90} 91 92// ---- Family predicates ------------------------------------------- 93 94// Returns 1 if category is in the SYSTEM family (default-allowed). 95func nxlc_is_system(c: i64) -> i64 { 96 if c == NXLC_SYSTEM_STATE { return 1 } 97 if c == NXLC_SYSTEM_PERF { return 1 } 98 if c == NXLC_SYSTEM_ERROR { return 1 } 99 if c == NXLC_SYSTEM_CONFIG { return 1 } 100 if c == NXLC_SYSTEM_SECURITY { return 1 } 101 return 0 102} 103 104// Returns 1 if category is in the PEOPLE family (refused by default). 105func nxlc_is_people(c: i64) -> i64 { 106 if c == NXLC_PEOPLE_PII { return 1 } 107 if c == NXLC_PEOPLE_BEHAVIOR { return 1 } 108 if c == NXLC_PEOPLE_LOCATION { return 1 } 109 return 0 110} 111 112// ---- Sealed enum: emit verdict ----------------------------------- 113 114const NXLC_OK: i64 = 0 115const NXLC_REFUSED_NO_OVERRIDE: i64 = 1 116const NXLC_BAD_CATEGORY: i64 = 2 117const NXLC_BAD_OVERRIDE: i64 = 3 118const NXLC_BAD_ARG: i64 = 4 119const NXLC_VERDICT_N: i64 = 5 120 121func nxlc_verdict_is_valid(v: i64) -> i64 { 122 if v < 0 { return 0 } 123 if v >= NXLC_VERDICT_N { return 0 } 124 return 1 125} 126 127func nxlc_verdict_name(v: i64) -> *u8 { 128 if v == NXLC_OK { return "OK" as *u8 } 129 if v == NXLC_REFUSED_NO_OVERRIDE { return "REFUSED_NO_OVERRIDE" as *u8 } 130 if v == NXLC_BAD_CATEGORY { return "BAD_CATEGORY" as *u8 } 131 if v == NXLC_BAD_OVERRIDE { return "BAD_OVERRIDE" as *u8 } 132 if v == NXLC_BAD_ARG { return "BAD_ARG" as *u8 } 133 return "INVALID" as *u8 134} 135 136// ---- Override token validation ----------------------------------- 137// 138// To emit a PEOPLE-category log, caller passes a non-null override 139// token + cite_reason. The token MUST be the literal byte string 140// "privacy-override" (16 bytes); cite_reason must be non-empty. 141// 142// This forces every people-data log call to: 143// (a) be visible to grep / static analysis 144// (b) carry an inline justification (legal cite, consent flow ID, 145// or `audit-only` annotation) 146// (c) be auditable by the racing-crew grader (queued: 147// bench/nx_privacy_override_audit.sh) 148 149func nxlc_override_is_valid(token: *u8, token_n: i64, 150 cite: *u8, cite_n: i64) -> i64 { 151 if token == (0 as *u8) { return 0 } 152 if token_n != 16 { return 0 } 153 let expected: *u8 = "privacy-override" as *u8 154 var i: i64 = 0 155 while i < 16 { 156 if token[i] != expected[i] { return 0 } 157 i = i + 1 158 } 159 if cite == (0 as *u8) { return 0 } 160 if cite_n <= 0 { return 0 } 161 return 1 162} 163 164// ---- Categorized emit gate --------------------------------------- 165// 166// Decide whether a log call carrying `category` is allowed. Returns 167// NXLC_OK if the caller can proceed to nx_log_emit_line, or a 168// non-OK verdict that the caller must propagate. 169// 170// SYSTEM categories: always OK. 171// PEOPLE categories: OK only if override_token + cite valid. 172 173func nx_log_category_gate( 174 category: i64, 175 override_token: *u8, override_n: i64, 176 cite: *u8, cite_n: i64) -> i64 { 177 if nxlc_category_is_valid(category) != 1 { return NXLC_BAD_CATEGORY } 178 if nxlc_is_system(category) == 1 { return NXLC_OK } 179 if nxlc_is_people(category) != 1 { return NXLC_BAD_CATEGORY } 180 if override_token == (0 as *u8) { return NXLC_REFUSED_NO_OVERRIDE } 181 if nxlc_override_is_valid(override_token, override_n, 182 cite, cite_n) != 1 { 183 return NXLC_BAD_OVERRIDE 184 } 185 return NXLC_OK 186} 187 188// ---- Convenience: log-call wrapper that includes the gate -------- 189// 190// Sample caller pattern: 191// 192// // SYSTEM_STATE -- always OK 193// let v: i64 = nx_log_category_gate(NXLC_SYSTEM_STATE, ...) 194// if v == NXLC_OK { nx_log_emit_line(... module ... msg ...) } 195// 196// // PEOPLE_PII -- requires override 197// let v: i64 = nx_log_category_gate( 198// NXLC_PEOPLE_PII, 199// "privacy-override" as *u8, 16, 200// "GDPR Art. 6(1)(b) -- session bound, deletes after logout" as *u8, 201// 58) 202// if v == NXLC_OK { 203// // emit allowed; explicit 204// } else { 205// // refused; substrate didn't leak the field 206// } 207 208// ---- Grader-friendly helper: count override usage --------------- 209// 210// Future bench/nx_privacy_override_audit.sh scans substrate source 211// for instances of `nx_log_category_gate(NXLC_PEOPLE_*, ...)` to 212// produce a register of every people-data log call + its cite. 213// Today's substrate has ZERO such instances. Caller asserts this 214// at startup via this helper (panic-free; returns count for the 215// caller to verify). 216 217func nx_log_count_people_overrides_in_buf(buf: *u8, n: i64) -> i64 { 218 if buf == (0 as *u8) { return 0 } 219 if n < 4 { return 0 } 220 // Naive substring scan for "NXLC_PEOPLE_" (12 bytes). Caller 221 // supplies the source file as `buf` (read via sys_read_file). 222 var count: i64 = 0 223 let needle: *u8 = "NXLC_PEOPLE_" as *u8 224 var i: i64 = 0 225 while i <= n - 12 { 226 var eq: i64 = 1 227 var j: i64 = 0 228 while j < 12 { 229 if buf[i + j] != needle[j] { eq = 0; j = 12 } 230 j = j + 1 231 } 232 if eq == 1 { count = count + 1 } 233 i = i + 1 234 } 235 return count 236}