Status: Live (DD-008 D1/D2/D3, #130) · applies from v0.1.0.
All nine packages release in lockstep (one version line, one tag). Publication happens only
from the protected Release / publish workflow on a tag from main — never from a workstation.
- During development (on
dev): every behavior-changing PR carries a human-written changeset (npx changeset; enforced by the Changeset presence check; docs/test/tooling PRs exempt, or labelno-changeset-neededwith justification). Pre-1.0 semantics per the support policy: minor may break (withbreaking-changelabel + migration note + AnyBridge impact check), patch = fixes. - Version PR (generated): the
Release / version PRworkflow maintains arelease: version packages (lockstep)PR againstdev— lockstep bumps, per-packageCHANGELOG.mds, internal@chestnutlabs/*ranges pinned to the exact new version (tools/release/sync-internal-ranges.mjs— the dev-time*wildcard never reaches a tarball;release:sync-checkguards it in the publish gate), and a refreshed lockfile. Never hand-edit versions or changelogs. Merging it versionsdev. - Promotion PR (
dev→main): a deliberate PR carrying the versioned state tomain, merged only with the required checks green. The first one (v0.1.0) ends the founding-baseline freeze onmain. - Tag + GitHub Release: tag
vX.Y.Zonmainand publish a GitHub Release for it. This — and nothing else — triggers publication. Release / publishworkflow: verifies the tag is onmain, freshnpm ci, then the full repository gate (build, root + package suites, typeCheck, lint, license, docs links, consumer fixture, pack-check, sync-check) before a dependency-orderednpm publish×9 with npm provenance. The orchestrator (tools/release/publish.mjs) refuses real publishes outside the workflow;npm run release:dry-runis the local rehearsal (it exercises the full pack + validation path without uploading).- Post-publish verification (phase 6/7): registry-mode consumer fixture + fresh smoke install per the README quick-start; then the release notes are announced.
- Intended: npm trusted publishing (OIDC) — no long-lived token. Configured on npmjs
against the user-owned
@chestnutlabsscope for this repository + therelease-publish.ymlworkflow (org conversion is deferred and not av0.1.0blocker). - Recorded fallback: a granular automation token scoped to the nine packages, stored as the
NPM_TOKENsecret (the workflow already wires it). If the registry cannot create new packages via OIDC at first publish,v0.1.0uses the token and later releases switch to OIDC. - Token must bypass 2FA (learned cutting
v0.1.0): with 2FA-on-publish set, a plain token getsE403 "Two-factor authentication or granular access token with bypass 2fa enabled is required". Use a classic Automation token (bypasses 2FA by design) or a Granular token with "Bypass 2FA" enabled + read/write on the packages. - 2FA-on-publish set on the owning account. These are maintainer prerequisites for phase 7, confirmed during the phase-6 rehearsal.
- GitHub Actions PR creation (discovered at the first #130 run): the org-level setting
Allow GitHub Actions to create and approve pull requests (ChestnutLabs → Settings → Actions →
General), plus the same repo-level toggle, must be enabled for
release-version.ymlto open the Version Packages PR itself. Until then the workflow still pusheschangeset-release/devcorrectly and the PR is opened manually once — the flow is degraded, not broken.
| Branch | Protection |
|---|---|
dev |
required check build (existing); the Changeset presence check runs on every PR |
main |
required check build (existing, kept name-stable); add node-24 as required at the rehearsal; no direct pushes; release PRs (promotion) only |
tags v* |
created only on main (the publish workflow independently verifies tag ∈ main and refuses otherwise) |
Publication is dependency-ordered; a mid-sequence failure stops the run loudly. Recovery is a
rerun (npm allows re-publishing a name@version only if that name@version never uploaded) or a
patch release — never npm unpublish as a workflow. A red post-publish verification blocks the
announcement and triggers an immediate patch; a genuinely broken published line is deprecated on
npm, not unpublished.