| Filename | Latest commit message | Latest commit date |
|---|---|---|
Implements steps 3 + 4 of #115, building on the classifier merged in #116. Now that bincraft **v4.4.3** applies registry `patch`/`makevars`/`configure_args` to the *target* package build (previously deps-only), a trial patched build is a meaningful acceptance gate, so the "propose" half is viable. ## Step 3 — propose, do not apply - **`local/propose-patches.R`** — for each classified, safe fix affecting a package with no current registry entry, emits a pre-filled `registry.json` entry and validates the candidate set against a *temporary* merged registry (the real one is never touched unless asked). - default: print candidates + validation, **take no action** - `--write`: append entries to `registry.json` + the proposals ledger (you commit + open the PR) - `--open-issue`: post/update a Forgejo tracking issue (reuses the weekly-audit `httr2` + `FORGEJO_TOKEN` pattern) - **`local/trial-build-patch.R`** — isolated bincraft build of one package with the registry applied (no upload/archive/metadata; `patchhash` keeps it out of the real cache). Exit 0/1, so it gates a CI step or manual pre-merge check. The human gate stays: nothing merges. Acceptance = `validate-patches.R` passes (checked automatically) **and** the trial build succeeds. Novel source diffs and unknown signatures are never proposed (they carry `auto = FALSE`). ## Step 4 — feedback loop - **`local/proposal-tracking.R`** (read-only) — signature hit rate (builds/pkgs/addressed/open per signature), proposed-vs-merged (a proposal counts merged once its package is in the registry), and retirement candidates (registry entries whose package no longer fails, i.e. likely fixed upstream). - **`local/proposal-tracking-lib.R`** — the pure metric/ledger helpers. ## Supporting changes - Refactored the classify helpers to expose a pure `build_triage_report()` + a list-returning entry builder; `failing-builds-report.R` now renders from the shared function (no behaviour change). - `validate-patches.R` gains optional `PATCH_DIR`/`REGISTRY_FILE` overrides (backward-compatible) so a candidate registry can be validated in isolation. - Documented the propose/trial-build/tracking workflow in `local/patches/README.md`. ## Verification - 71 unit tests pass (incl. new `test-proposal-tracking-lib.R`) under the Dockerized R 4.5.3 build env. - All pre-commit hooks pass (`air-format`, `validate-patches`, prettier, etc.). - Smoke-tested all three entrypoints end-to-end with a stubbed DB: dry-run, `--write` (produces a registry that passes the canonical validator + a valid ledger, then reverted), and the tracker. Closes #115 Reviewed-on: #117 |
||
| .. | ||
| fs | ||
| RcppParallel | ||
| README.md | ||
| registry.json | ||
Patch Registry
This directory contains the curated registry of per-package build-time patches consumed by bincraft's patches argument.
Schema
The registry is defined in registry.json as an array of patch entries. Each entry specifies lightweight build-time overrides (environment variables, configure arguments, Makevars) and optionally a source diff to apply before building.
Field semantics
| Field | Type | Required | Description |
|---|---|---|---|
package |
string | yes | CRAN package name. |
versions |
string | yes | "*" for any, a constraint such as ">=5.1.0", or an exact version "5.1.11-2". Env-tier fixes are typically "*"; source diffs are normally exact or lower-bounded because a diff is pinned to the source it was generated against. |
platforms |
array of strings | yes | Matched against the running build's platform tokens — distro family (alpine, ubuntu, redhat), codename (ubuntu-2604, alpine-324), and arch (amd64, arm64). An entry matches if any listed token matches any build token. ["*"] matches all platforms. |
env |
object | no | Environment variables exported only for this package's isolated build. |
configure_args |
array | no | Arguments passed as --configure-args to the isolated build. |
makevars |
object | no | Key/value pairs written into a package-local Makevars for the isolated build. |
patch |
string or null | no | Path (relative to local/patches/) to a unified diff applied to the unpacked CRAN source before building. |
reason |
string | yes | Human explanation, surfaced in logs and metadata. |
Adding an entry
To add a new patch entry:
-
Add an object to the array in
registry.jsonwith the fields documented above. Start with lightweight overrides (environment variables, configure arguments, Makevars) before resorting to source diffs. -
If a source diff is needed, place it in
local/patches/<package>/<file>.patchand reference its path in thepatchfield. For example, a diff forRcppParallelwould go inlocal/patches/RcppParallel/fix.patchand be referenced as"patch": "RcppParallel/fix.patch". -
The
reasonfield should clearly explain why the patch is needed and what problem it solves.
Validation
The registry is validated and applied by bincraft during the build process. For manual validation, run the validator from the repo root:
Rscript local/validate-patches.R
This validates the schema, referenced patch-file existence, and checks for duplicate entries across platforms and versions.
Triaging failures into entries
local/failing-builds-report.R turns recorded build failures into triaged patch suggestions instead of hand-scraping Crow logs (issue #115, steps 1 + 2).
It is read-only: it queries single_builds WHERE error_occurred, groups failures by a normalised error fingerprint, classifies each group against the known signature set in local/failing-builds-classify.R, and prints a report.
# All platforms/arches; needs the DB password.
PGPASS=... Rscript local/failing-builds-report.R
# Restrict scope and also emit a machine-readable report.
PGPASS=... Rscript local/failing-builds-report.R --platform alpine-321 --arch amd64 --json report.json
Each group is tagged AUTO-PROPOSABLE (a known env/makevars lever, or an already-curated package patch, safe to pre-fill as a registry.json entry) or HUMAN TRIAGE (unknown signature, or a fix that needs a novel source diff).
For auto-proposable groups it prints a ready-to-review registry entry; still run validate-patches.R and an isolated trial build before merging.
Novel source diffs and unknown signatures stay human-reviewed by design.
Add a new signature by appending a rule to build_signatures() in local/failing-builds-classify.R; the pure helpers are covered by local/tests/test-failing-builds-classify.R.
Proposing entries (step 3: propose, do not apply)
local/propose-patches.R takes the auto-proposable candidates one step further: for each classified, safe fix affecting a package with no current entry, it emits a pre-filled registry.json entry and validates the candidate set against a temporary merged registry (the real registry is never touched unless you ask).
The human gate stays: it never merges.
# Default: print candidates + validation, take no action.
PGPASS=... Rscript local/propose-patches.R
# Append the candidates to registry.json + the proposals ledger (you commit + open the PR).
PGPASS=... Rscript local/propose-patches.R --write
# Or post/update a Forgejo tracking issue instead (needs FORGEJO_TOKEN).
PGPASS=... FORGEJO_TOKEN=... Rscript local/propose-patches.R --open-issue
The acceptance criteria before merging a proposal are: validate-patches.R passes (checked automatically), and an isolated trial build succeeds.
Run the trial build inside the failing platform's build-env image; it uploads/archives nothing and writes no metadata:
Rscript local/trial-build-patch.R <package>
--write and --open-issue also append to local/patches/proposals-log.json, a ledger of what was proposed.
Feedback loop (step 4)
local/proposal-tracking.R reports the signature hit rate, proposed-vs-merged status (a proposal counts as merged once its package appears in the registry), and retirement candidates (registry entries whose package no longer appears in any current failure, so the upstream cause was likely fixed).
It is read-only.
PGPASS=... Rscript local/proposal-tracking.R --json metrics.json
The pure metric/ledger helpers live in local/proposal-tracking-lib.R and are covered by local/tests/test-proposal-tracking-lib.R.