feat(oci): add container virtual upstream schema (S32 plan: 2/19)
What this does
Creates container_virtual_repository_upstreams, the ordered association table between a container virtual repository and its hosted or remote upstream repositories.
The migration adds 64 hash partitions, a UUIDv7 identifier check, three foreign keys, the deferrable unique constraint for atomic position swaps, the unique upstream association constraint, and the reverse lookup index. The schema suite verifies the catalog shape, each constraint, all delete actions, and transactional reordering.
Decisions a reviewer should check first
- The constraint on
(namespace_id, container_virtual_repository_id, position)isDEFERRABLE INITIALLY DEFERRED. Two associations can exchange positions with twoUPDATEs in one transaction. The same swap fails in autocommit mode. positionis one-based.position = 0and negative values fail theposition >= 1check.- The virtual-repository foreign key cascades. The upstream repository foreign key uses
NO ACTION, so a listed upstream cannot disappear without an explicit association change. - The migration sets five-second lock and statement timeouts before the schema changes. Its Down section sets the same timeouts before all drops.
Spec coverage
Spec: docs/specs/S32-container-virtual.md
| Criterion | Tests |
|---|---|
| A listed upstream delete is refused and its association remains. | TestContainerVirtualUpstreamsConstraints_DeleteActions/listed_upstream_is_refused |
| Deleting a virtual repository removes its associations. | TestContainerVirtualUpstreamsConstraints_DeleteActions/virtual_repository_cascades |
| The upstream foreign key rejects a cross-namespace repository. | TestContainerVirtualUpstreamsConstraints_RejectsInvalidAssociations/cross_namespace_upstream |
| One upstream cannot occur twice in one virtual repository list. | TestContainerVirtualUpstreamsConstraints_RejectsInvalidAssociations/duplicate_upstream |
| Two updates reorder positions in one transaction, and an autocommit half-swap fails. | TestContainerVirtualUpstreamsConstraints_ReorderAndRejectsAutocommit |
| Positions below one are rejected. | TestContainerVirtualUpstreamsConstraints_RejectsInvalidAssociations/position_zero, position_negative |
| The parent has 64 hash partitions, its keys and indexes propagate to leaves, and its columns have the required shape. | TestContainerVirtualUpstreamsSchema_PartitionedTableAndColumns, KeysAndIndexes, PositionUniqueIsDeferredOnEveryLeaf |
| The migration has safe Up and Down structure. | TestContainerVirtualUpstreamsSchema_DeferrableMigrationShape |
Amendment URLs the step books
None. The ADR-007 amendment is not a prerequisite for this step.
Size
This MR has 755 reviewable lines: 389 lines of migration DDL, 358 lines of integration tests, and 8 changed test lines. The migration, generated schema, Jet output, and its schema suite form one atomic unit. Splitting them would leave an unverified schema or stale generated output.
The regenerated structure.sql and Jet files add 2,125 generated lines. The full diff is 2,866 added lines and one removed line.
Checks
ARTIFACT_REGISTRY_DATABASE_TEST_DSN='postgres://ar:pw@127.0.0.1:15433/ar?sslmode=disable' mise exec -- go test -tags=integration ./internal/datastore/migrations -count=1- The pre-commit hook passed for
test(migrations): fix upstream schema static assertions.
No e2e scenario is added or affected. This schema step creates no request path. S32 Step 18 owns the end-to-end harness and catalog entries.
Sibling overlap
- !2267 (merged) overlaps on
internal/datastore/migrations/structure.sqlandinternal/datastore/migrations/migrations_checksum_test.go. - !1011 (closed) overlaps on
internal/datastore/migrations/structure.sql,internal/datastore/migrations/migrations_checksum_test.go, andinternal/datastore/jet/artifact_registry/public/table/table_use_schema.go.
Both overlaps are regenerated artifacts. Rebase and regenerate after either MR merges first.
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 |
|---|---|---|---|
20260902100000_create_container_virtual_repository_upstreams.sql |
OK (1.63s / 407.38ms) | OK (999.28ms / 371.04ms) | OK (648.44ms / 205.62ms) |
Upstream validation
The foreign key enforces namespace membership only. S17 rejects a virtual upstream and an upstream outside the container format family at association time. The read path independently rejects a direct-SQL row whose upstream kind or format is invalid, so it cannot resolve through an unsupported repository.