nx_maint_ingest_test.nx source
↩ module page · 102 lines · 4808 B
1// nx_maint_ingest_test.nx -- gate for the hardware-facing ingest rung (R1).
2//
3// Proves: every sensor KIND routes to the right kernel; the data-driven
4// normalize math (Emporia mA->centi-A, DIY deci-degC->milli-degC, offsets);
5// UNKNOWN kind is FIRST-CLASS (value computed + recorded, never dropped, no
6// false routing); bad-arg is loud; liar-kill (value tracks raw + kernel tracks
7// kind, not constants).
8//
9// expect_exit: 0
10//
11// license_tier: ORIGINAL
12
13import "nx_syscalls_x86_64.nx"
14import "nx_maint_ingest.nx"
15
16func main() -> i64 {
17 // ---- sealed enums ----
18 if nx_sensor_kind_is_valid(NX_SENSOR_USAGE) != 1 { return 1 }
19 if nx_sensor_kind_is_valid(NX_SENSOR_N) != 0 { return 2 }
20 if nx_src_is_valid(NX_SRC_EMPORIA) != 1 { return 3 }
21 if nx_src_is_valid(NX_SRC_N) != 0 { return 4 }
22
23 // ---- routing KAT: kind -> kernel ----
24 if nx_maint_sensor_kernel(NX_SENSOR_TEMP) != NX_MK_THERMAL { return 5 }
25 if nx_maint_sensor_kernel(NX_SENSOR_RUNTIME) != NX_MK_THERMAL { return 6 }
26 if nx_maint_sensor_kernel(NX_SENSOR_CURRENT) != NX_MK_ELECTRICAL { return 7 }
27 if nx_maint_sensor_kernel(NX_SENSOR_VOLTAGE) != NX_MK_ELECTRICAL { return 8 }
28 if nx_maint_sensor_kernel(NX_SENSOR_VIBRATION) != NX_MK_ROTATING { return 9 }
29 if nx_maint_sensor_kernel(NX_SENSOR_PRESSURE) != NX_MK_FLUID { return 10 }
30 if nx_maint_sensor_kernel(NX_SENSOR_FLOW) != NX_MK_FLUID { return 11 }
31 if nx_maint_sensor_kernel(NX_SENSOR_USAGE) != NX_MK_CONSUMABLE { return 12 }
32 if nx_maint_sensor_kernel(99) != NX_MK_NONE { return 13 }
33
34 let r: *SensorReading = sys_mmap(64) as *SensorReading
35 let out: *NormSample = sys_mmap(64) as *NormSample
36
37 // ===== TEMP (sovereign DIY): deci-degC 215 -> milli-degC 21500 ==
38 r.kind = NX_SENSOR_TEMP; r.src = NX_SRC_SOVEREIGN_DIY
39 r.raw_value = 215; r.scale_num = 100; r.scale_den = 1; r.offset = 0
40 if nx_maint_ingest(r, out) != 1 { return 20 }
41 if out.value != 21500 { return 21 }
42 if out.kernel != NX_MK_THERMAL { return 22 }
43 if out.recognized != 1 { return 23 }
44
45 // ===== CURRENT (Emporia): milli-amps 15000 -> centi-amps 1500 ===
46 r.kind = NX_SENSOR_CURRENT; r.src = NX_SRC_EMPORIA
47 r.raw_value = 15000; r.scale_num = 1; r.scale_den = 10; r.offset = 0
48 if nx_maint_ingest(r, out) != 1 { return 30 }
49 if out.value != 1500 { return 31 }
50 if out.kernel != NX_MK_ELECTRICAL { return 32 }
51
52 // ===== VIBRATION -> rotating ===================================
53 r.kind = NX_SENSOR_VIBRATION; r.src = NX_SRC_SOVEREIGN_DIY
54 r.raw_value = 2000; r.scale_num = 1; r.scale_den = 1; r.offset = 0
55 if nx_maint_ingest(r, out) != 1 { return 40 }
56 if out.kernel != NX_MK_ROTATING { return 41 }
57
58 // ===== PRESSURE -> fluid =======================================
59 r.kind = NX_SENSOR_PRESSURE; r.src = NX_SRC_SOVEREIGN_DIY
60 r.raw_value = 6000; r.scale_num = 1; r.scale_den = 1; r.offset = 0
61 if nx_maint_ingest(r, out) != 1 { return 50 }
62 if out.kernel != NX_MK_FLUID { return 51 }
63
64 // ===== USAGE -> consumable =====================================
65 r.kind = NX_SENSOR_USAGE; r.src = NX_SRC_OBD
66 r.raw_value = 100; r.scale_num = 1; r.scale_den = 1; r.offset = 0
67 if nx_maint_ingest(r, out) != 1 { return 60 }
68 if out.kernel != NX_MK_CONSUMABLE { return 61 }
69
70 // ===== offset applied ==========================================
71 r.kind = NX_SENSOR_TEMP; r.src = NX_SRC_MANUAL
72 r.raw_value = 100; r.scale_num = 1; r.scale_den = 1; r.offset = 5
73 if nx_maint_ingest(r, out) != 1 { return 70 }
74 if out.value != 105 { return 71 }
75
76 // ===== UNKNOWN kind: first-class (value computed, NO kernel, recorded) =
77 r.kind = 99; r.src = NX_SRC_SOVEREIGN_DIY
78 r.raw_value = 42; r.scale_num = 1; r.scale_den = 1; r.offset = 0
79 if nx_maint_ingest(r, out) != 0 { return 80 }
80 if out.kernel != NX_MK_NONE { return 81 }
81 if out.recognized != 0 { return 82 }
82 if out.value != 42 { return 83 } // still computed -- recorded, not dropped
83
84 // ===== BAD_ARG: scale_den 0 (cannot normalize) =================
85 r.kind = NX_SENSOR_TEMP; r.scale_den = 0
86 if nx_maint_ingest(r, out) != (0 - 2) { return 90 }
87
88 // ===== LIAR-KILL: value tracks raw, kernel tracks kind =========
89 r.kind = NX_SENSOR_CURRENT; r.src = NX_SRC_EMPORIA
90 r.raw_value = 15000; r.scale_num = 1; r.scale_den = 10; r.offset = 0
91 nx_maint_ingest(r, out)
92 let v1: i64 = out.value
93 let k1: i64 = out.kernel
94 r.raw_value = 30000
95 nx_maint_ingest(r, out)
96 if out.value == v1 { return 92 } // value tracks raw (1500 vs 3000)
97 r.kind = NX_SENSOR_TEMP; r.raw_value = 215; r.scale_num = 100; r.scale_den = 1
98 nx_maint_ingest(r, out)
99 if out.kernel == k1 { return 93 } // kernel tracks kind (electrical vs thermal)
100
101 return 0
102}