CRISPcore

Stage S

Span

SP_CORE_SPAN

Span represents many as one, then answers as-is, as-was, as-was-at. It is read-only projection over Conform facts and Identity enrichment — no new business semantics. Restatement is not audit; counterfactual clustering is not a consumer API.

Where Span sits in CRISP
Rendering diagram…

Highlighted: Span represents many as one and projects time.

How Span is formed from Identity

Identity owns clustering and winner election (rules, exceptions, optional hints). Span projects those outcomes onto consume_*_key, cluster_role, and winner-facing columns — it does not re-run match logic or invent a second truth.

Identity rules → Span projection

Same teaching example as on Extensions: Northbridge Marine across billing vendors (A / B shown; more lanes follow the same Identity → Span path).

Native A · Conform

SYS_A:AH-77421

NORTHBRIDGE MARINE LTD

valid_from: 2019-03-01

Native B · Conform

SYS_B:BP-99102

Northbridge Marine Limited

valid_from: 2021-06-14

Identity · rules + exceptions

  1. Cluster rule — match key folds LTD↔LIMITED + party_kind → one hub, two members
  2. Winner rule winner_rank = valid_from ASC → A is WINNER, B is MEMBER
  3. Exceptions (when authored) — steward merge / force-discrete / equivalence can override before election

Span · PARTY (projected)

consume_party_key

CPT-NORTHBRIDGE-01

= COALESCE(cluster_party_key, party_header_key)

display_name ← winner

Northbridge Marine Ltd

A won on earliest valid_from

Members stay addressable (native grain / participants). Lane-only fields such as B’s lei ride in extensions — see Extensions.

Span does not invent sameness or winners — it projects Identity outcomes onto consume keys. Cluster match, winner election, and exceptions live in Identity rules.
Projection from Identity outcomes
# Identity already materialised
#   hub + members · cluster_role ∈ {WINNER, MEMBER}
#   winner_rank e.g. valid_from ASC (steward exceptions override)

consume_party_key(row) =
  COALESCE(row.cluster_party_key, row.party_header_key)

# Span.PARTY — enrich open Conform with Identity
SPAN.PARTY =
  conform_open(PARTY)
  LEFT JOIN identity_members
  SELECT
    consume_party_key,
    cluster_role,
    display_name,          # winner facade when clustered
    … typed canon columns,
    extensions             # participants / lane bag — see Extensions

# Collapsed consumer grain (often via Publish) uses consume_party_key
# Native grain keeps every member row for drill-down

For the full story of lane-only fields on participants (e.g. reading System B’s lei after collapse), see Extensions. Identity rule authorship lives on Identity.

Four surfaces — many as one, then three reads

Identity determines the match; Span projects it onto consume keys and temporal families. One consumer API cannot honestly answer “now”, “business-true at T”, and “what did we show in window W” with the same filter.

COALESCE · Many as one

Many as one

consume_{subject}_key = COALESCE(cluster, header)

How do many native rows become one subject for reporting?

Join Conform to Identity enrichment. Clustered natives share a consume key; singletons fall back to the header key.

three PAS parties → one consume_party_key

Representation for query — Identity already decided the match; Span projects it.

READ · AS_IS

AS_IS

SPAN.{entity}_AS_IS (views)

What do we believe now?

Current open Conform assertion (system_to IS NULL) joined to current open Identity hub. Everyday BI.

PARTY_AS_IS · consume_party_key = CP-77

Non-parameterised views — “today’s open facts + today’s clustering”.

READ · AS_WAS

AS_WAS

SPAN.{entity}_AS_WAS(business_ts)

What was business-true at T, knowing what we know now?

Slice Conform on valid_* at T; join current open Identity hub. Restatement — not “cluster as of T”.

AS_WAS('2024-06-30') on POLICY

Today’s clusters applied to the mid-year business slice — not a re-run of match rules at T.

READ · AS_WAS_AT

AS_WAS_AT

SPAN.{entity}_AS_WAS_AT(start, end)

Why did the platform show X in window W?

Conform overlapping W on system_* plus Identity hubs whose warehouse_* overlapped W. Close-day defence.

AS_WAS_AT('2024-03-01', '2024-03-08')

A Wednesday correction does not rewrite Monday’s AS_WAS_AT replay.

Counterfactual re-cluster at T is a governed rebuild-at-cut job — not a view. After CORE uplift, AS_WAS_AT also has an archive mode for literal old shape — see Evolution. Publish freezes consumer names and KPIs over these projections.

Pseudocode

Coalesce + temporal families
# Many as one — Identity enrich on Conform
consume_key(row) =
  COALESCE(row.cluster_{subject}_key, row.{subject}_header_key)

# Everyday — non-parameterised views
AS_IS(entity) =
  conform_open(entity)                    # system_to IS NULL
  LEFT JOIN identity_open
  ON consume_key

# Restatement — business time + today's clustering
AS_WAS(entity, business_ts) =
  conform WHERE valid_from <= business_ts < valid_to
  JOIN current_cluster                    # NOT cluster-as-of-T

# Audit — what the platform believed in window W
AS_WAS_AT(entity, audit_start, audit_end) =
  conform overlapping W on system_*
  JOIN Identity hubs whose warehouse_* overlapped W
  ON uplifted current-shape chain

# Counterfactual re-cluster at T → governed rebuild job, not a view