feat(npm): collection plumbing seams (S31 Step 13 Part 2, part 1/4)

Split into 4 stacked MRs to keep each within the review size limit (≈800 ideal, 1000 acceptable). Each part targets the previous (part 1 → main), reviewed/merged bottom-up.

Part 1 of 4 of docs/plans/2026-08-21-s31-npm-virtual.md — Step 13: metadata merge and serve surface (Part 2: collection over positions, and the outcome arms).

This part carries the supporting seam widening the collection work builds on: npm_packages.id on the hosted probe, HostedDocument.BlobSHA256, VirtualPosition.fetcher/.npmPackageID, and one pre-authorized correction to already-merged Part 1's MergeDistTags zero-survivors write. internal/format/npm/virtual_collect.go and its test file (the collection/merge logic itself) are not in this MR — they land across three further parts (remote-only collect, hosted positions + vetoes, and the merge/serve layer), stacked above this one.

Spec: S31 (npm-virtual) Plan: docs/plans/2026-08-21-s31-npm-virtual.md

Related to #894 (closed)

Stacked MRs (review/merge bottom-up)

Database Review Evidence

Queries

Note

Plans are from EXPLAIN (ANALYZE, BUFFERS) against an ephemeral PostgreSQL 17.10 container (matching GL_PG_CURR_VERSION from .gitlab-ci-other-versions.yml), with synthesized seed data rolled back per query and the container torn down at the end of the run. Numbers reflect moderate cardinality and do not capture production-scale effects. See Database review evidence for seed sizing, methodology, and the anomalies the skill flags. Expand each row's details for the seed shape, rendered SQL, bound args, and raw plan.

Method Plan node Index Rows (plan / actual) Cost Time Buffers (hit / read) Partitions
datastore.NpmVirtualHostedPackumentLookup Nested Loop Semi Join unique_npm_packages_ns_id_repo_id_name, index_npm_versions_on_ns_id_pkg_id_id 1 / 1 16.62 0.025ms 6 / 0 1/64, 1/64
datastore.NpmVirtualHostedDistTagsLookup Nested Loop Semi Join unique_npm_packages_ns_id_repo_id_name, index_npm_versions_on_ns_id_pkg_id_id 1 / 1 16.62 0.025ms 6 / 0 1/64, 1/64
datastore.NpmVirtualHostedPackumentLookup

Summary: This part widens the existence probe's projection to also carry npm_packages.id (a same-table column already scanned, no new join or predicate); the plan is unchanged from the pre-widening statement. Planner picks the partial unique index unique_npm_packages_ns_id_repo_id_name for the outer probe and the composite index_npm_versions_on_ns_id_pkg_id_id for the correlated live-version EXISTS, both pruning to a single partition. No anomalies.

Seed shape: namespaces=1, repositories=1, npm_repositories=1, npm_packages=5000, npm_versions=5000

Rendered SQL:

SELECT npm_packages.npm_repository_id AS "npm_packages.npm_repository_id",
     npm_packages.id AS "npm_packages.id"
FROM public.npm_packages
WHERE ((((npm_packages.namespace_id = $1::uuid) AND (npm_packages.npm_repository_id IN ($2::uuid))) AND (npm_packages.name = $3::text)) AND (npm_packages.soft_deleted_at IS NULL)) AND (EXISTS (
           SELECT npm_versions.id AS "npm_versions.id"
           FROM public.npm_versions
           WHERE ((npm_versions.namespace_id = npm_packages.namespace_id) AND (npm_versions.npm_package_id = npm_packages.id)) AND (npm_versions.soft_deleted_at IS NULL)
      ));

Bound args: [<test namespace uuid>, <test npm_repository_id uuid>, "review-prep-package"]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Nested Loop Semi Join  (cost=0.56..16.62 rows=1 width=32) (actual time=0.025..0.025 rows=1 loops=1)
  Buffers: shared hit=6
  ->  Index Scan using npm_packages_p53_namespace_id_npm_repository_id_name_idx on npm_packages_p53 npm_packages  (cost=0.28..8.30 rows=1 width=48) (actual time=0.015..0.015 rows=1 loops=1)
        Index Cond: ((namespace_id = '73c80dfc-22c3-7b18-8c4b-7b7d8adbdf9a'::uuid) AND (npm_repository_id = 'c1b0827e-1a89-7e8a-a5dd-302f3ebe3980'::uuid) AND (name = 'review-prep-package'::text))
        Buffers: shared hit=3
  ->  Index Scan using npm_versions_p53_namespace_id_npm_package_id_id_idx on npm_versions_p53 npm_versions  (cost=0.28..8.30 rows=1 width=32) (actual time=0.008..0.008 rows=1 loops=1)
        Index Cond: ((namespace_id = '73c80dfc-22c3-7b18-8c4b-7b7d8adbdf9a'::uuid) AND (npm_package_id = npm_packages.id))
        Filter: (soft_deleted_at IS NULL)
        Buffers: shared hit=3
Planning:
  Buffers: shared hit=402 read=1
Planning Time: 1.864 ms
Execution Time: 0.051 ms

Timings: planning 1.864ms, execution 0.051ms, total 1.915ms.

datastore.NpmVirtualHostedDistTagsLookup

Summary: npmVirtualHostedDistTagsLookupStmt builds the identical statement as the packument lookup above (same shared npmVirtualHostedProbeStmt frame, same existence rule) — rendered SQL, seed, and plan are byte-identical, reproduced here for completeness rather than re-run.

Seed shape: namespaces=1, repositories=1, npm_repositories=1, npm_packages=5000, npm_versions=5000

Rendered SQL:

SELECT npm_packages.npm_repository_id AS "npm_packages.npm_repository_id",
     npm_packages.id AS "npm_packages.id"
FROM public.npm_packages
WHERE ((((npm_packages.namespace_id = $1::uuid) AND (npm_packages.npm_repository_id IN ($2::uuid))) AND (npm_packages.name = $3::text)) AND (npm_packages.soft_deleted_at IS NULL)) AND (EXISTS (
           SELECT npm_versions.id AS "npm_versions.id"
           FROM public.npm_versions
           WHERE ((npm_versions.namespace_id = npm_packages.namespace_id) AND (npm_versions.npm_package_id = npm_packages.id)) AND (npm_versions.soft_deleted_at IS NULL)
      ));

Bound args: [<test namespace uuid>, <test npm_repository_id uuid>, "review-prep-package"]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Nested Loop Semi Join  (cost=0.56..16.62 rows=1 width=32) (actual time=0.025..0.025 rows=1 loops=1)
  Buffers: shared hit=6
  ->  Index Scan using npm_packages_p53_namespace_id_npm_repository_id_name_idx on npm_packages_p53 npm_packages  (cost=0.28..8.30 rows=1 width=48) (actual time=0.015..0.015 rows=1 loops=1)
        Index Cond: ((namespace_id = '73c80dfc-22c3-7b18-8c4b-7b7d8adbdf9a'::uuid) AND (npm_repository_id = 'c1b0827e-1a89-7e8a-a5dd-302f3ebe3980'::uuid) AND (name = 'review-prep-package'::text))
        Buffers: shared hit=3
  ->  Index Scan using npm_versions_p53_namespace_id_npm_package_id_id_idx on npm_versions_p53 npm_versions  (cost=0.28..8.30 rows=1 width=32) (actual time=0.008..0.008 rows=1 loops=1)
        Index Cond: ((namespace_id = '73c80dfc-22c3-7b18-8c4b-7b7d8adbdf9a'::uuid) AND (npm_package_id = npm_packages.id))
        Filter: (soft_deleted_at IS NULL)
        Buffers: shared hit=3
Planning:
  Buffers: shared hit=402 read=1
Planning Time: 1.864 ms
Execution Time: 0.051 ms

Timings: planning 1.864ms, execution 0.051ms, total 1.915ms.

Edited by David Fernandez

Merge request reports

Loading
Loading