npm hosted: wire the format route table to the real handlers (plan amendment + composition-root wiring)
Problem
internal/format/npm/handler.go builds the npm route table with a 501 notImplemented placeholder on every format route, and npm.NewHandler(resolver) accepts no handler dependencies. The real handlers are built and unit-tested, but nothing connects them to the router, so every npm endpoint returns 501 through the mounted server - including the read handlers (tarball download, packument GET, dist-tags GET) that already merged and are needlessly dark.
This was never assigned in the S11 plan. handler.go appears only as (Create) in Step 8; no later step lists it as (Modify), and it was never raised across the 133 review discussions on the two npm plan MRs (!186 (merged), !383 (merged)). It would first surface at Step 23 (conformance), but Step 23 is a test step whose Files list does not touch handler.go / wire_npm.go either.
OCI and Maven do not have this gap: both inject real handlers as dependencies at the composition root (cmd/artifact-registry/wire_oci.go, cmd/artifact-registry/wire_maven.go) and keep only narrow per-branch interim 501s. The fix is to make npm match them.
Plan amendment (docs MR, land first) — done in !826 (merged)
Amended docs/plans/2026-05-11-npm-hosted.md (merged as Step 26):
- Added a consolidated wiring step: "wire the npm route table to the real handlers", including the
NewHandlerseam refactor, thewire_npm.goinjection, and wiring tests. - Re-pointed Step 23's
Depends onat the new wiring step. - Recorded the sequencing: the wiring MR lands after the in-flight write stacks (Steps 16/17/19/21) and before Step 23 conformance. It is a prerequisite of conformance, not part of it.
Per the plan-MR-before-implementation guardrail, this docs MR merged before the code MR opens.
Code changes (one consolidated MR, after the write stacks land)
- Refactor
npm.NewHandlerto accept the real handlers as dependencies (mirror OCI'sNewDispatchHandlerWith*or Maven'sNewHandler(Deps{...})). A nil seam falls back to the interim 501, instead of a hardcoded placeholder on every route. - Update
cmd/artifact-registry/wire_npm.goto construct and inject the handlers (mirrorwireOCIWithStore/wireMavenWithResolver). - Wire all endpoints: download, packument GET, dist-tags GET (already merged), plus publish, deprecate, unpublish, and dist-tag write (Steps 16/17/19/21) once those land.
- Add wiring tests so a route can never silently regress to 501: mirror
internal/format/oci/handler_*_wiring_test.goand addcmd/artifact-registry/wire_npm_boot_integration_test.go.
Cross-format datastore alignment (converging the merged npm/Maven stores onto OCI's explicit qrm.DB provider-closure per ADR-023) is out of scope here and tracked in #256. This wiring step keeps the existing resolver signatures.
Ride-alongs — resolved out (not in the wiring MR)
Reassessed during the plan amendment (!826 (merged), Step 26); neither belongs in the wiring MR:
repositories.soft_deleted_at IS NULLgate on the async rebuild write path — already landed.NpmPackageByIDalready gates bothrepositories.soft_deleted_at IS NULL(join) andnpm_packages.soft_deleted_at IS NULL, and documents the off-request rebuilder as the reason. Nothing to do here.- Pool-relative
rebuildMaxInFlight— deferred to S27. It stays a fixed64under the existingTODO(s27-cache-rebuild)inpackument_cache.go; the jobsriver swap owns pool-aware backpressure. It does not ship with the packument path.
Acceptance
- Every implemented npm format route dispatches to its real handler through the mounted server (no 501 for an implemented endpoint).
- Wiring tests assert each endpoint is reachable through the dispatcher.
- Step 23 conformance can run a real
npmCLI round-trip end-to-end.
References
- Current placeholder table:
internal/format/npm/handler.go - Pattern to mirror:
cmd/artifact-registry/wire_oci.go,cmd/artifact-registry/wire_maven.go - Plan step:
docs/plans/2026-05-11-npm-hosted.mdStep 26 (added by !826 (merged)) - Sibling context: this closes the wiring gap that OCI (S12) and Maven (S10) already avoid.