nx_consumable.nx source
↩ module page · 119 lines · 4519 B
1// nx_consumable.nx -- consumable-depletion kernel (#3 of the 4 physics kernels).
2// The "REPLACE" intelligence: severity-weighted cumulative consumption vs the
3// consumable's rated life -> remaining life + a replace verdict, for engine
4// oil / brake pads / air+oil+water filters / printer toner / etc.
5//
6// THE EXCEED (independent + condition-aware): an OEM gives a FIXED interval
7// ("change oil every 8000") and a smart-monitor gives a vendor black box. We
8// track ACTUAL severity-weighted consumption -> gentle highway use EXTENDS life
9// (don't waste money replacing early); severe stop-and-go / towing / dust
10// SHORTENS it (replace before damage). SAME mileage, opposite verdict by
11// measured duty. Generalizes the printer-toner ledger (measure real coverage,
12// ignore the lying gauge) to every consumable.
13//
14// NEVER-BRICK (#26): reads usage, emits a verdict; writes nothing. Read-only.
15//
16// genealogy_id: project-maintenance-platform-sclass-2026-06-23 (kernel #3) + printer-toner ledger
17// license_tier: ORIGINAL
18//
19// nx_capability_claims:
20// needs: [pointer_arithmetic]
21// provides: [consumable_remaining_life, severity_weighted_consumption,
22// condition_aware_replace_verdict, vendor_independent_interval]
23// safety: [no_floating_point, no_syscall, bounded_iteration,
24// read_only_no_device_write, no_firmware_write_by_construction,
25// sealed_enum_verdict]
26// verdict: [sealed_enum_cons, no_silent_failure]
27// license: ORIGINAL
28// kind: maintenance_runtime_primitive
29
30const NX_CONS_INSUFFICIENT_DATA: i64 = 0
31const NX_CONS_OK: i64 = 1 // healthy remaining life
32const NX_CONS_DUE_SOON: i64 = 2 // within the soon threshold
33const NX_CONS_DUE: i64 = 3 // at / just past rated life
34const NX_CONS_OVERDUE: i64 = 4 // well past life -> risk
35const NX_CONS_BAD_ARG: i64 = 5
36const NX_CONS_N: i64 = 6
37
38func nx_cons_verdict_is_valid(v: i64) -> i64 {
39 if v < 0 { return 0 }
40 if v >= NX_CONS_N { return 0 }
41 return 1
42}
43
44// Data-driven spec = the consumable's envelope (#11; svc-config in prod).
45struct ConsSpec {
46 rated_life: i64, // rated capacity in normalized units (mi/hr/pages/gal/cycles)
47 soon_permille: i64, // replace-soon threshold (e.g. 150 = flag at <=15% left)
48 overdue_permille: i64, // overdue band past life (e.g. 100 = 10% past = OVERDUE)
49}
50
51struct ConsEff {
52 total_consumed: i64,
53 remaining: i64, // can be negative (past life)
54 remaining_permille: i64, // can be negative
55 verdict: i64,
56}
57
58// usage[i] = usage amount in interval i (miles / hours / pages / gallons).
59// severity_x100[i] = duty multiplier x100 (100 normal, 200 severe, 50 gentle).
60// prior_consumed = severity-weighted consumption accrued before this window
61// (additive #13 -> resumable from the ledger).
62func nx_cons_analyze(usage: *i64, severity_x100: *i64, n: i64,
63 prior_consumed: i64, spec: *ConsSpec, out: *ConsEff) -> i64 {
64 out.total_consumed = 0
65 out.remaining = 0
66 out.remaining_permille = 0
67 out.verdict = NX_CONS_INSUFFICIENT_DATA
68
69 if spec.rated_life <= 0 {
70 out.verdict = NX_CONS_BAD_ARG
71 return out.verdict
72 }
73 if n < 0 {
74 out.verdict = NX_CONS_BAD_ARG
75 return out.verdict
76 }
77 if prior_consumed < 0 {
78 out.verdict = NX_CONS_INSUFFICIENT_DATA
79 return out.verdict
80 }
81
82 var window: i64 = 0
83 var i: i64 = 0
84 while i < n {
85 let u: i64 = usage[i]
86 let s: i64 = severity_x100[i]
87 if u < 0 {
88 out.verdict = NX_CONS_BAD_ARG
89 return out.verdict
90 }
91 if s < 0 {
92 out.verdict = NX_CONS_BAD_ARG
93 return out.verdict
94 }
95 window = window + (u * s) / 100
96 i = i + 1
97 }
98
99 let total: i64 = prior_consumed + window
100 let remaining: i64 = spec.rated_life - total
101 out.total_consumed = total
102 out.remaining = remaining
103 out.remaining_permille = (remaining * 1000) / spec.rated_life
104
105 if out.remaining_permille >= spec.soon_permille {
106 out.verdict = NX_CONS_OK
107 return out.verdict
108 }
109 if out.remaining_permille >= 0 {
110 out.verdict = NX_CONS_DUE_SOON
111 return out.verdict
112 }
113 if out.remaining_permille >= (0 - spec.overdue_permille) {
114 out.verdict = NX_CONS_DUE
115 return out.verdict
116 }
117 out.verdict = NX_CONS_OVERDUE
118 return out.verdict
119}