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

Merged
pat-s merged 1 commit from fix/prune-from-recorded-verdicts into main 2026-09-09 15:01:22 +00:00
Owner

Why

A dry run of the prune on ubuntu-2404-amd64 (pipeline 12494):

Dry run: 3013 object(s) left in place. Re-run with --apply to delete.

3013 objects on one slot. The recorded verdicts say roughly 230 of that slot's objects actually fail dyn.load() anywhere.

The gap is the selector: the prune used abi_cache_risky_packages(), the source classifier, which calls 93% of compiled packages risky where the binaries' own symbols say 4.3%. Applying it would have deleted ~2800 working binaries and turned each into a source fallback for every client that cannot be routed by R minor.

This is the same mistake #129 fixed in the index writer. The prune was written before the per-object verdicts existed (#200, before #128/#129) and was never brought forward.

What changed

  • Selection comes from abi_flat_safety, every NOT safe row for the slot regardless of which minor it fails under, since the flat object is served to clients on all of them.
  • Matching is by object, <package>_<version>, not by package name. A package can have a safe flat binary at one version and an unsafe one at another; the old code deleted both.
  • The explicit [pkg ...] override is unchanged in behaviour and still matches by package name, which is what you want when naming a package by hand.
  • The refusal guard moves with the selector. An empty result now means the slot's flat-safety backfill never ran — the exact state rhel8 was found in today — and pruning nothing while reporting success would have hidden it.

Not changed

Still a dry run unless PRUNE_APPLY=yes, and still refuses to delete an object whose package CRAN no longer ships, since there would be no source to fall back to.

Ordering note

A prune converts each deleted binary into a source fallback. bincraft #131 fixes source fallbacks of archived versions being advertised as binaries, which breaks uvr outright. That should land before any large prune, or this will manufacture new instances of it.

## Why A dry run of the prune on `ubuntu-2404-amd64` (pipeline 12494): ``` Dry run: 3013 object(s) left in place. Re-run with --apply to delete. ``` 3013 objects on one slot. The recorded verdicts say roughly **230** of that slot's objects actually fail `dyn.load()` anywhere. The gap is the selector: the prune used `abi_cache_risky_packages()`, the source classifier, which calls **93%** of compiled packages risky where the binaries' own symbols say **4.3%**. Applying it would have deleted ~2800 working binaries and turned each into a source fallback for every client that cannot be routed by R minor. This is the same mistake #129 fixed in the index writer. The prune was written before the per-object verdicts existed (#200, before #128/#129) and was never brought forward. ## What changed - Selection comes from `abi_flat_safety`, every `NOT safe` row for the slot regardless of which minor it fails under, since the flat object is served to clients on all of them. - Matching is by **object**, `<package>_<version>`, not by package name. A package can have a safe flat binary at one version and an unsafe one at another; the old code deleted both. - The explicit `[pkg ...]` override is unchanged in behaviour and still matches by package name, which is what you want when naming a package by hand. - The refusal guard moves with the selector. An empty result now means the slot's flat-safety backfill never ran — the exact state rhel8 was found in today — and pruning nothing while reporting success would have hidden it. ## Not changed Still a dry run unless `PRUNE_APPLY=yes`, and still refuses to delete an object whose package CRAN no longer ships, since there would be no source to fall back to. ## Ordering note A prune converts each deleted binary into a source fallback. bincraft #131 fixes source fallbacks of *archived* versions being advertised as binaries, which breaks `uvr` outright. That should land before any large prune, or this will manufacture new instances of it.
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.
pat-s merged commit a84cca1949 into main 2026-09-09 15:01:22 +00:00
pat-s deleted branch fix/prune-from-recorded-verdicts 2026-09-09 15:01:22 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
devxy/build-cran-binaries!211
No description provided.