npm remote: wire npm_remote_versions.size_bytes on the tarball cache fill

Part of S15 npm remote (#287), carried over from #549 (closed) (npm artifact-level accounting), where the wire-or-drop decision settled on wire.

What is missing

npm_remote_versions.size_bytes and its size-ordered index exist since S15 Step 1 (#338 (closed)), and NpmRemoteVersionStore.AddNpmRemoteVersionSizeBytes exists with its own test suite. Nothing computes or emits a delta: the fill seam carries no size signal (UpsertNpmRemoteFileForBlobInput has no size field and the method returns only error), so the column stays 0.

The S15 plan assigns the emit to the tarball fill: the "Scope (storage accounting)" note in Step 6 of docs/plans/2026-07-15-npm-remote.md says the deltas (a fill adds the new blob size, a repoint adds new minus old) are applied off the request path via the format layer's buffered-update wrapper, "wired in Steps 9/12". Neither #346 (closed) nor #349 (closed) mentions the column, which is why this issue exists: that one sentence in a merged step's scope note is otherwise the only place the obligation is written down.

Shape of the fix (settled on #549 (closed))

  • UpsertNpmRemoteFileForBlob computes and returns the per-version size delta. It already reads the previous attachment row under the version's FOR UPDATE lock, so joining blob_storage_blobs.size for the old and new rows gives new minus old inside the fill transaction. An unchanged blob_sha256 yields 0, which is ADR-007's deduplicate-within-the-version rule.
  • The tarball fill hands the delta to AddNpmRemoteVersionSizeBytes through the format layer's bufferedUpdate wrapper, next to the last_downloaded_at bumper, never inside the fill transaction: the counter is advisory, and a lost bump must not fail or serialize a fill, which is the contract stated on the store method.
  • Metadata documents are out of scope: they hang off the package row and the counter is per version, so only the tarball fill moves it.

Done when

A cold fill leaves size_bytes equal to the cached tarball's blob size. A repoint moves it by new minus old, in both directions. A re-fill of the same blob_sha256 leaves it unchanged. A fill against a soft-deleted version writes nothing and does not fail the fill. A dropped buffered bump does not fail the request.

Blocked by #349 (closed) (the tarball proxy handler is the call site) and the Step 9 cache-store seam it widens.