docs(specs): S32's resolution decision is bounded by resolve_timeout

Summary

S32 rules that a container virtual read has no aggregate deadline of its own, and that the bound is the client's own deadline. Nothing on the server side holds that bound: Go's WriteTimeout does not cancel the handler, internal/format/oci mounts no http.TimeoutHandler, and both standalone read arms replace the connection's write deadline before the fetch, so server.timeouts.write is not a ceiling on the fan-out. Past the client's own patience its connection is gone while the fan-out keeps issuing upstream requests and holding a database connection, and a retrying client starts another.

S13 has since added virtual_repositories.resolution.resolve_timeout (spec !2249 (merged), implementation #1139 (closed), armed inside the resolver, 90s default sized to cover container's Phase 2 worst case). This amendment records that S32 consumes it and reverses the two sentences that said the opposite. The third stands: the key belongs on S13's shared block, not on this slice, and S32 still adds no proto field and no YAML key.

Two consequences were unrecorded, and both are here:

  • The Error Cases table gains a fifth row. The table calls itself "exhaustive over all three" S13 error classes and has none for a resolution abandoned on an aggregate deadline. It is a fifth row and not a fifth Retry-After value: S13 puts the expiry in the coalescing class, so the 503 carries Retry-After: 1 rather than a handler-computed value.
  • resolution_outcome gains budget_expired. The set had no value for the verdict and folded a collection-mode expiry under unavailable, which merges a self-inflicted timeout with a real upstream outage. The two clear on opposite levers: resolve_timeout or probe_concurrency for the first, an upstream's own recovery for the second. The name is merged S31's for the same verdict, adopted rather than coined, because a scraped label value cannot be renamed once it ships.

Spec-only. No code, no configuration schema, no proto field.

Governing ADRs

  • ADR-004 (data and application limits): the 20-upstream cap is what makes the unbounded sweep reachable, and the new passage cites it as the worst-case input. Conforms; no limit is changed.
  • ADR-009 (API design): fixes routes, URL uniformity, and the virtual tags/list / referrers 404 NAME_UNKNOWN. It fixes no read-failure envelope taxonomy, and this change adds no route, method, or client-facing URL. The new row reuses UNAVAILABLE, already in the envelope vocabulary. Conforms.

Mirror freshness checked with scripts/adr-freshness.sh: it reports STALE on one unsynced commit touching 012_usage_data_collection.md only, which neither ADR above is affected by.

Testing

None: documentation only. The behavior this records is already on main and already covered by #1139 (closed)'s suite, internal/virtual/resolve_budget_test.go (budget expiry in Phase 1 and Phase 2, the cached-copy serve, the warm-serve and cold-fill cases, the single-flight follower, and the client-disconnect companions that keep ResolveBudgetExpired and ResolverCancelled distinct).

Notes for the reviewer

  • This is the Step 11 half of the single S32 amendment the container-virtual plan books under ## Dependencies. !2830 (merged) carries the Step 10a half (the data-error cause list, three to six). The two halves touch disjoint passages and can merge in either order.
  • One S31 sentence is corrected here too, on reviewer request, after this MR originally left it to S31's owner. docs/specs/S31-npm-virtual.md:1242 said "Neither S30 nor S32 references it today" of resolve_timeout. S30 already referenced it (its budget row is written against the key, at docs/specs/S30-maven-virtual.md:546), so the sentence was half stale before this MR and fully stale after. b977bcc2 replaces it and keeps the placement argument it supported: the key sits on S13's block because the bound is a property of the resolution, and the contrast with the two keys S31 does propose (negative_cache_ttl, position_wait_timeout) survives.

Related to #1139 (closed)

🤖 Generated with Claude Code

Edited by Sylvia Shen

Merge request reports

Loading
Loading