feat(datastore): repository key enumeration part 2/4 (S09 Enforcement plan: 18/20)

Part 2 of 4 of the S09 enforcement plan — Step 18: Candidate repository enumeration.

The step is split into 4 stacked MRs to keep each within the review size limit (≈800 ideal). Each part targets the previous one (part 1 → main); review and merge bottom-up.

Stacked MRs (review/merge bottom-up)

This part (~440 reviewable LoC)

RepositoryStore.EnumerateRepositoryKeys and its unit tests: a keyset-paged read of repository ids plus the active sort's key, under List's namespace scoping, filters, sorts, and keyset semantics (via part 1's shared validate()/repositoryListClauses). The projection is two columns per sort so the three counter sorts — artifacts_count, downloads_count, size_bytes — plan as index-only scans against their partial (namespace_id, <col> DESC, id DESC) indexes. The name and last_updated_at sorts do not: id is absent from the active-name index and the COALESCE projection is not served index-only, so both stay heap-fetching Index Scans. The returned RepositoryCursor carries only ID plus the sort-matching field and is a store-level page boundary, not a wire cursor. Unit coverage: the guard chain, the per-sort projection SQL shape, the statement's predicate and ORDER BY, and the cursor narrowing. The integration suite lands in part 3 as its test-only companion; its TestRepositoryStore_EnumerateRepositoryKeys_DeepPageIsIndexBacked pins these plans per sort (a literal Index Only Scan assertion for each counter sort, and the heap-fetching plan asserted for name and last_updated_at). Captured EXPLAIN (ANALYZE, BUFFERS) plans for all five sorts: !2144 (comment 3768712093).

References

No e2e scenario is added or affected: datastore-only reads with no route change; no catalog covers the management API, and the listing filter's behavior is pinned by Step 19's handler tests (plan Testing Strategy).

Related to #860 (closed)

Edited by David Fernandez

Merge request reports

Loading
Loading