Correct nine S17 claims the merged code contradicts
S17's Phase 4 delete contract states nine facts the merged code contradicts. An implementer reading the spec as the source of truth builds the wrong thing in each case.
The attachment inventory counts eight tables, not nine
container_remote_manifests landed in 753dadd9 after the Phase 4 research and carries the same composite FK, so nine tables reference blob_storage_attachments. A reverse-reference check built from the spec's list frees an attachment a cached remote manifest still uses. The code-side widening is chore(datastore): count every table that refere... (!1450 - merged) • Hayley Swimelar • 19.3.
A malformed bulk batch does cost one database round trip
The subset-selector text and the Bounded blast radius bullet claim the body is validated before the namespace lookup, so a rejected batch costs no database round trip. slugMiddleware wraps all 18 management routes in internal/managementapi/handler.go and runs NamespaceStore.FindBySlug, one SELECT on namespaces, before next.ServeHTTP. Every bulk route registers behind that wrapper, so the lookup precedes the body decode.
The 1,000-entry cap does not clear an image's full tag set
countTagsForManifest counts container_tags by container_manifest_id, so ADR-004's 1,000-tag cap binds per manifest, and internal/config/container.go maps ADR-004's 25,000 versions per package onto manifests per image. An image at those limits holds far more than 1,000 tags. The tag-mutation section's per-image reading is wrong for the same reason, as is its claim that retargeting a tag at the cap succeeds: the limit check runs on the target manifest for any pointer change.
artifacts_count and size_bytes are maintained by shipped code today
The Resolution defers the repository columns on the claim that MarkRepoLastUpdated is a no-op stub awaiting S22 "and no code maintains them". The last clause is false: UnpublishPackageHandler, wired at cmd/artifact-registry/wire_npm.go:222, moves artifacts_count and size_bytes on every npm unpublish through the GREATEST-clamped updates in internal/datastore/repositories.go. The true and stronger reason for the management-delete deferral is that the emit site is centralized in one shared post-commit accounting emit rather than spread across the eight format arms. Raised on feat(managementapi): serve the npm package DELETE (!1532 - merged) • Hayley Swimelar • 19.3.
AC-62's completion sentence contradicts the accepted bulk-concurrency window
AC-62 says a delete_all collection "ends holding no entry the acceptance-time predicate covers". The shipped workers bound completion at committed state instead: each scope page read sees only rows committed before it ran, so an insert in a transaction that commits after the drain passed its position survives, and sealing the collection would take a repository-level lock the workers do not hold. drainBulkNpmScope documents the bound and the maven worker shares it. Amend the sentence to read on committed state (no entry committed before the drain read its position survives); the operative half, a later-created artifact survives, is already pinned by test. Raised on chore(managementapi): apply npm bulk deletes fo... (!1550 - merged) • Hayley Swimelar • 19.3.
The Delete-semantics mirror instruction names no canonical counter source
The Phase 4 Delete-semantics text instructs the management-delete arms to match the protocol surface so "the two surfaces cannot diverge", but names no canonical rule. An implementer mirroring a stale reading of the other surface builds the divergence the sentence forbids: the npm version-delete arm shipped a versions_count decrement that re-admitted publishes past the cap, because ADR-007's rule (the count includes tombstones and moves only on hard delete) lives outside the sentence. Point the instruction at ADR-007's counter rules as the canonical source instead of cross-surface mirroring. The file and dist-tag arms carry the same mirror instruction. Raised on feat(managementapi): serve the npm arm of the v... (!1535 - merged) • Hayley Swimelar • 19.3.
The bulk-versions prose settles versions_count at the marking step
The bulk-versions text says the pass "decrements versions_count" riding each entry's marking transaction. ADR-007's rule (the count includes tombstones and moves only at hard delete) and the merged S11 unpublish code contradict it: no delete surface decrements versions_count at marking, and the shipped bulk pass settles tags_count only. Rewrite the sentence to name the tags-count settlement and defer versions_count to hard delete. Raised on chore(managementapi): apply npm bulk deletes fo... (!1623 - merged) • Hayley Swimelar • 19.4.
The body-validation-order sentence reads against the family guard's 404 precedence
"The body is validated before the route's own path segments" reads as body-400 preceding every path rejection, but the shipped bulk routes answer the format-family guard's 404 ahead of body decode (a maven path under a docker segment 404s with a malformed body), and the contract's containerFormat prose resolves it that way. Scope the sentence to the artifact identifier segments before the packages-bulk implementer copies the precedence the words imply. Raised on feat(managementapi): serve the container bulk d... (!1627 - merged) • Hayley Swimelar • 19.4.
Execution note: while landing these corrections, harmonize the two comment sites inherited on main that still read "moves only when hard-deleted" about versions_count to the narrower "decrements only" wording (the column also increments on publish). The branch-side variants were narrowed on feat(managementapi): serve the npm arm of the v... (!1535 - merged) • Hayley Swimelar • 19.3; the inherited pair was left for this pass on the operator's ruling.
The delete_all concurrent-publish sentence justifies a predicate the code does not apply to repointed tags
The bulk delete_all text justifies the acceptance-time predicate with a concurrent-publish scenario, but a tag repointed after acceptance survives the pass under the shipped predicate (creation-time bound, not pointer-state), so the justification sentence describes protection the predicate does not give for repoints. The code matches the predicate; the sentence needs its scenario narrowed to creation races. Raised by arpitgogia on feat(managementapi): serve the container bulk d... (!1627 - merged) • Hayley Swimelar • 19.4.
Related to #313 (closed)