Repository navigation
release: snapshot one-click rc cut — a cut-rc workflow that bumps, versions, gates and publishes from ONE SHA, ending the two-treadmill freeze dance #7447
Description
Maintainer ruling (2026-08-10, directed in session session_01BPWqbmEFU8gJepBJTHESXd): approved for immediate implementation and dispatch. Background: cutting rc.6 today required chasing objectui main across four pin-bump laps (8aad9fd→9b9fa49→cfeb378→1b6188d→bcd3e02, every lap overtaken) and would have needed ~40 min of coordinated freezes across two repos. The root causes are design, not discipline: (1) the release path checks pin freshness against a moving objectui HEAD; (2) the standing Version Packages PR (#6208) is force-refreshed on every main push, so its CI can never finish on a busy day, and the version→publish gap invites content/record skew.
The design (adopted)
New workflow .github/workflows/cut-rc.yml — rc prereleases only. One human dispatch, one snapshot, zero freezes:
- Trigger:
workflow_dispatchONLY, inputversion= the expected resulting version (e.g.17.0.0-rc.6),environment: release,concurrencygroupcut-rc(no parallel cuts). This preserves the 2026-08-07 ruling verbatim: no push, bot, queue or schedule can synthesize the event; the human types the version. - Snapshot: checkout objectstack
main, recordSNAPSHOT_SHA. Resolve objectuimainHEAD once (git ls-remote), recordOBJECTUI_SHA. Everything downstream uses these two values; both repos may keep moving freely. - Pin bump: clone objectui (full enough for the digest walk — see traps below), run
scripts/bump-objectui.sh $OBJECTUI_SHAwithOBJECTUI_ROOTset, thenpnpm objectui:build,playwright install chromium-headless-shell(allowed in CI — this is not a dispatch container),pnpm sdui:manifest(the ADR-0082 D4 ratchet; mandatory second half of every pin move, sdui.manifest.json 的来源未定:声明一致性 ratchet 目前只在手工pnpm sdui:manifest时跑,CI 里从来不跑(#4690 的遗留决定) #5960),pnpm check:console-sha. - Pin self-consistency, NOT liveness: inside the run, assert
.objectui-sha == $OBJECTUI_SHA(inline compare). ⛔ Do NOT callcheck:objectui-pin-freshhere and do NOT change that script's semantics — objectui moving during the run must not fail the cut. The Release process: prevent frontend (objectui) changesets being missed when the console pin lags #3340 invariant this preserves is "everything shipped is covered by the changeset record" (true by construction: the bump changeset covers OLD_PIN..$OBJECTUI_SHA); commits past the snapshot are simply next release's record. - Pre-version gates (they read
.changeset/*, so they run BEFORE versioning):check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check-nul-bytes. - Version:
pnpm run version(⚠️ the repo script —changeset version && sync-protocol-version.mjs && sync-template-versions.mjs— never rawchangeset version). Pre mode (.changeset/pre.json, tag rc) is committed state and applies automatically. Then assert computed version (packages/cli/package.json) == the dispatch input; mismatch fails before anything irreversible. - Land the version commit on
mainFIRST, publish it SECOND — preserving release workflow: publish pushes tags + npm but its version commit never reaches main — twice now (rc.3 c6a52d3, rc.4 a10cbc77); landing the commit must be part of the publish lane #6170's invariant ("the publish lane may only ever ship a commit that is ALREADY on main") to the letter:- Primary route: push the single squashed version commit (bump + version output; file surface is
package.jsons / CHANGELOGs /.changeset/*/.objectui-sha— disjoint from lane PRs by construction) directly tomainusing a bypass credential, with a bounded fetch-rebase-retry loop for races. Admin prerequisite (maintainer, one-time): add a bypass actor for this push — either the Actions app on the ruleset bypass list scoped to this workflow, or a fine-grained PAT stored asRELEASE_PUSH_TOKENfor an account on the bypass list. - If bypass turns out impossible in this org: STOP and report
needs_decisionwith the measured constraint — the fallback (publish from a release ref + catch-up PR) is the rc.3/rc.4 accident shape (release workflow: publish pushes tags + npm but its version commit never reaches main — twice now (rc.3 c6a52d3, rc.4 a10cbc77); landing the commit must be part of the publish lane #6170) and is NOT to be adopted silently.
- Primary route: push the single squashed version commit (bump + version output; file surface is
- Publish:
changeset publish+ tag push from the just-landed main commit,NPM_TOKENvia thereleaseenvironment — mirrorrelease.yml's publish job for secrets/guard patterns (read itspublish:job before writing yours; its dispatch guards are the house style). - Docs:
docs/releases-maintenance.mdgains a "cutting an rc (snapshot flow)" section; the existing Version-PR flow is re-scoped as GA only (board-clearing, No producer files the final console bump card at the release-cut moment — the #6162 chore is keyed to a settled window, and the card it does file never reaches the release board #7275-A cut precondition, human changelog review all stay there). One cross-reference line, no edits torelease.yml's lanes.
Measured traps the implementer inherits (all hit today, all with receipts in session)
bump-objectui.shwith no sha argument pins the LOCAL objectui checkout's HEAD — stale by construction (chore: pin the console to objectui main8aad9fd50b16(approvals inbox + bell-badge breakdown) #7308 note 1). Always pass the resolved sha.- The changeset digest exits 2 on an unwalkable shallow range; deepen the objectui clone until OLD_PIN is reachable (
--depth=250sufficed at ~70 commits;fetch-depth: 0is simplest in CI). - A fresh workspace must build local dists before
pnpm objectui:build: the console's vite alias table (objectui#4103) resolves@objectstack/client→ localpackages/client/dist, whose DTS needs@objectstack/corebuilt.pnpm --filter "@objectstack/client..." build(dependency closure) is the fix;@objectstack/specbuild is also required for generated-artifact reads. pnpm sdui:manifestneeds a Playwright chromium; in CI install it normally. (The scratchpad symlink workaround indocs/releases-maintenance.mdis for agent dispatch containers only.)- Expected ratchet state today: 62 spec-only divergences == accepted baseline, 0 missing blocks — four consecutive laps confirmed no declaration drift from objectui
8aad9fd..bcd3e02.
Boundaries (⛔)
- No second publish path reachable without
workflow_dispatch+environment: release. The 2026-08-07 ruling andrelease.yml's lane-split comments are binding context — read them first. release.yml's three existing lanes andcheck-objectui-pin-fresh.mjssemantics are OUT of scope — GA keeps them unchanged.content/docs/releases/**untouched (standing rule).- Releases nothing →
skip-changesetlabel on the PR, per the Check Changeset gate's route 2.
Acceptance
- Workflow YAML passes actionlint/self-review; every guard failure path exits before
changeset publish. - A dry-run mode (
inputs.dry_run) that stops after step 6 and uploads the would-be version diff as an artifact — so the first real dispatch is not the first execution. - Docs section written; PR body walks the sequence and names the admin prerequisite for the maintainer.
Refs: #6170 / #3340 (invariants), #5960 (ratchet on-demand ruling), #7308 (previous bump lap + traps), #7275 (GA cut precondition, stays), #6162 (steward bump cards — unaffected; they keep feeding the advisory pin lag), #4898 (empty-changeset stall), 2026-08-07 manual-publish ruling (release.yml header).
Activity
os-zhuang commentedon Aug 10, 2026
Claim — maintainer-delegated dispatch, session
session_01BPWqbmEFU8gJepBJTHESXd(the session that produced the design and the four measured laps). Dispatching to anos-devsubagent now, per the maintainer's in-session directive 「这个任务创建好你帮我立刻就派发」.claude/issue-7447-cut-rc-snapshot-release.github/workflows/cut-rc.yml(new),docs/releases-maintenance.md. ⛔release.ymllanes,check-objectui-pin-fresh.mjs,content/docs/releases/**untouched.pm:dispatchedapplied with this claim (nopm:queueresidue — [decision] engine-core lane dropspm:queueat dispatch without applyingpm:dispatched— 7 instances of the ghost-card shape; pick the repair #7239 atomic pair).cut-rc.yml(new file);docs/releases-maintenance.mdlast landed finding: the ADR-0082 D4 ratchet's only trigger needs a Playwright browser the dev containers cannot supply at the expected revision #7315's container note — the dev merges on top of currentmain.needs_decision, do not adopt the catch-up-PR fallback silently); any scope expansion past the ruled design is disclosed before implementation.If a claim comment with a different session ID appears above this one, that claim wins by timestamp and this dispatch stands down.
Generated by Claude Code
docs(release): what happens to the standing Version Packages PR after…
feat(release): cut-rc — snapshot one-click rc release (objectstack-ai…