feat(maven): the winner-path read's plumbing (S30 plan: 17/25)

Summary

The plumbing Step 17's winner-path read assembles over, landed ahead of the handler so the read MR reviews on its own:

  • The batched remote lookup projects the checksum columns. Both maven_virtual_remote_lookup.go statements project maven_remote_files.sha1 and .md5 beside blob_sha256, and the verdict carries both. A NULL md5 maps to a nil slice — the shape the MD5-under-FIPS rule will read.
  • The hosted primary serve extracts its shared shape (download.go): serveResolvedPrimary carries the access bump and the If-None-Match conditional out of servePrimaryDownload's wrapper, behavior-preserving; the hosted path's tests pin it unchanged.
  • The usage stream gains the two virtual-only ADR-012 dimensions: AnchoredEvent gains CacheHit and UpstreamType, TrackAnchored copies both onto the emitted Attrs, and EventVirtualCacheMiss (artifact_registry_virtual_cache_miss) joins the catalog (internal/usagedata/events.go, docs/dev/usage-data.md).

No route behavior changes: the dispatch slot keeps the interim 501 until the stacked handler MR.

Scope

Layer 1 of 2 of Step 17 of the S30 plan (### Step 17). The handler layer is !3003 (merged), stacked on this branch. !3003 (merged) owns two follow-throughs from this layer:

  • the VirtualPosition fields, the facade's drain-fallback call, and the revalidate-flag binding test — counted here by an earlier description revision, all three are !3003 (merged)'s diff;
  • dropping the three not yet emitted marks in docs/dev/usage-data.md (the intro line, the cache_hit cell, the virtual_cache_miss row) in the same MR as its emitter, so the qualifier cannot outlive this stack;
  • moving the miss booking to the serve outcome, per the semantics call the ADR-012/S23 owner made on thread 10e9a52c (confirmed in review by the MR author, 2026-09-28): a hosted winner and a cold remote fill book the miss; a warm copy's hit books the pull alone with cache_hit=true — npm/OCI's one-verdict-per-read pattern (remote_cache_event.go). !3003 (merged)'s miss booking point changes accordingly.

Plan and spec amendments

None — this layer touches no plan or spec text.

Spec coverage

Spec: docs/specs/S30-maven-virtual.md. Plan: docs/plans/2026-09-10-s30-maven-virtual.md — the Files entry's download and usagedata rows; the checksum projection modifies Step 6's maven_virtual_remote_lookup.go.

Acceptance criteria

Behavior arrives with the handler layer; this layer's criteria are structural:

Criterion Test
Both batched statements project sha1/md5; NULL md5 → nil slice maven_virtual_remote_lookup_integration_test.go (round-trip subtests); the statement render check runs in maven_virtual_remote_lookup_test.go
servePrimaryGet reports the arm it served TestPrimaryGet_ReportsTheServeArm (redirect, stream, rejected-URL)
TrackAnchored projects the new dimensions TestTracker_TrackAnchored_ProjectsCacheHitAndUpstreamType
The miss event joins the catalog events_test.go, events_internal_test.go catalog assertions, and the microCatalog row
The hosted serve is unchanged by the extraction the existing download_test.go suite, unmodified

Governing ADRs

  • ADR-007 — no schema change; existing columns projected.
  • ADR-012 — the two dimensions and the miss event join the stream and the operator catalog; no emitter until the handler layer.

Tests

go build ./..., go test ./..., golangci-lint run, and the comment-cap gate pass on this layer's own tree (verified standalone, with the handler layer's files absent). golangci-lint run --build-tags=integration ./internal/datastore/... under the guardrail's flags (--max-same-issues=0 --max-issues-per-linter=0 --uniq-by-line=false) reports the package's seed-helper baseline plus 9 new contextcheck hits of the same kind at maven_virtual_remote_lookup_integration_test.go:295-311 — the md5 subtest calls the same context-less seed helpers; threading the contexts is the baseline's cleanup, not this diff's.

User documentation

No docs/user/ surface changes: no route behavior changes on this layer, and docs/user/repositories/_index.md already scopes virtual repositories as in development.

Related to #289 (closed)

Edited by Moaz Khalifa

Merge request reports

Loading
Loading