Database authority and governed mutation
Control-plane authority
- The control plane uses Postgres. Use
yoke <subcommand>andyoke db read "SELECT ..."; never invent DB paths or use worktrees as control planes.yoke env listlists connections. Missing mutations: ask the control-plane operator. - Raw item reads join
item_refs r ON r.item_id = items.idand selectr.public_ref. - Read one scalar setting at a time:
yoke projects environment-settings get --project P --environment E --path KEY.PATH. - Code and tests use model validation (
model.runner.connection_env_var, defaultYOKE_DB); control-plane commands useCANONICAL_YOKE_DB. Client code relays to the control plane and never connects; code that truly owns a local database declareslocal_authority_exempt()at the call site. Converge and apply refuse on a protected connection unless the serving build declaresserving_build_authority()at the call site.
Governed DB mutation
Applies to projects with a migration_model capability.
Model: databases.
- Write the item's DB claim only through
db_claim.amend(DB claim). - Net-new tables and columns go in the schema module; boot converges them. No migration needed.
- Drops, backfills, rewrites and bulk data on a declared authoritative DB go only through the
ordered migration history. Never run ad hoc write SQL there. A new audit-fingerprint
exception call site needs
docs/archive/decisions/<helper-name>.mdandexception_reason. - Bounded row repairs use
yoke operator data-repair --dry-runfrom a live steering seat after the operator approves the digest (data repair). - Items author and rehearse; boot applies. A new entry takes the next number. A destructive
entry sets
MINIMUM_SERVING_VERSION = "next-release", never a literal version. - Never edit an applied entry. Retire a wrong invariant in a new entry (
RETIRES_INVARIANTS). - A destructive apply needs a named restore point; the applier refuses without one.
- Rows under a digest or immutability guarantee use the readers' canonical serializer.
- A row-transforming entry is idempotent when its output already exists: fold, do not recreate.
- Rehearse with
yoke migration rehearse PREFIX-Nfrom the configured local-Postgres authority that owns the item; with none configured, escalate. It holdsLIVE_DB_MIGRATION:<model>until the merge lands. From a source lane:yoke dev run [--lane <path>] -- yoke --env <name> migration rehearse PREFIX-N(--envbeforedev runis refused).rehearsal_commandsare tests, never the rehearse command. - Several items with entries: assign ordinals, stack each lane on the previous branch, list every module on the top item's DB claim, rehearse once on the top item, land in order, ship in one release.
- Before a release carrying an unapplied entry, run
yoke watch preflight -- --project P [--model M] <environment>; the release refuses without that environment's receipt (migration fleet). - Pick
migration_strategyper the project'sbreakage_policy:hard_cutoverundercompatibility_required, orexpand_contractunderfounder_cutover, needs amigration_strategy_justification.compatibility_classis a separate axis; never relax it silently (DB claim). - Before releasing a stranded migration lease, read stranded lease recovery.