fix(abi): prune the objects recorded broken, not every risky package

The prune selected its targets with `abi_cache_risky_packages()`, the source
classifier. A dry run on ubuntu-2404-amd64 reports what that costs:

    Dry run: 3013 object(s) left in place.

The classifier calls 93% of compiled packages risky; the binaries' own symbols
say 4.3%. Applying it would have deleted roughly 3000 working flat objects to
fix about 230 broken ones, turning every one of them into a source fallback for
clients that cannot be routed.

Select from `abi_flat_safety` instead, matching the object rather than the
package name: a package can have a safe flat binary at one version and an
unsafe one at another, and deleting both throws away a working binary. This is
the same correction #129 made to the index writer; the prune was written before
the verdicts existed and never followed.

The refusal guard moves with it. An empty result now means the slot's
flat-safety backfill never ran, which is exactly the state rhel8 was found in,
and pruning nothing while reporting success would have hidden it.
This commit is contained in:
Patrick Schratz 2026-09-09 13:06:05 +00:00
commit 68c3b6e66e
No known key found for this signature in database
GPG key ID: 62050D5BC68AB6DC

View file

@ -1,11 +1,18 @@
# Remove flat-slot binaries belonging to ABI-risky packages, then re-index.
# Remove flat-slot binaries recorded unable to load under some R minor, then
# re-index.
#
# `upload_single_binary()` writes an ABI-risky package only to the per-minor
# slot, so a risky package should have no flat binary at all. Packages built
# before they were classified risky still do, and the flat slot is what every
# client that cannot be routed by R minor receives. That binary was built under
# whichever R was primary at the time, so it dies at load under any minor that
# dropped a symbol it uses:
# The list comes from `abi_flat_safety`, so it names the objects the binaries
# themselves report as broken, not the ones a source heuristic suspects. That
# distinction is the whole cost of the operation: the heuristic calls 93% of
# compiled packages risky and would delete roughly 3000 objects per slot to fix
# about 230.
#
# `upload_single_binary()` has written a non-portable package only to the
# per-minor slot since v5.3.0, so this is a one-time cleanup of what was
# uploaded before that. The flat slot is what every client that cannot be
# routed by R minor receives, and such a binary was built under whichever R was
# primary at the time, so it dies at load under any minor that dropped a symbol
# it uses:
#
# base64enc.so: undefined symbol: SETLENGTH
#