nx_water_activity.nx
buildroot/runtime/nx_water_activity.nx
about
nx_water_activity.nx -- FOOD-SCIENCE SUITE / WATER ACTIVITY + HURDLE rung.
Water activity is the second great preservation variable after pH, and it
falls straight out of arithmetic this ecosystem is already doing: the same
dissolved-solute count that sets the freezing point sets aw, because both
are colligative. nx_icecream already computes those moles, so aw costs
one Raoult ratio rather than a new model.
aw = n_water / (n_water + n_solute)
THE POINT IS THE HURDLE MODEL, NOT THE NUMBER. Food is not made safe by
one barrier but by whichever barrier actually holds, and until now the
ecosystem could reason about two of them in isolation: nx_chem_solution
owns the pH 4.6 line, nx_thermal_process owns lethality and the cold
chain. Neither knew about water. wa_hurdle_verdict composes all three
and NAMES the barrier doing the work:
aw < 0.85 -> safe by WATER ACTIVITY (FDA non-PHF); honey and
milk powder live here, and nothing else matters
pH < 4.6 -> safe by ACID
low-acid, ambient -> only a 12D thermal process will do
low-acid, chilled -> pasteurisation plus the COLD CHAIN
Naming the hurdle matters: "safe" without knowing which barrier holds is
how a reformulation quietly removes the only thing that was working.
AND IT IS WILLING TO SAY THE UNCOMFORTABLE THING. An ice cream mix comes
out at aw ~0.977, which is well above the 0.93 that C. botulinum needs.
The mix is NOT protected by water activity, and this rung says so rather
than reporting a reassuring number -- that is precisely why the cold chain
is load-bearing for frozen dessert.
Units: aw is a 0..1 ratio carried as _q4 (x10000), because the decisions
sit at the third decimal (0.850 vs 0.858) and _q3 would round them away.
Grounding (cited; researcher-groundable):
raoult_law_water_activity_ideal_solution
fda_21cfr113_114_potentially_hazardous_food_aw_0_85
icmsf_minimum_water_activity_for_growth_by_organism
beuchat_xerophilic_mould_growth_limit_0_61
genealogy_id: hurdle_technology + nishi_food_science_suite
dependencies 4 imports · 2 importers
imports: nx_syscalls.nxnx_icecream.nxnx_chem_solution.nxnx_thermal_process.nx
imported by: nx_labsci_gate.nxnx_labsci_svc.nx
structs
| none |
consts
| 45 | const WA_MAGIC_10000: i64 = 10000 |
| 48 | const WA_UMOL_PER_G_WATER: i64 = 55509 |
| 50 | const WA_INVALID: i64 = 0 - 1 |
| 54 | const WA_ORG_SALMONELLA: i64 = 0 |
| 55 | const WA_ORG_CBOT: i64 = 1 |
| 56 | const WA_ORG_STAPH: i64 = 2 |
| 57 | const WA_ORG_YEAST: i64 = 3 |
| 58 | const WA_ORG_MOLD: i64 = 4 |
| 59 | const WA_ORG_XEROPHILE: i64 = 5 |
| 60 | const WA_ORG_N: i64 = 6 |
| 62 | const WA_AW_SALMONELLA: i64 = 9400 |
| 63 | const WA_AW_CBOT: i64 = 9300 |
| 64 | const WA_AW_STAPH: i64 = 8600 // lowest of the bacterial pathogens |
| 65 | const WA_AW_YEAST: i64 = 8800 |
| 66 | const WA_AW_MOLD: i64 = 8000 |
| 67 | const WA_AW_XEROPHILE: i64 = 6100 // below this NOTHING grows at all |
| 70 | const WA_FDA_PHF_LIMIT: i64 = 8500 |
| 74 | const WA_UNSAFE: i64 = 0 |
| 75 | const WA_SAFE_BY_AW: i64 = 1 |
| 76 | const WA_SAFE_BY_ACID: i64 = 2 |
| 77 | const WA_SAFE_BY_THERMAL: i64 = 3 |
| 78 | const WA_SAFE_BY_COLD_CHAIN: i64 = 4 |
functions
| 82 | func wa_water_umol(water_g: i64) -> i64 |
| 91 | func wa_from_solutes_q4(water_g: i64, solute_umol: i64) -> i64 |
| 102 | func wa_from_mix_q4(m: *NxIceMix) -> i64 |
| 111 | func wa_min_growth_q4(organism: i64) -> i64 called by 1: wa_supports_growth |
| 123 | func wa_supports_growth(aw_q4: i64, organism: i64) -> i64 |
| 132 | func wa_organisms_supported(aw_q4: i64) -> i64 |
| 143 | func wa_is_potentially_hazardous(aw_q4: i64) -> i64 called by 1: lab_water_activity |
| 155 | func wa_solute_umol_for_target(water_g: i64, target_aw_q4: i64) -> i64 calls 1: wa_water_umol |
| 171 | func wa_hurdle_verdict(ph_milli: i64, aw_q4: i64, f0_ms: i64, pasteurized: i64, ambient_stable: i64) -> i64 |
| 189 | func wa_is_safe(ph_milli: i64, aw_q4: i64, f0_ms: i64, pasteurized: i64, ambient_stable: i64) -> i64 calls 1: wa_hurdle_verdict |