Skip to content

chore(release): derive the RC promotion line from package.json - #8865

Merged
bokelley merged 2 commits into
mainfrom
chore/promote-rc-3-3
Nov 9, 2026
Merged

bokelley merged 2 commits into
mainfrom
chore/promote-rc-3-3

Conversation

@bokelley

@bokelley bokelley commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

npm run promote:rc only accepted the 3.2.0 line. The WG wants a 3.3 release candidate on Mon Nov 16, so this PR derives the line from package.json. The script now promotes the current line's final beta, X.Y.0-beta.N, to X.Y.0-rc.0.

  • scripts/promote-release-candidate.mjs: the three 3.2 literals now come from the package version:

    • the line restriction;
    • the marker's to: '3.2.0-rc.0';
    • the '3.2.0-beta.' intermediate guard.

    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;
    • a marker that doesn't name the current beta's rc.0 refused;
    • no intermediate beta.

    Only X.Y.0 betas can be promoted. --check and --prepare now 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:

    • added and removed changesets;
    • cross-line and stale markers;
    • patch-line betas;
    • extra prerelease identifiers.

    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:

    • how to handle the open beta Version Packages PR;
    • that the marker goes stale when another changeset lands, and the main freeze;
    • the X.Y-rc docs label;
    • the hosted training agent preview bump.
  • 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

Surface Result
scripts/promote-release-candidate.mjs:31,104,189 3.2 literals. Fixed here.
scripts/version-packages.mjs:4 Comment only ("3.2 beta -> rc.0"). Fixed here.
.github/workflows/release.yml No hardcoding. .changeset/ makes the marker push release-relevant (:125). npm run version dispatches on the marker (:389). --prerelease comes from *-* (:503, :529).
scripts/fence-changesets.cjs:143 Generic. The PR title follows the tested pre.json tag.
.github/workflows/release-docs.yml:35-44 + scripts/update-release-docs-nav.mjs Generic: v3.3.0-rc.0 becomes the 3.3-rc label. I simulated it locally: copied the beta.5 snapshot to rc.0, then ran rewrite-dist-links.sh and update-release-docs-nav.mjs. Result: a 3.3-rc selector beside 3.3-beta, plus .dockerignore and DOCS_SCHEMA_RELEASES entries. Tests passed: docs-nav-validation and update-release-docs-nav 42/42, Addie schema-tools and docs-indexer 95/95.
server/src/training-agent/candidate-version.ts:28-31 Deliberately pinned to 3.3-beta.5 / 3.3.0-beta.5, because it must match what the installed @adcp/sdk negotiates. It can't follow package.json. Move it to 3.3-rc.0 in 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 Generic semver. Aliases skip prereleases, -rc.N serves by exact path, and superseded_by is derived. The only literals are the withdrawn/unpublished map (3.1.3, 3.2.0-rc.5, 3.2.0).
RELEASING.md:136-218 3.2-specific. Made version-neutral here.
.agents/playbook.md:579-582,602 Stale 3.2 RC wording. Fixed in #8868.
.agents/shortcuts/cut-minor-ga.md 3.2-specific, but it is the GA runbook, not the RC path. Left for 3.3 GA.

Verification

  • npm run test:release-workflow: all suites pass.
  • npm run promote:rc -- --check on this branch:
    Ready to prepare 3.3.0-beta.5 -> 3.3.0-rc.0.
    Pending changesets folded into 3.3.0-rc.0 (8):
      gate-image-creative-on-format-kind.md
      inline-legacy-asset-slots.md
      product-signal-targeting-wholesale-gate.md
      python-sdk-beta5-support-docs.md
      refresh-3-3-release-docs-beta5.md
      test-agent-preview-beta4-docs.md
      test-agent-preview-beta5-docs.md
      versioning-three-rules.md
    
  • I also ran --prepare and --version with the real Changesets CLI in a throwaway worktree, which I then deleted. No marker was committed. The result:
    • package and lockfile at 3.3.0-rc.0;
    • pre.json tag rc;
    • the changelog opens at ## 3.3.0-rc.0 with no beta.6 heading;
    • all 8 changesets moved to .changeset/pre/;
    • the marker deleted.

Monday Nov 16: cutting 3.3.0-rc.0

Merge first, in this order

  1. chore(release): derive the RC promotion line from package.json #8865 (this RC script fix). It doesn't touch any workflow files, so ordinary human review is enough.
  2. DR-0036, docs(governance): DR-0036 records open schemas within a major; withdraw DR-0032 and DR-0033 #8858 ("records open schemas within a major"). Supersede or close Konstantin's docs(governance): state DR-0036 as a decision; corrections live in the register #8777 to match.
  3. The 3.3 open-schemas PR on 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.
  4. Forward merge chore(release): forward-merge 3.2.x maintenance fixes into main #8820 (3.2.x). Land it before the marker PR, or hold it until rc.0 has published. Never merge it in between. The same applies to any forward merge for 3.2.10. chore(release): forward-merge AdCP 3.1.33 into main #8851 (3.1.33) already merged on Nov 9.

Commands

gh release view v3.3.0-beta.5 --json isPrerelease,assets   # or the last beta, if beta.6 is cut first
# Beta VP PR #8801: either leave it open (it regenerates in place as rc.0,
# as #7196 did for 3.2), or `gh pr close 8801 --delete-branch`.
# Never close it and keep the branch: the release fence then stops the run.
git fetch origin
git switch -c chore/prepare-3.3-rc0 origin/main
npm ci --ignore-scripts
npm run promote:rc -- --check     # expect "Ready to prepare 3.3.0-beta.N -> 3.3.0-rc.0." and the pool
npm run promote:rc -- --prepare
git diff --check
git add .changeset/rc-promotion.json
git commit -m "chore(release): prepare 3.3.0-rc.0"
git push -u origin chore/prepare-3.3-rc0
gh pr create --base main --title "chore(release): prepare AdCP 3.3.0-rc.0"
  • Keep the marker PR state-only. If any changeset reaches main before it merges, delete the marker, rebase, and run --prepare again.
  • Freeze main from the marker PR's merge until rc.0 has finished publishing.
  • release.yml regenerates the Version Packages PR at 3.3.0-rc.0 as a Draft. Before approving, confirm git merge-base <head> origin/main equals the tip of origin/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.json and the lockfile are at 3.3.0-rc.0, and .changeset/pre.json is {"mode":"pre","tag":"rc"}.
  • The changelog opens at ## 3.3.0-rc.0, holds only changes meant for the candidate, and has no beta.6 heading.
  • dist/schemas, dist/compliance, and dist/protocol/3.3.0-rc.0.tgz with its .sha256, .sig and .crt all carry that exact version.
  • The compact lifecycle storyboards and the training-agent profile tests pass.
  • The SDK disposition is recorded (see below).
  • The 10 open 3.3.0 milestone items are closed or moved out by their owners.

SDK disposition to record

SDK Version Bundles Status
TypeScript @adcp/sdk 17.0.0-beta.21 3.3.0-beta.5 Negotiates only 3.3-beta.5. rc.0 needs a new SDK prerelease.
Python adcp 10.0.0b13 3.3.0-beta.5 Same as TypeScript.
Go adcp/v3 v3.2.1 3.2.0-rc.1 types No 3.3 support. Record it as unsupported.
Java none none No SDK. Record it as unsupported.

After the merge

  • Run RELEASING's VERSION=3.3.0-rc.0 verification: tag, prerelease release with exactly 4 assets, schemas, compliance, and the tgz on the CDN.
  • Merge the auto/docs-v3.3.0-rc.0 snapshot PR, which adds the 3.3-rc selector. The banner ("AdCP 3.3 beta is open") is a manual edit.
  • When an SDK that negotiates 3.3-rc.0 ships, move TRAINING_AGENT_HOSTED_PREVIEW to { wireVersion: '3.3-rc.0', bundle: '3.3.0-rc.0' } in server/src/training-agent/candidate-version.ts, and update its preview tests in the same PR.

🤖 Generated with Claude Code

`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>
aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Nov 9, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean refactor of RC-promotion tooling, no blocking findings.

Checked:

  • scripts/promote-release-candidate.mjs: the three hardcoded 3.2 literals now derive the release line from package.json via releaseLine(), and readPreparedRcPromotion derives targetVersion through planRcPromotion instead of a hardcoded 3.2.0-rc.0. Validation stays fail-closed — new prerelease.length !== 2 and patch !== 0 guards 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/*). No static/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.)

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.md is under the hard approval gate (.agents/**); human/CODEOWNERS review is required before merge. The gate lifts once review_decision becomes APPROVED.

Why human review

  • Touches gated path .agents/playbook.md (matches .agents/**) and review_decision is 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.

@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Nov 9, 2026
CodeQL flagged the version-escaping helper for escaping only dots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bokelley
bokelley force-pushed the chore/promote-rc-3-3 branch from fc17cc1 to 90ef730 Compare November 9, 2026 18:57
@bokelley bokelley added the ladon/force-review Force Ladon to review the next eligible PR event label Nov 9, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.md matching .agents/** under REVIEW_REQUIRED. The current diff touches only RELEASING.md, scripts/promote-release-candidate.mjs, scripts/version-packages.mjs, and tests/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: planRcPromotion tightens prerelease validation and swaps the 3.2 restriction for patch !== 0; readPreparedRcPromotion derives the target via planRcPromotion so stale/cross-line markers fail closed; the intermediate-beta guard anchors to releaseLine(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.ts reference verified to exist.

No blocking or medium findings; outcome is approve per row 9.

@bokelley bokelley removed the ladon/needs-human-review Ladon has escalated this PR for human review. label Nov 9, 2026
@bokelley
bokelley merged commit e68419e into main Nov 9, 2026
32 checks passed
@bokelley
bokelley deleted the chore/promote-rc-3-3 branch November 9, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/force-review Force Ladon to review the next eligible PR event

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants