devxy/build-cran-binaries
Watch
1
0
Fork
You've already forked build-cran-binaries
0
Commit graph

1,006 commits

Author SHA1 Message Date
f9dd20a757 chore: remove plans and specs design docs
Drop the internal plans/ and specs/ design documents, the README link to the patching spec and their markdownlint ignores.
15h ago
987958fc6e chore(deps): update terraform bunnynet to v0.20.2 (#250)
Some checks are pending
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline is running
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline is running
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
1d ago
94a221dec9 chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.10.1 (#249)
Some checks are pending
ci/crow/cron/process-updates/8 Pipeline is running
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
2d ago
7d822d57cc chore(deps): update pre-commit hook davidanson/markdownlint-cli2 to v0.24.1 (#248)
2d ago
cfdd9932b7 chore(deps): update terraform bunnynet to v0.20.1 (#247)
Some checks are pending
ci/crow/cron/weekly-rebuild-missing/31 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/38 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline is running
ci/crow/cron/process-updates/12 Pipeline is running
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline is running
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline is running
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
8d ago
2af5970d61 chore(deps): update terraform bunnynet to ~> 0.20 (#246)
All checks were successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
11d ago
2eec2271ca chore(deps): update pre-commit hook posit-dev/air-pre-commit to v0.13.0 (#245)
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline failed
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline failed
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
12d ago
21335d42b4 chore(deps): lock file maintenance (#244)
All checks were successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/38 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
20d ago
8d89e8f794 chore(deps): update dependency nbafrank/uvr to v0.4.8 (#243)
20d ago
e23bd3e539 perf: seed pure-R binaries into a new slot, interleave shards, and stop builds before the timeout (#242)
All checks were successful
ci/crow/cron/weekly-rebuild-missing/28 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/24 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/8 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
Speeds up the full rebuild for a new slot, e.g. the upcoming Alpine version.

## Changes

- **Seed pure-R binaries** (`local/seed-pure-r.R`, `local/seed-helpers.R`), opt-in via the new `SEED_FROM` variable on `build-all-versions-install-deps`.
  About 74% of the ~84k candidate versions have no compiled code and cost ~20s each to build; their R objects are identical across slots.
  Before the build list is computed, each donor candidate is downloaded and verified, then copied server-side:
  - donor must be the same OS family and arch;
  - DESCRIPTION has `Built` (not a CRAN source fallback) with an empty platform and no `libs/`;
  - built by the target's primary R minor;
  - bincraft's `tarball_abi_verdict()` calls it portable across every installed minor (unknown means no seed).

  Each copy gets the `single_builds` and `abi_flat_safety` rows an upload writes, so build-all skips it and the per-minor indexes keep it.
  Re-runs skip existing objects and rewrite rows idempotently.
- **Interleaved shards** in `local/build-all.R` via `shard_slice()`; contiguous alphabetical quarters ranged from 0.1h to 28h.
- **Shared build deadline**: `build-all-versions` sets `BUILD_DEADLINE` from `BUILD_BUDGET_HOURS` (44h, repo timeout 50h); `build-all.R` and `build-newer-r.R` stop cleanly when it passes, so archiving still runs.
- `codename_platform()` replaces the hard-coded codename-to-platform list.

## Testing

- New unit tests for the seed verdict, candidate filter, platform names and deadline; all `local/tests` pass.
- Verdicts checked on real amd64/alpine324 tarballs: R6 2.6.1/2.5.1 and jsonstat seeded, cli refused as compiled.
- `crow lint .crow/` passes.
- The seed has not run against B2/Postgres yet; the first bootstrap run is its end-to-end test.

## Usage

Trigger `build-all-versions` with `target_arch`, `OS`, `OS_VERSION` and `SEED_FROM="alpine324 alpine323"`.
The new Alpine version still needs adding to the `OS_VERSION` options once its image exists.

Reviewed-on: #242
22d ago
63149e246a fix(build-newer-r): pass the system CA bundle to the ABI-verdict query (#241)
Follow-up to #240.
The bulk skip in `build-newer-r.R` never took effect: in all 16 `process-updates` runs on `773add0` (14300–14315) the ABI-verdict query failed with `root certificate file "/root/.postgresql/root.crt" does not exist`.
The fallback did its job: every run logged `0 of 1323 already carry a binary … 1323 left for bincraft` and built exactly as before. So nothing broke, but the run saved no time either.

## Changes

- `local/build-newer-r.R`: pass `sslrootcert = bincraft::postgres_sslrootcert("verify-full")` to the connection, as every other DB script in `local/` already does. With `verify-full` and no `sslrootcert`, libpq looks for `~/.postgresql/root.crt`.

## Verification

- In the `build-env-ubuntu:jammy`, `build-env-redhat:9` and `build-env-alpine:3.24` images, connecting with the distro's CA bundle gets past TLS verification to password authentication (tested with a deliberately wrong password).
- The S3 listings in the same runs logged no errors.

## Behaviour change

- The next runs should log a non-zero "N of M already carry a binary at their routed path" count and skip those candidates without calling bincraft.

Reviewed-on: #241
22d ago
773add042c perf: use ccache and parallel make, and skip already-built newer-R candidates in bulk (#240)
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline failed
22d ago
e7821a75d5 chore(deps): update pre-commit hook davidanson/markdownlint-cli2 to v0.24.0 (#239)
All checks were successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
24d ago
e77686affc fix(ci): install the R packages pipelines use instead of relying on the image (#238)
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline failed
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
Every `process-cran-updates-redhat-9-arm64` run since bincraft v5.5.1 fails with `there is no package called 'progressr'` (e.g. pipeline 14179).

## Cause

bincraft v5.5.1 dropped `lubridate`, `dplyr`, `purrr`, `data.table`, `gert`, `gh` and `cranlike` from its imports.
The pipelines call some of these directly, and so far got them from the build-env image's site library or the shared `R_LIBS_USER` cache.
The arm64 `redhat:9` image has no `progressr` (and no `bincraft`) under R 4.4.3, and no `RPostgres`, `dplyr` or `purrr` under R 4.5.3.
The amd64 image has all of them, which is why only this slot broke.

## Changes

- `process-updates.yaml`: install `progressr` and `lubridate`, which the inline R calls use (`progressr::handlers`, `$INTERVAL`).
- `build-all-versions*.yaml`: install `purrr` for `packages-to-build.R`.
- `weekly-audit-missing.yaml`: install `data.table` for the audit script.
- `local/packages-to-build.R`: drop the unused `dplyr` and `progressr` `library()` calls.
- `reindex`, `weekly-rebuild-reindex`, `weekly-rebuild-missing`, `backfill-*`, `rebuild-abi-gap`, `repair-unsafe-flat-objects`, `prune-stale-flat-binaries`: install `RPostgres`, because bincraft quietly skips the metadata DB without it and the per-minor index build aborts.
- `prune-stale-flat-binaries.yaml`: reinstall bincraft in the re-index step, since its `/tmp/R-pkgs` library doesn't survive from the prune step.

## Verification

- `crow lint .crow/` passes; `prek` passes on the changed files.
- The image contents were checked by exporting the arm64 and amd64 `build-env-redhat:9` images.
- Not yet run in CI.

Reviewed-on: #238
25d ago
c61d951875 fix(repair-built-stamp): patch the published PACKAGES.rds once bincraft drops cranlike (#236)
Some checks failed
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
Follow-up to https://codefloe.com/rpkgs/bincraft/pulls/228 (bincraft#33), which drops the cranlike and desc forks.

## Why

After that change, `upload_package_index()` no longer keeps a `PACKAGES.db`.
It reuses the records of the slot's published `PACKAGES.rds`, as long as each tarball is still listed with the same ETag.
`local/repair-built-stamp.R` patched `PACKAGES.db`, so it would stop having any effect.

## Changes

- `local/repair-built-stamp.R` now patches `Built` in each slot's `PACKAGES.rds` and then re-emits the index.
  - Only the slot's own rows are patched: the generic slot's rows without a `Path`, or a per-minor slot's rows whose `Path` is its minor.
  - A missing stamp is not counted as broken, since bincraft clears it on purpose for source fallbacks.
  - With a bincraft release that still loads cranlike, the script patches `PACKAGES.db` as before, so merge order does not matter.
  - `bincraft::built_stamp()` was never exported, so the script failed at that line before this change; it now calls `bincraft:::built_stamp()`.
- The `GITHUB_PAT` comments in `reindex`, `weekly-rebuild-reindex` and `backfill-flat-safety` now give the current reason: bincraft reads DESCRIPTIONs from raw.githubusercontent.com.
- The README section on index files describes `upload_package_index()` instead of the forks.

## Testing

Tested against a moto S3 bucket, with bincraft installed from the bincraft#228 branch:

- A slot was indexed, then 3 of its 5 `Built` stamps were set to `R 4.5.0; NA; ...`.
- The dry run reported 5 entries, 3 broken.
- `--apply` rewrote the 3 stamps, and the re-emit logged `Index records: 5 reused, 0 read, 0 unreadable.`
- The published `PACKAGES` then had a valid stamp on all 5 records.
- With the released bincraft, which still loads cranlike, the script chose `PACKAGES.db`.

The stale `PACKAGES.db` objects in the slots can be deleted once a bincraft release with #228 is in use.

Reviewed-on: #236
27d ago
8f659ef4f7 fix(renovate): automerge with squash to match the repo's merge settings (#237)
Some checks failed
ci/crow/cron/weekly-rebuild-reindex/9 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline failed
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
Renovate automerge fails in this repo.
The shared preset uses `automergeStrategy: fast-forward`, but devxy/build-cran-binaries only allows squash merges, so Forgejo answers every merge call with `405 Method Not Allowed`.

This overrides the strategy to `squash` for this repo only, so eligible minor/patch/digest PRs merge again in the automerge window.
Same fix as devxy/k8s-talos#419.

Reviewed-on: #237
28d ago
3618168572 fix(ci): pass the metadata DB to per-minor reindexes and fail on errors (#234)
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/auto-apply-patches Pipeline failed
ci/crow/cron/weekly-audit-missing/1 Pipeline was successful
ci/crow/cron/weekly-audit-missing/2 Pipeline was successful
ci/crow/cron/weekly-audit-missing/4 Pipeline was successful
ci/crow/cron/weekly-audit-missing/5 Pipeline was successful
ci/crow/cron/weekly-audit-missing/6 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline failed
Step 1 of rpkgs/bincraft#211: pass the metadata database explicitly so bincraft can drop its implicit production defaults.

## Changes

- Pass `metadata_db_*` explicitly to every per-minor `upload_package_index()` call in `reindex.yaml`, `process-updates.yaml`, `weekly-rebuild-reindex.yaml`, `build-all-versions.yaml` and `prune-stale-flat-binaries.yaml`.
- Replace `|| true` in those per-minor loops with a list of failed minors: every minor is still attempted, then the step exits 1 naming the ones that failed.
- Give the "Upload package indexes" step of `build-all-versions.yaml` the `PGPASS` secret. It never had it, so its per-minor reindexes always aborted and `|| true` hid that.
- Run the CDN purge in `process-updates.yaml` and `prune-stale-flat-binaries.yaml` even when a reindex failed, as `reindex.yaml` and `weekly-rebuild-reindex.yaml` already do, because the generic index was still replaced.
- `local/repair-built-stamp.R` passes the database too, and fails once all minors are tried instead of only printing the error.

The generic (non-per-minor) calls are unchanged: they never read the database.

## Behaviour change

A per-minor reindex that fails now turns the pipeline red instead of passing silently.
Expect build-all-versions runs to start reindexing per-minor slots for real, since they now have the password.

## Ordering

Merge this before rpkgs/bincraft's companion PR is released: `local/install-bincraft.R` installs the latest bincraft tag, and the explicit arguments work with both the current and the next release.

Reviewed-on: #234
28d ago
a310790ad8 chore(deps): update terraform bunnynet to v0.19.2
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
1mo ago
5dad51c76a chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.10
All checks were successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
1mo ago
d992a2b636 fix(ci): give each xvfb-run its own display (#230)
All checks were successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
Every `process-cran-updates-ubuntu-2204-arm64` cron run since pipeline 13744 has failed with `xvfb-run: error: Xvfb failed to start` (e.g. 13829).

## Cause

The newer-R loop added in #216 runs two `xvfb-run` calls back to back: the R-minor-sensitive `process_cran_updates` pass, then `local/build-newer-r.R`.
Without `-a`, `xvfb-run` always uses display `:99`, and on exit it kills its Xvfb without waiting for it.
The second call can therefore start while the old server still holds the `:99` lock, so the new Xvfb refuses to start.
Only ubuntu-2204-arm64 hits this because it is the only image with a second R minor installed, so the loop body only runs there.

## Change

- Default `XVFB_ARGS` to `-a` (`--auto-servernum`) in `process-updates.yaml`, `build-all-versions.yaml` and `weekly-rebuild-missing.yaml`, so each call picks a free display.
- The RHEL 10 `xwfb-run` branch still overrides `XVFB_ARGS` with `-c weston`, so it is unchanged.

## Verification

`crow lint .crow/` passes.
A local repro was not possible (`docker run` hangs on the dev host), so the next ubuntu-2204-arm64 cron run is the real check.

Reviewed-on: #230
1mo ago
3426d5f59f chore(deps): update dependency nbafrank/uvr to v0.4.7
Some checks failed
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
1mo ago
40a0a6e02d fix(patches): cover every RcppParallel 6.x release with the bundled-TBB patch (#228)
Some checks failed
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/auto-apply-patches Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline failed
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline failed
ci/crow/cron/process-updates/6 Pipeline was successful
1mo ago
317990a40f chore(deps): update pre-commit hook posit-dev/air-pre-commit to v0.12.0
All checks were successful
ci/crow/cron/weekly-rebuild-missing/25 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/28 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/9 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/31 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/33 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/32 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/38 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/4 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/6 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/2 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
1mo ago
5231758c00 chore(deps): update terraform bunnynet to v0.19.1
Some checks failed
ci/crow/cron/weekly-rebuild-missing/23 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/28 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/8 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline is running
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline is running
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
1mo ago
b18c21aa8d chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.9
Some checks failed
ci/crow/cron/process-updates/11 Pipeline is running
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
1mo ago
e8b0df0c91 chore(deps): update terraform bunnynet to ~> 0.19
Some checks are pending
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline is running
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
1mo ago
3962ed6d61 fix(installer): install gettext headers on Alpine (#222)
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline failed
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
1mo ago
aa6e5e9dd8 chore(deps): update pre-commit hook davidanson/markdownlint-cli2 to v0.23.3
Some checks failed
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline failed
ci/crow/cron/process-updates/3 Pipeline failed
ci/crow/cron/process-updates/14 Pipeline was successful
1mo ago
212065f5a4 chore(deps): update pre-commit hook editorconfig-checker/editorconfig-checker to v4.0.2
Some checks failed
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/33 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/38 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline failed
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline failed
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
1mo ago
caefd1131f chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.8
Some checks failed
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/auto-apply-patches Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
1mo ago
3325a7bda2 chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.7
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline failed
1mo ago
b0bade879b chore(deps): lock file maintenance
Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline failed
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
2mo ago
6b764d2014 fix(build): build packages requiring newer R on compatible minors (#216)
Some checks failed
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline failed
ci/crow/cron/process-updates/16 Pipeline failed
ci/crow/cron/process-updates/14 Pipeline failed
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
2mo ago
d80d3e814e feat(slots): add a retirement workflow and a drift check (#214)
All checks were successful
ci/crow/cron/weekly-rebuild-missing/23 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/2 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/2 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/24 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/8 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/28 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
## Why

Retiring a slot means three separate things in three separate places, and nothing tied them together.

Alpine 3.22 is what that costs.
It was removed from `local.rpkgs_slots` in `cdn.tf` at some point, so the edge stopped routing it, but it kept:

- a matrix row in **twelve** pipelines
- **six** cron jobs on the Crow server
- roughly **50000 objects** in the bucket

Nightly builds kept producing binaries nobody could reach.
Worse, an unrouted slot is not inert: every request falls through to the flat index, so R 4.4 and R 4.6 clients got `LOAD_FAILED` at `dyn.load()` rather than simply nothing.
It took a fleet-wide `verify_routing=all` run to notice.

## What changed

**`local/check-slots.R`** (`just check-slots`) fails when any `.crow/*.yaml` still targets a slot missing from `local.rpkgs_slots`.
`cdn.tf` stays the source of truth; the checker reads it rather than restating the list.

**`local/retire-slot.R`** (`just retire-slot <codename>`) does the cleanup:

- strips the slot from every pipeline matrix, dropdown option and `OS_VERSION` tag, and moves a dropdown default that pointed at the retired tag
- deletes `amd64/<codename>/` and `arm64/<codename>/` from the bucket
- prints the cron jobs that are left, with the API call, since they live on the Crow server and cannot be removed from here

Dry run by default.
It refuses any slot still listed in `cdn.tf`, so it cannot be pointed at a live slot however it is invoked.

**`.crow/retire-slot.yaml`** runs the asset half in CI, where the B2 credentials exist.

**README** gains a `## Retiring a slot` section with the ordering.
Step 4 before step 2 is the one ordering that actively breaks things: the next nightly rebuilds everything just deleted.

## Verification

Both scripts were run against the tree as it stood at `523424b`, immediately before #213.

The checker names exactly the twelve files that PR edited by hand:

```
.crow/archive-missed-packages.yaml            targets unpublished: alpine322
.crow/backfill-flat-safety.yaml               targets unpublished: alpine-322
.crow/process-updates.yaml                    targets unpublished: alpine-322, alpine322
...
12 file(s) target a slot the edge does not route.
```

`retire-slot.R alpine322 --config-only --apply` reproduces that commit's structural changes byte for byte across all 18 pipeline files, and additionally catches the two `OS_VERSION` dropdowns.
The only differences from the hand-made commit are two prose lines, a usage example and a dropdown `description:`, which the script deliberately leaves alone.

Guards exercised: a live slot (`alpine323`) is refused, an unknown codename is rejected by name, and the asset half refuses to run without `B2_S3_ACCESS_KEY` rather than treating B2's empty unauthenticated listing as an already-clean slot.

`crow lint .crow/` reports all 19 configs valid.
`air` and `jarl` are clean on both new scripts.

## Next

`alpine321` and `alpine322` still hold objects in the bucket (22922 and 25308 records respectively, both architectures).
Once this merges they can be removed with the pipeline this PR adds.

Reviewed-on: #214
2mo ago
416a2d64d9 chore(alpine): drop the deprecated Alpine 3.22 slot (#213)
All checks were successful
ci/crow/manual/verify-repo-routing/11 Pipeline was successful
ci/crow/manual/verify-repo-routing/13 Pipeline was successful
ci/crow/manual/verify-repo-routing/2 Pipeline was successful
ci/crow/manual/verify-repo-routing/15 Pipeline was successful
ci/crow/manual/verify-repo-routing/1 Pipeline was successful
ci/crow/manual/verify-repo-routing/3 Pipeline was successful
ci/crow/manual/verify-repo-routing/4 Pipeline was successful
ci/crow/manual/verify-repo-routing/7 Pipeline was successful
ci/crow/manual/verify-repo-routing/12 Pipeline was successful
ci/crow/manual/verify-repo-routing/8 Pipeline was successful
ci/crow/manual/verify-repo-routing/9 Pipeline was successful
ci/crow/manual/verify-repo-routing/14 Pipeline was successful
ci/crow/manual/verify-repo-routing/10 Pipeline was successful
ci/crow/manual/verify-repo-routing/16 Pipeline was successful
ci/crow/manual/verify-repo-routing/5 Pipeline was successful
ci/crow/manual/verify-repo-routing/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
## Why

Alpine 3.22 is deprecated and should be dropped.

It was never a published slot to begin with.
`local.rpkgs_slots` in `cdn.tf` enumerates eight distros and alpine322 is not one of them, so `UNION_SLOTS` never gated per-minor rewriting for it.
The website's `DistroId` union lists the same eight.
Every request to the slot therefore fell through to the flat index, which holds R 4.5 builds.

## Evidence

The fleet-wide routing verification (pipeline 12591, `verify_routing=all`) measured this end to end.

Across all 16 published slots, both architectures, three R minors and both contractual URL forms: **1056 of 1056 install-and-load checks passed.**

Every failure in the run was alpine322, identical on amd64 and arm64:

```
amd64/alpine322 R 4.4 via arch|generic|flat:  8 of 11
amd64/alpine322 R 4.6 via arch|generic|flat: 10 of 11
arm64/alpine322 R 4.4 via arch|generic|flat:  8 of 11
arm64/alpine322 R 4.6 via arch|generic|flat: 10 of 11
```

The tell is that all three forms agree.
On a routed slot `arch` and `generic` diverge from `flat`, because that divergence *is* the routing.
On alpine322 there is nothing to diverge from.
R 4.5 clients were 11 of 11 on every form, because flat happens to be what they need.

The data itself is not broken, only unreachable.
`alpine322/contrib/4.4/data.table_1.18.6.1.tar.gz` is genuinely `Built: R 4.4.3` and the 4.6 object is `Built: R 4.6.0`.
Correct objects, correct per-minor indexes, never served.

## What changed

- alpine-322 matrix rows and dropdown options removed from the 12 pipelines that carried them, so `=all` no longer fans out to a slot nobody can reach.
- `3.22` removed from the `OS_VERSION` dropdowns in `build-all-versions.yaml` and `repair-built-stamp.yaml`; the latter's default moves to `3.23`.
- Stale `3.22` examples updated in `local/packages-to-build.R`.

`crow lint .crow/` reports all 18 configs valid.

## Also done outside this diff

The six alpine-322 cron jobs are deleted from the Crow server, since a cron whose matrix row is gone keeps firing against nothing:

```
5   process-cran-updates-alpine-322-amd64     0 5/8 * * *
6   process-cran-updates-alpine-322-arm64     30 5/8 * * *
68  weekly-audit-missing-alpine-322-amd64     20 0 * * 0
69  weekly-audit-missing-alpine-322-arm64     30 0 * * 0
82  weekly-rebuild-missing-alpine-322-amd64   0 4 * * 0
83  weekly-rebuild-missing-alpine-322-arm64   10 4 * * 0
```

They are listed here so they can be recreated if this is ever reversed.

## Not done

The published objects and indexes under `amd64/alpine322` and `arm64/alpine322` are left in the bucket.
Deleting them is a separate decision, and nothing routes to them in the meantime.

Reviewed-on: #213
2mo ago
523424bd68 fix(abi): inspect flat objects of packages CRAN has removed (#212)
Some checks failed
ci/crow/manual/reindex/4 Pipeline was successful
ci/crow/manual/reindex/6 Pipeline was successful
ci/crow/manual/reindex/5 Pipeline was successful
ci/crow/manual/reindex/16 Pipeline was successful
ci/crow/manual/reindex/18 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline was successful
ci/crow/manual/reindex/10 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/manual/verify-repo-routing/13 Pipeline was successful
ci/crow/manual/verify-repo-routing/3 Pipeline was successful
ci/crow/manual/verify-repo-routing/1 Pipeline failed
ci/crow/manual/verify-repo-routing/15 Pipeline was successful
ci/crow/manual/verify-repo-routing/2 Pipeline failed
ci/crow/manual/verify-repo-routing/4 Pipeline was successful
ci/crow/manual/verify-repo-routing/17 Pipeline was successful
ci/crow/manual/verify-repo-routing/5 Pipeline was successful
ci/crow/manual/verify-repo-routing/6 Pipeline was successful
ci/crow/manual/verify-repo-routing/9 Pipeline was successful
ci/crow/manual/verify-repo-routing/11 Pipeline was successful
ci/crow/manual/verify-repo-routing/14 Pipeline was successful
ci/crow/manual/verify-repo-routing/16 Pipeline was successful
ci/crow/manual/verify-repo-routing/10 Pipeline was successful
ci/crow/manual/verify-repo-routing/12 Pipeline was successful
ci/crow/manual/verify-repo-routing/7 Pipeline was successful
ci/crow/manual/verify-repo-routing/8 Pipeline was successful
ci/crow/manual/verify-repo-routing/18 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
## Why

The backfill decided which flat objects were worth inspecting by looking the package up in **CRAN's current index**:

```r
compiled_names <- cran[NeedsCompilation == "yes", "Package"]
keep <- flat_pkg %in% compiled_names
```

CRAN lists only what it currently ships. A package CRAN has **archived** is absent from that index, so it is never recognised as compiled and never inspected, and no verdict is ever recorded for it.

`union_index_records()` meanwhile reads the slot's *own* `NeedsCompilation`, finds `yes`, and drops the record because the source classifier flags the package and no safe verdict exists to clear it. The repair cannot rescue it either: it works from recorded verdicts, and there is no row.

The result is unrecoverable, and identical in shape to #132 but from a different cause: dropped from every per-minor index, on every re-index, forever.

## Evidence

`mixedMem` and `vcpen` survived a backfill, two re-indexes and a repair while missing from all three rhel8 per-minor indexes on **both** architectures:

```
rhel8 amd64 4.5: missing=3 [mixedMem timbr vcpen]
rhel8 arm64 4.5: missing=2 [mixedMem vcpen]
```

Neither appears anywhere in either repair log, because neither was ever in the unsafe set. Their per-minor objects are 404 at every minor. And in CRAN's index:

```
mixedMem  CRAN version=ABSENT  NeedsCompilation=ABSENT
vcpen     CRAN version=ABSENT  NeedsCompilation=ABSENT
```

Both removed from CRAN. Their flat records in our own index say `NeedsCompilation: yes`.

## What changed

`NeedsCompilation` now comes from the slot's own flat index, which describes exactly the objects being inspected rather than a different repository's opinion of them.

- Fetched **from the bucket**, not over HTTPS. This runs inside R, so the edge would route the request to a per-minor index and the flat objects would not all be there. Same reason the object listing above it comes from S3 (#203).
- Keyed on `<package>_<version>`, not the package name: a slot can carry several versions and only some of them compile.
- Refuses to proceed on an empty read, so an unreadable index cannot silently mean "nothing is compiled" and skip the entire slot.

## Effect

Re-running the backfill on a slot will now inspect these objects and record verdicts, after which the index writer keeps the safe ones and the repair can act on the unsafe ones. Already-recorded objects are still skipped, so re-running stays cheap.

Reviewed-on: #212
2mo ago
03e007069a fix(ci): do not print a missing timing as "NAs" (#210)
All checks were successful
ci/crow/manual/reindex/17 Pipeline was successful
ci/crow/manual/reindex/7 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/8 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
## Why

A `MISSING_FROM_INDEX` row has no install to time, and `sprintf("%.1fs", NA_real_)` renders it as the literal `NAs`:

```
ROW  arch  amd64  alpine323  4.5  Rcpp  MISSING_FROM_INDEX  |NAs
```

Read quickly, `NAs` looks like a unit rather than a missing measurement.

## What changed

Rows without a timing print the `built` field alone. Every other row is unchanged.

## Where it showed up

Pipeline 12492, the deliberate failure-path check against a slot known to have gaps. That run is otherwise a good result: it caught `Rcpp` missing from the alpine323 4.5 and 4.6 indexes on both contractual URL forms, and it caught the reverse-direction ABI break on the flat slot (objects built under R 4.5.3 failing `dyn.load()` under 4.4), which no previous reprex had surfaced.

Reviewed-on: #210
2mo ago
a84cca1949 fix(abi): prune the objects recorded broken, not every risky package (#211)
## 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.

Reviewed-on: #211
2mo ago
af4cc6f414 feat(ci): verify what clients actually receive from every published slot (#209)
Some checks failed
ci/crow/manual/verify-repo-routing/15 Pipeline was successful
ci/crow/manual/verify-repo-routing/3 Pipeline failed
ci/crow/manual/prune-stale-flat-binaries/15 Pipeline was successful
ci/crow/manual/reindex/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/verify-repo-routing/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
## Why

Everything built so far reasons about the *binaries*: `abi_flat_safety` records what an object's symbols say it can load under, and the index writer drops records on that verdict.
None of it proves what a **client** actually receives, which is the product of the CDN rewrite, the per-minor indexes and the `Path:` field acting together.

The reprex that found the `base64enc` failure ran on a workstation, could only reach amd64, and did not survive the session.
This makes it a pipeline.

## What it does

For every slot, under every R minor the image carries, it installs a fixed package set through each URL form the website documents and checks that each one loads in a fresh subprocess.

| form | repository | user agent |
| --- | --- | --- |
| `arch` | `https://cran.rpkgs.com/<arch>/<codename>/latest` | R's own |
| `generic` | `https://cran.rpkgs.com/` | the string the website's snippet builds |
| `flat` | the arch URL | `curl/8.5.0`, so the edge cannot read an R minor |

`arch` and `generic` are contractual, so a failure there fails the run.
`flat` measures what a client hiding its R minor is exposed to: it is reported and never fatal, because pruning the flat slot is a separate decision.

Two details that matter:

- **CRAN is deliberately absent from `repos`.** A package missing from our index must fail loudly rather than be quietly compiled from source, which would hide exactly the gap this exists to find.
- **One process per form.** `available.packages()` caches its index in `tempdir()` keyed by repository URL, and `arch` and `flat` share a URL. In a single process the second form would read the first form's index and prove nothing.

## Verification

Run against the live repository in `build-env-ubuntu:noble` under R 4.6.0, mid-repair:

```
amd64/noble R 4.6 via arch:    11 of 11 packages usable
amd64/noble R 4.6 via generic: 11 of 11 packages usable
amd64/noble R 4.6 via flat:     8 of 11 packages usable
```

The three `flat` failures are `Rcpp`, `data.table` and `yaml`, each `Built: R 4.4.3` and each failing `dyn.load()` under 4.6.
That is the unrouted-client exposure, measured rather than estimated.

The rows also show the routed forms serving a mix of per-minor and flat objects (`Rcpp` at `R 4.6.0`, `stringi` at `R 4.4.3`), which is the intended behaviour: only objects that cannot load cross-minor get a per-minor copy.

Reviewed-on: #209
2mo ago
4342fa773a fix(abi): do not error on the nothing-to-repair path (#208)
Some checks are pending
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline is pending
ci/crow/manual/reindex/7 Pipeline was successful
ci/crow/manual/backfill-flat-safety/7 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/manual/backfill-flat-safety/8 Pipeline was successful
## Why

Pipeline 12480 shows this for slots with nothing to do:

```
Error in sprintf("%s/%s: %d objects recorded, none unsafe. Nothing to repair.",  :
```

`RPostgres` returns `count(*)` as `integer64`, and `%d` rejects it. So a slot in the **best possible state** — verdicts recorded, nothing unsafe — failed its pipeline step, while slots with real work to do succeeded. Exactly the wrong signal.

## What changed

Formats the count as a string. One line, plus a comment recording why `%d` is wrong here.

Reviewed-on: #208
2mo ago
e3b7212eaf feat(abi): skip objects that already have the per-minor builds they need (#207)
Some checks failed
ci/crow/manual/repair-unsafe-flat-objects/7 Pipeline is pending
ci/crow/manual/repair-unsafe-flat-objects/9 Pipeline failed
ci/crow/manual/repair-unsafe-flat-objects/13 Pipeline failed
ci/crow/manual/repair-unsafe-flat-objects/15 Pipeline failed
ci/crow/manual/repair-unsafe-flat-objects/8 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/10 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/14 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/16 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/17 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/11 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/18 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/12 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/4 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/2 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/3 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/5 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/6 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/1 Pipeline was successful
## Why

The fleet repair (12410) was interrupted after 14 of 18 slots, having done:

```
2522 objects enumerated | 2568 uploads | 1451 symbol overrides
```

Resuming would repeat all of it. The verdict in `abi_flat_safety` describes the **flat** object, and building a per-minor copy does not change that object, so the repair list is identical on the next run. Roughly 2500 objects of duplicated compute.

## What changed

`list-unsafe-flat-objects.R` now drops rows that are already repaired: an object counts as repaired once a per-minor build exists for **every** minor that cannot load the flat one.

- The bucket is the source of truth, listed directly (it cannot be routed).
- Where `unsupported` is empty — unsafe without a recorded reason — a build under every minor the image carries is required, rather than assuming one suffices.
- It reports how many were skipped, so an unexpectedly short list is visible rather than silent.
- It **fails when the bucket cannot be listed**, because an empty listing would make every object look unrepaired and silently restore the full rebuild.

## Verification

The predicate, exercised directly:

```
Rcpp   needs[4.4,4.6]      -> SKIP (repaired)
Rcpp   needs[4.4,4.5,4.6]  -> REBUILD     (4.5 missing)
yaml   needs[4.4]          -> SKIP (repaired)
lobstr needs[]             -> REBUILD     (no recorded minors: all required)
```

## Note

~70 packages fail to build regardless — `glmmTMB`, `tmbstan`, `OpenMx`, `Cyclops`, `RSiena`, `pdftools`, `odbc` among them — all on `uvr sync --install-system-deps`. They keep their unsafe flat binaries and stay broken for the minors they cannot load under. That is a missing-system-dependency problem in the build images, not an ABI one, and needs separate attention.

Reviewed-on: #207
2mo ago
ee4562d44c feat(abi): repair from the recorded verdicts rather than an ad-hoc scan (#206)
Some checks failed
ci/crow/manual/repair-unsafe-flat-objects/13 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/14 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/15 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/16 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/17 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/18 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/6 Pipeline is pending
ci/crow/manual/repair-unsafe-flat-objects/4 Pipeline is pending
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/5 Pipeline failed
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/11 Pipeline failed
ci/crow/manual/repair-unsafe-flat-objects/1 Pipeline failed
ci/crow/manual/repair-unsafe-flat-objects/3 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
## Why

The reprex found 44 routed-path failures: `Rcpp`, `Matrix` and `RJSONIO` served to R 4.4 from 4.5 builds. Two causes, both now fixed (#205 here, #129 in bincraft) — but the repair itself also needs redoing, and the lists it ran from no longer exist.

Those lists came from a one-off local symbol scan, seeded from a candidate set derived on a single slot. That made them a lower bound by construction: the scan found 846 package-slot pairs, while inspecting every object found **4077** unsafe.

`abi_flat_safety` now holds the authoritative answer for every slot, written by the flat-safety backfill from the binaries themselves:

```
95418 inspected, 91325 safe, 4077 unsafe (4.3%)
```

against the 93% of compiled packages the source classifier suspects.

## What it does

- `local/list-unsafe-flat-objects.R` prints the objects recorded as unable to load under some minor, for one slot.
- The workflow rebuilds each under **every** R minor installed in the image, with **no `--sensitive-only` gate**. Since bincraft v5.3.0 the destination is decided by the built binary's symbols, so a package needing a per-minor slot lands there and a portable one lands in the flat slot. Gating on the source classifier is exactly what let `Rcpp` slip through.

## Safety

It **fails loudly when a slot has no verdicts at all**, rather than printing an empty list. An empty repair list is indistinguishable from "nothing to repair" and would read as success while doing nothing — the same shape of silent failure as the missing `PGPASS`.

`crow lint` passes.

## After this

Run it fleet-wide, re-index, then re-run the reprex. The routed paths are the ones that must come back clean; the `flat` form's failures are the separate prune question.

Reviewed-on: #206
2mo ago
cceda03935 fix(ci): do not gate the targeted repair on the source classifier (#205)
All checks were successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/manual/reindex/4 Pipeline was successful
## Why

The repair workflow ran `build-one.R --sensitive-only`. That flag skips any version the **source** classifier does not call r-minor-sensitive — and it misses `Rcpp`.

So the repair skipped `Rcpp` on every slot, leaving its 4.5-built flat binary as the only copy:

```
flat   200  built under R 4.5.3
4.4/   404
4.5/   404
4.6/   404
```

Every R 4.4 client on those slots then failed at `dyn.load()`. A real install check across 8 slots x 3 minors x 3 repository forms found **44 such failures**, `Rcpp`, `Matrix` and `RJSONIO` among them.

## What changed

Drops `--sensitive-only`.

Since bincraft v5.3.0 the destination is decided by the built binary's symbols in `upload_single_binary()`, so building unconditionally is safe and correct: a package that needs a per-minor slot lands there, one that does not lands in the flat slot. Skipping before the build is exactly what removed that decision from the path.

`crow lint` passes.

## Companion

bincraft #129 is the other half: the index build could not compensate either, because it only considered dropping records whose *package* was flagged risky, and `Rcpp` is not — even though the backfill had recorded that object as unable to load under 4.4.

Reviewed-on: #205
2mo ago
f3984f337d fix(ci): authenticate uvr's GitHub resolution in the index workflows (#204)
All checks were successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/3 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/46 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/48 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/47 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/16 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
## Why

The post-backfill re-index (12257) reported failure. Five slots could not write their indexes:

```
WARN Failed to fetch git Remote pat-s/cranlike@s3 (GitHub API error: 403 Forbidden);
     falling back to registry resolution
! Attempt 1/3 to update PACKAGES failed (unused argument (built = built)). Retrying in 5s...
Error: Failed to update PACKAGES after 3 attempts.
       Last error: unused argument (built = built)
```

uvr resolves bincraft's dependencies through the GitHub API, including the `pat-s/cranlike@s3` fork. Unauthenticated, that is rate limited. uvr does not fail on the 403 — it **warns and falls back to the registry copy of cranlike**, which has no `built` parameter, so `update_PACKAGES(built = ...)` dies three retries later.

Affected: alpine323, rhel8, rhel9, rhel10, noble. The remaining 13 slots resolved the fork fine and indexed correctly, which is what makes this insidious: the same pipeline passes or fails on identical input depending on the rate-limit window.

`build-all-versions.yaml` and `rebuild-abi-gap.yaml` already pass `GITHUB_PAT`, which is why they were never affected.

## What changed

Adds the `GITHUB_PAT` secret to `reindex.yaml`, `weekly-rebuild-reindex.yaml` and `backfill-flat-safety.yaml`, with a comment recording why its absence is quiet rather than loud.

`crow lint` passes on all three.

## Context

The re-index itself did what it was meant to. Drops per per-minor index fell from ~1800-2200 to:

```
4.4: avg 129    4.5: avg 172    4.6: avg 145
```

so the per-object safety verdicts recovered roughly 93% of the coverage while still dropping every object that genuinely cannot load. This PR is about the five slots that never got to apply it.

Reviewed-on: #204
2mo ago
844ad9749b fix(abi): enumerate the flat slot from S3, not through the edge (#203)
Some checks failed
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/manual/backfill-flat-safety/8 Pipeline was successful
ci/crow/manual/backfill-flat-safety/6 Pipeline was successful
ci/crow/manual/backfill-flat-safety/16 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/manual/backfill-flat-safety/12 Pipeline was successful
ci/crow/manual/backfill-flat-safety/2 Pipeline was successful
ci/crow/manual/reindex/7 Pipeline failed
ci/crow/manual/reindex/11 Pipeline failed
ci/crow/manual/reindex/15 Pipeline failed
ci/crow/manual/reindex/9 Pipeline failed
ci/crow/manual/reindex/3 Pipeline failed
ci/crow/manual/reindex/13 Pipeline was successful
ci/crow/manual/reindex/17 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline was successful
ci/crow/manual/reindex/4 Pipeline was successful
ci/crow/manual/reindex/1 Pipeline was successful
ci/crow/manual/reindex/2 Pipeline was successful
ci/crow/manual/reindex/5 Pipeline was successful
ci/crow/manual/reindex/6 Pipeline was successful
ci/crow/manual/reindex/10 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/manual/reindex/12 Pipeline was successful
ci/crow/manual/reindex/14 Pipeline was successful
ci/crow/manual/reindex/16 Pipeline was successful
ci/crow/manual/reindex/18 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
## Why

The first backfill run reported:

```
amd64/resolute: 27105 flat binaries, 8187 compiled and worth inspecting
Done: 300 inspected, 7 safe for every minor, 1 unsafe, 292 skipped
```

292 of 300 skipped, and `27105` is larger than the flat index (~24k). Both have the same cause: the script read `PACKAGES.gz` over HTTPS from inside R, which sends an R User-Agent, so **the edge routed it to a per-minor index**. It then enumerated union records carrying `Path: <minor>`, whose objects do not exist at the flat path, and every download 404'd.

An ironic failure given what this whole change is about, and one the trial run existed to catch.

## What changed

- List the flat slot with `s3fs::s3_dir_ls()`, keeping only objects with no `<minor>/` prefix and nothing under `Archive/`. The bucket cannot be routed and is authoritative about what is actually in the flat slot.
- Fetch each object from S3 too. The edge does not rewrite tarball requests, but it does cache them, and the verdict is about the object.
- `NeedsCompilation` still comes from CRAN's own index, which is not behind our edge.

## Verification

The next trial run is the check: `flat objects` should now match the flat index rather than exceed it, and `skipped` should be near zero.

Reviewed-on: #203
2mo ago
c216e44578 feat(abi): backfill per-object flat-slot safety verdicts (#202)
All checks were successful
ci/crow/manual/backfill-flat-safety/17 Pipeline was successful
## Why

bincraft #128 lets `union_index_records()` keep a carried flat record when that specific object is recorded safe. On its own it changes nothing for the records already being dropped, because they are legacy objects with no verdict:

```
4.4: 16398 dropped across 9 indexes  (~1822 each)
4.5: 20076 dropped across 9 indexes  (~2230 each)
4.6: 15532 dropped across 9 indexes  (~1726 each)
```

Every one of those resolves to CRAN source for clients the routing serves correctly. This backfill inspects the objects already in the bucket and writes their verdicts, which is what actually restores the coverage.

## How the verdict is made

By symbols, not heuristics. A binary fails at `dyn.load()` under minor M exactly when it references a symbol M does not export, and the volatile set is derived by diffing the `libR.so` exports of the R builds installed in the image — so a new R release updates it with no curated list to maintain.

That matters here because the source-level classifier calls **93%** of compiled packages risky (`LinkingTo: Rcpp` alone is enough), while a symbol scan of the same slot found **17** packages that break under 4.6 and **72** under 4.4. Recording the real answer per object is what makes the difference between ~2000 dropped records and the few dozen that genuinely need dropping.

## Safety

- **Refuses to run where fewer than two R minors are installed.** With nothing to compare, every verdict would read "safe" — writing a bucket full of false clearances is far worse than writing none.
- Skips packages with no compiled code: they cannot fail this way and are never dropped, so downloading them to prove it is wasted.
- Resumable; already-recorded objects cost one query.

`crow lint` passes.

## Sequencing

Merge and release bincraft #128 first, then run this per slot, then re-index. Verifying the drop counts fall is the point of the exercise, so that re-index is where the fix is confirmed rather than assumed.

Reviewed-on: #202
2mo ago
e1114bc145 fix(ci): give the index writers the metadata database password (#201)
All checks were successful
ci/crow/manual/reindex/11 Pipeline was successful
ci/crow/manual/reindex/9 Pipeline was successful
ci/crow/manual/reindex/15 Pipeline was successful
ci/crow/manual/reindex/13 Pipeline was successful
ci/crow/manual/reindex/17 Pipeline was successful
ci/crow/manual/reindex/1 Pipeline was successful
ci/crow/manual/reindex/3 Pipeline was successful
ci/crow/manual/reindex/5 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/manual/reindex/2 Pipeline was successful
ci/crow/manual/reindex/4 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline was successful
ci/crow/manual/reindex/6 Pipeline was successful
ci/crow/manual/reindex/10 Pipeline was successful
ci/crow/manual/reindex/12 Pipeline was successful
ci/crow/manual/reindex/14 Pipeline was successful
ci/crow/manual/reindex/16 Pipeline was successful
ci/crow/manual/reindex/18 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
## Why

Pipeline 12207 logs one of these per slot:

```
Error: connection to server at "r-binaries.devxy.io" (116.203.165.191), port 15432 failed:
  fe_sendauth: no password supplied
```

bincraft's index build calls `abi_cache_risky_packages()` to decide which packages may be carried from the flat slot into a per-minor index. `reindex.yaml` and `weekly-rebuild-reindex.yaml` never passed `PGPASS`, so the query cannot connect.

It fails soft by design, which is what makes this worth fixing rather than tolerating: the run still reports **success** while using an empty cache-derived risky set. The index is then written as though no package were known risky from the classifier, which is the exact state the cache was added to fix.

`build-all-versions.yaml` already passes `PGPASS`, which is why classification behaved correctly there and silently degraded here.

## What changed

Adds the `PGPASS` secret to both index-writing workflows, with a comment explaining why its absence is invisible rather than loud.

`crow lint` passes on both files.

## Note

The tarball-derived half of the risky set still worked, so indexes written without this are not wrong so much as incomplete: they miss packages that are known risky from classification but have no per-minor tarball yet. A re-index after this merges applies the full set.

Reviewed-on: #201
2mo ago
f9ebb3dba4 fix(abi): prune flat-slot binaries of ABI-risky packages (#200)
Some checks failed
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/manual/reindex/1 Pipeline was successful
ci/crow/manual/reindex/3 Pipeline was successful
ci/crow/manual/reindex/9 Pipeline was successful
ci/crow/manual/reindex/5 Pipeline was successful
ci/crow/manual/reindex/13 Pipeline was successful
ci/crow/manual/reindex/15 Pipeline was successful
ci/crow/manual/reindex/11 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/4 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/6 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/manual/reindex/2 Pipeline was successful
ci/crow/manual/reindex/4 Pipeline was successful
ci/crow/manual/reindex/8 Pipeline failed
ci/crow/manual/reindex/6 Pipeline was successful
ci/crow/manual/reindex/10 Pipeline was successful
ci/crow/manual/reindex/12 Pipeline was successful
ci/crow/manual/reindex/14 Pipeline was successful
ci/crow/manual/reindex/16 Pipeline was successful
ci/crow/manual/reindex/18 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
## Why

`base64enc` still fails to install under R 4.6 even after it was built into the 4.6 slot:

```
base64enc.so: undefined symbol: SETLENGTH
```

The per-minor binary is correct and serves correctly to any client the router can identify. But the **flat slot still holds a binary built under R 4.4.3**, and that is what every client receives when it cannot be routed by R minor.

That object should not exist. `upload_single_binary()` writes an ABI-risky package only to the per-minor path:

```r
if (is_r_minor_sensitive) {
  remote_tarball_path <- file.path(remote_bin_path, minor_version, tarball_name)
} else {
  remote_tarball_path <- file.path(remote_bin_path, tarball_name)
}
```

`base64enc`'s flat binary is a legacy artifact from before it was classified risky. Removing it makes the outcome correct regardless of routing, user agent, downloader or renv configuration, which is the part I could not otherwise guarantee.

## What it does

`local/prune-stale-flat-binaries.R` lists a slot's flat objects, intersects them with the risky set, and deletes them. Deleting is safe here: the source fallback republishes the CRAN source under the same key, so the package stays installable everywhere and compiles against the client's own R, while routed clients keep getting the per-minor binary.

Safety posture, given this deletes production objects:

- **dry run by default**; nothing is removed without `--apply`
- takes an **explicit package list**, so the first runs need not trust the classifier cache at all
- **refuses to proceed on an empty risky set**, which is indistinguishable from an unreachable cache and would otherwise report success having pruned nothing
- **keeps objects whose package CRAN no longer ships**, since there would be no source to fall back to and the package would vanish
- **re-indexes and purges in the same run**. This is not optional: a published index naming deleted files serves 404s, which is worse than the binary it replaced.

## Use

```sh
# dry run first
crow pipeline create devxy/build-cran-binaries \
  --var prune_flat=ubuntu-2604-amd64 --var PRUNE_PACKAGES="base64enc lobstr"

# then apply
crow pipeline create devxy/build-cran-binaries \
  --var prune_flat=ubuntu-2604-amd64 --var PRUNE_PACKAGES="base64enc lobstr" \
  --var PRUNE_APPLY=yes
```

`crow lint` passes.

## Sequencing

Run with an explicit list first, on one slot, and confirm the flat URL then serves source while the per-minor URLs still serve binaries. Only widen to the cache-derived set once the backfill has finished and its output looks sane: the first 250 classifications came back 232 r-minor-sensitive, and a rate that high suggests the source-grep classifier is broader than the set that actually breaks, which is worth checking before pruning thousands of flat binaries.

Reviewed-on: #200
2mo ago
853b924765 feat(abi): backfill classifier verdicts for pre-per-minor packages (#199)
All checks were successful
ci/crow/manual/rebuild-abi-gap/17 Pipeline was successful
ci/crow/manual/backfill-abi-classification Pipeline was successful
## Why

bincraft PR #124 makes the `abi_classification` cache authoritative for the risky-package set, breaking the circularity where a package counted as ABI-risky only once it had already been built per-minor.

On its own that changes nothing for the packages actually at risk. The cache only holds verdicts for packages that passed through the build pipeline after the per-minor scheme existed; everything older has no verdict, and no verdict means the flat binary is carried into every per-minor index. That is exactly how a `base64enc` built under R 4.4.3 reached an R 4.6.1 client:

```
base64enc.so: undefined symbol: SETLENGTH
```

This is the backfill that gives those packages a verdict.

## What it does

`local/backfill-abi-classification.R` enumerates a slot's flat index and runs each compiled package through `bincraft::classify_r_minor_sensitive()`, which looks the verdict up in the cache, and on a miss downloads the CRAN source, classifies it and stores the result.

The verdict is a property of the source, independent of OS, arch and R minor, so **one run populates the cache for every slot**. The arch/codename arguments only choose which flat index to enumerate.

Only `NeedsCompilation=yes` packages are classified: a package with no compiled code has no symbols to bind and cannot fail this way, so proving it by download would be wasted work. On amd64/resolute that is 4585 packages rather than 23218.

Re-running is cheap and resumable: cached verdicts return without touching the network, so a second run costs one query per package and downloads only the remainder.

## Verification

The enumeration was run against the live indexes and matches an independent symbol scan of the same slot exactly:

```
flat binaries: 23218 | due classification: 4585
base64enc included: TRUE
lobstr included:    TRUE
```

4585 is the same population I scanned with `nm -D --undefined-only` when establishing the blast radius, and both packages confirmed to break under 4.6 are in it.

`crow lint` passes.

## Sequencing

Merge after bincraft #124 and after a bincraft release the pipelines pick up, otherwise the verdicts are written but nothing reads them yet. Writing them early is harmless.

Then re-index the slots so the per-minor indexes are rebuilt with the widened risky set. Expect coverage in the per-minor indexes to *drop* slightly as newly-recognised risky packages are dropped rather than served from a mismatched minor; those then need per-minor builds, either through the normal pipeline or the targeted workflow in devxy/build-cran-binaries#198.

Reviewed-on: #199
2mo ago
26406a3e86 feat(ci): add a targeted per-R-minor rebuild workflow (#198)
All checks were successful
ci/crow/manual/rebuild-abi-gap/7 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/9 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/11 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/13 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/17 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/2 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/1 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/15 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/3 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/6 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/5 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/8 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/10 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/12 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/14 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/16 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/18 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/manual/rebuild-abi-gap/4 Pipeline was successful
## Why

A user hit this on amd64/resolute under R 4.6.1:

```
base64enc.so: undefined symbol: SETLENGTH
```

R 4.6 no longer exports `SETLENGTH`:

```
R 4.4: missing -> R_ClosureEnv R_ClosureFormals R_MakeMissingBinding R_PromiseEnv R_PromiseValue R_mkClosure
R 4.5: missing -> R_MakeMissingBinding R_PromiseEnv R_PromiseValue
R 4.6: missing -> R_PromiseEnv R_PromiseValue SETLENGTH
```

`base64enc` calls `SETLENGTH` (`base64.c:206`, `253`), its flat binary was built under R 4.4.3, and it has no per-minor copy at all, so the union index hands that binary to a 4.6 client.

The safety net missed it because the risky set is defined circularly:

```r
risky_packages_across_minors <- function(...) {
  # a package is "risky" iff it already has a tarball in some per-minor slot
```

A package counts as ABI-risky only if it has *already* been built per-minor. `base64enc` never was, and having no new CRAN version it never enters the build list to be classified. So the per-minor protection only covers packages that passed through the pipeline after the scheme existed.

## Scope

Scanning all 4,585 compiled binaries in amd64/resolute's flat index for symbols R 4.6 does not export found 10 referencing `SETLENGTH`. Most already have per-minor builds and are served correctly. Two do not:

```
base64enc_0.1-6   flat=200  4.4=404  4.5=404  4.6=404
lobstr_1.2.1      flat=200  4.4=404  4.5=200  4.6=404
```

(`iotools` lacks a 4.5 copy but 4.5 still exports `SETLENGTH`, so it does not break.)

## What this adds

Rebuilding one package into one minor was only possible with `just rebuild` from a workstation holding the S3 and Postgres credentials. This adds the CI path:

```sh
crow pipeline create devxy/build-cran-binaries \
  --var rebuild_abi_gap=ubuntu-2604-amd64 \
  --var ABI_PACKAGES="base64enc@0.1-6 lobstr@1.2.1" \
  --var ABI_R_MINOR=4.6
```

- reuses `reindex.yaml`'s slot matrix verbatim, so the slot-to-image mapping cannot drift
- runs `build-one.R --sensitive-only`, which reclassifies each version and skips anything not ABI-risky rather than writing it to the wrong slot
- mounts no shared cache volume, so it cannot disturb the build pipeline's per-agent caches
- attempts every package, then exits non-zero if any failed

`crow lint` passes.

## Not in this PR

This is the remediation path, not the fix. The circular `risky_packages_across_minors()` definition is still in place, so new instances of this class can still appear. That is the follow-up.

Reviewed-on: #198
2mo ago