Skip to content

Typology Reference — column types & roll-up

The Typology is how a Gold column declares what kind of value it is — a measurement, an identifier, an ordered rank, a category. Every column carries its type in the entity YAML’s column_types: block, sibling to the columns: role registry.

A number without a declared type is undeclared — not a licence to guess. The compiler (typologycheck.py) verifies each declaration; the KLS carries data only. Types are declarations, not runtime data.

Conceptual background: Sense 54 — The Typology and Sense 53 — The Codex.

# entities/<entity>.yaml
column_types:
material_id: { kind: identifier, subkind: foreign_key, references: materials.material_id }
quantity: { kind: quantity, standard: null, rollup: additive }
unit_price: { kind: quantity, standard: iso_4217, unit: CHF, rollup: non_additive }
level: { kind: ordinal } # a tree depth — ordered, not summable
billing_status:{ kind: category }
billing_time: { kind: temporal, subkind: instant, standard: iso_8601 }

Each entry declares exactly one kind, plus optional refinements.

Every column is exactly one:

KindWhat it isExamples
quantityA measured value with units and (usually) uncertaintymass_g, temperature_c, unit_price
identifierA key that identifies an entity — primary, business, external, foreignsensor_id, serial_number, iso_country_code
categoryA value from a bounded, unordered vocabularystatus, event_type, region_name
ordinalA value from an ordered scale — rank / grade / level. Orderable but not summablelevel (hierarchy depth), severity_rank
temporalA time-shaped value — instant, interval, duration, periodphenomenon_time, deployment_window
booleanTwo-valued truth (optional third state)is_active, has_calibration
narrativeUncontrolled text for human reading, not grouping or filteringnotes, interpretation
geometryStructured spatial data with a coordinate reference systemboundary_geojson

The line between category and ordinal is order: a category is a plain set (statuses, event types); an ordinal is a ranked scale where min/max/ median are meaningful but a sum is not (rank 1 + rank 2 ≠ rank 3).

FieldApplies toMeaning
kindallOne of the eight above (required)
subkindallRefines the kind — identifier.foreign_key, temporal.instant, geometry.polygon
standardquantity, temporal, geometryA Codex standard id (ucum, iso_4217, iso_8601, rfc_7946_geojson). The checker enforces it legally binds the kind
unitquantityStatic unit — UCUM for physical quantities, an ISO 4217 code (CHF) for currency
unit_columnquantityPolymorphic unit — carried per-row in a sibling column (log-shaped data)
referencesidentifier.foreign_keyFK target as entity.column
derived_fromquantity{entity, column, standard} — a typed edge: this column is produced from another by a cited conversion
rollupquantityRoll-up policy up a hierarchy — see below

Roll-up — how a quantity aggregates up a hierarchy

Section titled “Roll-up — how a quantity aggregates up a hierarchy”

rollup answers: when this column is summarised over the children of a hierarchy node (the Level Ladder — see Sense 42 — The Landscape), what is the honest aggregate? It is a property of the type (intensive vs extensive), not display configuration — it never cascades and never overrides.

ValueAggregateUse for
additiveSUMExtensive quantities — counts, loads, money totals. Summing is honest
averageableAVGIntensive quantities that average — a rate already normalised per unit
non_additivedoes not rollPrices, extrema (min/max), ratios, percentages, pre-computed averages. Neither sum nor average is honest
distinct_countCOUNT(DISTINCT …) recomputed over the subtreeGroup values that need recomputation, not aggregation of parts (distinct-of-a-union ≠ sum-of-distincts)

A cross-node total and share % are only meaningful for additive — the “total” of a set of averages or distinct-counts is not their sum.

Leaving rollup off a quantity is not an instruction to sum. An undeclared rollup means the measure does not roll up at all — because guessing is the wrong act. A declaration means a person decided, on the record; a silent default means the engine decided, invisibly, where a wrong number looks exactly like a right one — the principle of no silent behavioural defaults (see Sense 54 — The Typology). The typology-coverage gauge counts a quantity with no rollup as a gap, so a non-rolling measure is visible, not just silently inert.

ordinal, category, identifier, etc. carry no rollup — they are not summed up a hierarchy.

jin make bakes an inspector-only typology_coverage table per entity: typed / untyped / phantom columns and a coverage %. Complete coverage — every Gold column typed, every quantity’s rollup declared — is a data-engineering requirement, not a metric to optimise. You inspect a single column’s full type at the point of use via the Column Passport.

Terminal window
# Validate every column_types declaration (kind + Codex binding + rollup vocab)
python3 scripts/typologycheck.py
python3 scripts/typologycheck.py entities/cases.yaml # one or more explicit files
# Bake the inspector tables (runs inside `jin make` as a post-dbt step)
python3 scripts/typologycompile.py --kls <kls> --tenant <t> --entities-root <afs>/entities
jazzisnow jinflow is a jazzisnow product
v0.64.7 · built 2026-09-20 19:48 UTC