code wiki / (root) / nx_printer_health.nx

nx_printer_health.nx source

↩ module page · 166 lines · 7973 B

1// nx_printer_health.nx -- honest-status / anti-silent-failure model layer (R1) over nx_ipp_codec. 2// 3// THE operator complaint this targets: printers "silently fail". A real IPP printer always tells you 4// WHY it is stuck via printer-state + printer-state-reasons; Brother's UI swallows it. This layer reads 5// a parsed Get-Printer-Attributes response and answers, honestly and mechanically, the only question a 6// user cares about: "can this thing actually print right now, and if not, exactly why?" 7// 8// Grounded in RFC 8011 sec 5.4.11/5.4.12 (fetched by the sovereign researcher -> ipp_rfc8011.raw): 9// - printer-state: idle=3 processing=4 stopped=5 10// - printer-state-reasons (1setOf keyword): each value MAY carry a severity suffix 11// '-report' (least severe; MUST NOT affect output) 12// '-warning' (won't stop the Job; output may be lower quality) 13// '-error' (most severe; if ANY error reason is present the printer MUST be 'stopped') 14// If a value has NO suffix and is not 'none': it is an ERROR when the printer is 'stopped', 15// otherwise a WARNING. 'none' means there are no reasons. 16// - printer-is-accepting-jobs (boolean, sec 5.4.23) 17// 18// NEVER-BRICK (#26): pure model logic; no syscalls, no hardware writes. Safe by construction. 19// no_silent_failure: a malformed response yields NX_PR_UNKNOWN, never a false "ready". 20// Sovereign: imports only nx_ipp_codec.nx; nx_cc -> nxasm, no gcc. 21// 22// genealogy_id: project-printer-management-ipp-sclass-2026-06-20 23// license_tier: ORIGINAL 24// 25// nx_capability_claims: 26// provides: [printer_reason_severity, printer_worst_severity, printer_accepting, printer_can_print, 27// printer_diagnose] 28// safety: [no_unchecked_deref, no_floating_point, no_syscall, bounded_iteration, 29// never_brick_pure_model, defensive_bounds_checked] 30// verdict: [sealed_enum_severity, sealed_enum_can_print, no_silent_failure] 31// sss: [S6, S7] 32 33import "nx_ipp_codec.nx" 34 35// ---- sealed severity enum (RFC 8011 sec 5.4.12 levels) ------------- 36const NX_SEV_NONE: i64 = 0 37const NX_SEV_REPORT: i64 = 1 38const NX_SEV_WARNING: i64 = 2 39const NX_SEV_ERROR: i64 = 3 40 41// ---- sealed can-print verdict ------------------------------------- 42const NX_PR_CAN_PRINT: i64 = 1 // ready 43const NX_PR_DEGRADED: i64 = 2 // will print, but needs attention (a warning is active) 44const NX_PR_BLOCKED: i64 = 3 // will NOT print until a human acts (stopped / not accepting / error) 45const NX_PR_UNKNOWN: i64 = 4 // could not be determined (malformed/absent) -- never a false "ready" 46const NX_PR_VERDICT_N: i64 = 5 47 48func nx_pr_verdict_is_valid(v: i64) -> i64 { 49 if v <= 0 { return 0 } 50 if v >= NX_PR_VERDICT_N { return 0 } 51 return 1 52} 53 54// 1 if buf[off .. off+len) ends with the null-terminated suffix `suf`. 55func nx_ph_ends_with(buf: *u8, off: i64, len: i64, suf: *u8) -> i64 { 56 let sl: i64 = nx_ipp_strlen(suf) 57 if sl > len { return 0 } 58 let start: i64 = off + len - sl 59 return nx_ipp_name_eq(buf, start, suf, sl) 60} 61 62// Severity of one printer-state-reasons keyword value buf[off .. off+len), given the printer-state. 63func nx_ph_reason_severity(buf: *u8, off: i64, len: i64, pstate: i64) -> i64 { 64 if len == 4 { 65 if nx_ipp_name_eq(buf, off, "none", 4) == 1 { return NX_SEV_NONE } 66 } 67 if nx_ph_ends_with(buf, off, len, "-error") == 1 { return NX_SEV_ERROR } 68 if nx_ph_ends_with(buf, off, len, "-warning") == 1 { return NX_SEV_WARNING } 69 if nx_ph_ends_with(buf, off, len, "-report") == 1 { return NX_SEV_REPORT } 70 // no suffix and not 'none' (RFC 8011 sec 5.4.12) 71 if pstate == NX_IPP_PSTATE_STOPPED { return NX_SEV_ERROR } 72 return NX_SEV_WARNING 73} 74 75// Walk EVERY value of printer-state-reasons (the attribute value + its 1setOf additional-values) and 76// return the worst severity; writes the value count via out_count. Returns -1 if the message is 77// malformed (length overrun) -- the no-silent-failure signal. Bounded: off strictly increases. 78func nx_ph_worst_reason_severity(buf: *u8, n: i64, pstate: i64, out_count: *i64) -> i64 { 79 out_count[0] = 0 80 if n < 8 { return 0 - 1 } 81 var off: i64 = 8 82 var worst: i64 = NX_SEV_NONE 83 var cnt: i64 = 0 84 var in_reasons: i64 = 0 85 var bad: i64 = 0 86 var keep: i64 = 1 87 while keep == 1 { 88 if off >= n { keep = 0 } 89 else { 90 let tag: i64 = buf[off] as i64 91 if tag == NX_IPP_TAG_END { keep = 0 } 92 else { 93 if tag <= 0x0f { off = off + 1; in_reasons = 0 } 94 else { 95 if (off + 3) > n { bad = 1; keep = 0 } 96 else { 97 let nlen: i64 = nx_ipp_get_u16(buf, off + 1) 98 let name_off: i64 = off + 3 99 if (name_off + nlen + 2) > n { bad = 1; keep = 0 } 100 else { 101 let vlen_off: i64 = name_off + nlen 102 let vlen: i64 = nx_ipp_get_u16(buf, vlen_off) 103 let val_off: i64 = vlen_off + 2 104 if (val_off + vlen) > n { bad = 1; keep = 0 } 105 else { 106 if nlen > 0 { 107 if nx_ipp_name_eq(buf, name_off, "printer-state-reasons", 21) == 1 { in_reasons = 1 } 108 else { in_reasons = 0 } 109 } 110 if in_reasons == 1 { 111 let sev: i64 = nx_ph_reason_severity(buf, val_off, vlen, pstate) 112 if sev > worst { worst = sev } 113 cnt = cnt + 1 114 } 115 off = val_off + vlen 116 } 117 } 118 } 119 } 120 } 121 } 122 } 123 if bad == 1 { return 0 - 1 } 124 out_count[0] = cnt 125 return worst 126} 127 128// printer-is-accepting-jobs: returns 1 (accepting), 0 (refusing), or -1 (not present / malformed). 129// `scratch3` is a caller-provided i64[3] work area. 130func nx_ph_accepting(buf: *u8, n: i64, scratch3: *i64) -> i64 { 131 let p_tag: *i64 = scratch3 132 let p_voff: *i64 = ((scratch3 as i64) + 8) as *i64 133 let p_vlen: *i64 = ((scratch3 as i64) + 16) as *i64 134 let v: i64 = nx_ipp_find(buf, n, "printer-is-accepting-jobs", p_tag, p_voff, p_vlen) 135 if v != NX_IPP_OK { return 0 - 1 } 136 if p_tag[0] != NX_IPP_VT_BOOLEAN { return 0 - 1 } 137 if p_vlen[0] != 1 { return 0 - 1 } 138 return buf[p_voff[0]] as i64 139} 140 141// The honest verdict: can this printer print right now? 142func nx_printer_can_print(pstate: i64, accepting: i64, worst_sev: i64) -> i64 { 143 if pstate < 0 { return NX_PR_UNKNOWN } 144 if worst_sev < 0 { return NX_PR_UNKNOWN } 145 if pstate == NX_IPP_PSTATE_STOPPED { return NX_PR_BLOCKED } 146 if accepting == 0 { return NX_PR_BLOCKED } 147 if worst_sev == NX_SEV_ERROR { return NX_PR_BLOCKED } 148 if worst_sev == NX_SEV_WARNING { return NX_PR_DEGRADED } 149 return NX_PR_CAN_PRINT 150} 151 152// One-shot diagnosis of a Get-Printer-Attributes response. Fills out_state (printer-state enum or -1), 153// out_sev (worst reason severity or -1), out_count (#reasons), out_accepting (1/0/-1). Returns the 154// sealed can-print verdict. `scratch3` is a caller-provided i64[3] work area. 155func nx_printer_diagnose(buf: *u8, n: i64, scratch3: *i64, 156 out_state: *i64, out_sev: *i64, out_count: *i64, out_accepting: *i64) -> i64 { 157 let ev: i64 = nx_ipp_get_enum(buf, n, "printer-state", scratch3, out_state) 158 var pstate: i64 = 0 - 1 159 if ev == NX_IPP_OK { pstate = out_state[0] } 160 else { out_state[0] = 0 - 1 } 161 let worst: i64 = nx_ph_worst_reason_severity(buf, n, pstate, out_count) 162 out_sev[0] = worst 163 let acc: i64 = nx_ph_accepting(buf, n, scratch3) 164 out_accepting[0] = acc 165 return nx_printer_can_print(pstate, acc, worst) 166}