test(maven): the virtual conformance harness and e2e catalog (S30 plan: 20/25)
What
Step 20 of the S30 plan: the hermetic end-to-end conformance harness and the e2e.maven.virtual.* catalog group.
internal/format/maven/virtual_conformance_integration_test.go composes the production handler over the real virtual seams, a real database, and an in-process stub Maven upstream, then drives the route a client addresses. Each case exercises the whole path — path parsing, the upstream-list load, rule evaluation, the health gate, the batched lookups, the winner rule and the merge, the cache fill, and the serve — rather than one seam in isolation.
Ten cases: merged-metadata round trip, a hosted publish visible through the merge only once its stored document names it, merged_partial under an outage, the cache fallback, an unhealthy remote contributing from cache only, a rule denial re-routing to the next upstream, cross-repository read coalescing, per-position merge-fill coalescing, parallel distinct-path fills, and the merge entry's byte-weighted admission under Step 16a's cap.
This MR adds no production code. Step 20 is Type: test in the plan: the harness is the deliverable.
Stack
!3081 (merged) (Step 18) merged to main and this MR's target auto-retargeted to main. The branch was rebased onto main's tip 5fbd6fcc0, so the diff is against main directly and no stacking remains — the branch carries only this step's own commits (the harness, the catalog group, and the plan row).
Review fixes
The branch carries the step's own work plus the fixes a branch review proved:
| Commit | Fix |
|---|---|
edf77b3c7 |
say what the wired retry-after budget proves |
57e09b56d |
assert the fallback's row-derived checksum headers |
3d37b76bc |
name the deployed run as the blocked rows' subject |
35731339e |
name Step 19b's event as outside Step 20's coverage |
92742f1e5 |
pin proxy delivery on the virtual rows that assert a body |
41ca766bf |
assert the virtual group's ADR-012 emissions |
564300c2c |
cover S30's single-repository coalescing criterion |
f9c69b5f4 |
apply the step-20 branch-review fixes |
a7e976f22 |
state the coalescing criteria without the spec coordinate |
7e3de9731 |
name where each outside behavior's disposition is booked |
add0dede3 |
record the S30 Step 20 MR in the status table |
add0dede3 fills this step's own row.
Plan and spec amendments
Two review-proven corrections to Step 20's own plan entry (docs/plans/2026-09-10-s30-maven-virtual.md) ride along on this branch, which the step MR is the place for; neither touches the Status table.
| Commit | Correction |
|---|---|
35731339e |
Step 20's Acceptance named Step 16b's 429 refusal as the one behavior outside the harness's e2e-revisit duty. Step 19b's merge-path wide event is outside it too and Step 19b is unlanded, so the entry now names both. |
7e3de9731 |
The same entry's "each books its own e2e disposition" asserted a booking no artifact records. The entry now states where each is booked: Step 16b's entry books the 429 refusal's, and Step 19b's MR will book the merge-path event's. |
Diff size
| Group | Added | Removed |
|---|---|---|
Conformance harness (virtual_conformance_integration_test.go) |
1539 | 0 |
e2e catalog (docs/testing/e2e/maven.md) |
49 | 0 |
| Plan (review corrections + Status row) | 4 | 3 |
| Total | 1592 | 3 |
Every added line is test or catalog prose; there is no production code. The 500-reviewable-LOC ceiling counts reviewable source, and a hermetic harness that drives one journey through fixtures that only make sense together is not separable into smaller reviewable units — the ten cases share one seed helper, one stub upstream, and one gate/peak harness.
e2e scenarios and user documentation
- e2e catalog:
docs/testing/e2e/maven.mdgains the## Virtual repositoriesgroup with tene2e.maven.virtual.*rows. - User documentation: not affected. This MR changes no customer-visible surface.
- Run recipe: not affected. Step 20's Files entry does not list
.claude/skills/run-artifact-registry/.
Spec coverage
Each row names the criterion and the test that covers it: this MR's harness (TestMavenVirtualConformance_*) or the suite a landed step already owns. Rows this MR does not cover carry an explicit gap, listed under Coverage gaps this MR records.
Acceptance criteria - Resolution
| ID | Criterion | Tests |
|---|---|---|
RES-1 |
Single winner on an artifact | TestVirtualRead_WarmRemoteWinnerShortCircuits (a lower fresh hit wins over a failing position); this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip (the version only the lower position holds serves from it) |
RES-2 |
Hosted-and-remote mix | TestVirtualRead_HostedAndRemoteMixServesTheHostedWinner; this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip (a hosted hit below a remote miss) |
RES-3 |
Priority winner over a fresh hosted hit | TestVirtualRead_HostedAndRemoteMixServesTheHostedWinner, TestVirtualRead_WarmRemoteWinnerShortCircuits |
RES-4 |
Warm read short-circuits | TestVirtualRead_WarmRemoteWinnerShortCircuits |
RES-5 |
Version-level metadata resolves single-winner | TestVirtualRead_VersionLevelMetadataServesTheWinnerVerbatim |
RES-6 |
A sidecar resolves its parent | TestVirtualReadIntegration_SidecarResolvesItsParentWithOneUpstreamGet; this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip |
RES-7 |
No winner | TestVirtualRead_NoWinnerAnswers404 |
RES-8 |
No upstreams configured | TestVirtualRead_NoUpstreamsAnswers404 |
RES-9 |
An all-soft-deleted list answers the same way | TestVirtualRead_AllSoftDeletedAnswers404, TestVirtualRead_AllSoftDeletedIsIndistinguishableFromNoUpstreams, TestVirtualReadIntegration_AllSoftDeletedAnswersTheNoUpstreams404 |
RES-10 |
All eligible remotes unhealthy | TestVirtualRead_AllEligibleRemotesUnhealthyAnswers503 |
RES-11 |
Hosted miss beside an unhealthy remote is a 404 | TestVirtualRead_HostedMissBesideAnUnhealthyRemoteAnswers404 |
RES-12 |
Outage is not an absence | TestVirtualReadIntegration_OutageWithNoCachedCopyAnswers503 |
RES-13 |
Cache fallback serves a non-winning position | TestVirtualReadIntegration_CacheFallbackServesTheHighestPriorityCopy; this MR's TestMavenVirtualConformance_OutageServesTheConsultedPositionsCachedCopy |
RES-14 |
A rule-excluded position is barred from the fallback | TestVirtualReadIntegration_RuleExcludedPositionIsBarredFromTheFallback |
RES-15 |
A soft-deleted upstream cannot supply the fallback | TestVirtualReadIntegration_SoftDeletedUpstreamCannotSupplyTheFallback |
RES-16 |
Winner Fetch failure does not fall through | TestVirtualRead_WinnerFetchRefusalRelaysTheUpstreamStatus, TestMavenVirtualReadErrors_WinnerFetchFailedRelaysTheUpstreamStatus, TestVirtualReadIntegration_WinnerTransportFailureWithNoCopyAnswers503 (one fetch attempt, no lower position) |
RES-17 |
Winner transport failure falls to the cache | TestVirtualReadIntegration_WinnerTransportFailureServesTheWinnersOwnCopy, TestVirtualReadIntegration_WinnerTransportFailureWithNoCopyAnswers503 |
RES-18 |
An upstream of an unexpected kind fails closed | TestVirtualRead_AnUnexpectedUpstreamKindAnswers500 |
RES-19 |
An upstream of the wrong format fails closed too | TestVirtualRead_WrongFormatUpstreamAnswers500, TestVirtualReadIntegration_DataErrorBesideACachedCopyServesTheCopy |
RES-20 |
A data error withholds the not-found | TestVirtualRead_DataErrorWithholdsTheNotFound |
RES-21 |
Per-read statement count independent of upstream count | TestMavenVirtualUpstreamAssembly_StatementCountIsIndependentOfUpstreamCount |
RES-22 |
The health status costs no statement | TestMavenVirtualUpstreamAssembly_HealthCostsNoStatement, TestMavenVirtualHealthStatusReader_TwentyPositionsIssueNoStatement |
RES-23 |
Artifact-class cold fill carries the cold-fill header subset | TestVirtualRead_ColdRemoteFillStreamsTheHeaderSubset, TestVirtualReadIntegration_ArtifactColdFillStreamsThenWarms |
RES-24 |
A metadata winner's cold fill carries the full header set | TestVirtualReadIntegration_MetadataColdFillCommitsBeforeTheFirstHeader |
RES-25 |
A drain failure before the first header takes the cache fallback | TestVirtualReadIntegration_MetadataDrainFailureServesTheWinnersCachedCopy, TestVirtualReadIntegration_MetadataDrainFailureWithoutACachedCopyAnswers503, TestVirtualReadIntegration_HeadArtifactDrainFailureServesTheWinnersCachedCopy, TestVirtualReadIntegration_HeadArtifactDrainFailureWithoutACachedCopyAnswers503 |
RES-26 |
A hosted winner carries S10's full header contract | TestVirtualRead_HostedWinnerCarriesS10sFullHeaderContract |
RES-27 |
The shared budget answers a long resolution | TestVirtualRead_BudgetExpiryAnswers503WithAOneSecondWait, TestMavenVirtualReadErrors_ABudgetExpiryIsNotAnUpstreamOutage |
Acceptance criteria - Metadata merge
| ID | Criterion | Tests |
|---|---|---|
MRG-1 |
Union of versions | TestVirtualRead_PackageLevelMetadataServesTheMergedDocument, TestMergeMetadataContributions_VersionUnion; this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip |
MRG-2 |
Position-major ordering | TestMergeMetadataContributions_PositionMajorOrderingProperty; this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip, TestMavenVirtualConformance_MergeBudgetOmitsThePositionsPastTheAdmittedPrefix, TestMavenVirtualConformance_HostedPublishReachesTheMergeThroughItsStoredDocument |
MRG-3 |
Newest timestamp wins the hints | TestMergeMetadataContributions_* (hint table in virtual_metadata_merge_test.go), TestMavenMergeServe_GetServesTheMergedDocument |
MRG-4 |
<lastUpdated> is the maximum |
TestMergeMetadataContributions_* (hint table in virtual_metadata_merge_test.go) |
MRG-5 |
Coordinates come from the request | TestMavenMergeServe_GetServesTheMergedDocument |
MRG-6 |
A remote contributor's freshness governs its input | TestMavenMergeCollect_RemoteFetch; this MR's TestMavenVirtualConformance_MergeOmitsTheFailedPositionAndServesPartial (the stale position's revalidation carries the stored validator) |
MRG-7 |
Best-effort under outage | this MR's TestMavenVirtualConformance_MergeOmitsTheFailedPositionAndServesPartial; TestMavenMergeServe_AReadPassFailureOmitsThePosition, TestMavenMergeCollect_ARemoteCachedBlobFailureIsStillOmitted |
MRG-8 |
The merge memory budget bounds the contributor set | this MR's TestMavenVirtualConformance_MergeBudgetOmitsThePositionsPastTheAdmittedPrefix; TestMavenMergeServe_BudgetOmitsThePositionsPastTheAdmittedPrefix, TestMavenMergeServe_AZeroAdmissionBudgetIsUnavailable. Gap: the positions[] half — omitted_budget per omitted position and the merged_partial outcome value — is Step 19b's, not landed on this branch; the harness asserts the response observables (200, no ETag, a body short of the omitted position) instead |
MRG-9 |
An unhealthy remote contributes from cache only | this MR's TestMavenVirtualConformance_UnhealthyRemoteContributesFromCacheOnly |
MRG-10 |
A hosted publish is visible through its stored document | this MR's TestMavenVirtualConformance_HostedPublishReachesTheMergeThroughItsStoredDocument |
MRG-11 |
All-absent is a 404 | TestVirtualRead_PackageLevelMetadataAllAbsentAnswers404 |
MRG-12 |
All-failed is a 503 | TestMavenMergeServe_EveryReadPassFailingIsUnavailable |
MRG-13 |
A data error vetoes the merge 404 | TestCollectVerdict_AnIneligiblePositionWithholdsTheNotFound, TestCollectVerdict_AnUnservedPresenceWithholdsTheNotFound (internal/virtual/collect_verdict_test.go — the verdict withholds the not-found while an ineligible or unserved position holds the path) |
MRG-14 |
A malformed remote input cannot fail the read | TestMavenMergeServe_AMalformedStoredDocumentOmitsThePosition, TestMavenMergeCollect_BooksOnlyARemoteUnusableDocumentAsADataError |
MRG-15 |
A hosted stored-read failure vetoes the read | TestMavenMergeServe_AHostedReadFailureVetoesTheRead, TestMavenMergeCollect_AHostedStoredReadFailureVetoesTheRead |
MRG-16 |
A rejection decided on the committing read leaves the cache holding it | TestMavenMergeCollect_ACacheFillFailureContributesTheDocument, TestMavenMergeCollect_KnownDivergence_ASecondLeaderLossServesTheCachedCopy |
MRG-17 |
A plugins section is served from its lowest-position holder | TestMavenMergeServe_PluginsDocumentServedVerbatim, TestMavenMergeServe_AMixedCollectionServesBothSections, TestMavenMergeServe_AStreamedPluginsDocumentServedVerbatim, TestMergeMetadataContributions_LowestPluginsSourceProperty |
MRG-18 |
No sidecar fetch upstream | TestVirtualSidecar_MergedParentSynthesizesEveryExtension; this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip (the .sha1 attests the served bytes) |
MRG-19 |
Determinism | TestMavenMergeServe_DeterminismAcrossWinnerKinds |
MRG-20 |
Merge statement count is independent of upstream count | TestMavenVirtualUpstreamAssembly_StatementCountIsIndependentOfUpstreamCount, TestVirtualHostedUpstream_RepeatedLookupIssuesOneStatement |
MRG-21 |
Merge fan-out is bounded | TestCollect_ConcurrencyNeverExceedsProbeConcurrency (internal/virtual/collect_test.go; the foundation owns the fan-out bound) |
MRG-22 |
snapshot_metadata_always_revalidate does not reach the merge path |
TestRemoteMetadata_SnapshotAlwaysRevalidate_PackageLevelUnaffected (the package-level row ignores the flag) |
MRG-23 |
Round trip | this MR's TestMavenVirtualConformance_MergedMetadataRoundTrip |
MRG-24 |
A winner change between dependent reads is visible, not masked | TestVirtualSidecar_WinnerChangeBetweenDependentReadsIsVisible |
MRG-25 |
FIPS short-circuit on the merged sidecar | TestVirtualSidecar_FIPSTurnsAwayMD5BeforeResolution, TestVirtualSidecar_MergedParentSynthesizesEveryExtension |
MRG-26 |
Merged metadata HEAD |
TestVirtualRead_PackageLevelMetadataHeadMatchesGet, TestMavenMergeServe_HeadRunsTheFullMerge |
MRG-27 |
A listed version may be unfetchable | TestVirtualRead_NoWinnerAnswers404 (the listed version's artifact fetch is the ordinary winner-path 404); TestMavenMergeServe_GetServesTheMergedDocument (no pre-merge reconciliation against artifact rows) |
Acceptance criteria - Conditional requests
| ID | Criterion | Tests |
|---|---|---|
CND-1 |
Merged-document validator | TestMavenMergeServe_ConditionalRequest, TestVirtualRead_PackageLevelMetadataConditionalAnswers304 |
CND-2 |
A partial merge carries no validator | TestMavenMergeServe_PartialMergeCarriesNoETag, TestVirtualRead_PackageLevelMetadataPartialCarriesNoValidator; this MR's TestMavenVirtualConformance_MergeOmitsTheFailedPositionAndServesPartial, TestMavenVirtualConformance_UnhealthyRemoteContributesFromCacheOnly, TestMavenVirtualConformance_MergeBudgetOmitsThePositionsPastTheAdmittedPrefix |
CND-3 |
Validator tracks inputs | TestMergeValidator_TracksInputs, TestMergeValidator_CanonicalEncoding, TestMergeValidator_PositionOrderIsCanonical |
CND-4 |
Winner-path conditional request | TestVirtualRead_HostedWinnerConditionalRequest, TestVirtualRead_WarmRemoteWinnerConditionalRequest |
CND-5 |
A streamed cold fill carries no ETag | TestVirtualReadIntegration_ArtifactColdFillStreamsThenWarms (the cold 200 carries no ETag; the next read does) |
CND-6 |
Sidecar conditional request | TestVirtualSidecar_ConditionalRequestAnswers304 |
Acceptance criteria - Allow/deny rules
| ID | Criterion | Tests |
|---|---|---|
RUL-1 |
Denial re-routes to the next upstream | this MR's TestMavenVirtualConformance_RuleDenialReroutesToTheNextUpstream |
RUL-2 |
All upstreams denied | TestVirtualRead_AllDeniedAnswers404 |
RUL-3 |
Version rule does not govern a merge | TestMavenVirtualResolution_TheVersionRuleGovernsOnlyVersionLevelRequests |
RUL-4 |
Version rule governs that version's requests | TestMavenVirtualResolution_TheVersionRuleGovernsOnlyVersionLevelRequests |
RUL-5 |
Group and artifact rules admit matches | TestMavenVirtualResolution_GroupAndArtifactRulesAdmitMatches, TestNewVirtualCoordinate_GroupIDRules, TestNewVirtualCoordinate_ArtifactIDRules |
RUL-6 |
Corrupt rule fails closed | TestMavenVirtualResolution_ACorruptRuleFailsClosedOnBothRequestLevels, TestNewVirtualCoordinate_CorruptRuleValuesFailClosed |
RUL-7 |
A corrupted deny rule does not stop denying | TestMavenVirtualResolution_ACorruptedDenyRuleDoesNotStopDenying |
RUL-8 |
Every upstream ineligible for a data error | TestVirtualRead_AllIneligibleAnswers500 |
RUL-9 |
A data error alongside a policy denial is still a 500 | TestVirtualRead_AllIneligibleAnswers500, TestVirtualRead_DataErrorWithholdsTheNotFound |
Acceptance criteria - Write unavailability
| ID | Criterion | Tests |
|---|---|---|
WRT-1 |
All PUTs rejected | TestDispatchHandler_PUT_VirtualKind_WriteClasses_405NoBodyRead |
WRT-2 |
No request body is read | TestDispatchHandler_PUT_VirtualKind_WriteClasses_405NoBodyRead |
WRT-3 |
Authorization precedes the kind dispatch | TestDispatchHandler_PUT_VirtualKind_SuspendedNamespace_403PrecedesThe405 (the namespace gate ahead of the 405); the denying-decision arm is the authorization middleware's own suite (internal/authz) |
WRT-4 |
A suspended namespace refuses the write first | TestDispatchHandler_PUT_VirtualKind_SuspendedNamespace_403PrecedesThe405, TestGatingIntegration_MavenSuspendedIsReadOnly |
Acceptance criteria - Validation and reads
| ID | Criterion | Tests |
|---|---|---|
VAL-1 |
HEAD matches GET |
TestVirtualRead_HeadMatchesGet, TestVirtualRead_PackageLevelMetadataHeadMatchesGet, TestVirtualSidecar_HeadMatchesGet |
VAL-2 |
Traversal rejected | TestDispatchHandler_PathTraversalMatrix_GET, TestDispatchHandler_VirtualKind_ParseRejections_PrecedeKindDispatch |
VAL-3 |
Shallow group-level metadata rejected | TestParsePath_Rejected, TestDispatchHandler_VirtualKind_ParseRejections_PrecedeKindDispatch |
VAL-4 |
Invalid coordinates rejected | TestParsePath_Rejected, TestDispatchHandler_VirtualKind_ParseRejections_PrecedeKindDispatch |
VAL-5 |
Read-path 404 shape | TestMavenVirtualReadErrors_ReadPathNotFoundsAreIndistinguishable, TestMavenVirtualReadErrors_ReadPath404ShapeHoldsOnHEAD |
VAL-6 |
A read past the rate limit is refused before resolution | Gap, owned by Step 16b. The 429 row waits on the S05 rate-limiting primitive, which is not landed on this branch; docs/testing/e2e/maven.md lists it out of scope until it ships, and the plan books the burst as Step 16b's own test |
Acceptance criteria - Concurrency
| ID | Criterion | Tests |
|---|---|---|
CON-1 |
One upstream fetch across concurrent virtual reads | this MR's TestMavenVirtualConformance_ConcurrentReadsCoalesceAcrossVirtualRepositories; TestRemoteArtifact_ConcurrentMiss_SingleUpstreamGet (the standalone twin) |
CON-2 |
Coalescing holds across virtual repositories and positions | this MR's TestMavenVirtualConformance_ConcurrentReadsCoalesceAcrossVirtualRepositories |
CON-3 |
Merge fills coalesce per position | this MR's TestMavenVirtualConformance_MergeFillsCoalescePerPosition |
CON-4 |
Distinct paths still fill in parallel | this MR's TestMavenVirtualConformance_DistinctPathsFillInParallel |
Acceptance criteria - Schema
| ID | Criterion | Tests |
|---|---|---|
SCH-1 |
Reorder in one transaction | TestMavenVirtualUpstreamsConstraints_ReorderAndRejectsAutocommit |
SCH-2 |
Duplicate upstream rejected | TestMavenVirtualUpstreamsConstraints_RejectsInvalidAssociations |
SCH-3 |
Deleting a listed upstream is refused | TestMavenVirtualUpstreamsConstraints_DeleteActions |
SCH-4 |
Deleting the virtual repository removes its list | TestMavenVirtualUpstreamsConstraints_DeleteActions, TestMavenVirtualUpstreamRulesConstraints_DeleteCascades |
SCH-5 |
Range and length constraints hold | TestMavenVirtualUpstreamRulesConstraints_RejectsInvalidRules, TestMavenVirtualUpstreamRulesConstraints_AcceptsEveryEnumeratedValue, TestMavenVirtualUpstreamsConstraints_RejectsInvalidAssociations |
SCH-6 |
Namespace isolation | TestMavenVirtualUpstreamsConstraints_RejectsInvalidAssociations, TestMavenVirtualRepositoriesConstraints_RepositoryFKRejectsCrossNamespaceParent |
Error cases
| ID | Criterion | Tests |
|---|---|---|
E-1 |
Any PUT on a virtual repository → 405 |
TestDispatchHandler_PUT_VirtualKind_WriteClasses_405NoBodyRead |
E-2 |
A read past the rate limit → 429 | Gap, owned by Step 16b (the S05 primitive is not landed; see VAL-6) |
E-3 |
No winner, an absence established → 404 | TestVirtualRead_NoWinnerAnswers404 |
E-4 |
Merge produced no document, an absence established, no omission → 404 | TestVirtualRead_PackageLevelMetadataAllAbsentAnswers404 |
E-5 |
No upstreams, or every association soft-deleted → 404 | TestVirtualRead_NoUpstreamsAnswers404, TestVirtualRead_AllSoftDeletedAnswers404, TestVirtualRead_AllSoftDeletedIsIndistinguishableFromNoUpstreams |
E-6 |
Every upstream denied by well-formed rules → 404 | TestVirtualRead_AllDeniedAnswers404 |
E-7 |
Every rule-eligible position is an unhealthy remote → 503 | TestVirtualRead_AllEligibleRemotesUnhealthyAnswers503 |
E-8 |
No absence and no consulted cache entry → 503 | TestVirtualReadIntegration_OutageWithNoCachedCopyAnswers503; TestMavenMergeServe_EveryReadPassFailingIsUnavailable (the merge arm) |
E-9 |
No absence and a consulted position holds a cache entry → 200 | TestVirtualReadIntegration_CacheFallbackServesTheHighestPriorityCopy; this MR's TestMavenVirtualConformance_OutageServesTheConsultedPositionsCachedCopy, TestMavenVirtualConformance_MergeOmitsTheFailedPositionAndServesPartial |
E-10 |
Winner's Fetch fails after a successful Probe → the winner's status | TestVirtualRead_WinnerFetchRefusalRelaysTheUpstreamStatus, TestMavenVirtualReadErrors_WinnerFetchFailedRelaysTheUpstreamStatus |
E-11 |
Winner's Fetch fails on transport before the first header → 200 or 503 | TestVirtualReadIntegration_WinnerTransportFailureServesTheWinnersOwnCopy, TestVirtualReadIntegration_WinnerTransportFailureWithNoCopyAnswers503 |
E-12 |
Winner's Fetch fails on transport after the first header → cut short | TestServeVirtualRead_BooksTheDrainArm, TestMavenMergeServe_AFailedBodyWriteHoldsBackTheRemoteBumps |
E-13 |
Merge read with some positions omitted → 200 | this MR's TestMavenVirtualConformance_MergeOmitsTheFailedPositionAndServesPartial, TestMavenVirtualConformance_UnhealthyRemoteContributesFromCacheOnly, TestMavenVirtualConformance_MergeBudgetOmitsThePositionsPastTheAdmittedPrefix; TestMavenMergeServe_PartialMergeCarriesNoETag. Gap: the wide-event half — the merged_partial outcome and the per-position positions[] bookkeeping — is Step 19b's, not landed on this branch; the harness asserts the response observables instead |
E-14 |
A hosted Lookup Hit whose own document read fails → 500 | TestMavenMergeServe_AHostedReadFailureVetoesTheRead, TestMavenMergeCollect_AHostedStoredReadFailureVetoesTheRead |
E-15 |
Merge produced no document, a data-error position anywhere → 503 | TestCollectVerdict_AnIneligiblePositionWithholdsTheNotFound, TestCollectVerdict_AnUnservedPresenceWithholdsTheNotFound (the data-error veto of the 404). Gap: the all-ineligible merge path's 500 arm has no test on this branch — the read-path arm is TestVirtualRead_AllIneligibleAnswers500 |
E-16 |
Abandonment: the client disconnected or its deadline expired | TestServeVirtualRead_BooksAnAbandonedRead, TestMavenVirtualReadErrors_ADepartedCallerIsStampedNotLeftAt200, TestMavenVirtualReadErrors_ADepartedCallerDuringTheAssemblyIsNotA500 |
E-17 |
Budget: resolution.resolve_timeout expired → 503 with Retry-After: 1 |
TestVirtualRead_BudgetExpiryAnswers503WithAOneSecondWait, TestMavenVirtualReadErrors_ABudgetExpiryIsNotAnUpstreamOutage |
E-18 |
Infrastructure: a cache read or write failed → 500 | TestVirtualRead_MetadataColdFillFailsLocallyAnswers500, TestVirtualRead_WarmRemoteWinnerStorageFaultsAnswer500, TestMavenMergeCollect_ARemoteCachedBlobFailureIsStillOmitted |
E-19 |
Infrastructure: nothing eligible and a data-error position → 500 | TestVirtualRead_AllIneligibleAnswers500 |
E-20 |
Infrastructure: a coalesced follower outwaited its leader → 503 | TestMavenVirtualReadErrors_CoalescingRowsShareOneRetryAfter, TestRemoteArtifact_ConcurrentTruncation_LeaderInterruptedFollowers503 |
E-21 |
Infrastructure: a coalesced leader was canceled mid-fill → 503 | TestMavenVirtualReadErrors_CoalescingLiteralMirrorsTheConstant, TestRemoteArtifact_ConcurrentTruncation_LeaderInterruptedFollowers503 |
E-22 |
Infrastructure: a coalesced leader's fill was abandoned → 503 | TestMavenVirtualReadErrors_CoalescingRowsShareOneRetryAfter |
E-23 |
Infrastructure: the winner's fill was refused a staging session → 503 | TestServeVirtualRead_StagingRefusalAnswersTheShed503, TestMavenVirtualReadErrors_StagingShedJittersItsRetryAfter, TestMavenVirtualReadErrors_StagingShedKeepsItsNeighboursIntact |
E-24 |
Infrastructure: the upstream request was rejected before it was sent → 500 | TestMavenVirtualReadErrors_MapsEveryTaxonomyValue, TestMavenVirtualReadErrors_TaxonomyIsDerivedFromFallbackEligible, TestMavenVirtualReadErrors_DefaultArmIsReachedOnlyByAWrappedDatastoreError |
E-25 |
Path malformed → 400 | TestDispatchHandler_PathTraversalMatrix_GET, TestParsePath_Rejected, TestDispatchHandler_VirtualKind_ParseRejections_PrecedeKindDispatch |
E-26 |
.md5 sidecar under FIPS-on → 422 |
TestDispatchHandler_VirtualKind_MD5_FIPS_422, TestVirtualSidecar_FIPSTurnsAwayMD5BeforeResolution |
E-27 |
.md5 under FIPS-off with a NULL column → 404 |
TestVirtualSidecar_MD5NullColumnOnTheWinnerArmAnswers404, TestVirtualReadIntegration_MD5NullColumnOnTheWinnerArmAnswers404 |
E-28 |
Range outside the cached blob on a hit → 416 |
TestPrimaryGET_RangeOutOfRange_Returns416, TestVirtualRead_WarmRemoteWinnerRangeArms |
Security considerations
| ID | Criterion | Tests |
|---|---|---|
SEC-1 |
No credentials of its own | TestMavenVirtualReadErrors_LogsNoCredentialOnAnyArm, TestMavenVirtualReadErrors_ServesNoCredentialOnAnyArm; S14's credential suite covers the remote legs |
SEC-2 |
Authorization is on the addressed repository | TestDispatchHandler_PUT_VirtualKind_SuspendedNamespace_403PrecedesThe405; the requester-level decision is the authorization middleware's suite (internal/authz). Resolution adds no per-upstream check, so there is no per-upstream test to write |
SEC-3 |
A composition can widen access, and that is the accepted model | No test, deliberately. The pairing is a write-surface posture with no read-path difference; S17's association endpoint owns the authorization |
SEC-4 |
Position order decides which upstream shadows another's versions | No test, deliberately. Ordering is configuration, decided as no write-side control on #792; the merged list is advisory discovery and the winner rule is covered by RES-1..RES-5 |
SEC-5 |
The recursion guard is defended twice | TestVirtualRead_AnUnexpectedUpstreamKindAnswers500 (the read side); the association route's own suite (internal/managementapi) covers the write side |
SEC-6 |
Denied upstreams are indistinguishable in the response | TestVirtualRead_AllDeniedAnswers404, TestMavenVirtualReadErrors_ReadPathNotFoundsAreIndistinguishable |
SEC-7 |
Read-triggered event volume is bounded | Gap, owned by Step 16b (the shared rate-limiting primitive is not landed; see VAL-6) |
SEC-8 |
The merge parses upstream-controlled XML; the parser is the hardening | surface FuzzParseMetadataMergeInput, TestParseMetadataMergeInput_NamesTheBoundItBroke, TestParseMetadataMergeInput_InputErrorClassification, TestMetadataMergeDocSize_BoundsTheEscapedBody, TestTagGuardReader_CountsEachTagByte |
SEC-9 |
No new outbound surface | TestMavenVirtualRemoteFetcher_* (the position fetches through the shared flight); the SSRF covers, redirect credential stripping, and path-segment validation are the upstream client's own suite (internal/remote) |
SEC-10 |
Streaming bounds are the upstream's | TestMetadataMergeDocSize_BoundsTheEscapedBody, TestParseMetadataMergeInput_NamesTheBoundItBroke (the merge's per-input cap); the remote body caps are internal/remote's suite |
SEC-11 |
The merge's contributor set is admitted against a memory budget | TestMergeCap_ConcurrentReadsShareOneBudget, TestMavenMergeServe_BudgetOmitsThePositionsPastTheAdmittedPrefix; this MR's TestMavenVirtualConformance_MergeBudgetOmitsThePositionsPastTheAdmittedPrefix |
Coverage gaps this MR records
- The merge path's wide event (
resolution_outcome=merged/merged_partial,positions[]withcontributed/contributed_stale/omitted_budget/failed/no_stored_document/unhealthy) is Step 19b's, and Step 19b is not landed on this branch. The harness asserts the merge's response observables instead — status, the version union, the presence or absence of the input-derivedETag, per-position upstream request counts, and the committed cache rows — which is why MRG-8 and E-13's rows above carry a partial gap. - The read-path rate limit (
429, before any resolution) is Step 16b's, gated on the S05 primitive. VAL-6, E-2, and SEC-7 record it. - SEC-3 and SEC-4 are accepted postures with no read-path behavior to assert; each row states why.
- The merge-fill coalescing and distinct-path parallelism cases (CON-3, CON-4)
hold a fill open for a bounded window to let the reads that must join it get
in flight, the technique the Maven single-flight suites already use. The
assertions are the upstream
GETcount and the observed peak concurrency, not the window.
Related to #289 (closed)