Repository navigation
chore(release): derive the RC promotion line from package.json - #8865
Conversation
`npm run promote:rc` refused anything but 3.2.0. It now promotes the current line's final beta, `X.Y.0-beta.N` from package.json, to `X.Y.0-rc.0`, so the 3.3 candidate can use the same guarded path. The marker check and the intermediate-beta guard derive the target and line from the package version instead of literals. The safety properties are unchanged: one-way, beta pre mode required, the exact changeset pool snapshotted by SHA-256, any changed, added or removed changeset refused, and no intermediate beta. `--check` and `--prepare` now list the pending changesets that fold into rc.0. RELEASING's RC section is version-neutral and records the open beta Version Packages PR handling, the marker invalidation and main freeze, the docs-snapshot label, and the hosted training agent preview bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean refactor of RC-promotion tooling, no blocking findings.
Checked:
scripts/promote-release-candidate.mjs: the three hardcoded3.2literals now derive the release line frompackage.jsonviareleaseLine(), andreadPreparedRcPromotionderivestargetVersionthroughplanRcPromotioninstead of a hardcoded3.2.0-rc.0. Validation stays fail-closed — newprerelease.length !== 2andpatch !== 0guards reject malformed and patch-line betas.- Tests exercise both 3.3.0 and 3.2.0 lines plus added/removed-changeset, stale/cross-line-marker, and literal-regression cases.
- Scope: release scripts + runbooks only (
RELEASING.md,scripts/*,tests/*). Nostatic/schemas/source/**,dist/**, or normative-docs surface touched, so no changeset required — scope check confirms. No protocol-policy/governance question, no oneOf/discriminator surface, no breaking-class change.
Decision table: no critical/high/medium findings; gated_paths false; high_risk false; no no-auto-approve team match; first review. Rows 1–8 do not fire → row 9 approve. (review_decision is REVIEW_REQUIRED, but gated_paths is false and no prose hard gate applies, so this does not force escalate.)
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated path touched and review not yet approved.
This PR modifies .agents/playbook.md, which matches the gated glob .agents/** (gated_paths: true). The review_decision is REVIEW_REQUIRED, not APPROVED, so the hard approval gate (decision table row 2) is not satisfied and the PR cannot be auto-approved despite a clean diff.
Content assessment: The reviewer found no blocking issues. The delta is a single file (.agents/playbook.md, ~31 lines) making the pre-mode paragraph version-neutral; verified accurate against repo state (pre.json {"mode":"pre","tag":"beta"}, package.json 3.3.0-beta.5), with 3.2 history preserved correctly. No code, wire, schema, or changeset-scoped change. The prior pass also had no blockers.
Blocking findings: None.
Escalation reasons:
.agents/playbook.mdis under the hard approval gate (.agents/**); human/CODEOWNERS review is required before merge. The gate lifts oncereview_decisionbecomesAPPROVED.
Why human review
- Touches gated path
.agents/playbook.md(matches.agents/**) andreview_decisionis REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS review required before merge. - This PR touches a path under a hard, non-overridable approval gate (.agents/playbook.md (modified) matches
.agents/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
CodeQL flagged the version-escaping helper for escaping only dots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fc17cc1 to
90ef730
Compare
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean pass on a release-tooling generalization.
What I checked:
- The prior decision (
escalate) was driven entirely by a gated path.agents/playbook.mdmatching.agents/**under REVIEW_REQUIRED. The current diff touches onlyRELEASING.md,scripts/promote-release-candidate.mjs,scripts/version-packages.mjs, andtests/promote-release-candidate.test.cjs— no gated path (gated_paths: false), so row 2 no longer applies. The sticky-escalation rule (row 6) requires a fresh critical/high/medium finding to persist the prior escalate; there are none, so it does not stick. - No critical/high/medium findings (rows 1, 4, 5, 8 don't fire).
high_risk: false(rows 3, 5 don't fire). No no-auto-approve team match (row 7 doesn't fire). Falls through to row 9. - Core logic is sound:
planRcPromotiontightens prerelease validation and swaps the 3.2 restriction forpatch !== 0;readPreparedRcPromotionderives the target viaplanRcPromotionso stale/cross-line markers fail closed; the intermediate-beta guard anchors toreleaseLine(parse(currentVersion)). All branches covered by parametrized tests over 3.2/3.3/4.0 lines. - Changeset correctly omitted — neither release script is in the scope gate's PROTOCOL_SCOPED_PATHS. RELEASING.md's
candidate-version.tsreference verified to exist.
No blocking or medium findings; outcome is approve per row 9.
Summary
npm run promote:rconly accepted the 3.2.0 line. The WG wants a 3.3 release candidate on Mon Nov 16, so this PR derives the line frompackage.json. The script now promotes the current line's final beta,X.Y.0-beta.N, toX.Y.0-rc.0.scripts/promote-release-candidate.mjs: the three 3.2 literals now come from the package version:to: '3.2.0-rc.0';'3.2.0-beta.'intermediate guard.The safety properties are unchanged:
Only
X.Y.0betas can be promoted.--checkand--preparenow list the pending changesets that fold into rc.0.tests/promote-release-candidate.test.cjs: runs the full prepare, tamper and version cycle for both 3.3.0-beta.5 and 3.2.0-beta.10. It adds cases for:It also fails if a version literal comes back into the script.
RELEASING.md: the "Cutting a release candidate" section is version-neutral. It also records:mainfreeze;X.Y-rcdocs label;The playbook's stale pre-mode paragraph is fixed separately in docs(agents): describe pre mode and RC promotion for any line #8868, because
.agents/**is human-gated in Ladon. Merge it after this PR.No workflow files change, and no changeset is needed (the scope check finds no protocol-scoped changes).
RC-path audit
scripts/promote-release-candidate.mjs:31,104,189scripts/version-packages.mjs:4.github/workflows/release.yml.changeset/makes the marker push release-relevant (:125).npm run versiondispatches on the marker (:389).--prereleasecomes from*-*(:503,:529).scripts/fence-changesets.cjs:143pre.jsontag..github/workflows/release-docs.yml:35-44+scripts/update-release-docs-nav.mjsv3.3.0-rc.0becomes the3.3-rclabel. I simulated it locally: copied the beta.5 snapshot to rc.0, then ranrewrite-dist-links.shandupdate-release-docs-nav.mjs. Result: a3.3-rcselector beside3.3-beta, plus.dockerignoreandDOCS_SCHEMA_RELEASESentries. Tests passed:docs-nav-validationandupdate-release-docs-nav42/42, Addieschema-toolsanddocs-indexer95/95.server/src/training-agent/candidate-version.ts:28-313.3-beta.5/3.3.0-beta.5, because it must match what the installed@adcp/sdknegotiates. It can't followpackage.json. Move it to3.3-rc.0in the PR that adopts an SDK negotiating rc.0. RELEASING now says so.workers/artifact-cdn/src/index.js,server/src/schemas-middleware.ts,scripts/build-schemas.cjs-rc.Nserves by exact path, andsuperseded_byis derived. The only literals are the withdrawn/unpublished map (3.1.3,3.2.0-rc.5,3.2.0).RELEASING.md:136-218.agents/playbook.md:579-582,602.agents/shortcuts/cut-minor-ga.mdVerification
npm run test:release-workflow: all suites pass.npm run promote:rc -- --checkon this branch:--prepareand--versionwith the real Changesets CLI in a throwaway worktree, which I then deleted. No marker was committed. The result:3.3.0-rc.0;pre.jsontagrc;## 3.3.0-rc.0with nobeta.6heading;.changeset/pre/;Monday Nov 16: cutting 3.3.0-rc.0
Merge first, in this order
main. It isn't open yet; fix(schemas): open schemas that were closed by accident (3.2.x backport) #8864 is its 3.2.x backport. Decide whether it supersedes Konstantin's fix(schemas): open the capability blocks and containers 3.3 extends, against DR-0019 (#8501) #8772 or that one lands too. Then any other rc.0 content, each with its own changeset.Commands
mainbefore it merges, delete the marker, rebase, and run--prepareagain.mainfrom the marker PR's merge until rc.0 has finished publishing.release.ymlregenerates the Version Packages PR at3.3.0-rc.0as a Draft. Before approving, confirmgit merge-base <head> origin/mainequals the tip oforigin/main. Then mark it Ready, approve it on the final head (a non-author human with write access), and merge.Confirm before merging the RC Version Packages PR (from RELEASING)
package.jsonand the lockfile are at3.3.0-rc.0, and.changeset/pre.jsonis{"mode":"pre","tag":"rc"}.## 3.3.0-rc.0, holds only changes meant for the candidate, and has nobeta.6heading.dist/schemas,dist/compliance, anddist/protocol/3.3.0-rc.0.tgzwith its.sha256,.sigand.crtall carry that exact version.3.3.0milestone items are closed or moved out by their owners.SDK disposition to record
@adcp/sdk17.0.0-beta.213.3.0-beta.53.3-beta.5. rc.0 needs a new SDK prerelease.adcp10.0.0b133.3.0-beta.5adcp/v3v3.2.13.2.0-rc.1typesAfter the merge
VERSION=3.3.0-rc.0verification: tag, prerelease release with exactly 4 assets, schemas, compliance, and the tgz on the CDN.auto/docs-v3.3.0-rc.0snapshot PR, which adds the3.3-rcselector. The banner ("AdCP 3.3 beta is open") is a manual edit.3.3-rc.0ships, moveTRAINING_AGENT_HOSTED_PREVIEWto{ wireVersion: '3.3-rc.0', bundle: '3.3.0-rc.0' }inserver/src/training-agent/candidate-version.ts, and update its preview tests in the same PR.🤖 Generated with Claude Code