code wiki / (root) / nx_calibration_drift_monitor.nx

nx_calibration_drift_monitor.nx source

↩ module page · 223 lines · 11423 B

1// nx_calibration_drift_monitor.nx -- scheduled re-characterization + drift alerts. 2// 3// module: nishi-core.perception.calibration_drift_monitor 4// depends: nishi-core.perception.profile + nishi-core.perception.transducer_characterizer + 5// nishi-core.perception.provenance_curve_store + nishi-core.perception.instrument_diagnostician + 6// nishi-core.io.syscalls 7// disk_kb: 5 8// capability: PERCEPTION 9// wired_status: PARTIAL_WIRED 10// 11// MISSING_CAPABILITIES: 12// - SCHEDULE_PERSIST (cron-style schedule serialized to disk + restored 13// on substrate restart; depends on nx_race_timing already FULLY_WIRED 14// — wire the call site) 15// - CURVE_DIFF (compute delta between current FRF and stored baseline; 16// queued, depends on nx_fft once landed) 17// - ALERT_DISPATCH (surface drift findings to nx_audit_dashboard + 18// optional notification path; depends on dashboard UI) 19// - DIAGNOSTIC_HANDOFF (on drift detected, hand result to 20// nx_instrument_diagnostician for "is this just aging or is something 21// broken?" verdict) 22// 23// license_tier: PUBLIC_NISHI_SUBSTRATE 24// genealogy_id: feedback-substrate-does-heavy-lifting-user-is-partner-not-gate_2026 + 25// feedback-substrate-primitives-meta-not-one-off_2026 + 26// feedback-self-surfacing-intelligence-staged-autonomy + 27// feedback-racing-timing-modes-sealed-enum + 28// shewhart_1931_statistical_process_control 29// 30// Per cardinals [[feedback-substrate-does-heavy-lifting-user-is-partner-not-gate]] 31// and [[feedback-substrate-primitives-meta-not-one-off]]: 32// THIS primitive re-runs nx_transducer_characterize on a schedule, 33// compares the result to the stored baseline curve, and surfaces drift 34// before the drift invalidates the measurement chain. 35// 36// User contribution: zero day-to-day. Substrate watches. User only 37// hears from substrate when drift exceeds a configurable threshold + 38// substrate needs ratification on the proposed action (re-calibrate, 39// replace component, accept as new baseline). 40// 41// Reuse set served by this single primitive: 42// - Verification mic aging (MEMS capsule sensitivity drifts over months) 43// - Speaker ribbon tension creep (ribbon tweeter shifts resonance over months) 44// - DAC reference voltage drift (LT1019 PPM/°C tracks ambient temp) 45// - Amplifier bias-current drift (lateral MOSFET thermal coefficient) 46// - Camera sensor pixel-response drift (dead pixels, dark current) 47// - Scent cartridge dispense depletion (chemical inventory monitoring) 48// - Hydrophone pressure-response aging (saltwater + epoxy degradation) 49// - Display backlight degradation (LED brightness fade) 50// - Heart-rate strap electrode contact resistance change (conductive 51// fabric wears over wash cycles) 52// - Every calibrated artifact in every Nishi hardware product, indefinitely 53 54import "nx_syscalls.nx" 55import "nx_perceptual_profile.nx" 56import "nx_transducer_characterizer.nx" 57import "nx_provenance_curve_store.nx" 58import "nx_instrument_diagnostician.nx" 59 60// ===== Drift kind sealed enum ===================================== 61// 62// What KIND of drift was detected. Drives downstream action selection. 63 64const NX_DRIFT_KIND_NONE: i64 = 0 // no drift detected 65const NX_DRIFT_KIND_MONOTONIC_DECLINE: i64 = 1 // sensitivity dropping 66const NX_DRIFT_KIND_MONOTONIC_INCREASE: i64 = 2 // gain creep 67const NX_DRIFT_KIND_FREQUENCY_SHIFT: i64 = 3 // resonance moved 68const NX_DRIFT_KIND_NEW_RESONANCE_PEAK: i64 = 4 // peak appeared not in baseline 69const NX_DRIFT_KIND_LOST_RESONANCE_PEAK: i64 = 5 // baseline peak disappeared 70const NX_DRIFT_KIND_NOISE_FLOOR_RISE: i64 = 6 // SNR degradation 71const NX_DRIFT_KIND_DISTORTION_INCREASE: i64 = 7 // THD climbed 72const NX_DRIFT_KIND_INTERMITTENT_DROPOUT: i64 = 8 // not always reproducing 73const NX_DRIFT_KIND_TEMPERATURE_RELATED: i64 = 9 // correlates with ambient temp 74const NX_DRIFT_KIND_CARTRIDGE_DEPLETION: i64 = 10 // chemical inventory low 75const NX_DRIFT_KIND_PIXEL_DEFECT: i64 = 11 // visual: new dead/hot pixels 76 77func nx_drift_kind_name(k: i64) -> *u8 { 78 if k == NX_DRIFT_KIND_NONE { return "NONE" } 79 if k == NX_DRIFT_KIND_MONOTONIC_DECLINE { return "MONOTONIC_DECLINE" } 80 if k == NX_DRIFT_KIND_MONOTONIC_INCREASE { return "MONOTONIC_INCREASE" } 81 if k == NX_DRIFT_KIND_FREQUENCY_SHIFT { return "FREQUENCY_SHIFT" } 82 if k == NX_DRIFT_KIND_NEW_RESONANCE_PEAK { return "NEW_RESONANCE_PEAK" } 83 if k == NX_DRIFT_KIND_LOST_RESONANCE_PEAK { return "LOST_RESONANCE_PEAK" } 84 if k == NX_DRIFT_KIND_NOISE_FLOOR_RISE { return "NOISE_FLOOR_RISE" } 85 if k == NX_DRIFT_KIND_DISTORTION_INCREASE { return "DISTORTION_INCREASE" } 86 if k == NX_DRIFT_KIND_INTERMITTENT_DROPOUT { return "INTERMITTENT_DROPOUT" } 87 if k == NX_DRIFT_KIND_TEMPERATURE_RELATED { return "TEMPERATURE_RELATED" } 88 if k == NX_DRIFT_KIND_CARTRIDGE_DEPLETION { return "CARTRIDGE_DEPLETION" } 89 if k == NX_DRIFT_KIND_PIXEL_DEFECT { return "PIXEL_DEFECT" } 90 return "UNKNOWN_DRIFT_KIND" 91} 92 93// ===== Drift action sealed enum =================================== 94// 95// What substrate recommends doing about a detected drift. 96 97const NX_DRIFT_ACTION_NONE: i64 = 0 // no action; drift within tolerance 98const NX_DRIFT_ACTION_ACCEPT_NEW_BASELINE: i64 = 1 // drift normal; new baseline stored 99const NX_DRIFT_ACTION_AUTO_RECOMPENSATE: i64 = 2 // substrate updates compensator 100 // curve in place; no user action 101const NX_DRIFT_ACTION_PROMPT_RECALIBRATE: i64 = 3 // ask user to re-run characterize 102const NX_DRIFT_ACTION_PROMPT_REPLACE_PART: i64 = 4 // drift beyond compensation 103const NX_DRIFT_ACTION_HALT_USE: i64 = 5 // measurement no longer trustworthy 104const NX_DRIFT_ACTION_DIAGNOSTIC_HANDOFF: i64 = 6 // hand to instrument_diagnostician 105 // for root-cause analysis 106 107func nx_drift_action_name(a: i64) -> *u8 { 108 if a == NX_DRIFT_ACTION_NONE { return "NONE" } 109 if a == NX_DRIFT_ACTION_ACCEPT_NEW_BASELINE { return "ACCEPT_NEW_BASELINE" } 110 if a == NX_DRIFT_ACTION_AUTO_RECOMPENSATE { return "AUTO_RECOMPENSATE" } 111 if a == NX_DRIFT_ACTION_PROMPT_RECALIBRATE { return "PROMPT_RECALIBRATE" } 112 if a == NX_DRIFT_ACTION_PROMPT_REPLACE_PART { return "PROMPT_REPLACE_PART" } 113 if a == NX_DRIFT_ACTION_HALT_USE { return "HALT_USE" } 114 if a == NX_DRIFT_ACTION_DIAGNOSTIC_HANDOFF { return "DIAGNOSTIC_HANDOFF" } 115 return "UNKNOWN_DRIFT_ACTION" 116} 117 118// ===== Monitor schedule sealed enum =============================== 119// 120// Composes with [[feedback-racing-timing-modes-sealed-enum]] — the 121// drift monitor is a CONTINUOUS / SCHEDULED / IDLE-opportunistic 122// substrate process that yields to user-interactive workloads. 123 124const NX_DRIFT_SCHED_DAILY: i64 = 1 125const NX_DRIFT_SCHED_WEEKLY: i64 = 2 126const NX_DRIFT_SCHED_MONTHLY: i64 = 3 127const NX_DRIFT_SCHED_QUARTERLY: i64 = 4 128const NX_DRIFT_SCHED_ON_TEMPERATURE_DROP: i64 = 5 // when ambient temp shifts >5°C 129const NX_DRIFT_SCHED_ON_USE_HOURS: i64 = 6 // after N hours of use 130const NX_DRIFT_SCHED_ON_DEMAND: i64 = 7 // manual trigger only 131const NX_DRIFT_SCHED_CONTINUOUS: i64 = 8 // every characterization run 132 133func nx_drift_sched_name(s: i64) -> *u8 { 134 if s == NX_DRIFT_SCHED_DAILY { return "DAILY" } 135 if s == NX_DRIFT_SCHED_WEEKLY { return "WEEKLY" } 136 if s == NX_DRIFT_SCHED_MONTHLY { return "MONTHLY" } 137 if s == NX_DRIFT_SCHED_QUARTERLY { return "QUARTERLY" } 138 if s == NX_DRIFT_SCHED_ON_TEMPERATURE_DROP { return "ON_TEMPERATURE_DROP" } 139 if s == NX_DRIFT_SCHED_ON_USE_HOURS { return "ON_USE_HOURS" } 140 if s == NX_DRIFT_SCHED_ON_DEMAND { return "ON_DEMAND" } 141 if s == NX_DRIFT_SCHED_CONTINUOUS { return "CONTINUOUS" } 142 return "UNKNOWN_SCHEDULE" 143} 144 145// ===== Drift finding struct ======================================= 146 147struct NxDriftFinding { 148 instrument_serial_hash_ptr: *u8 149 instrument_serial_hash_len: i64 150 drift_kind: i64 // NX_DRIFT_KIND_* 151 drift_magnitude_x1000: i64 // milli-units of deviation from baseline 152 affected_freq_lo_hz: i64 153 affected_freq_hi_hz: i64 154 recommended_action: i64 // NX_DRIFT_ACTION_* 155 confidence_score: i64 // 0..100 156 baseline_curve_hash_ptr: *u8 157 baseline_curve_hash_len: i64 158 current_curve_hash_ptr: *u8 159 current_curve_hash_len: i64 160} 161 162// ===== Top-level entry stubs ====================================== 163 164// nx_drift_monitor_enable -- begin watching a specific instrument on the 165// given schedule. Schedule persisted; substrate re-arms across restarts. 166 167func nx_drift_monitor_enable(instrument_serial_ptr: *u8, instrument_serial_len: i64, 168 schedule: i64, 169 threshold_pct_x10: i64) -> i64 { 170 if instrument_serial_len <= 0 { return 0 } 171 if schedule < NX_DRIFT_SCHED_DAILY { return 0 } 172 if schedule > NX_DRIFT_SCHED_CONTINUOUS { return 0 } 173 if threshold_pct_x10 <= 0 { return 0 } 174 // PARTIAL_WIRED: schedule persistence + tick wiring queued. 175 return 0 176} 177 178// nx_drift_monitor_disable -- stop monitoring this instrument. 179 180func nx_drift_monitor_disable(instrument_serial_ptr: *u8, instrument_serial_len: i64) -> i64 { 181 if instrument_serial_len <= 0 { return 0 } 182 return 1 183} 184 185// nx_drift_monitor_check_now -- run a single drift check immediately 186// outside the schedule. Used by audit dashboard "verify rig is still good" 187// button + by post-incident triage. 188 189func nx_drift_monitor_check_now(instrument_serial_ptr: *u8, instrument_serial_len: i64, 190 finding_ptr: *NxDriftFinding) -> i64 { 191 if instrument_serial_len <= 0 { return NX_DRIFT_KIND_NONE } 192 // PARTIAL_WIRED: needs nx_transducer_characterize + curve_diff + 193 // pattern matching. 194 return NX_DRIFT_KIND_NONE 195} 196 197// nx_drift_monitor_handle_finding -- substrate decides what to do with 198// a detected drift: accept new baseline, auto-recompensate, prompt user, 199// or hand off to instrument diagnostician. Per 200// [[feedback-self-surfacing-intelligence-staged-autonomy]] Stage 1 201// SUPERVISED: substrate proposes action, user ratifies. 202 203func nx_drift_monitor_handle_finding(finding_ptr: *NxDriftFinding, 204 user_ratified: i64) -> i64 { 205 if user_ratified != 1 { return NX_DRIFT_ACTION_NONE } // refuse Stage-3 206 // unsupervised today 207 return NX_DRIFT_ACTION_NONE 208} 209 210// nx_drift_monitor_get_age_days -- how many days since this instrument 211// was last characterized? Useful for batch "what needs checking" queries. 212 213func nx_drift_monitor_get_age_days(instrument_serial_ptr: *u8, instrument_serial_len: i64) -> i64 { 214 if instrument_serial_len <= 0 { return -1 } 215 return -1 216} 217 218// nx_drift_monitor_count_monitored -- inspector: how many instruments 219// currently being watched? 220 221func nx_drift_monitor_count_monitored() -> i64 { 222 return 0 223}