Skip to Content
EngineeringDecisions (ADRs)ADR 0006 Enumerations as text with CHECK

ADR 0006: Enumerations as text columns with named CHECK constraints

Status
Accepted
Date
Deciders
Founder, product team

Context

Trovensa records carry many lifecycles (program status, source status, hypothesis status, plan, protocol, experiment and report statuses, check and review-finding states, deviation status, milestone status, approval status, agent-run and sync-run states, assertion kinds, origins). Native database enum types make renames and additions painful to migrate and cannot be compared by alembic check; the reference profile stores enumerations as text with a CHECK constraint.

Decision

Every enumeration is a text column with a CHECK (column IN (...)) constraint named through the convention ck_<table>_<name> in api/app/db/base.py, created with enum_check() from app/db/models/_enums.py. Value tuples are exported next to the model and reused by the DTO Literal types. Values are lower-case snake_case, listed in PRODUCT-CONTRACT.md section 4.2 and on the docs “Statuses” page with one state diagram per lifecycle. Release statuses of products and providers use the five status words. Coloured chips always carry the text label; a single tone map (pass, review, fail, info, neutral) is mirrored in the web app and the docs.

Consequences

  • Adding a value is a migration that alters one CHECK constraint; renaming a value is a data migration covered by the round-trip test.
  • alembic check stays clean because CHECK constraints are compared by name and expression.
  • The docs statuses page and web/lib/status.ts must change together with the model tuples.

Alternatives considered

  • PostgreSQL enum types: harder to alter, not comparable by autogenerate; rejected.
  • Unconstrained text: silently accepts typos; rejected.

Follow-ups

  • none