Add a PR-scoped artifact regeneration workflow - #69
Merged
Conversation
A build-code change necessarily rewrites the recorded build lineage (cascade_meta.rds carries build_script_md5 and source_adapters_md5), so rebuild-contracts cannot go green on a source-only head: the artifact family must be regenerated by a builder whose bytes match this CI runner. There was no in-CI way to obtain one from a PR branch, because refresh-data.yml is gated to master. This workflow rebuilds on the same runtime as rebuild-contracts (same runner, R version, dependency pins, action SHAs, OpenBLAS kernel and thread width) and uploads the four data artifacts, manifest.json and a SHA-256 receipt for reviewed promotion. It is read-only: contents: read, no persisted credentials, and no commit, push or deploy step. It omits only the global.R boot guard (which fails by design on the head being regenerated) and the byte gate (bytes are expected to move); every other contract still runs inside rebuild_all.R. Adds no build input and changes no artifact, so this lands independently of any pending science change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
tgilbert14
marked this pull request as ready for review
August 9, 2026 16:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap this closes
data/cascade_meta.rdsrecordsbuild_script_md5andsource_adapters_md5, so any build-code change rewrites the recorded lineage. That meansrebuild-contractscan never go green on a source-only head — the artifact family has to be regenerated first, by a builder whose bytes match this CI runner.Until now there was no in-CI way to get such a family from a PR branch:
refresh-data.ymlis the only CI builder and its gate and publisher are restricted tomaster. That leaves every build-code change (like #68) structurally stuck.This was found the hard way. Regenerating in an agent container on the same OS (Ubuntu 24.04.4, Posit R 4.5.2, the pinned RSPM closure via pak) produced content-identical artifacts that were still byte-wrong: rebuilding unmodified master there failed to reproduce master's own committed artifacts —
identical content: TRUE, 110113 bytes (CI) vs 110122 (container), a ~9-byte deflate-stream difference no compression setting could dial in. Matching the platform is not the same as being byte-compatible.What it does
Rebuilds on exactly the
rebuild-contractsruntime — same runner, R version, dependency pins, action SHAs, OpenBLAS kernel and thread width — then uploads the four data artifacts,manifest.json, and a SHA-256 receipt for reviewed promotion.Read-only by construction:
permissions: contents: read,persist-credentials: false, and no commit, push, or deploy step. The family leaves only as a workflow artifact; promotion stays a reviewed step.It omits exactly two things from
rebuild-contracts, both deliberately:source("global.R")boot guard — it fails by design on the head being regenerated, which is the whole reason this workflow exists;Every other contract still runs inside
scripts/rebuild_all.R, which stays fail-closed on any scientific, provenance, or manifest violation.The
siblingsinputpinned(default) — rebuild against the source lock recorded in the committed artifact. Values must not move; only lineage changes. This is the correct mode for promoting a build-code change.current— fetch each sibling's default branch. This is the mode that adopts upstream data.Scope
Adds no build input and changes no artifact, so it lands independently of any pending science change. Separated from #68 deliberately: a
workflow_dispatchworkflow must exist on the default branch before it can be dispatched at all.🤖 Generated with Claude Code
https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
Generated by Claude Code