Skip to content

3.1: wort clarity and krausen handling on the fermentation procedure #279

Open

Description

@ndreno

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

Checklist

  • I have searched existing issues and discussions
  • I have checked whether measureable_units.json already has a suitable measurement type (both are categorical, so no measurement type applies)
  • I have read SCHEMA_STYLE.md

Activity

  1. matty0ung commented on Nov 11, 2026

    @matty0ung
    Contributor

    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:

    • Wort clarity (applied to IAA): very clear 1.30, clear 1.20, somewhat clear 1.10, average 1.00 (default), somewhat cloudy 0.90, cloudy 0.80, very cloudy 0.70, extremely cloudy 0.60.
    • Krausen (applied to IAA, with the loss roughly tripled for non-IAA components): mixed back in 1.127; minor / medium (default) / heavy / very heavy deposits on the fermenter 1.05 / 1.00 / 0.95 / 0.90; blown off with slow / normal / vigorous fermentation 0.938 / 0.833 / 0.729.

    So, as proposed:

    • wort_clarity has 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 cloudy
    • krausen_handling: mixed in, minor deposits, medium deposits, heavy deposits, very heavy deposits, blown off, slow fermentation, blown off, normal fermentation, blown off, vigorous fermentation

    It 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.

  2. matty0ung commented on Nov 11, 2026

    @matty0ung
    Contributor

    One additional point: I think wort_clarity would be better added to RecipeType than FermentationProcedureType. It's not really part of the fermentation procedure, and is something that can differ between two beers that share the same fermentation procedure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions