nx_ferment_process.nx
buildroot/runtime/nx_ferment_process.nx
about
nx_ferment_process.nx -- R2 process rung: the ferment state machine.
A fermentation recipe is a SEQUENCE OF PHASES, each with a target
temperature (for the R1 thermal controller) and an exit condition
(temperature reached, pH reached, or time elapsed). This is the
yogurt-maker / cheesemaker LOGIC: pasteurize -> cool -> inoculate ->
ferment-hold -> chill (yogurt); ripen -> rennet -> cut -> cook ->
drain -> press -> age (cheese). One generic executor, data-driven
per Rule 6/11 -- the phase table is data, not code.
SAFETY COMPOSITION: every phase flagged is_ferment passes through the
R0 never-poison law (nx_ferment_validate) BEFORE its exit is checked.
Any refusal HALTS the whole process (status = HALTED_UNSAFE) and
records the verdict. The never-poison law thus propagates up the
ladder -- an unsafe batch can never run to "done".
Non-ferment phases (e.g. the 82 C pasteurization, which is above
culture-kill) are NOT validated by the ferment law -- no culture is
present yet, so culture-kill does not apply. That separation is why
nx_ferment_validate documents itself as the ferment-HOLD predicate.
genealogy_id: nishi_ferment_safety_envelope_2026 (via nx_ferment_safety)
+ state_machine_recipe_executor_pattern
dependencies 2 imports · 1 importers
imports: nx_syscalls.nxnx_ferment_safety.nx
imported by: nx_ferment_process_test.nx
structs
| 57 | struct NxFermentPhase |
| 68 | struct NxFermentProcess |
consts
| 27 | const NX_MAGIC_82000: i64 = 82000 |
| 28 | const NX_MAGIC_43000: i64 = 43000 |
| 29 | const NX_MAGIC_4500: i64 = 4500 |
| 30 | const NX_MAGIC_5000: i64 = 5000 |
| 34 | const NX_FP_PASTEURIZE: nx_int = 0 |
| 35 | const NX_FP_COOL: nx_int = 1 |
| 36 | const NX_FP_INOCULATE: nx_int = 2 |
| 37 | const NX_FP_FERMENT: nx_int = 3 |
| 38 | const NX_FP_CHILL: nx_int = 4 |
| 39 | const NX_FP_PRESS: nx_int = 5 |
| 40 | const NX_FP_AGE: nx_int = 6 |
| 44 | const NX_FX_TEMP_AT_OR_ABOVE: nx_int = 0 // temp >= threshold (heating done) |
| 45 | const NX_FX_TEMP_AT_OR_BELOW: nx_int = 1 // temp <= threshold (cooling done) |
| 46 | const NX_FX_PH_AT_OR_BELOW: nx_int = 2 // pH <= threshold (acidified) |
| 47 | const NX_FX_TIME_ELAPSED: nx_int = 3 // elapsed >= threshold |
| 51 | const NX_PR_RUNNING: nx_int = 0 |
| 52 | const NX_PR_COMPLETE: nx_int = 1 |
| 53 | const NX_PR_HALTED_UNSAFE: nx_int = 2 |
| 66 | const NX_FP_PHASE_BYTES: nx_size = 48 |
functions
| 79 | func nx_ferment_phases_new(n: nx_size) -> *NxFermentPhase |
| 84 | func _fp_phase_at(phases: *NxFermentPhase, idx: nx_size) -> *NxFermentPhase |
| 88 | func nx_ferment_phase_set(phases: *NxFermentPhase, idx: nx_size, |
| 102 | func nx_ferment_process_new(env: *NxFermentSafetyEnvelope, |
| 118 | func nx_ferment_process_target(pr: *NxFermentProcess) -> i64 |
| 125 | func nx_ferment_process_current_is_ferment(pr: *NxFermentProcess) -> nx_int |
| 134 | func nx_ferment_process_step(pr: *NxFermentProcess, |
| 184 | func nx_ferment_build_yogurt(phases: *NxFermentPhase) -> i64 |