Repository navigation
Plan the recipe and its pH reagent together; add pH-up reagents (#74-#77) - #81
Merged
Merged
Conversation
…75, #76, #77) Grower-path audit: none of the 26 shipped formulas in RO water got a usable pH plan. The recipe met N and P exactly and the acid then broke those targets (#74); a feed below the target pH had no correction (#75); phosphoric acid chosen as a P source drove five formulas to pH 3.0-3.4 (#76); and a 1% target miss blocked acid planning (#77). - ph_adjustment workflow stage and plan_coupled_ph(): fit the recipe without acids as nutrient salts, solve the acid or base dose to the target pH on the same equilibrium model, count the reagent's nutrients as supply and refit until recipe and dose agree. A bracketed search on F(d) - d settles both slow oscillations and recipes that switch products between nearby doses; candidates keep their dose when rejected. - reagent_dose(): one acid/base solve (acid anion or K+ with implicit hydroxide, KHCO3 and K2CO3 with closed inorganic carbon). plan_acid_options uses it with bit-identical results (16 formulas x 3 acids compared). - Catalogue: Potassium Hydroxide (45% solution) and Potassium Bicarbonate added; Potassium Carbonate linked to its sourced theoretical analysis (K 56.581 -> 56.580316 %, owner-approved). All three role ph_reagent, never selected by recommend(). Sigma-Aldrich 417661, 237205, 209619. catalogue_ph_reagents() returns their reagent records. 32 products. - The mixed_target_ph_nitric PHREEQC fixture is recaptured with pinned PHREEQC 3.8.6 (it contains potassium carbonate; nitric dose -7.8e-6 relative). tools/phreeqc_evidence.py gains --case and writes LF JSON. Audit after the change: all 62 applicable candidates get a dose at exactly pH 5.8 (re-adding it and recalculating reproduces the target), the pH-3 feeds now mix at 4.5-4.9 and receive a base; every candidate is still rejected by the unchanged precipitation gate (hydroxylapatite and MnHPO4), which #78 addresses next.
The previous commit's message described this change, but it was not included. write_text on Windows produced CRLF in expected.json, which is stored byte-exact; the recaptured fixture was normalised by hand.
…d count verify_distribution hard-coded 30 products, so the 32-product catalogue failed CI on every Python version. The packaged count is now compared with src/flahax/data/library.json.
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #74. Closes #75. Closes #76. Closes #77.
Problem (grower-path audit)
In RO water at target pH 5.8, none of the 26 shipped formulas got a usable pH plan:
wrong_reagent_direction), and the catalogue had no pH-up product.Fix
ph_adjustmentworkflow stage /plan_coupled_ph(). The recipe and its pH reagent are planned together:not_applicable.reagent_dose(). One acid/base solve:plan_acid_optionsnow uses it. Results are bit-identical: I compared 16 formulas × 3 acids.Catalogue (#75, owner decisions, sources on #75):
role: ph_reagentand are never selected byrecommend().catalogue_ph_reagents()returns ready reagent records for them.Evidence (same audit after the change)
unmetTargets.Also
mixed_target_ph_nitricPHREEQC fixture was recaptured with pinned PHREEQC 3.8.6, because it contains potassium carbonate (nitric dose −7.8e-6 relative).tools/phreeqc_evidence.pygains--caseand now writes LF JSON.Known
The coupled plan calls
recommend()several times per reagent: about 1–3 s per candidate, about 7 s per formula with five reagents. That's acceptable for a batch plan; it can be optimised later.Tests
tests/test_ph_adjustment.py, 8 new).recommend()never selects them.