Skip to content

Reference-Data Module Pattern

Reference data is the slowly-changing, deliberately-edited data everything else points at: the catalog of Items, the Business Affiliates a tenant deals with, the Staff work is assigned to. Because operational modules build commitments on top of these records — orders, receipts, production runs — the modules that own them share one discipline for how the records change and how everyone else refers to them. This page is the single statement of that discipline; each module page states only what is specific to its own entities and links here for the rest.

Every change to a reference-data record writes a new version; nothing is ever overwritten.

  • The version history is the record. The system can answer what any record looked like as of any version, forever.
  • Owned collections fold into the versions. A record’s child content — an affiliate’s roles, an item’s supplies — is part of its versioned state: granting a role or editing a supply is a new version of the owning record. There is no separate child history to reconcile.
  • Corrections ride the recorded axis. The records are bitemporally persisted (see the Data Authority Module Pattern for the persistence machinery): fixing what was recorded wrongly is a correction on the recorded axis, distinct from a new version that changes what is. Neither ever rewrites history in place.

Each reference-data entity carries the same deliberately simple lifecycle:

PlantUML diagram

  • Created Live. A record is usable from the moment it exists.
  • Updates keep it Live. Each update writes the next version. (An entity whose identity is its only content — Staff today — omits Update as vacuous.)
  • Deleting retires it — permanently. Retirement is terminal and history-preserving: the record and its whole version history stay readable forever, but for anything new, a retired record behaves as if it never existed. Reinstatement is a deliberately reserved future extension, not a current behavior.

Consuming modules do not copy reference data and do not hold live foreign keys — they hold a version pin: a reference to the record as of a specific version (at runtime, the pair of the entity’s identity and the recorded version it points at). Two reading styles follow, and each consumer chooses at the point where a commitment is worth freezing:

  • Floating. While a document is being composed, its pin follows the record: each edit of the holder re-pins the record’s then-current version, so a draft always shows today’s data.
  • Frozen. When the document commits, its pin freezes. From then on it permanently shows the record as it was agreed — through renames, edits, and even retirement. Nothing is copied onto the document; the pinned version is its descriptor.

Consequences the consuming pages rely on:

  • Pins never dangle. A pin names a recorded version, and recorded versions are never deleted — including after retirement.
  • No propagation machinery. There is nothing to push when reference data changes: floating readers see the new version on their next read, frozen documents deliberately do not. Cached-copy refresh listeners and stale-marking flags are dissolved by construction.
  • Staleness is a derived reading. Whether a pin points at a since-retired record is answered by comparing the pin against the record’s current status — at any time, by anyone, without stored flags.

Retirement gates — at the point of choice

Section titled “Retirement gates — at the point of choice”

Retirement is enforced where a person actually chooses a target, and never where a reference merely flows along with in-flight work:

  • Gated (inception): creating or linking against the record directly — a new demand for an item, a from-scratch order line, a new item supply naming a vendor, a blind receiving line. Choosing a retired record is refused with a precise reason.
  • Gated (commitment re-check): the moments a composed document goes out — an order’s Submit re-checks that its vendor is linked and unretired, because a draft composed before the retirement must not become a new commitment after it.
  • Never re-gated (propagation): references that ride an existing commitment — a queued production request attached to an order line, a receipt against an already-placed order. The commitment was vetted when it was made and is honored as agreed.

A related affordance: a record may be referenced by name only before it is linked at all (a supplier typed onto a supply or a draft order). Deferred linking is an ordinary state, not an error; the commitment re-check is what finally requires the link.

Reference-data modules expose the same operation shape: Create (born Live), Update (a new version; refused once retired), Delete (retire — terminal), and queries — with every refusal carrying a specific, typed reason rather than a generic error. Module-specific operations (resolve-or-create for suppliers, print and image capabilities for items) layer on top without changing the discipline.

  • Adopters: Item, Business Affiliate, Staff.
  • Deliberately not an adopter: the Processing Network’s stations and loops are configuration with a one-way retirement latch — their shape and identities don’t version, they get marked. That is a structural mechanism of the network, not this pattern.