nx_validation.nx source
↩ module page · 161 lines · 5062 B
1// nx_validation.nx -- GO-TO-MARKET / VERIFICATION & VALIDATION. Turns a
2// gated DESIGN into a falsifiable TEST PLAN: for each design claim it names
3// the measurement, pulls the model's PREDICTION straight from the organs,
4// sets an acceptance rule (a tolerance band, a safety ceiling, or a quality
5// floor), and decides pass/fail against a real measured value. When every
6// test passes on a built prototype, the technology is VALIDATED (TRL 3 ->
7// TRL 4) -- the physical proof the model was right.
8//
9// Composes nx_water_awg + nx_water_quality + nx_water_design so the test
10// targets are the ACTUAL predictions (not hand-typed): predicted yield =
11// wa_daily_yield_ml(...), predicted remineralized TDS = the designed
12// sample's TDS, etc. INTEGER-EXACT. Safety tests are zero-slack ceilings.
13//
14// THE exceed: the acceptance test is DERIVED from the model, so building
15// the prototype either confirms the design or falsifies a specific claim --
16// a real V&V protocol, not a vague "see if it works".
17//
18// grounded: verification_and_validation + technology_readiness_level_4
19// genealogy_id: design_verification_validation + nishi_go_to_market
20
21import "nx_syscalls.nx"
22import "nx_water_awg.nx"
23import "nx_water_quality.nx"
24import "nx_water_design.nx"
25
26// ===== Acceptance rule kinds ======================================
27
28const VAL_BAND: i64 = 0 // |actual - predicted| within tolerance percent
29const VAL_CEIL: i64 = 1 // actual <= predicted (safety / max limit)
30const VAL_FLOOR: i64 = 2 // actual >= predicted (a minimum quality)
31
32// ===== Measurement ids (for labeling) =============================
33
34const VM_YIELD: i64 = 0
35const VM_ENERGY: i64 = 1
36const VM_COND_TDS: i64 = 2
37const VM_REMIN_TDS: i64 = 3
38const VM_TASTE: i64 = 4
39const VM_BACTERIA: i64 = 5
40const VM_LEAD: i64 = 6
41
42// ===== Struct: NxTestCase =========================================
43
44struct NxTestCase {
45 measure_id: i64,
46 kind: i64,
47 predicted: i64,
48 tolerance_pct: i64,
49 trl: i64,
50 safety: i64,
51}
52
53// ===== The water bench-prototype validation plan (model-derived) ==
54
55func val_water_count() -> i64 {
56 return 7
57}
58
59func val_water_case(i: i64) -> *NxTestCase {
60 let tc: *NxTestCase = (sys_mmap(64)) as *NxTestCase
61 tc.measure_id = i
62 tc.kind = VAL_BAND
63 tc.predicted = 0
64 tc.tolerance_pct = 20
65 tc.trl = 4
66 tc.safety = 0
67 if i == VM_YIELD {
68 tc.measure_id = VM_YIELD
69 tc.kind = VAL_BAND
70 tc.predicted = wa_daily_yield_ml(100, wa_extractable_x10(30, 70, 5))
71 tc.tolerance_pct = 20
72 }
73 if i == VM_ENERGY {
74 tc.measure_id = VM_ENERGY
75 tc.kind = VAL_BAND
76 tc.predicted = wa_specific_energy_whl(wa_extractable_x10(30, 70, 5))
77 tc.tolerance_pct = 25
78 }
79 if i == VM_COND_TDS {
80 tc.measure_id = VM_COND_TDS
81 tc.kind = VAL_CEIL
82 tc.predicted = 10
83 }
84 if i == VM_REMIN_TDS {
85 tc.measure_id = VM_REMIN_TDS
86 tc.kind = VAL_BAND
87 let best: *NxWaterSample = wd_design_best_water()
88 tc.predicted = best.tds
89 tc.tolerance_pct = 15
90 }
91 if i == VM_TASTE {
92 tc.measure_id = VM_TASTE
93 tc.kind = VAL_FLOOR
94 tc.predicted = 90
95 tc.trl = 5
96 }
97 if i == VM_BACTERIA {
98 tc.measure_id = VM_BACTERIA
99 tc.kind = VAL_CEIL
100 tc.predicted = 0
101 tc.safety = 1
102 }
103 if i == VM_LEAD {
104 tc.measure_id = VM_LEAD
105 tc.kind = VAL_CEIL
106 tc.predicted = WQ_LEAD_PPB
107 tc.safety = 1
108 }
109 return tc
110}
111
112// ===== Pass / fail =================================================
113
114func val_pass(tc: *NxTestCase, actual: i64) -> i64 {
115 if tc.kind == VAL_CEIL {
116 if actual <= tc.predicted { return 1 }
117 return 0
118 }
119 if tc.kind == VAL_FLOOR {
120 if actual >= tc.predicted { return 1 }
121 return 0
122 }
123 // VAL_BAND: relative tolerance around the prediction.
124 var diff: i64 = actual - tc.predicted
125 if diff < 0 { diff = 0 - diff }
126 if diff * 100 <= tc.predicted * tc.tolerance_pct { return 1 }
127 return 0
128}
129
130// ===== Run the plan over measured values ==========================
131
132// measured[i] = the observed value for test case i.
133func val_run(measured: *i64) -> i64 {
134 var pass: i64 = 0
135 var i: i64 = 0
136 while i < val_water_count() {
137 let tc: *NxTestCase = val_water_case(i)
138 if val_pass(tc, measured[i]) == 1 { pass = pass + 1 }
139 i = i + 1
140 }
141 return pass
142}
143
144// Every safety-critical test must pass (a single safety failure is fatal).
145func val_critical_pass(measured: *i64) -> i64 {
146 var i: i64 = 0
147 while i < val_water_count() {
148 let tc: *NxTestCase = val_water_case(i)
149 if tc.safety == 1 {
150 if val_pass(tc, measured[i]) == 0 { return 0 }
151 }
152 i = i + 1
153 }
154 return 1
155}
156
157// Validated iff every test passes (and hence every safety test passes).
158func val_validated(measured: *i64) -> i64 {
159 if val_run(measured) != val_water_count() { return 0 }
160 return 1
161}