Strongly-Typed String Enums

Rule

Database string columns with a fixed set of valid values are canonical enums. Source of truth lives in one TypeScript module (e.g., apps/web/lib/backlog.ts for EPIC_STATUSES); MCP tool definitions reference the same array. Adding a new value requires updating both the enum source and every consumer (MCP tool schema, UI types, validation) in the same commit, before any data uses the new value.

Why

Without typed enums, string columns drift: someone inserts "in_progress" (underscore) into a column that the rest of the code reads as "in-progress" (hyphen). The mismatch is invisible until a query returns the wrong rows. With typed enums, both the producer and every consumer are checked against the same source — drift becomes a compile error or a failing test, not a silent production bug. The hyphen-vs-underscore convention exists because both are otherwise legal in JSON / SQL / TypeScript; pick one and lint for it.

Applies To

In-platform coworkers managing DB writes, external coding agents calling MCP tools that accept enum-typed parameters. Symmetric. Applies to status, type, tier, kind, and any other fixed-value categorical column.

How To Apply

When adding a new fixed-value column, declare the value array in one module and import everywhere else. Reference the array from the MCP tool’s enum: [...] field rather than re-typing the values. Adding a new value: update the enum source first, update every consumer in the same commit, ship the data that uses the new value last. Hyphens, not underscores. Renames are migrations, not edits.

Decision Dimensions

Examples

Sources

(Rendered from the sources: frontmatter by WikiSourceCitations.)