maven_packages tombstones reach no purger scan, the hosted sibling of #728
The gap
maven_packages carries a soft_deleted_at writer and a discovery index, and no purger scan reads it.
| Table | Writer | Discovery index | Scan level |
|---|---|---|---|
maven_packages |
MavenBulkMarkers.MarkMavenPackage, internal/datastore/maven_bulk_markers.go:47 |
present | none |
The writer is production-reachable: the management API's Maven bulk delete worker calls it.
LifecycleScanStore carries eight scans on main, and none reads maven_packages:
ScanTombstonedRepositories, ScanTombstonedNpmPackages, ScanTombstonedContainerImages, ScanTombstonedMavenVersions, ScanTombstonedMavenRemoteVersions, ScanTombstonedNpmVersions, ScanTombstonedNpmRemoteVersions, ScanTombstonedContainerRemoteManifests.
MavenPackageReaper exists at internal/datastore/lifecycle_reap_maven.go:301, and the repository walk is its only caller.
The mark does not cascade
markMavenPackageTx marks the package row alone.
It reads the live version count through CountLiveVersions for the accounting delta and marks none of those versions:
// internal/datastore/maven_bulk_markers.go — markMavenPackageTx
res, err := instrumentExec(ctx, queryMavenPackagesUpdateMark,
softDeleteMavenPackageStmt(namespaceID, mavenPackageID), tx)
...
hiddenVersions, err = m.versions.CountLiveVersions(ctx, tx, namespaceID, mavenPackageID)So ScanTombstonedMavenVersions finds nothing under the mark, and the upward leg from a version has no tombstoned row to start from.
The whole subtree stays: every maven_versions row, every maven_files row, and every one of their blob_storage_attachments rows.
ADR-025 reclaims a blob when its attachment count reaches zero, so an unreaped subtree blocks reclamation with no error and no metric.
Relationship to #728
This is the hosted-Maven sibling of #728, which covers the same shape for npm_remote_packages, container_remote_images and maven_remote_packages.
#728's title and table are scoped to remote cache tables and do not name maven_packages.
The S20-A spec's Follow-ups entry for that obligation names only the three remote tables as well.
internal/lifecycle/purge_integration_test.go:530-534 is the one place in the tree that lists all four together:
maven_packages,maven_remote_packages,npm_remote_packagesandcontainer_remote_imageseach carry a discovery index and no scan level, and are reached by walking down from a repository tombstone instead.
The walk is not a route today
That test's "reached by walking down from a repository tombstone" is true of the design and not of main.
ScanTombstonedRepositories requires repositories.soft_deleted_at IS NOT NULL, and the only writer of that column, RepositoryStore.SoftDelete, has test callers only.
The destructive repository DELETE that writes it is plan step 18, still open.
So while step 18 is unmerged, a Maven package tombstone is reachable by nothing at all. Once step 18 merges, it is reachable only when someone also destroys the whole repository.
What closes it
Either of two shapes, and choosing between them is part of the work:
- A
maven_packagesscan level, in the shapeScanTombstonedNpmPackagesuses, plus a downward walk from the package tombstone, because the mark leaves the versions live. This mirrors what #728 asks for on the remote side. - Cascade the mark, so
MarkMavenPackagetombstones the versions beneath it and the existingScanTombstonedMavenVersionslevel reaps them. This changes what the accounting delta counts, so it needs S22's emit contract checked against it.
npm's hosted path already answers this differently: SoftDeleteNpmPackage has a cascade and ScanTombstonedNpmPackages is a scan level, so npm has both halves and Maven has neither.
Acceptance criteria
- A
maven_packagesrow tombstoned through the management API's bulk delete is reaped without a repository tombstone. - Its
maven_versions,maven_filesandblob_storage_attachmentsrows are gone after the reap, so a blob the package held reaches zero attachments. - Whichever shape is chosen, the counter deltas the reap emits agree with what the mark reported hidden.
type::bug. The maven_packages tombstone purger scan is missing — a production-reachable code path marks rows as soft-deleted but no lifecycle scan ever picks them up, meaning the subtree (versions, files, blob attachments) is never reaped and blob reclamation is silently blocked. This is clearly a functional defect rather than a feature request or maintenance task.
The following labels have been confirmed/applied:
type::bugCategory:Artifact Registrydevops::packagegroup::package registry
If this classification doesn't look right to you, please feel free to update the labels and let us know!