Repository navigation
UN-4522 [MISC] Patch a released line and add a late target in the release tooling - #2441
chandrasekharan-zipstack merged 25 commits into
Conversation
A target whose first RC comes after another target's GA on the line (on-prem enabled after cloud GA) no longer takes the line back to stabilizing. relstate derives "late" from registry push times, and the line state counts a late target with no GA as stabilized: Backport picks only RM-confirmed security/critical fixes, Retire does not list the line, and the OSS line keeps stabilized/X.Y. Take RC build drops the job that deleted that tag. The owed-picks table on a forced late target is information only and asks the RM to label any fix the line needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A target added after the line's first GA keeps the line stabilized until its own GA, so retiring that line early is held like a stabilized on-prem line: refused without force. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings relmgr.py and test_links.py in line with the enterprise repo, so .github/release is identical in both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With confirm_stabilized, a plain fix now goes onto the stabilized lines named in branches. With branches empty it skips them, and the summary says why. Security and critical routing and the push-to-main rescan are unchanged. Release state lists, per stabilized line, the main fixes merged since its latest GA that it lacks, ready to paste into Backport commits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plain fix can now reach a stabilized line through Backport with confirm_stabilized and branches, so the summary says how instead of asking for a security or critical label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a rerun Take RC plans builds only for the targets an earlier run missed. If that earlier run failed before its prerelease job, the release the rerun creates listed only those targets. The plan step now also outputs the ticked targets, which are all built once the run succeeds, and the prerelease job lists those. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
relmgr.line normalises "0.186" or "release/0.186" to "0.186" and refuses anything else; relmgr.vtag adds the leading v. Backport's branches input goes through line, and its Next hints print X.Y. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It takes release lines X.Y; the CLI flag is --lines and the Next hints print -f lines=. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Release line inputs no longer strip whitespace and accept ASCII digits only, so Take RC's concurrency group (keyed on the raw input) cannot be split by a padded value. Backport `lines` splits on commas or spaces. - Retire's early-retirement refusal checks the cloud target is actually stabilized; a late cloud target with no GA needs force, like on-prem. - Backport: a plain fix naming a stabilized line without confirm_stabilized says so (warning) instead of "not a target". - State's patch list reads from each line's first GA, not its latest, so fixes merged before a later patch are not dropped. A line with no GA, or a gh/git failure on one line, is reported instead of failing the run. - Comments and docstrings follow the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chandrasekharan-zipstack
left a comment
There was a problem hiding this comment.
Review: round 1 (review-deep, INITIAL) at be2c5ff30e9639cbf93e26b46d534034955c20bc
Self-review round 1, run as unstract:review-deep because review-shallow refuses this PR (it changes CI workflows). Diff: merge base a1940732b9c65007b77e712fcd376ab696ab7267 to be2c5ff30, 10 files, 1051 lines. The base was fetched fresh. Signals raised lenses 4, 8, 11, 16 and 17.
Verdict — REQUEST CHANGES
Summary — Critical: 0 · High: 0 · Medium: 5 · Low: 7 · Lenses run: 19/19 (5, 6, 12, 14, 18 and 19 are N/A, with reasons below)
Security deep-dive: done, 0 findings (no candidate reached confidence 8).
Boundary sweep: 6 outbound sinks traced (step summary, ::warning::/::error:: lines, PR comments, held notes, state.json, the run log). None carries a credential or token.
Findings
The 12 numbered findings are posted as inline comments below.
Unanchored findings
- The PR body says "The RC prerelease target list is fixed". In this repo that change only adds a test,
TakeRcPrerelease, which reads the enterprise workflow. The body should say so. - Lens 1: this repo states no PR-title convention. The title follows the workspace convention, and the type
[MISC]fits release tooling. - The public functions
oss.reopenandrelstate.reopensare removed. Neither repo has a caller left.
Lens checklist
- Correctness — Clean
- Readability & maintainability — Clean
- Error handling — See findings #1, #8
- Security — Clean (security deep-dive done, boundary sweep clean)
- Data integrity & migrations — N/A — no database, migration or persisted schema; state.json is regenerated on every run
- Concurrency — N/A — no new concurrency; the workflow concurrency groups are unchanged
- API compatibility — See findings #3, #4, #9, #10, #11 (consumer search done in both repos by the orchestrator)
- Reliability & resilience — Clean
- Performance — Clean
- Observability — Clean
- Operational safety — Clean
- LLM/agent — N/A — no prompt, model or agent configuration
- Tests — See findings #2, #5, #12
- Dependencies & build — N/A — no dependency or lockfile change
- Style & lint — Clean (pre-commit ruff and ruff-format passed at this commit)
- Doc accuracy — See findings #1, #6, #7
- Cross-document consistency — See findings #7
- On-prem experience — N/A — release tooling for the repo's own CI; nothing reaches a customer cluster
- Scaling & workload lifecycle — N/A — no worker, scaling or lifecycle configuration
I assessed these lenses myself: 4, 5, 6, 7 (the consumer search), 8, 11, 12, 14, 15, 17, 18 and 19.
Open questions for the author
None.
Assumptions made
- The paired enterprise PR merges together with this one, as the body says. Findings #3 and #4 rely on that.
cost: agents=7 wall=12:36 lenses-examined=13 of 19 files=10 lines=1051
Unanchored findings
.github/workflows/backport.yaml:8(outside the diff hunk): #7 [Low] [Lens 16, 17] — The OSS backport.yaml header is stale —.github/workflows/backport.yaml:L8(outside the diff hunk). It still says "Security/critical fixes reach stabilized lines only with confirm_stabilized". A plain fix now also reaches them, withconfirm_stabilizedandlines. Made stale by:.github/workflows/backport.yaml:L24.
The State list bounded each line at its first GA, which dropped a fix still owed from before it: a label added after the GA, or a push run that failed or ran after Promote. The trailer filter already drops what was picked, so the cutoff only removed owed commits. The PR listing still starts at the oldest GA. Also adds a test that the Backport Pick step passes only flags and inputs that exist, and corrects the Backport workflow header: a plain fix also reaches a stabilized line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every gh call Backport and its record job make now goes through one helper that retries a 5xx, a reply cut short, or a timeout, twice with a short wait. A 4xx is GitHub's answer and is never retried. The squash merge and PR create are writes that can land although gh reports a failure, so they are not retried blindly. A failed squash checks whether the PR merged before retrying or failing. A failed create looks for the PR first; when none exists after the retries, the run deletes the head it pushed, so the next run picks the commit again instead of finding an orphan head. The 405 "Base branch was modified" retry is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fix Backport failed to land on a stabilizing line used to show first at Promote's convergence gate, after QA had tested the RC. Release state now lists, per stabilizing line, the owed main fixes the line lacks, as Backport `commits`, and the open backport conflict PRs on it here and in the OSS repo. A clean line says none; a listing that fails says so rather than reading as clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each release workflow's run summary now renders commits, release lines, tags and PRs as links to the repo they live in: OSS pins, OSS commits and cross-repo conflict PRs link to the OSS repo. Lines people paste into Backport (the commits lists and gh commands) stay plain. Retire links a branch only on a dry run and the archive tag only on a real run, since a real run deletes the one and creates the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub's commit-to-PR lookups can miss a squash merge, so Backport read
a merged fix as "no PR" and skipped it.
- fix_class: when commits/{sha}/pulls is empty, take the trailing (#N)
from the commit subject and accept that PR only if it is merged and
its merge_commit_sha equals the commit. A ::notice:: records the use.
- dispatch: a PR named by number is classed from the PR already
fetched, without the backward lookup.
- rescan: an unclassifiable commit fails the run with ::error:: until
it is picked or declined.
- dispatch: a named commit with no PR is a failed row, not "not a fix".
A PR whose class is not a fix stays a skip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI sets GITHUB_SERVER_URL, and summaries render links only when it is set, so the release tests passed locally and failed in CI. Pin it in each suite that reads summaries and assert the linked form we ship. Checks of the plain form now clear the variable explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[High impact] The PR appears safe to merge with the paired enterprise change described in the rollout.
|
Backport now ends red when an owed fix is not picked, declined, held for the RM, on a pick PR, or answered by a failed row of the run. The skips that stood for a missed pick are now errors; the warnings that remain say why they are safe. The State run also runs daily. It fails on an owed fix on a stabilizing line that was merged more than OWED_GRACE ago and not picked, on any unclassifiable commit, and on a backport conflict PR open longer than CONFLICT_GRACE. A held security or critical fix is listed, not failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…before a Backport run oss.py rc used to only preview the OSS line's convergence gate. Now it blocks on MISSING picks unless --force is given, as promote does. A gate that did not run also blocks. When forced, it prints a warning and writes the override and its reason to the --notes file. When Backport leaves a commit unsettled that this run never touched, the error and the summary now say the commit was owed before this run and was not caused by it. The run still fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a pick's PR create and the follow-up lookup both fail, the head stays with no PR. A later run that finds the head older than the pick timeout, with no PR open or closed, now deletes it and fails the row, so the run after that picks the fix again. A head whose delete fails still asks for a manual delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frontend Lint Report (Biome)✅ All checks passed! No linting or formatting issues found. |
Keeps .github/release identical to the cloud repo, whose Take RC now carries its notes onto the RC prerelease. The new tests skip here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unstract test resultsPer-group results
Critical paths
|
TakeRcNotes sat after the unittest.main() block, so running the file directly exited before collecting it. Move the block to the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
105470d
into
un-4522/ci-skip-release-paths
|
…kip product tests for .github/.claude (#2431) * chore: sync the release tooling with the cloud cleanup Mirror the cloud release tooling: refusals now say a release manager may override with force, Cut accepts a minor whose line was abandoned, and the test for the retired cloud workflows is gone with them. Mark create-release as the public OSS release, separate from the ee- release-branch tags, and drop the "V2 " prefix from the release workflow names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix(release): abandon deletes the on-prem RC chart versions Mirror of the release tooling change that pushes an on-prem RC chart with each on-prem RC. Chart versions carry no "v" prefix, so the RC pattern Abandon deletes by accepts both forms. The test for the RC build summary's chart result is mirrored too, so the release tooling stays identical between the two repositories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix(release): keep the newest RC chart on abandon and never reuse its RC Mirror of the release tooling change in the cloud repository. Abandon sorts chart versions numerically, so it keeps rc.10 rather than rc.9, and RC allocation skips RC numbers that the on-prem RC chart already holds. The repository has no on-prem target, so the allocation change does nothing here; it keeps the release tooling identical in both repositories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * docs: trim release comments to the why Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: State skips RC numbers the on-prem RC chart holds Take RC build already skips them, so State showed an RC number the build would not use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: skip the product test suites for .github and .claude changes A change to ci-test.yaml itself still runs them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: run the release tooling tests inside ci-test so report gates on them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: run release-tests when any release path changes The release paths shared the `every` quantifier of the ignore filter, so no file could match them all and release-tests always skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * UN-4522 [MISC] Patch a released line and add a late target in the release tooling (#2441) * ci: keep a line stabilized when a target is added late A target whose first RC comes after another target's GA on the line (on-prem enabled after cloud GA) no longer takes the line back to stabilizing. relstate derives "late" from registry push times, and the line state counts a late target with no GA as stabilized: Backport picks only RM-confirmed security/critical fixes, Retire does not list the line, and the OSS line keeps stabilized/X.Y. Take RC build drops the job that deleted that tag. The owed-picks table on a forced late target is information only and asks the RM to label any fix the line needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: a late target with no GA needs force to retire A target added after the line's first GA keeps the line stabilized until its own GA, so retiring that line early is held like a stabilized on-prem line: refused without force. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: sync the release tooling with the enterprise copy Brings relmgr.py and test_links.py in line with the enterprise repo, so .github/release is identical in both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: patch a released line through Backport dispatch With confirm_stabilized, a plain fix now goes onto the stabilized lines named in branches. With branches empty it skips them, and the summary says why. Security and critical routing and the push-to-main rescan are unchanged. Release state lists, per stabilized line, the main fixes merged since its latest GA that it lacks, ready to paste into Backport commits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: owed picks summary points to Backport for a released line A plain fix can now reach a stabilized line through Backport with confirm_stabilized and branches, so the summary says how instead of asking for a security or critical label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: an RC prerelease lists every ticked target On a rerun Take RC plans builds only for the targets an earlier run missed. If that earlier run failed before its prerelease job, the release the rerun creates listed only those targets. The plan step now also outputs the ticked targets, which are all built once the run succeeds, and the prerelease job lists those. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: accept a release line as X.Y and a version tag without its v relmgr.line normalises "0.186" or "release/0.186" to "0.186" and refuses anything else; relmgr.vtag adds the leading v. Backport's branches input goes through line, and its Next hints print X.Y. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: rename the Backport input branches to lines It takes release lines X.Y; the CLI flag is --lines and the Next hints print -f lines=. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: address round-1 review of the patch dispatch - Release line inputs no longer strip whitespace and accept ASCII digits only, so Take RC's concurrency group (keyed on the raw input) cannot be split by a padded value. Backport `lines` splits on commas or spaces. - Retire's early-retirement refusal checks the cloud target is actually stabilized; a late cloud target with no GA needs force, like on-prem. - Backport: a plain fix naming a stabilized line without confirm_stabilized says so (warning) instead of "not a target". - State's patch list reads from each line's first GA, not its latest, so fixes merged before a later patch are not dropped. A line with no GA, or a gh/git failure on one line, is reported instead of failing the run. - Comments and docstrings follow the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: list every owed fix since the cut in Patch a released line The State list bounded each line at its first GA, which dropped a fix still owed from before it: a label added after the GA, or a push run that failed or ran after Promote. The trailer filter already drops what was picked, so the cutoff only removed owed commits. The PR listing still starts at the oldest GA. Also adds a test that the Backport Pick step passes only flags and inputs that exist, and corrects the Backport workflow header: a plain fix also reaches a stabilized line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: retry transient GitHub failures in Backport Every gh call Backport and its record job make now goes through one helper that retries a 5xx, a reply cut short, or a timeout, twice with a short wait. A 4xx is GitHub's answer and is never retried. The squash merge and PR create are writes that can land although gh reports a failure, so they are not retried blindly. A failed squash checks whether the PR merged before retrying or failing. A failed create looks for the PR first; when none exists after the retries, the run deletes the head it pushed, so the next run picks the commit again instead of finding an orphan head. The 405 "Base branch was modified" retry is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: list missed picks on stabilizing lines in Release state A fix Backport failed to land on a stabilizing line used to show first at Promote's convergence gate, after QA had tested the RC. Release state now lists, per stabilizing line, the owed main fixes the line lacks, as Backport `commits`, and the open backport conflict PRs on it here and in the OSS repo. A clean line says none; a listing that fails says so rather than reading as clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: link commits, lines, tags and PRs in release run summaries Each release workflow's run summary now renders commits, release lines, tags and PRs as links to the repo they live in: OSS pins, OSS commits and cross-repo conflict PRs link to the OSS repo. Lines people paste into Backport (the commits lists and gh commands) stay plain. Retire links a branch only on a dry run and the archive tag only on a real run, since a real run deletes the one and creates the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: class a squash merge GitHub cannot map back to its PR GitHub's commit-to-PR lookups can miss a squash merge, so Backport read a merged fix as "no PR" and skipped it. - fix_class: when commits/{sha}/pulls is empty, take the trailing (#N) from the commit subject and accept that PR only if it is merged and its merge_commit_sha equals the commit. A ::notice:: records the use. - dispatch: a PR named by number is classed from the PR already fetched, without the backward lookup. - rescan: an unclassifiable commit fails the run with ::error:: until it is picked or declined. - dispatch: a named commit with no PR is a failed row, not "not a fix". A PR whose class is not a fix stays a skip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: pin the server URL so summary tests assert the linked form CI sets GITHUB_SERVER_URL, and summaries render links only when it is set, so the release tests passed locally and failed in CI. Pin it in each suite that reads summaries and assert the linked form we ship. Checks of the plain form now clear the variable explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: fail a release run that leaves an owed fix unsettled Backport now ends red when an owed fix is not picked, declined, held for the RM, on a pick PR, or answered by a failed row of the run. The skips that stood for a missed pick are now errors; the warnings that remain say why they are safe. The State run also runs daily. It fails on an owed fix on a stabilizing line that was merged more than OWED_GRACE ago and not picked, on any unclassifiable commit, and on a backport conflict PR open longer than CONFLICT_GRACE. A held security or critical fix is listed, not failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: block an RC on the OSS line's missing picks, and name fixes owed before a Backport run oss.py rc used to only preview the OSS line's convergence gate. Now it blocks on MISSING picks unless --force is given, as promote does. A gate that did not run also blocks. When forced, it prints a warning and writes the override and its reason to the --notes file. When Backport leaves a commit unsettled that this run never touched, the error and the summary now say the commit was owed before this run and was not caused by it. The run still fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: delete a pick head that never got a PR, so the next run picks again When a pick's PR create and the follow-up lookup both fail, the head stays with no PR. A later run that finds the head older than the pick timeout, with no PR open or closed, now deletes it and fails the row, so the run after that picks the fix again. A head whose delete fails still asks for a manual delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: cover Take RC notes on the RC prerelease Keeps .github/release identical to the cloud repo, whose Take RC now carries its notes onto the RC prerelease. The new tests skip here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: run the Take RC notes tests TakeRcNotes sat after the unittest.main() block, so running the file directly exited before collecting it. Move the block to the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * fix: retry gh calls with exponential backoff and jitter Five tries, waits doubling from 2-4 s with jitter so parallel jobs do not retry in step. A primary or secondary rate limit (403 or 429) is now retried, waiting at least a minute as GitHub asks when Retry-After is not visible. Other 4xx answers are still never retried. Squash, PR create and convgate's PR and comment lookups use the same schedule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * chore: drop a comment that restates GH_TRIES Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: sync release tooling review fixes; ci-test header names every skipped path - Backport no longer deletes the head when PR create still fails after its retries: GitHub may have opened a PR the listing does not show yet, and the delete would close it as a decline. The next run cleans up an orphan head once it is past the pick timeout. - The record job refuses to decline a PR the release App closed. - A dispatch no longer fails on a fix it did not touch that merged less than the State grace period ago. - Take RC: test that a gate error on any target wins over MISSING picks, and name everything force overrides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: promote order no longer blocks Take RC; a convgate usage error is an error Take RC runs convgate, which exited 2 for an older line not GA yet as well as for MISSING picks. A newer line takes RCs while an older one stabilizes, so that failed every first RC of an overlapping cut. The order still prints in the Promote preview; Promote enforces it. An argparse usage error also exited 2 and read as MISSING picks, which force could override; it now returns 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * test: keep the convgate exit-code test off the network It reached gh for conflict PR and failure-comment lookups, which passed only where gh is logged in. CI runs it without a token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: send gh retry warnings to stderr oss.py promote prints the new tag on stdout, and promote.yaml captures it. A retried gh call printed its warning there too, so a recovered GitHub error put the warning into the captured tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * docs: state the registry layout late-target detection relies on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: time a GA by its Promote tag when it shares the RC registry version With one repository for RC and stable images, the GA tag lands on the RC image version, whose create time is the RC build. An on-prem RC built between that RC and the cloud GA then read as late, which marked the line stabilized. A GA now counts from the later of its registry time and the tagger date of Promote's annotated tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…kip product tests for .github/.claude (#2431) * chore: sync the release tooling with the cloud cleanup Mirror the cloud release tooling: refusals now say a release manager may override with force, Cut accepts a minor whose line was abandoned, and the test for the retired cloud workflows is gone with them. Mark create-release as the public OSS release, separate from the ee- release-branch tags, and drop the "V2 " prefix from the release workflow names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix(release): abandon deletes the on-prem RC chart versions Mirror of the release tooling change that pushes an on-prem RC chart with each on-prem RC. Chart versions carry no "v" prefix, so the RC pattern Abandon deletes by accepts both forms. The test for the RC build summary's chart result is mirrored too, so the release tooling stays identical between the two repositories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix(release): keep the newest RC chart on abandon and never reuse its RC Mirror of the release tooling change in the cloud repository. Abandon sorts chart versions numerically, so it keeps rc.10 rather than rc.9, and RC allocation skips RC numbers that the on-prem RC chart already holds. The repository has no on-prem target, so the allocation change does nothing here; it keeps the release tooling identical in both repositories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * docs: trim release comments to the why Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: State skips RC numbers the on-prem RC chart holds Take RC build already skips them, so State showed an RC number the build would not use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: skip the product test suites for .github and .claude changes A change to ci-test.yaml itself still runs them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: run the release tooling tests inside ci-test so report gates on them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * ci: run release-tests when any release path changes The release paths shared the `every` quantifier of the ignore filter, so no file could match them all and release-tests always skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * UN-4522 [MISC] Patch a released line and add a late target in the release tooling (#2441) * ci: keep a line stabilized when a target is added late A target whose first RC comes after another target's GA on the line (on-prem enabled after cloud GA) no longer takes the line back to stabilizing. relstate derives "late" from registry push times, and the line state counts a late target with no GA as stabilized: Backport picks only RM-confirmed security/critical fixes, Retire does not list the line, and the OSS line keeps stabilized/X.Y. Take RC build drops the job that deleted that tag. The owed-picks table on a forced late target is information only and asks the RM to label any fix the line needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: a late target with no GA needs force to retire A target added after the line's first GA keeps the line stabilized until its own GA, so retiring that line early is held like a stabilized on-prem line: refused without force. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: sync the release tooling with the enterprise copy Brings relmgr.py and test_links.py in line with the enterprise repo, so .github/release is identical in both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: patch a released line through Backport dispatch With confirm_stabilized, a plain fix now goes onto the stabilized lines named in branches. With branches empty it skips them, and the summary says why. Security and critical routing and the push-to-main rescan are unchanged. Release state lists, per stabilized line, the main fixes merged since its latest GA that it lacks, ready to paste into Backport commits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: owed picks summary points to Backport for a released line A plain fix can now reach a stabilized line through Backport with confirm_stabilized and branches, so the summary says how instead of asking for a security or critical label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: an RC prerelease lists every ticked target On a rerun Take RC plans builds only for the targets an earlier run missed. If that earlier run failed before its prerelease job, the release the rerun creates listed only those targets. The plan step now also outputs the ticked targets, which are all built once the run succeeds, and the prerelease job lists those. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: accept a release line as X.Y and a version tag without its v relmgr.line normalises "0.186" or "release/0.186" to "0.186" and refuses anything else; relmgr.vtag adds the leading v. Backport's branches input goes through line, and its Next hints print X.Y. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: rename the Backport input branches to lines It takes release lines X.Y; the CLI flag is --lines and the Next hints print -f lines=. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: address round-1 review of the patch dispatch - Release line inputs no longer strip whitespace and accept ASCII digits only, so Take RC's concurrency group (keyed on the raw input) cannot be split by a padded value. Backport `lines` splits on commas or spaces. - Retire's early-retirement refusal checks the cloud target is actually stabilized; a late cloud target with no GA needs force, like on-prem. - Backport: a plain fix naming a stabilized line without confirm_stabilized says so (warning) instead of "not a target". - State's patch list reads from each line's first GA, not its latest, so fixes merged before a later patch are not dropped. A line with no GA, or a gh/git failure on one line, is reported instead of failing the run. - Comments and docstrings follow the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: list every owed fix since the cut in Patch a released line The State list bounded each line at its first GA, which dropped a fix still owed from before it: a label added after the GA, or a push run that failed or ran after Promote. The trailer filter already drops what was picked, so the cutoff only removed owed commits. The PR listing still starts at the oldest GA. Also adds a test that the Backport Pick step passes only flags and inputs that exist, and corrects the Backport workflow header: a plain fix also reaches a stabilized line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: retry transient GitHub failures in Backport Every gh call Backport and its record job make now goes through one helper that retries a 5xx, a reply cut short, or a timeout, twice with a short wait. A 4xx is GitHub's answer and is never retried. The squash merge and PR create are writes that can land although gh reports a failure, so they are not retried blindly. A failed squash checks whether the PR merged before retrying or failing. A failed create looks for the PR first; when none exists after the retries, the run deletes the head it pushed, so the next run picks the commit again instead of finding an orphan head. The 405 "Base branch was modified" retry is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: list missed picks on stabilizing lines in Release state A fix Backport failed to land on a stabilizing line used to show first at Promote's convergence gate, after QA had tested the RC. Release state now lists, per stabilizing line, the owed main fixes the line lacks, as Backport `commits`, and the open backport conflict PRs on it here and in the OSS repo. A clean line says none; a listing that fails says so rather than reading as clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: link commits, lines, tags and PRs in release run summaries Each release workflow's run summary now renders commits, release lines, tags and PRs as links to the repo they live in: OSS pins, OSS commits and cross-repo conflict PRs link to the OSS repo. Lines people paste into Backport (the commits lists and gh commands) stay plain. Retire links a branch only on a dry run and the archive tag only on a real run, since a real run deletes the one and creates the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: class a squash merge GitHub cannot map back to its PR GitHub's commit-to-PR lookups can miss a squash merge, so Backport read a merged fix as "no PR" and skipped it. - fix_class: when commits/{sha}/pulls is empty, take the trailing (#N) from the commit subject and accept that PR only if it is merged and its merge_commit_sha equals the commit. A ::notice:: records the use. - dispatch: a PR named by number is classed from the PR already fetched, without the backward lookup. - rescan: an unclassifiable commit fails the run with ::error:: until it is picked or declined. - dispatch: a named commit with no PR is a failed row, not "not a fix". A PR whose class is not a fix stays a skip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: pin the server URL so summary tests assert the linked form CI sets GITHUB_SERVER_URL, and summaries render links only when it is set, so the release tests passed locally and failed in CI. Pin it in each suite that reads summaries and assert the linked form we ship. Checks of the plain form now clear the variable explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: fail a release run that leaves an owed fix unsettled Backport now ends red when an owed fix is not picked, declined, held for the RM, on a pick PR, or answered by a failed row of the run. The skips that stood for a missed pick are now errors; the warnings that remain say why they are safe. The State run also runs daily. It fails on an owed fix on a stabilizing line that was merged more than OWED_GRACE ago and not picked, on any unclassifiable commit, and on a backport conflict PR open longer than CONFLICT_GRACE. A held security or critical fix is listed, not failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: block an RC on the OSS line's missing picks, and name fixes owed before a Backport run oss.py rc used to only preview the OSS line's convergence gate. Now it blocks on MISSING picks unless --force is given, as promote does. A gate that did not run also blocks. When forced, it prints a warning and writes the override and its reason to the --notes file. When Backport leaves a commit unsettled that this run never touched, the error and the summary now say the commit was owed before this run and was not caused by it. The run still fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: delete a pick head that never got a PR, so the next run picks again When a pick's PR create and the follow-up lookup both fail, the head stays with no PR. A later run that finds the head older than the pick timeout, with no PR open or closed, now deletes it and fails the row, so the run after that picks the fix again. A head whose delete fails still asks for a manual delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: cover Take RC notes on the RC prerelease Keeps .github/release identical to the cloud repo, whose Take RC now carries its notes onto the RC prerelease. The new tests skip here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: run the Take RC notes tests TakeRcNotes sat after the unittest.main() block, so running the file directly exited before collecting it. Move the block to the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * fix: retry gh calls with exponential backoff and jitter Five tries, waits doubling from 2-4 s with jitter so parallel jobs do not retry in step. A primary or secondary rate limit (403 or 429) is now retried, waiting at least a minute as GitHub asks when Retry-After is not visible. Other 4xx answers are still never retried. Squash, PR create and convgate's PR and comment lookups use the same schedule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * chore: drop a comment that restates GH_TRIES Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: sync release tooling review fixes; ci-test header names every skipped path - Backport no longer deletes the head when PR create still fails after its retries: GitHub may have opened a PR the listing does not show yet, and the delete would close it as a decline. The next run cleans up an orphan head once it is past the pick timeout. - The record job refuses to decline a PR the release App closed. - A dispatch no longer fails on a fix it did not touch that merged less than the State grace period ago. - Take RC: test that a gate error on any target wins over MISSING picks, and name everything force overrides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: promote order no longer blocks Take RC; a convgate usage error is an error Take RC runs convgate, which exited 2 for an older line not GA yet as well as for MISSING picks. A newer line takes RCs while an older one stabilizes, so that failed every first RC of an overlapping cut. The order still prints in the Promote preview; Promote enforces it. An argparse usage error also exited 2 and read as MISSING picks, which force could override; it now returns 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * test: keep the convgate exit-code test off the network It reached gh for conflict PR and failure-comment lookups, which passed only where gh is logged in. CI runs it without a token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: send gh retry warnings to stderr oss.py promote prints the new tag on stdout, and promote.yaml captures it. A retried gh call printed its warning there too, so a recovered GitHub error put the warning into the captured tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * docs: state the registry layout late-target detection relies on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga * fix: time a GA by its Promote tag when it shares the RC registry version With one repository for RC and stable images, the GA tag lands on the RC image version, whose create time is the RC build. An on-prem RC built between that RC and the cloud GA then read as late, which marked the line stabilized. A GA now counts from the later of its registry time and the tagger date of Promote's annotated tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jfBJqWg2hcUEBx2rvJMga --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit ac341d7)



Stacked on #2431: review and merge that one first.
Why
This is the OSS half of the enterprise release-tooling change.
.github/releaseis shared with the enterprise repo and must stay byte-identical there.The enterprise change covers:
What
.github/releaseis synced with the enterprise copy:confirm_stabilizedputs a plain fix on the stabilized lines named inlines, and the owed-picks summary points there. Withoutconfirm_stabilized, a named stabilized line gets a warning row.relmgr.lineandrelmgr.vtaginput helpers;linerefuses padded values.backport.yaml:branchesis renamed tolinesand accepts0.186orrelease/0.186;--lines;confirm_stabilizedandlines.state.yaml: new "Patch a released line" step, which lists the fixes each stabilized line lacks since its cut. A failed lookup on one line is reported, not fatal.stabilized/X.Ywhen a late target is added.ghcall. A failed squash or PR create checks whether it landed before retrying, and a create that never landed deletes the head it pushed.ghcommands stay plain.(#N)from the subject and accepts that PR only if it is merged with that exact merge commit. An unclassifiable commit now fails a rescan, and a dispatched commit with no PR is a failed row.state.yaml: new "Missed picks on stabilizing lines" step, which lists per stabilizing line the owed fixes it lacks and the open conflict PRs on it in both repos.Testing
All six suites in
.github/releasepass:python3 test_*.py, one file at a time. Workflow tests that need the enterprise workflows are skipped here and run in the enterprise repo.Mutation checks, each mutant run against the full suite in the enterprise repo:
bash -nonly; Take RC build's fail headers and Prerelease line)Rollout
.github/releasemust stay byte-identical.ci-test.yaml; this branch merges it in.backport.yaml -f branches=...no longer works. Use-f lines=0.186,0.188.🤖 Generated with Claude Code