Skip to content

Decide whether the database should enforce the scope and reset-alignment vocabularies #1421

Description

@peteski22

The question

Should the database refuse a scoped_budgets.scope_type or a budgets.reset_alignment value that is outside its vocabulary?

Where things stand

#1417 gives both vocabularies one home, ScopeType and ResetAlignment in src/gateway/models/budgets.py, with the columns they name. The request models are typed with them, so the API refuses an unknown value with a 422. Nothing in the schema does. Both columns are plain strings with no CHECK constraint, unlike ck_budgets_single_period_source on the same budgets table.

So a row written by anything other than the API (a migration, a restore, a direct SQL write, the hosted overlay) can hold a value this build does not know. The code is written to survive that: the response models keep str | None so such a row still reads back, the period roll logs and leaves the window in place, and scope resolution treats an unknown scope type as owned by nobody, which refuses instead of leaking. It fails closed everywhere it was checked.

Why this needs a decision and not just a migration

The unconstrained column is deliberate. The ScopedBudget docstring says scope_type "is a plain string rather than a database enum so a new scope needs no enum migration". A CHECK constraint built from SCOPE_TYPES brings that cost back in a different form: adding a scope would again need a migration, to widen the constraint, and the migration would have to land before any row uses the new value, in this repository and in the overlay that shares the table.

Two coherent answers:

  • Keep it as it is. The API boundary is the guard, the code tolerates what gets past it, and adding a scope stays a code-only change. Record that in the column's comment so the next reader does not file this again.
  • Add the constraints. The schema then states what the models module now states in Python, and a bad write fails loudly at the write and not quietly at the next read. The cost is one migration per vocabulary change, coordinated with the overlay.

reset_alignment and scope_type do not have to get the same answer. The alignment vocabulary has been three values since it was introduced and a bad one is harder to tolerate (no window can be derived from it), so it is the stronger candidate.

Relevant issues

Follow-up from #1202, raised in review of #1417. Related: #1416, which moves the reservation status names beside their column and meets the same question for budget_reservations.status.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/backendBackend service implementationneeds-decisionRequires product/security decision

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions