Repository navigation
Open
Labels
Description
What cannot be represented today
Hosom's SMPH model (IBUs and the SMPH model) estimates IBUs from the whole brew day, not only the boil. It needs two observations that brewers make but the format cannot carry:
- Wort clarity: "how visually clear or cloudy the wort is when it is transferred to the fermentation vessel". Cloudy wort (a short vorlauf, brew in a bag) ends up with more bitterness than clear wort.
- Krausen handling: whether the krausen falls back in, dries on the vessel walls, is skimmed, or leaves through a blow-off tube. Isomerized alpha acids collect in the krausen, so the last three lose bitterness.
Every other SMPH input already has a home:
| SMPH input | Already in BeerJSON |
|---|---|
| Boiling temperature (altitude) | boil step start_temperature / end_temperature |
| Wort pH | boil step start_ph / end_ph |
| Hop form, alpha and beta acids, amounts, timing | hop additions |
| Hop age and storage | percent_lost, year, and the measured alpha_acid / beta_acid on the addition |
| Cooling after flameout, hop stands | post-boil boil steps, once #271 settles how they are classified |
| Finings | miscellaneous additions of type fining |
| Flocculation | culture flocculation |
| Conditioning time and temperature | fermentation steps |
| Wort clarity | none |
| Krausen handling | none |
Proposed change
FermentationProcedureType, both optional:
wort_clarity: enum"very clear","clear","somewhat cloudy","cloudy","very cloudy". How clear the wort looks, judged by eye, when it is transferred to the fermenter.krausen_handling: enum"mixed in","left on walls","skimmed","blown off". What happens to the krausen during fermentation."mixed in"also covers an anti-foam that keeps it from forming.
Both describe the wort and the fermentation rather than the calculation, so a program that doesn't estimate IBUs can still record them.
Example
{
"beerjson": {
"version": 3.1,
"fermentations": [
{
"name": "Ale, blow-off tube",
"wort_clarity": "somewhat cloudy",
"krausen_handling": "blown off",
"fermentation_steps": [
{
"name": "Primary",
"start_temperature": { "unit": "C", "value": 19 },
"step_time": { "unit": "day", "value": 10 }
}
]
}
]
}
}I applied the change to a copy of the schemas, with 3.1 added to VersionType, and checked it with Ajv (draft 2020-12): this example validates, an unknown krausen_handling value is rejected, and every document under tests/ still validates. I have not run the jest suite.
Compatibility
- Additive. Every 3.0 document stays valid. As with any minor version (ADR-0004), a 3.0 validator rejects a 3.1 document that uses the new fields.
- Breaking.
Alternatives
- A measured turbidity (NTU or EBC haze units) instead of a visual scale: more precise, but homebrewers don't measure wort haze, and SMPH takes a visual judgment. A measurement can sit next to the scale later if software needs it.
- On each fermentation step instead of the procedure: the krausen forms during primary only, and the clarity is a single observation at transfer, so per-step fields would be repeated or empty.
- Notes: not machine-readable, so an IBU estimate cannot use them.
Software support
- Werb: needs both for its SMPH work (IBU model: adopt the full SMPH (Specific-Model-of-IBU) calc engine werb-dev/werb#27), which waits on the format. I can implement reading and writing there.
- Other programs that don't model post-boil losses can ignore them.
Checklist
- I have searched existing issues and discussions
- I have checked whether
measureable_units.jsonalready has a suitable measurement type (both are categorical, so no measurement type applies) - I have read SCHEMA_STYLE.md
Activity
matty0ung commentedon Nov 11, 2026
Thanks for this. The upcoming 5.3 release of Brewken/Brewtarget adds support for SMPH, so this is good timing from my POV.
One concern is that the proposed BeerJSON values don’t line up with the categories in Hosom’s calculator (
ibu.js,getWortClarityValue/getKrausenValue), which is where the loss factors come from:So, as proposed:
wort_clarityhas no “average”, which is both the model’s baseline (loss factor 1.0) and the calculator’s default. It also lacks “somewhat clear” and “extremely cloudy”."left on walls"would cover four categories spanning 0.90–1.05, and "blown off" three spanning 0.729–0.938.A program implementing SMPH would have to guess a mapping, and different programs would guess differently. I’d suggest enumerating the calculator’s categories one-to-one:
wort_clarity:very clear,clear,somewhat clear,average,somewhat cloudy,cloudy,very cloudy,extremely cloudykrausen_handling:mixed in,minor deposits,medium deposits,heavy deposits,very heavy deposits,blown off, slow fermentation,blown off, normal fermentation,blown off, vigorous fermentationIt would also help for the descriptions to say that an absent value means “average” and “medium deposits” respectively. Programs that don’t model these losses then get the same answer whether or not the field is set.
matty0ung commentedon Nov 11, 2026
One additional point: I think
wort_claritywould be better added toRecipeTypethanFermentationProcedureType. It's not really part of the fermentation procedure, and is something that can differ between two beers that share the same fermentation procedure.