Prompt & Configuration Registry  ·  View 11 of 21  ·  Data

Data Model

Twelve entities, one of which uses its content hash as its primary key.

Editable source SVG draw.io All views
config_key key_id PK namespace owning_group unit_type user|session|tenant confidential bool safe_default_digest version digest PK sha256 key_id FK -> config_key author rationale required model_pin state draft|review|published created_at fragment fragment_id PK digest content-addressed name owning_group variable variable_id PK digest FK -> version name type required default environment_pointer key_id FK -> config_key environment PK part digest FK -> version rollout_pct killed bool updated_at promotion promotion_id PK key_id FK -> config_key from_digest to_digest FK -> version environment actor kind promote|rollback|kill at approval approval_id PK promotion_id FK -> promotion approver gate verdict at gate_verdict verdict_id PK digest FK -> version gate_name score threshold passed bool experiment experiment_id PK key_id FK -> config_key environment salt immutable primary_metric min_exposures exclusion_group state variant variant_id PK experiment_id FK -> experiment digest FK -> version weight_pct exposure exposure_id PK experiment_id FK -> experiment variant_id FK -> variant unit_hash digest at 90 d hot audit_event event_id PK subject digest|key|promotion actor action at append-only prev_hash 1 : N N : M 1 : N 1 : N 1 : N 1 : N 1 : N 1 : N 1 : N 1 : N 1 : N Data Model digest is the primary key of a version, not a surrogate: identity and content are the same thing. An experiment is scoped to a key and an environment, so it hangs off the pointer. v 1.0 · owner Platform Architecture · d 2026-09

The modelling decisions

  • version.digest is the primary key, not a surrogate. Identity and content are the same thing, which is what makes "which configuration served this answer?" a lookup rather than a reconstruction.
  • environment_pointer is keyed by (key_id, environment) and holds exactly one digest. Promotion is an update to this row; the history lives in promotion and in the audit ledger, never in the pointer.
  • experiment hangs off the pointer rather than off the key, because an experiment runs in one environment and a staging experiment must not assign production traffic.

What is deliberately absent

  • No assignment table. Variant membership is recomputed from hash(unit, salt) wherever it is needed, including offline (ADR-09), so there is nothing to keep consistent and nothing to lose.
  • No rendered-prompt entity. Exposure records a digest and a unit hash, not the text that was sent (ADR-14).
  • rationale is a required column on version, not an optional note. A version without one is not promotable.

Risks

  • experiment.salt is immutable and load-bearing: changing it silently reassigns every unit, which looks like a result rather than a bug. It is marked immutable in the schema and enforced in the API.
  • unit_hash in exposure is a pseudonymised identifier, not an anonymous one. It is re-identifiable by anyone holding the unit identifier, and must be treated as personal data.