docs(specs): record S32 virtual downloads on the supplying position
What
S32 now states where a virtual container pull records its download. The position that supplied the bytes records it, under that position's own kind rules:
| Supplying position | Rule it follows |
|---|---|
| Hosted | S12's counter and timestamp updates |
| Remote | S16's download signals |
The supplying position is the winner, or the position whose cached copy the cache fallback served. The virtual repository records no download of its own. A read that fails, or whose body is cut short, records nothing.
Why
Before this change, S32 named only S16's last_downloaded_at bump, in the statement-count criterion, and said nothing about a hosted winner. The Step 12 serve surface (!2900 (merged)) records no download for either kind. The retention scans order last_downloaded_at NULLS FIRST, so an image used only through a virtual repository would be the first one evicted. S30 already records on the supplying position for Maven.
What changed
### Container virtual resolution: one paragraph that states the rule.## Acceptance Criteria,### Resolution: one criterion for each supplying kind, plus the virtual repository, the failed read, and the gating on each source spec.## Dependencies: S18 must pass the image, plus the manifest on a manifest read, at every hosted serve point, S32's included, becauseemitDownloadcarries neither.## Resolutions: one bullet with the reason.- Review corrections elsewhere in S32:
- The
Retry-Aftercriterion names the budget-expiry row, and both relayed-value clauses carry S16's one-hour cap. - The batched rules read states its bound: 20,000 rules.
- A smaller
nclears only the collection work bound, not the emitted-key bound. - A native referrers
404recordsunsupported, notabsent. - The
page_sizeCHECKholds onlypage_size >= 1; the handler enforces the configured maximum. - A merged walk must finish inside the 15-minute absolute session lifetime. The rejections counter gains
session_expired_absolute, and a Follow-ups entry books renewal on advance. - The wide-event vocabulary states the contributed-position filter for npm and OCI.
- The
resolve_timeoutclause prices collection legs at S13's20s, and referrers takes the two-requests-per-source limit. - The list read states its bound: 40 associations.
- The tag-digest criterion gates on the container opt-in (#918), not #433.
- A finished listing keeps no session row, and admission counts only open walks.
- Every collection-session
CHECKis enumerated and named. - The hosted
downloads_countincrement ships today throughCounterSink.emitDownload; only the hosted timestamps,container_images.last_downloaded_atandcontainer_manifests.last_downloaded_at, wait on S18, which must pass the image, plus the manifest on a manifest read, at every hosted serve point. - The budget clause names the
22.5sposition_wait_timeoutexpiry threshold and states the leg-against-concurrency dependence; referrers gains a work-bound criterion. - The collection-bound
503takes a handler-suppliedRetry-After. The per-position records seam coversCollect's guard and Phase 1 returns. Referrers states its default-ngap, with a Follow-ups entry for a short page plusLink. - Smaller wording fixes: collection session and collection cursor throughout, the settled relayed
Retry-Afterfallback, the emitted-keys cost claim, the S13 row's importers, the winner-fetchRetry-Afterclamp, the referrers tag schema, the tag-grammar row, and small-nwalks.
- The
S32 emits the signals at its own serve and cache-fallback points, because S12 and S16 scope theirs to their own handlers. The remote last_downloaded_at bump is asserted on the virtual path. At a hosted serve point, S32 books the download count through the writer S12's direct reads call; the hosted timestamps wait on S18. The remote download count stays unassigned.
Related to #291 (closed)