feat(migrations): add container virtual upstream rules schema (S32 plan: 3/19)

What this does

Adds the container_virtual_upstream_rules schema. The table stores allow and deny rules for a container virtual upstream association.

The migration defines 64 namespace hash partitions, the UUIDv7 primary key, the required checks, foreign keys, and the rules lookup index. It also regenerates the schema snapshot and Jet bindings.

Decisions a reviewer should check first

  • The association foreign key uses ON DELETE CASCADE. A repository delete removes the association and its rules as one subtree.
  • The namespace foreign key uses ON DELETE NO ACTION. A namespace delete refuses while rule rows exist.
  • The lookup index is non-partial. The batched rules read has no predicate that can use a partial index.
  • The migration uses NO TRANSACTION. Each partition statement releases its locks before the next partition statement.

Spec coverage

# Criterion Tests
AC-Schema-1 Upstream delete is refused and the referencing rows survive. TestContainerVirtualRulesConstraints_DeleteActions/listed_upstream_delete_leaves_rules_intact
AC-Schema-2 Deleting the virtual repository removes its whole subtree, rules included. TestContainerVirtualRulesConstraints_DeleteActions/repositories_delete_cascades_three_levels, TestContainerVirtualRulesConstraints_DeleteActions/virtual_repository_delete_cascades_two_levels, TestContainerVirtualRulesConstraints_DeleteActions/association_delete_cascades
AC-Schema-3 Namespace isolation: the composite FK rejects a cross-namespace reference. TestContainerVirtualRulesConstraints_RejectsAbsentReferences/cross_namespace_association
AC-Schema-4 Double association is impossible. Owned by container_virtual_repository_upstreams. Not this table.
AC-Schema-5 Reordering is transactional and the deferral is what makes it work. Owned by container_virtual_repository_upstreams. This table declares no deferrable constraint: TestContainerVirtualRulesSchema_NothingIsDeferrable
AC-Schema-6 Range constraints bind: rule_type outside (0, 1), target_field outside (0, 1), and a pattern over 255 characters are each refused. TestContainerVirtualRulesConstraints_RejectsOutOfRangeValues, TestContainerVirtualRulesConstraints_AcceptsEveryInRangeValue
AC-Rules-corrupt-target-field A corrupt target_field fails closed on the requests that do not address it. Read-path criterion, owned by the resolution steps. The write-side half is the CHECK: TestContainerVirtualRulesConstraints_RejectsOutOfRangeValues/target_field_above_the_range
AC-Rules-corrupt-rule A corrupt rule answers 500. Read-path criterion, owned by the resolution steps. The write-side half is the CHECK: TestContainerVirtualRulesConstraints_RejectsOutOfRangeValues
AC-Resolution-, AC-Probe-, AC-Rules-* (evaluation), AC-Method-, AC-Concurrency- Resolution, probe, rule evaluation, method discipline, and concurrency. Owned by later steps. No schema surface in this MR.
Requirement Tests
64 HASH partitions, primary key, columns and nullability TestContainerVirtualRulesSchema_PartitionedTableAndColumns
Partition routing by hash of namespace_id TestContainerVirtualRulesSchema_PartitionRoutingByHashOfNamespaceID
The batched read's index, its column order, and its leaf clones TestContainerVirtualRulesSchema_KeysAndIndexes
Both FK actions and the CHECK count TestContainerVirtualRulesSchema_ForeignKeysAndChecks
Each CHECK's rendered definition and reported name TestContainerVirtualRulesSchema_CheckShapes
No deferrable constraint, and an immediate primary-key index on every leaf TestContainerVirtualRulesSchema_NothingIsDeferrable
Constraint-name arithmetic TestContainerVirtualRulesSchema_ConstraintNamesFitIdentifierLimit
Migration apply and rollback structure, and the bracketed lock and statement budgets TestContainerVirtualRulesSchema_MigrationShape
Every Up statement guarded, and none an ADD CONSTRAINT TestContainerVirtualRulesSchema_UpIsReplayable
The migration applies after the table its foreign key targets TestContainerVirtualRulesSchema_AppliesAfterTheAssociationTable

No e2e scenario changes apply. This step adds only database schema. No endpoint is reachable from this change.

Size

This MR has 4,312 reviewable LOC. The schema snapshot adds 1,625 LOC. The migration adds 668 LOC. The schema integration test adds 1,227 LOC. The row-shape integration test adds 675 LOC. Generated Jet bindings add 115 LOC. The remaining migration guards add 2 LOC. These artifacts are one schema change and must land together.

Checks

  • Full pre-commit hook suite passed during commit creation.
  • pgFormatter SQL format passed.
  • squawk migration lint passed.

Sibling overlap

These open MRs also add a migration and touch the shared generated files: !2697 (merged) (20260915170000), !2695 (merged) (20260915170840), and !2659 (merged) (20260915160000). !2630 (merged), !2662 (merged), !2681 (merged), and !2579 (merged) have merged, which moved main's applied head to 20260915160000.

Every one of those versions is below this branch's 20260915180000, so this branch needs no renumber. goose runs with WithAllowOutofOrder(false), so the merge order matters in one direction only: if this MR merges first, each of the three renumbers above 20260915180000. If one of them merges first, this branch rebases the generated files and migrations_checksum_test.go and keeps its version.

Related to #291

Database Review Evidence

Migrations

Note

Timings are from CI (db:migrate matrix, goose verbose) against an empty database, in apply / rollback order per PG version. Production-scale validation via Database Lab is not yet available. See Database review evidence for the matrix rationale and how to read the numbers.

Migration PG 16 PG 17 PG 18
20260915180000_create_container_virtual_upstream_rules.sql OK (698.19ms / 238.25ms) OK (213.15ms / 155.44ms) OK (393.95ms / 159.49ms)
Edited by Radamanthus Batnag

Merge request reports

Loading
Loading