docs(specs): record ADR-021's dist-tag verb split in S17
📝 Summary
S17 Phase 4 binds the npm dist-tag DELETE route to delete_artifact, and recorded that binding as a contested reading: ADR-021's Create row listed "dist-tag management", its Delete row listed "tags", so dist-tag removal had two readings. The spec took the Delete row, accepted a surface asymmetry, and left the ADR an owed disambiguation.
The GitLab package registry settles which reading is right. Its npm dist-tag routes authorize the PUT against create_package (Developer) and the DELETE against destroy_package (Maintainer), and its granular-access-token permission groups file create_npm_package_tag under create and delete_npm_package_tag under delete. Tag operations split by verb, not by tag kind.
ADR-021 now says so directly: handbook!20854 merged, giving the tag verbs a row each in the artifact-operations table and naming both tag kinds in all three artifact permission descriptions. So the binding S17 already requires is correct, and what changes here is the framing around it.
🔄 What changed
Spec text only, in docs/specs/S17-rest-management-api.md:
- Security Considerations, "Write authorization". States the verb split directly — create or retarget a tag needs
create_artifact, remove one needsdelete_artifact, for container image tags and npm dist-tags alike. The "ADR-021 reads both ways" paragraph is gone, and so is the accepted asymmetry: the npm protocol path requiresdelete_artifactfor removal too, so an Artifact Contributor can add a dist-tag on either surface and remove one on neither. - Artifact write routes (Phase 4). The ADR-021 mapping line names the npm dist-tag delete explicitly, since that is the route a reader questions.
- Dependencies. The ADR-021 entry names both permissions Phase 4's writes bind to; container tag upsert has always been a
create_artifactwrite. - Follow-ups, ADR amendments. The owed ADR-021 dist-tag item is removed, because the amendment merged. The Phase 8 items (per-artifact statistics mapping to
read_artifact, and the:tagspelling) are untouched.
✅ Behavior
🔍 Scope notes
docs/adr/is a daily-synced read-only mirror and is not touched. The amendment landed upstream in handbook 638f9c576ff70a1d744ef9c65006bc703aaa93b7; the mirror picks it up on the next sync run, after whichdocs/adr/021_authorization.mdcarries the split this spec describes.- A grep of
docs/plans/found no plan restating the dist-tag permission binding, and S09 and S11 bind no permission to the protocol dist-tag routes, so nothing else in-tree repeats the claim. The npm action table in the authorization-enforcement work is where the protocol-side split gets enforced.
♻️ History
This MR previously carried the opposite change — moving the dist-tag DELETE to create_artifact on the reading that ADR-021's Create row governs every dist-tag verb. Checking the package registry showed that reading disagrees with the implementation being migrated from, so the branch was rewritten to keep the delete_artifact binding and amend the ADR instead.
Related to #652 (closed)