feat(maven): remote cache store Lookup + freshness (S14 Step 8, part 2/2)
What
Adds the Maven remote cache store wrapper — Step 8, part 2/2 of the S14
Maven remote vertical slice. Stacked on the part 1/2 MR (the
datastore backing store; this branch's target is its branch): the
internal/format/maven files land on top of
internal/datastore/maven_remote_cache.go.
internal/format/maven/remote_store.go — the remote.CacheStore wrapper:
parses the inbound path at the seam, selects the freshness window through
the pure SelectFreshness, delegates row resolution to the backing store,
and sets remote.LookupResult.Fresh via remote.IsFresh against a
per-request reference time (construct one per request; a shared instance
would freeze every freshness verdict). Carries the compile-time
var _ remote.CacheStore anchor. Two return shapes: the interface Lookup
returns the format-agnostic remote.LookupResult; the Maven-typed
LookupRow beside it returns the full row for the serve and sidecar paths.
internal/format/maven/remote_freshness.go — the pure class-to-column
selection: artifacts select cache_validity_hours (0 pins the row fresh),
maven-metadata.xml selects metadata_cache_validity_hours, and
snapshot_metadata_always_revalidate forces version-level (snapshot)
metadata stale regardless of age while package-level metadata in the same
repository stays inside its window.
The seam's BlobRef is the stored blob_sha256 content address carried
verbatim (sha256:<hex>), per the spec's cache-hit contract — re-hashing
the stored bytes would address a blob that never existed.
Coverage
internal/format/maven/remote_freshness_test.go(unit) — the three-way selection and the snapshot override.internal/format/maven/remote_store_test.go(unit) — the constructor's nil-backing guard.internal/format/maven/remote_store_integration_test.go(integration) — the wrapper's parse → select → delegate → IsFresh pipeline: hits, clean misses, both freshness windows, the snapshot opt-in, cross-repository isolation, parse rejection as a wrapped error, and the verbatimBlobRef(asserted against an independently-built expectation).
Size note
Part 2/2 is ~1,205 Go LOC, roughly half of the original single MR; the overage against the plan's ~400 estimate (per the plan's Step 8 size row) is the wrapper integration suite's seed/assert boilerplate and the pure selection's unit coverage. The operator accepted the size rather than splitting further.
Review note
The snapshot_metadata_always_revalidate column consumed by
SelectFreshness is a spec-sanctioned divergence from ADR-007 as
published, pending an ADR-007 amendment via the handbook repo (the repo
guardrail forbids editing docs/adr/ in-tree; the amendment patch is
staged out-of-tree). The divergence is recorded in S14's "Data model"
section.
Validation
Re-ran the step-8 validation after addressing every finding of the first
pass; all five categories passed. This MR carries the format half of those
fixes: spec PASS (BlobRef now the stored content address, pinned by an
independent test expectation), acceptance PASS, dev guidelines PASS
(constructor panics name the constructor, process-state citations scrubbed,
anonymous table struct, tt subtests). The plan-amendment and size-record
edits ride on the part 1/2 MR.
Related to #286 (closed)