Loading
feat(virtual): decision core and upstreams (S13 Step 12, part 1/2)
📚 Stacked MRs
This change is split into 2 stacked MRs. Each part targets the previous one (part 1 targets main); review and merge proceed bottom-up. Part 2 carries a documented review-size waiver — see its description.
📦 What this MR does
Part 1 of 2 of S13 virtual/remote foundation — Step 12: virtual resolution: the pure, network-free half of the virtual resolver — the slice the plan's step-12 "Size watch" note names as the natural first cut.
- The decision-array vocabulary from Virtual resolution: the per-position
decision(undecided, failed, succeeded), the winner verdict (first success preceded only by failures), the Phase 2 probe set, the Lookup-result and Probe-outcome decision mappings, and the conditional-request validator (If-None-Matchonly for a revalidate-conditional snapshot). - The
ResolveResultverdict shape: serve-from-cache vs stream plus the winning position. The resolver performs no blob I/O; the caller dispatches on the verdict. - Upstream positions:
UpstreamSpecwith validatingNewHostedUpstream/NewRemoteUpstreamconstructors and hosted/remote kind derivation from the remote handle. - The winner computation is pinned three ways: the spec worked examples, a
rapidconfluence property (once the verdict is determined, no resolution order of the remaining positions changes it), and a differential against a naive reference implementation. - Extends the ADR 023 no-reverse-dependency guard to
internal/virtual(.golangci.yaml). - Adds the canonical Phase 2/3 fakes (
FakeProber,FakeFetcher) tointernal/remote/remotetest, each panicking when nothing is configured so a test that forgets to script one fails loudly instead of reading as an upstream failure. The constructor tests here use them, and part 2's resolver suite builds on them.
⚠️ Review-size waiver
This MR is ~1,100 reviewable LoC, above the 500 guideline in docs/dev/development-model.md. It ships whole deliberately:
- The slice is the one the plan's step-12 "Size watch" note sanctions: the pure decision-array core, with no network.
- The decision vocabulary, the verdict shape, and the upstream-position constructors are one dependency cluster, and their tests — the spec worked examples, the
rapidconfluence property, the naive-reference differential, and the constructor guards — must land with the code they pin. - Splitting the cluster further would produce parts that strand tests from the functions they pin, which is strictly worse for review than the size.
- The review round grew it further: the canonical prober/fetcher fakes and their guard tests moved into
internal/remote/remotetestrather than being minted locally, which is the placement the seam's other consumers will share.
✅ Spec coverage
| Requirement | Tests |
|---|---|
| Virtual resolution decision-array worked examples | TestWinner_SpecWorkedExamples, TestProbeSet |
| Lookup and probe outcomes map to positional decisions; hosted misses fail, remote misses stay probe-eligible | TestDecisionForLookup, TestDecisionForProbe |
| Conditional HEAD only for a stale cache row with a stored validator | TestConditionalETag |
| Winner stability under any probe-completion order | TestWinner_StableOnceDetermined, TestWinner_MatchesNaiveReference (property-based) |
| Upstream-set construction rejects nil collaborators and zero IDs | TestNewHostedUpstream, TestNewRemoteUpstream, TestUpstreamKind_String, TestResolveOutcome_String |
🔍 Notes for reviewers
- Plan drift, sanctioned: the plan's step-12 Files list names only
resolve.go/resolve_test.go; the step's own "Size watch" note directs this exact split ("the pure decision-array winner computation and eligibility filtering (no network) is the natural first slice"), and the.golangci.yamlguard extension was ratified to ride in the implementing MR. - No e2e scenario catalog update:
internal/virtualis an internal library with no user-reachable surface until the virtual repository HTTP handlers (S30–S32) compose it.
Related to #333 (closed)
:bricks: Stacked MRs (review/merge bottom-up)
Edited by David Fernandez