Skip to main content
Private Preview·Early access by invitation.Request access →
Kirimana.
Docs · Contracts

Conformed dimensions across goals

A conformed dimension is one you build once and reuse across several star schemas — a customer dimension that sales_mart and finance_mart both join to, meaning the same thing, keyed the same way, in both. Conforming dimensions is what lets a business ask a question that spans marts and get one consistent answer. Kirimana makes conformance an explicit, enforced contract property rather than a convention you hope everyone follows.

Declare a dimension as conformed

A gold dimension opts in to reuse with one flag:

customProperties:
  - property: kiri.lifecycle.state
    value: gold
  - property: kiri.gold.kind
    value: dimension
  - property: kiri.gold.scd_type
    value: type_2
  - property: kiri.gold.business_keys
    value: [customer_id]
  - property: kiri.gold.surrogate_key_strategy
    value: hash
  - property: kiri.gold.surrogate_key_column
    value: customer_key
  - property: kiri.gold.conformed
    value: true
  - property: kiri.gold.star_schema
    value: sales_mart

kiri.gold.conformed: true is the declaration: this dimension is reusable across reporting goals. It carries an obligation with it — every place the dimension is re-declared must match bit-for-bit on SCD type, business keys, and surrogate-key strategy. That triple is the identity of a conformed dimension; if two marts disagree on any of it, they are not actually conforming, and Kirimana treats that as an error rather than letting two subtly different “customer” dimensions coexist.

The registry, and why it’s not a separate file

The conformed-dimension registry is not a side file you maintain — it is derived from the contracts themselves. Every gold dimension carrying conformed: true is an entry; the star_schema names it belongs to are read from the facts that reference it. The contract set is the registry, which means it can’t drift out of sync with the models, and a review of the dimension’s contract is a review of its conformance.

A dimension used by facts in more than one star_schema must be conformed. That is the star-schema-conformity lint rule: a non-conformed dimension may live in exactly one mart; the moment a second mart’s fact references it, either it is conformed or the project doesn’t lint clean.

Reference a conformed dimension from a fact

A fact in any mart references the shared dimension by its gold URN — it does not redefine it:

customProperties:
  - property: kiri.gold.kind
    value: fact
  - property: kiri.gold.grain
    value: [customer_key, invoice_date]
  - property: kiri.gold.dimension_refs
    value:
      - urn:kirimana:gold:dim_customer
  - property: kiri.gold.star_schema
    value: finance_mart

finance_mart’s fact and sales_mart’s fact both point at urn:kirimana:gold:dim_customer. There is one dimension contract, one build, one surrogate-key column — and both marts join on it. That is conformance made physical: not two copies that happen to agree, but one dimension referenced twice.

Role-playing dimensions

A single dimension often plays several roles in one fact — a Date dimension playing both order_date and ship_date. Register the extra roles on the dimension with kiri.gold.role_playing_aliases, and a fact references a specific role with the ::<alias> URN suffix:

# On dim_date:
  - property: kiri.gold.role_playing_aliases
    value: [order_date, ship_date]

# On the fact:
  - property: kiri.gold.dimension_refs
    value:
      - urn:kirimana:gold:dim_date::order_date
      - urn:kirimana:gold:dim_date::ship_date

An unregistered alias is caught by the role-playing-unregistered lint rule — you can’t reference a role the dimension didn’t declare. Role-playing is how one physical dimension serves several fact columns without cloning itself into dim_order_date and dim_ship_date: there is still one build, one surrogate-key column, and one conformed identity — the fact simply joins it under two names.

Cross-goal conflict detection at PR time

The whole point of conformance is that it’s enforced where change happens: in the pull request, before the divergence reaches the warehouse. Governance runs in git, so kiri contract lint sees every contract in the project at once and can reason across marts:

kiri contract lint --format pr

Two rules do the cross-goal work:

  • conformed-dim-conflict fires when two declarations of a conformed dimension disagree on SCD type, business keys, or surrogate-key strategy. A PR that would introduce a second, incompatible “customer” dimension fails here.
  • star-schema-conformity fires when a dimension is referenced from facts in more than one star schema but is not marked conformed, or when a fact’s star_schema disagrees with its non-conformed dimensions.

Because cross-contract rules run against the whole project even when you scope lint to one domain, a conflict introduced in finance_mart still fires against the sales_mart dimension it collides with. lint exits non-zero on any error-severity finding, so wiring it into CI means a conformance conflict can’t reach main — the first mart to define a dimension sets its shape, and the second must conform or the build stays red.

This is the payoff of making conformance a contract property rather than a review convention: the check runs at PR time, in the same place the change is proposed, before either mart ships. Two teams working two marts can’t quietly diverge on what “customer” means, because the moment their declarations disagree the shared project fails to lint. Conformance stops being a thing a data architect polices after the fact and becomes a gate the pipeline enforces on every change — the guarantee that a cross-mart question resolves to one consistent answer is checked, not hoped for.

Where next

Updated 5 July 2026 · v1.0.0-beta.1