state-hub/docs/evidence/repository-collection-projection-20260905.md
tegwick 3578dc2f32 fix: bound repository collection identity projection
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06ed7-828d-7ca0-a8d4-0c3e5a0c4102
2026-09-05 02:03:52 +02:00

2.2 KiB

Repository collection query bound — 2026-09-05

STATE-WP-0087 review of the pending patch found a second loading path to bound: ManagedRepo.domain could eagerly fetch domain topics/goals, and resolving a filter with a full Domain object could load its entire repository graph. The collection now joins only the domain row needed for domain_slug, suppresses other relationships, and resolves domain filters with a scalar ID query. Canonical/alias records are fetched together in one registry query.

Production-shaped measurement

Command: uv run pytest -q -s tests/test_repository_collection_projection.py

Real local PostgreSQL (custodian_test), FastAPI through HTTPX ASGITransport, with canonical slug records, an alias, and a pre-backfill repository. Measurements cover HTTP handling and serialization, excluding fixture setup. These are single local samples, not deployed-service latency or a percentile benchmark. The regression asserts SQL counts rather than timing thresholds.

Repository count Domain filter SQL SELECTs Request seconds
4 No 2 0.0377
131 No 2 0.0627
501 No 2 0.1751
4 Yes 3 0.0480
131 Yes 3 0.0642
501 Yes 3 0.1686

Exactly one SELECT reads repository_slugs in each nonempty case. The 501-row case exceeds SQLAlchemy's usual select-in batch size and guards against accidentally restoring eager relationship batching. An empty collection skips the registry query. Tests also compare collection/detail behavior for absent registry entries, missing canonicals, and mismatched canonicals; classification and secondary-domain filters retain their existing behavior.

This bounds database round trips, not response size: the existing unpaginated list still requires memory and serialization proportional to the fleet size. The optional SBOM owner read remains unchanged. No deployment was performed.

Regression validation

uv run pytest -q tests/test_repository_collection_projection.py tests/test_routers_core.py tests/test_repository_alias_routing.py tests/test_repository_rename_api.py tests/test_repository_rename_persistence.py tests/test_sbom_nexus_compat.py

Result: 102 passed in 129.14s. git diff --check passed.