Builder contract
A builder translates one verified provider feed into the shared source shape, then delegates profile derivation and publication. It does not redefine the public JSON shape or renderer behaviour.
Required invariants
Section titled “Required invariants”- Catalogue agreement. The slug, kind, levels, cadence, horizon,
capability presence, and field semantics match
models.json. - Complete-run selection. A builder selects a provider run only after its
declared final product is available, and skips an already-published
referenceTimewithout rewriting output. - Domain honesty. A sample too far from a site signals out-of-domain clamping; the build fails rather than publishing a boundary value.
- Unit and direction normalization. Source values reach the profile contract’s units and meteorological FROM-direction before publication.
- Absence stays absent. Missing records, masked sentinels, and unsupported optional fields are omitted, never converted to zero.
- Semantics are supplied, not inferred. The verified builder passes gust
and precipitation semantics into
derive_windgram_profile. - Derived values have one authority. Builders supply source fields;
pipeline/src/windgram/derive.pysuppliesderived.*. - Publication is deterministic at the edge. Shared rounding and JSON writers own precision and serialized shape.
Source hour versus published hour
Section titled “Source hour versus published hour”builder source published profiletemperatureC ─┐ surface.temperatureCdewPointDepressionC ├─→ surface.dewPointCheat fluxes + sampled levels ├─→ derived.*optional provider fields └─→ optional surface/level fieldsThe source dictionary is internal and may carry provider-facing intermediate names such as dew-point depression. The published contract is the stable boundary. Do not expose a builder intermediate merely to avoid an appropriate derivation.
Ensemble additions
Section titled “Ensemble additions”Ensemble builders derive every member independently, then aggregate matching
numeric positions. run.members is total membership;
EnsembleValue.members counts contributors at that position and can be lower
when null or censored member values are excluded. Wind direction uses circular
aggregation. Height censoring uses ceiledMembers only on positions where the
pipeline records a column ceiling.
Focused builder tests should use committed fixtures or injected transport responses. They must not require live provider access; verification establishes facts and tests make behaviour repeatable.