Skip to content

ADR-0033 — Patient-identifier representation: namespace/profile split and the matching-survivable normalized form

  • Status: Accepted
  • Date: 2026-06-27
  • Refines: ADR-0014

Context

Demographics §4.2 already settles the projection policy for patient identifiers (national ID, insurance, program IDs): a multi-valued set keyed by issuing system, set union, never LWW, with same-system different-value = very strong evidence against link — a hard veto (identity §5.2). What §4 had not specified is representation: what an issuing system is as a globally-meaningful key, how a value is validated, and how the hard veto behaves on a node lacking the system's validator. This is the identifier analogue of the gap ADR-0032 closed for addresses.

The divergence from the address case is load-bearing: address matching is advisory/weak; identifier matching carries a hard veto. A naive port of the ADR-0032 address profile (one content-addressed namespace@hash that is both system identity and validator) would mean two nodes on different validator versions of one logical system (different hash) fail to recognise "same system", mis-firing or silently weakening the veto. And a node lacking the validator could read two formatting variants of one number as a mismatch and demote a good link to under-review — a principle 3 (paper-parity) regression caused by a space character. The identifier value shape is a can't-retrofit, day-one decision (as with ADR-0013 / ADR-0032), so it is fixed now.

This concerns the patient's external identifier and is distinct from ADR-0031, which owns the term canonical identifier for the system's own UUIDv7 + multihash. To avoid collision this ADR says "normalized form" for the matching key, never "canonical".

Decision

A patient identifier is asserted through the existing §4.1 mechanism; the value has these facets:

  1. value (mandatory) — the as-entered identifier string; the evidence/legibility facet (principle 1, principle 11 analogue), always sufficient alone, never destroyed or rewritten.
  2. system (mandatory) — the stable content-addressed namespace the hard veto keys on (nhs-number, medicare-au), globally meaningful with no central registry. May be an explicit unknown sentinel (principle 4: an unrecognised number is still recordable — weak evidence, never a veto).
  3. normalized (optional, materialised at authoring when the profile is present) — the profile's normalized form of value, the matching key. Materialising it into the signed event is the identifier analogue of ADR-0032 materialising display: a node lacking the profile code can still veto-match on the normalized form instead of mis-firing on formatting noise.
  4. profile (optional) — namespace@hash, the versioned validator bundle (format + checksum + normalizer + matching comparator), riding the security §7.6 distribution plane. Evolves independently of system — the split that lets the veto key on stable identity while validators version freely.
  5. use/type (optional) — a recommended-but-open vocabulary (national-id, insurance, program, mrn): recommended so the common case interoperates, open so it cannot become capture.

Matching & honest degradation. "Different value" in the hard veto means different normalized forms, not different value strings (9434765919 and 943 476 5919 are the same identifier — no veto). The veto forces a human decision, never an auto-link and never an auto-reject (identity §5.2). A node decides "same vs different value" only on a basis it can trust: it compares materialised normalized forms (works without the profile code); if a normalized form is absent and the node lacks the profile to derive one, it may treat string-equal as a positive signal but must not declare a same-system mismatch from string inequality — it holds for human review rather than firing the veto or demoting a link. This is the identifier analogue of ADR-0032's "never reinterpret parts under a substitute profile": a node never fires a hard veto on a basis it cannot trust. system: unknown never participates in the veto.

Advisory validation; culture-neutral floor. Per-profile validators (checksum, length, format) flag for human review, never reject (principle 4). The in-DB floor enforces only structural invariants — value non-empty text; system present (possibly unknown); normalized is text when present; normalized materialised ⇒ profile named — and never holds a profile, never runs a checksum, never rejects on validation (principle 12). Cross-facet verification (normalized == normalizer(value)) is advisory by profile-holding nodes, not floor-gated.

The professional-ID boundary. Patient identifiers answer "who is this patient?" (subject = the patient) and live in demographics §4. Professional/provider identifiers — AHPRA/GMC/NPI registration numbers, billing provider numbers — answer "who is licensed / who may sign / who bills?" (subject = the clinician as an actor) and belong to the §7.5 actor registry. They are never conflated: a person who is both carries patient IDs in demographics and registration numbers in the actor registry — conflating them would let a billing number act as a patient match key, or a patient ID act as a signing credential. A provider number is relational (different per practice/location → scoped to person×org); that model is deferred — this ADR only draws the line and states the non-conflation invariant.

Consequences

  • Easier: any issuing system is supported with no schema migration (system + profile are data); the hard veto keys reliably across nodes/locales via the stable namespace; advisory validation catches transcription errors without ever blocking a write; identifier history is intact (append-only).
  • Harder / the bet: moving validation to data trades away DB-guaranteed format/checksum enforcement (recovered as advisory per-profile validators). A profile-less authoring node cannot materialise normalized, so its identifiers route to human review at matching time on capable nodes — the safe degradation, but it shifts work to humans where validators have not yet propagated. We bet (as in ADR-0014) that content-addressed profiles distribute reliably off the clinical plane.
  • How we'd know the bet fails: identifiers arrive whose system no available profile can normalize at scale (watch the human-review yield for same-system holds); or a node is observed firing a same-system veto without a trustworthy normalized basis (a correctness bug — the degradation rule was violated).