rainix-tag-release must not push to the consumer branch (deploy repos can't rely on unprotected main)
rainix-autopublish was made push-free in #335/#336, but rainix-tag-release (deploy repos) still does git push origin HEAD:$MAIN in its "Commit the snapshot back to main" step. On a branch-protected main that push is rejected (GH006), so the release fails after publishing — the same failure class datacontract hit. Today it only works because deploy repo mains happen to be unprotected, which is not something to rely on.
Why this is NOT a straight copy of the library fix
The library fix wrote nothing to main because the only pushed content was a cosmetic version line. Deploy repos push real, depended-on content: the frozen src/generated/<version>/ deploy-pin snapshot. Two readers consume it FROM main:
- The daily drift sweep — the workflow comment states main carries the current release's pins "so the daily drift sweep has live constants to check."
- The repo's own snapshot tests — e.g.
ExtrospectDeploySnapshotTest's frozen-record walk reads src/generated/ from the working tree; fs_permissions grants it.
So "just stop pushing" breaks both. The fix has to move the snapshot to main by a protection-compatible path, or redirect those readers.
Current flow (for reference)
Human runs the manual on-chain deploy, then pushes sol-v<x.y.z> on the main tip. The workflow: resolve version from the tag → set foundry.toml version → regenerate+freeze the snapshot (deterministic from bytecode, no chain access) → commit → append-only gate → verify live chain matches the fresh pins → publish to Soldeer → push the release commit to main → GitHub release. Note the tag was made on the PRE-release commit, so today the tag does not even point at the released snapshot.
Options (need a ruling on the release-flow change)
A — Reviewed PR before the tag (recommended). Release becomes: deploy on-chain → open a PR that regenerates+commits the snapshot + version bump → PR CI runs the append-only gate + chain-match verification → human merges (normal protected-merge) → tag sol-v<x.y.z> on the merged commit → workflow only publishes to Soldeer + creates the GitHub release, ZERO branch writes. main gets the snapshot via the reviewed PR (protection-compatible); drift sweep + tests unchanged; the tag points at the actual released content (fixes today's divergence); deploy pins (addresses consumers trust) get human review BEFORE they publish. Cost: release is two steps (merge, then tag) instead of one.
B — Workflow opens a PR instead of pushing. Keep the one-step trigger (human tags, workflow does everything) but replace git push origin HEAD:$MAIN with "push a branch + open a PR"; publish + tag + release still happen immediately from the runner tree. main's snapshot lands when the PR merges. Cost: main (and therefore the drift sweep) lags the publish until a human merges; pins publish unreviewed as they do today.
C — Tag-only, redirect the readers. Workflow tags the release commit and pushes only the tag ref (no branch write); rework the drift sweep and the snapshot tests to read src/generated/<version>/ from the tag/Soldeer zip instead of main. Cost: largest — touches the drift sweep (rain-org-health) and every deploy repo's snapshot tests; main stops accumulating the snapshot history.
Recommendation: A — it is the only option that both keeps every current reader working and reviews deploy pins before they ship, and it mirrors the library principle (content reaches main via reviewed PR; the release workflow is read-only publish + tag). B is the smaller change if the two-step release is unacceptable.
Scope
rainix-tag-release.yaml + any helper it calls.
- The append-only-snapshot and chain-verify steps move to run on the PR (option A) or stay in the workflow (B).
- RAINIX_SHA advance + the two-commit pattern as usual.
- Consumer deploy repos: release-process doc update (the new flow). No foundry.toml
[external.package] sweep — deploy repos keep their version line by the existing ruling.
Context
rainix-tag-release must not push to the consumer branch (deploy repos can't rely on unprotected main)
rainix-autopublishwas made push-free in #335/#336, butrainix-tag-release(deploy repos) still doesgit push origin HEAD:$MAINin its "Commit the snapshot back to main" step. On a branch-protected main that push is rejected (GH006), so the release fails after publishing — the same failure class datacontract hit. Today it only works because deploy repo mains happen to be unprotected, which is not something to rely on.Why this is NOT a straight copy of the library fix
The library fix wrote nothing to main because the only pushed content was a cosmetic version line. Deploy repos push real, depended-on content: the frozen
src/generated/<version>/deploy-pin snapshot. Two readers consume it FROM main:ExtrospectDeploySnapshotTest's frozen-record walk readssrc/generated/from the working tree;fs_permissionsgrants it.So "just stop pushing" breaks both. The fix has to move the snapshot to main by a protection-compatible path, or redirect those readers.
Current flow (for reference)
Human runs the manual on-chain deploy, then pushes
sol-v<x.y.z>on the main tip. The workflow: resolve version from the tag → set foundry.toml version → regenerate+freeze the snapshot (deterministic from bytecode, no chain access) → commit → append-only gate → verify live chain matches the fresh pins → publish to Soldeer → push the release commit to main → GitHub release. Note the tag was made on the PRE-release commit, so today the tag does not even point at the released snapshot.Options (need a ruling on the release-flow change)
A — Reviewed PR before the tag (recommended). Release becomes: deploy on-chain → open a PR that regenerates+commits the snapshot + version bump → PR CI runs the append-only gate + chain-match verification → human merges (normal protected-merge) → tag
sol-v<x.y.z>on the merged commit → workflow only publishes to Soldeer + creates the GitHub release, ZERO branch writes. main gets the snapshot via the reviewed PR (protection-compatible); drift sweep + tests unchanged; the tag points at the actual released content (fixes today's divergence); deploy pins (addresses consumers trust) get human review BEFORE they publish. Cost: release is two steps (merge, then tag) instead of one.B — Workflow opens a PR instead of pushing. Keep the one-step trigger (human tags, workflow does everything) but replace
git push origin HEAD:$MAINwith "push a branch + open a PR"; publish + tag + release still happen immediately from the runner tree. main's snapshot lands when the PR merges. Cost: main (and therefore the drift sweep) lags the publish until a human merges; pins publish unreviewed as they do today.C — Tag-only, redirect the readers. Workflow tags the release commit and pushes only the tag ref (no branch write); rework the drift sweep and the snapshot tests to read
src/generated/<version>/from the tag/Soldeer zip instead of main. Cost: largest — touches the drift sweep (rain-org-health) and every deploy repo's snapshot tests; main stops accumulating the snapshot history.Recommendation: A — it is the only option that both keeps every current reader working and reviews deploy pins before they ship, and it mirrors the library principle (content reaches main via reviewed PR; the release workflow is read-only publish + tag). B is the smaller change if the two-step release is unacceptable.
Scope
rainix-tag-release.yaml+ any helper it calls.[external.package]sweep — deploy repos keep their version line by the existing ruling.Context