You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@michaelneale@i386 here's how I think we should cut releases from here on. Feedback wanted before anyone writes code.
This is the parent ticket. The work splits into two stages, each its own sub-issue:
Stage 1, release branches with manual backports (release train stage 1: release branches with manual backports #1729). The branch, the ruleset, the workflow changes, the release skill, the docs. The release owner does the cherry-picks by hand. That's everything needed to ship 0.77 off a release branch.
Stage 2, automated backports (release train stage 2: automated backports #1730). A bot opens the cherry-pick PR when a label goes on, auto-merges the clean ones, and leaves conflicted ones as drafts for a human. Built on Stage 1, and only after Stage 1 has survived a release.
Why
v0.76.0 has had 9 RCs since 2026-08-11 and the stable cut keeps resetting. The mechanism:
release.yml:83 rejects a workflow_dispatch from anything except refs/heads/main, and the source SHA is whatever the tip of main happens to be at dispatch time.
The gate is five green Main / <lane> runs on that exact SHA, then a full canary=true Release dispatch with all GPU bundles, then real-host validation per .agents/skills/release-validation. That's hours.
The freeze we've been running is a chat post. The main ruleset (id 20090642) requires a PR and the five PR / <lane> checks, but it has 0 required approvals, no bypass actors, and repo-wide auto-merge is on. Nothing stops a merge. The Do not merge label exists and nothing reads it.
One landmine to check before the next stable dispatch
The pull_request rule on the main ruleset was added after rc9 (rc9 was 2026-09-02, the rule appeared between 2026-09-03 and 2026-09-04). Every dispatch since has been a canary, and canary skips the bump push. The next stable dispatch runs git push ... $source_sha:refs/heads/main at release.yml:187 using GITHUB_TOKEN, and bypass_actors on that ruleset is empty. I expect that push to get rejected. Nobody has hit it yet, so somebody should confirm before scama burns another gate cycle on it.
The model
Cut release/0.76 from the gated SHA. Main never freezes, and agents never target the release branch. Fixes land on main the way they do now, get cherry-picked onto the branch, and the release owner merges the pick. The freeze is a ruleset on release/**, so nobody has to announce anything. The branch just refuses.
The invariant is that nothing ships unless it's also on main. A fix found during validation lands on release/0.76 first, since that's the code being tested, then gets forward-ported to main. Ordinary fixes land on main and get backported to the branch. Same mechanism in both directions, and which direction you're going is policy.
The backport release/0.76 and backport main labels exist from Stage 1 onward. In Stage 1 they're a to-do marker the release owner acts on by hand. In Stage 2 a bot acts on them.
Per-release flow, once stage 1 lands
Release owner cuts release/0.76 at the gated SHA. Bump PR into the branch. Main lanes run on the merge. Main goes to 0.77.0-dev.
canary=true dispatch from the branch, then real-host validation.
Fix lands on main, gets backport release/0.76, the release owner opens the cherry-pick PR (Stage 1) or the bot does (Stage 2), owner merges, re-gate the delta only.
canary=false dispatch from the branch. Tag lands on the branch. The publish step refuses to tag while any commit on the release branch is missing a merged forward-port to main.
Sequencing
Ship 0.76.0 with what we have now. Stage 1 for 0.77. Stage 2 once Stage 1 has carried a release, so the bot automates a flow we've run instead of one we've drawn.
For 0.76.0 today, the tag-push path (release.yml:96) accepts any commit reachable from main, not just the tip. Land the bump via PR, tag that commit, push the tag. The window drops from hours to the minutes between opening and merging one PR. Two caveats. Check the ruleset landmine above first, and the tag-push path needs Package.swift and the SDK console assets prepared in the tag commit (see AGENTS.md), which the dispatch path normally handles for us.
@michaelneale @i386 here's how I think we should cut releases from here on. Feedback wanted before anyone writes code.
This is the parent ticket. The work splits into two stages, each its own sub-issue:
Why
v0.76.0 has had 9 RCs since 2026-08-11 and the stable cut keeps resetting. The mechanism:
release.yml:83rejects aworkflow_dispatchfrom anything exceptrefs/heads/main, and the source SHA is whatever the tip of main happens to be at dispatch time.Main / <lane>runs on that exact SHA, then a fullcanary=trueRelease dispatch with all GPU bundles, then real-host validation per.agents/skills/release-validation. That's hours.mainruleset (id 20090642) requires a PR and the fivePR / <lane>checks, but it has 0 required approvals, no bypass actors, and repo-wide auto-merge is on. Nothing stops a merge. TheDo not mergelabel exists and nothing reads it.One landmine to check before the next stable dispatch
The
pull_requestrule on themainruleset was added after rc9 (rc9 was 2026-09-02, the rule appeared between 2026-09-03 and 2026-09-04). Every dispatch since has been a canary, and canary skips the bump push. The next stable dispatch runsgit push ... $source_sha:refs/heads/mainatrelease.yml:187usingGITHUB_TOKEN, andbypass_actorson that ruleset is empty. I expect that push to get rejected. Nobody has hit it yet, so somebody should confirm before scama burns another gate cycle on it.The model
Cut
release/0.76from the gated SHA. Main never freezes, and agents never target the release branch. Fixes land on main the way they do now, get cherry-picked onto the branch, and the release owner merges the pick. The freeze is a ruleset onrelease/**, so nobody has to announce anything. The branch just refuses.The invariant is that nothing ships unless it's also on main. A fix found during validation lands on
release/0.76first, since that's the code being tested, then gets forward-ported to main. Ordinary fixes land on main and get backported to the branch. Same mechanism in both directions, and which direction you're going is policy.The
backport release/0.76andbackport mainlabels exist from Stage 1 onward. In Stage 1 they're a to-do marker the release owner acts on by hand. In Stage 2 a bot acts on them.Per-release flow, once stage 1 lands
release/0.76at the gated SHA. Bump PR into the branch. Main lanes run on the merge. Main goes to0.77.0-dev.canary=truedispatch from the branch, then real-host validation.backport release/0.76, the release owner opens the cherry-pick PR (Stage 1) or the bot does (Stage 2), owner merges, re-gate the delta only.canary=falsedispatch from the branch. Tag lands on the branch. The publish step refuses to tag while any commit on the release branch is missing a merged forward-port to main.Sequencing
Ship 0.76.0 with what we have now. Stage 1 for 0.77. Stage 2 once Stage 1 has carried a release, so the bot automates a flow we've run instead of one we've drawn.
For 0.76.0 today, the tag-push path (
release.yml:96) accepts any commit reachable from main, not just the tip. Land the bump via PR, tag that commit, push the tag. The window drops from hours to the minutes between opening and merging one PR. Two caveats. Check the ruleset landmine above first, and the tag-push path needsPackage.swiftand the SDK console assets prepared in the tag commit (seeAGENTS.md), which the dispatch path normally handles for us.Open questions