code wiki / (root) / nx_preservation.nx

nx_preservation.nx source

↩ module page · 171 lines · 7616 B

1// nx_preservation.nx -- FOOD-SCIENCE SUITE / PRESERVATION rung. The 2// classic food-preservation science the ferment ladder didn't yet cover: 3// thermal death kinetics (D-value / z-value / the 12-D botulinum cook), 4// water activity (aw), and Leistner HURDLE technology -- with a 5// never-poison canning gate. 6// 7// All INTEGER-EXACT (no float, no precision cliff): decimal reduction and 8// z-value scaling are powers of ten (exact), water-activity + pH control 9// are threshold rules (exact). Quantities in milli-units: 10// time -> milli-minutes (mmin) 11// temp -> milli-Celsius (mC) 12// aw, pH -> x1000 (aw 0.850 = 850; pH 4.600 = 4600) 13// log-reductions -> milli-reductions (12 log = 12000) 14// 15// THE never-poison line (mirrors nx_ferment_safety, Global Rule 26): a 16// LOW-ACID food (pH >= 4.6, where C. botulinum can grow) may NEVER be 17// preserved by boiling-water-bath canning -- it MUST be pressure-canned to 18// achieve the 12-D botulinum cook. Structural refusal, liar-killed by the 19// gate (the #1 cause of home-canning botulism). 20// 21// THE measured exceed: a single-factor checker calls a food unsafe unless 22// pH<4.6 OR aw<0.85 alone. The HURDLE model correctly finds foods that 23// are stable because pH AND aw are BOTH moderately reduced together 24// (Leistner) -- how shelf-stable fermented sausage, aged cheese, and many 25// intermediate-moisture foods actually work. 26// 27// Grounding (cited; researcher-groundable like nx_probiome): 28// fda_21cfr113_114_low_acid_acidified_canning (pH 4.6 line) 29// c_botulinum_12D_D121_0.21min_z_10C (thermal death) 30// nchfp_pressure_vs_boiling_water_canning (method rule) 31// fda_water_activity_0.85_not_potentially_hazardous (aw pathogen floor) 32// leistner_hurdle_technology_combined_preservation (hurdle exceed) 33// 34// genealogy_id: nishi_ferment_safety_r0_never_poison + food_preservation_science 35 36import "nx_syscalls.nx" 37 38// ===== Canonical grounded constants =============================== 39 40const PV_BOTULINUM_PH_MILLI: i64 = 4600 // FDA acidified-foods line 41const PV_HURDLE_PH_MILLI: i64 = 5000 // upper pH for a hurdle-stable food 42const PV_AW_NO_GROWTH_MILLI: i64 = 600 // below this: NO microbial growth 43const PV_AW_NO_PATHOGEN_MILLI: i64 = 850 // below this: no pathogen (FDA non-TCS) 44const PV_AW_HURDLE_MILLI: i64 = 910 // upper aw for a hurdle-stable food 45const PV_AW_BOTULINUM_MILLI: i64 = 930 // C. botulinum minimum aw 46const PV_BOT_D121_MMIN: i64 = 210 // C. botulinum D at 121.1 C = 0.21 min 47const PV_BOT_Z_MILLI_C: i64 = 10000 // z-value = 10 C 48const PV_12D_TARGET_MREDUX: i64 = 12000 // 12 log reductions (botulinum cook) 49const PV_PASTEUR_TARGET_MREDUX: i64 = 5000 // 5 log (pasteurization pathogen target) 50const PV_BOT_MIN_F0_MMIN: i64 = 2520 // 12 x 0.21 = 2.52 min minimum process 51 52// ===== Sealed enums =============================================== 53 54const PV_AW_UNSAFE: i64 = 0 // aw >= 0.85: pathogens can grow 55const PV_AW_MOLD_ONLY: i64 = 1 // 0.60 <= aw < 0.85: no pathogen, spoilage molds 56const PV_AW_SHELF: i64 = 2 // aw < 0.60: nothing grows 57 58const PV_STABLE_ACID: i64 = 0 // pH < 4.6 (high-acid) 59const PV_STABLE_DRY: i64 = 1 // aw < 0.60 60const PV_STABLE_LOW_AW: i64 = 2 // aw < 0.85 (no pathogen) 61const PV_STABLE_HURDLE: i64 = 3 // combined pH + aw hurdle (Leistner) 62const PV_UNSTABLE: i64 = 4 // needs refrigeration or a kill-step 63 64const PV_METHOD_WATER_BATH: i64 = 0 65const PV_METHOD_PRESSURE_CAN: i64 = 1 66 67const PV_CAN_OK: i64 = 0 68const PV_CAN_REFUSED_LOW_ACID_WB: i64 = 1 // low-acid via water bath = botulism 69const PV_CAN_REFUSED_BAD_METHOD: i64 = 2 70 71// ===== Thermal death kinetics (integer-exact) ===================== 72 73// 10^k for a non-negative integer k (guarded; 10^18 still fits i64). 74func pv_pow10(k: i64) -> i64 { 75 if k < 0 { return 0 } 76 if k > 18 { return 0 } 77 var v: i64 = 1 78 var i: i64 = 0 79 while i < k { 80 v = v * 10 81 i = i + 1 82 } 83 return v 84} 85 86// Log-reductions (x1000) achieved by an isothermal hold at a temperature 87// whose D-value is d_mmin. reductions = hold / D. 88func pv_reductions_milli(hold_mmin: i64, d_mmin: i64) -> i64 { 89 if d_mmin <= 0 { return 0 } 90 return hold_mmin * 1000 / d_mmin 91} 92 93// Does an isothermal process achieve the 12-D botulinum cook? 94func pv_is_12d(hold_mmin: i64, d_mmin: i64) -> i64 { 95 if pv_reductions_milli(hold_mmin, d_mmin) >= PV_12D_TARGET_MREDUX { return 1 } 96 return 0 97} 98 99// Minimum hold (mmin) to achieve a target number of log-reductions. 100func pv_min_process_mmin(d_mmin: i64, target_mredux: i64) -> i64 { 101 return d_mmin * target_mredux / 1000 102} 103 104// D-value after k z-value steps from the reference temperature. Hotter 105// (k>0) -> D shrinks 10x per step; colder (k<0) -> D grows 10x per step. 106// EXACT at integer z-steps (the honest, cliff-free core of z-value math). 107func pv_d_at_z_steps(d_ref_mmin: i64, k: i64) -> i64 { 108 if k == 0 { return d_ref_mmin } 109 if k > 0 { return d_ref_mmin / pv_pow10(k) } 110 return d_ref_mmin * pv_pow10(0 - k) 111} 112 113// ===== Water activity + hurdle stability ========================== 114 115func pv_water_activity_class(aw_milli: i64) -> i64 { 116 if aw_milli < PV_AW_NO_GROWTH_MILLI { return PV_AW_SHELF } 117 if aw_milli < PV_AW_NO_PATHOGEN_MILLI { return PV_AW_MOLD_ONLY } 118 return PV_AW_UNSAFE 119} 120 121// Microbiological shelf-stability from pH + aw. Flat guard layers, most 122// decisive single-factor lines first, then the combined hurdle. 123func pv_shelf_stable(ph_milli: i64, aw_milli: i64) -> i64 { 124 if ph_milli < PV_BOTULINUM_PH_MILLI { return PV_STABLE_ACID } 125 if aw_milli < PV_AW_NO_GROWTH_MILLI { return PV_STABLE_DRY } 126 if aw_milli < PV_AW_NO_PATHOGEN_MILLI { return PV_STABLE_LOW_AW } 127 // Leistner hurdle: neither single line met, but pH AND aw both moderately 128 // reduced -> the combination controls pathogens (aw < 0.93 alone stops 129 // C. botulinum; the lowered pH controls the rest). 130 if ph_milli < PV_HURDLE_PH_MILLI { 131 if aw_milli < PV_AW_HURDLE_MILLI { return PV_STABLE_HURDLE } 132 } 133 return PV_UNSTABLE 134} 135 136// Would a naive SINGLE-FACTOR checker (pH<4.6 OR aw<0.85) call this food 137// stable? Used to demonstrate the hurdle EXCEED. 138func pv_single_factor_stable(ph_milli: i64, aw_milli: i64) -> i64 { 139 if ph_milli < PV_BOTULINUM_PH_MILLI { return 1 } 140 if aw_milli < PV_AW_NO_PATHOGEN_MILLI { return 1 } 141 return 0 142} 143 144// 1 iff the hurdle model finds stability that the single-factor checker misses. 145func pv_hurdle_beats_single(ph_milli: i64, aw_milli: i64) -> i64 { 146 var hurdle: i64 = 0 147 if pv_shelf_stable(ph_milli, aw_milli) != PV_UNSTABLE { hurdle = 1 } 148 let single: i64 = pv_single_factor_stable(ph_milli, aw_milli) 149 if hurdle == 1 { if single == 0 { return 1 } } 150 return 0 151} 152 153// ===== Canning method + the never-poison gate ===================== 154 155// The REQUIRED canning method for a food of a given pH. 156func pv_canning_method(ph_milli: i64) -> i64 { 157 if ph_milli < PV_BOTULINUM_PH_MILLI { return PV_METHOD_WATER_BATH } 158 return PV_METHOD_PRESSURE_CAN 159} 160 161// NEVER-POISON gate: refuse a low-acid food processed by boiling-water-bath 162// (it cannot reach the 12-D botulinum cook -> botulism). Sealed verdict. 163func pv_canning_admit(ph_milli: i64, method: i64) -> i64 { 164 if method != PV_METHOD_WATER_BATH { 165 if method != PV_METHOD_PRESSURE_CAN { return PV_CAN_REFUSED_BAD_METHOD } 166 } 167 if ph_milli >= PV_BOTULINUM_PH_MILLI { 168 if method == PV_METHOD_WATER_BATH { return PV_CAN_REFUSED_LOW_ACID_WB } 169 } 170 return PV_CAN_OK 171}