test(e2e): the npm HEAD-fill row, and two rows' reads behind the harness surface

What this adds

One npm catalog row, the reads behind two more, and a correction to a limitation entry whose stated reason was measurably false.

  • e2e.npm.remote.tarball-head-fills implemented, with registry.Version.LastDownloadedAt and the shared polling helpers in e2e/bootstrap/counters.go it needs.
  • Two rows' tests without their scenario ids, in e2e/bootstrap/harness/npm_counters_test.go. See below.
  • The counter limitation re-filed as the two cadences it actually is.

The entry that was wrong

### A counter is not in the response claimed the figures are absent from every response and that a read races the drain. Both halves are false: artifacts_count, downloads_count and size_bytes are all required on the Repository schema, and the race is what AwaitCounters and AssertCountersHold already handle — three container counter rows are implemented against them. The entry is deleted and replaced by ### A counter settles on a cadence the rig does not shorten, which names the two real clocks: lifecycle.sweep_interval at 5 minutes and storage_accounting.reconciliation_interval at an hour, against a 30-second poll.

downloads_count is not the column these rows want. Its only writer is MavenRepositoryStore.BumpRepoDownloadCount, reached only from Maven's archive GET. An npm test asserting it stayed at 0 could not fail. The rows read last_downloaded_at on the cached version instead, and each carries a positive control — a delivering fresh-hit GET that must move the record — so a column nothing writes cannot satisfy the negative.

Two rows carry tests but no scenario id

e2e.npm.remote.tarball-conditional and e2e.npm.lifecycle.repository-storage-counters stay uncovered, because each cell has a clause this suite cannot reach: a storage read that leaves no trace outside the process, and a purge that waits out a 5-minute sweep. Rather than assert the reachable parts and mark the rows covered, the tests moved to the harness surface declaring no id, and both clauses are indexed. e2e/README.md's "A scenario id is a subtest name, and a client surface holds only those" is what decides where they live.

One line of rig values (lifecycle: sweep_interval) makes both this row and the management-delete row writable — named as the Lifted by on the entry.

A precedent that needs its own decision

e2e.npm.remote.tarball-name-rejected is implemented and is narrowed two ways. Its "answered before any cache lookup" clause is unasserted, and — larger — its cell enumerates four file-name shapes that must be refused (.., /, a backslash, a control byte) while the test drives one address covering two of them. No %5c, no %00. Left untouched here; it is its own change and its own decision.

Reviewable LOC

9 files, +619/−33. Past 500, and the harness-surface file is the bulk of it.

Group +/−
e2e/bootstrap/harness/npm_counters_test.go +356
e2e/bootstrap/counters.go shared helpers +79/−2
e2e/bootstrap/npm/remote_test.go +37
harness clients +29/−7
patterns.go +8
docs (limitations.md, npm.md, e2e/README.md) +110/−24

If it should be split, the cut is the conditional test (~110) from the counter journey (~245).

Verification

  • e2e-catalog check: 0 disagreements.
  • go build -tags=e2e ./e2e/..., go test ./e2e/...: pass.
  • golangci-lint --build-tags=e2e at the pinned 2.13.2: 0 issues.
  • check-comment-caps.sh and --base origin/main: both OK.

Unverified against a live caproni rig. The counter journey's footprint arithmetic in particular has never been run against real bytes.

Merge request reports

Loading
Loading