Skip to content

[STG-2187] ci: single changeset publish in release workflow#2197

Open
shrey150 wants to merge 1 commit into
mainfrom
shrey/release-single-publisher
Open

[STG-2187] ci: single changeset publish in release workflow#2197
shrey150 wants to merge 1 commit into
mainfrom
shrey/release-single-publisher

Conversation

@shrey150

@shrey150 shrey150 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

The Release workflow had two publishers for browse, and they raced — surfaced by run 27043820691 failing with 403 cannot publish over the previously published versions: 0.8.3 (browse@0.8.3 still shipped fine; the duplicate attempt is what went red, and it skipped the downstream core canary).

Root cause: the changesets action ran publish: pnpm run release (= changeset publish), and changeset publish does not honor the ignore list (ignore governs versioning, not publishing) — so it published browse like any other public package. A separate bespoke pnpm pack / npm publish step then published browse again. When no core changesets were pending, both fired on the same browse-release commit; npm's read-after-write lag defeated the bespoke step's npm view guard, yielding the 403.

Fix — one publisher

Collapse to a single changeset publish:

  • New "Publish to npm" step runs pnpm run release once, before the changesets action (which switches branches to open the Version-Packages PR), on the clean pushed commit. It publishes whatever was just versioned — core (after a Version-Packages PR merges) or browse (after a release/browse PR merges) — exactly once, then pushes the tags changeset publish creates.
  • The changesets action is reduced to Version-Packages-PR creation only (publish: input removed).
  • The bespoke browse publish + tag + detection steps are removed. The browse canary is re-gated inline (fires on CLI changes that aren't a version bump).

Core's publish path is unchanged in substance — it already went through changeset publish; this just relocates that command to its own step and adds an explicit tag push (the action used to push tags).

Why this is safe (verified empirically)

Assumption Result Evidence
changeset publish makes a correct browse pkg published browse@0.8.3 has @browserbasehq/stagehand: "3.5.0"workspace:* rewritten by pnpm
Provenance preserved without --provenance 0.8.3 carries an SLSA attestation; auth is pure Trusted Publishing / OIDC (no NPM_TOKEN anywhere), so provenance is automatic
Tags still created/pushed changeset publish tags by default; core tags @browserbasehq/stagehand@3.5.0 already exist; step adds git push origin --tags
Always-on publish won't misfire every publishable pkg's current version is already on npm → changeset publish is a no-op right now; evals/server-v3 are private → auto-skipped
Tag push needs no extra token the old "Tag browse release" step pushed tags with the checkout-persisted credential and no GITHUB_TOKEN env

E2E Test Matrix

Check Observed Sufficiency
yaml.safe_load of the workflow parses; 10 steps in intended order (Publish to npmCreate Release Pull Request → canaries) Confirms valid syntax + ordering (publish before the branch-switching action).
Diff scope only .github/workflows/release.yml, +42/-68 No code/package changes; CI-only.
changeset publish dry state on current main all publishable versions already on npm → would no-op Confirms the always-on publisher is safe when nothing is pending.

Staged rollout (the one thing inspection can't prove — a live publish): after merge, the next browse release (a low-stakes, independent bump) exercises the exact changeset publish path core will use. A green browse release de-risks the next core release by construction; core is never the first to traverse the new path.

CI-only change — no changeset.

🤖 Generated with Claude Code


Summary by cubic

Switch the Release workflow to a single publisher using changeset publish to prevent duplicate browse releases and 403 errors. Addresses STG-2187.

  • Bug Fixes

    • Remove the bespoke pnpm pack/npm publish path for browse that raced changeset publish.
    • Prevent 403 “cannot publish over the previously published versions” and avoid skipping downstream canaries.
  • Refactors

    • Add a dedicated “Publish to npm” step that runs pnpm run release on main before the changesets action and pushes tags.
    • Reduce changesets/action to Version-Packages PR creation only (no publish: input).
    • Re-gate the browse canary to run only on CLI changes that aren’t a version bump.

Written for commit 1a640af. Summary will update on new commits.

Review in cubic

The Release workflow had two code paths that both published `browse`:
the changesets action (`publish: pnpm run release` → `changeset publish`,
which does NOT honor the `ignore` list) and a bespoke pnpm-pack/npm-publish
step. When no core changesets were pending, both fired on a browse release
and the second hit `403 cannot publish over the previously published
versions` (npm read-after-write lag defeated the `npm view` guard), which
also skipped the downstream core canary.

Collapse to a single publisher: run `changeset publish` once in a dedicated
"Publish to npm" step (before the changesets action switches branches),
push the tags it creates, and reduce the changesets action to Version-
Packages-PR creation only. `changeset publish` already produces a correct,
provenance-signed browse artifact (workspace:* is rewritten to the real
version — verified on the published browse@0.8.3), so the bespoke browse
publish/tag steps are redundant and removed. The browse canary is re-gated
inline (fires on CLI changes that aren't a version bump) since it no longer
depends on the removed detection step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 5, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1a640af

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant GH as GitHub Actions
    participant Check as Check Changesets
    participant NPM as npm Registry
    participant Publish as Publish to npm Step
    participant Changesets as changesets/action
    participant Canary as Browse Canary Step

    Note over GH,Canary: Release workflow on push to main

    GH->>Check: Check pending changesets
    Check->>Check: Determine if changesets action should run
    Check-->>GH: should_run flag

    Note over GH,NPM: Sole publisher — runs before changesets action

    GH->>Publish: Publish to npm (always on main)
    Publish->>Publish: git config + pnpm run release
    Note over Publish: changeset publish — publishes any package with local version ahead of npm
    Publish->>NPM: npm publish browse@x (if bumped)
    NPM-->>Publish: publish success
    Publish->>Publish: git push origin --tags
    Publish-->>GH: tags pushed

    alt should_run == true
        GH->>Changesets: Create Release Pull Request
        Note over Changesets: Only creates Version Packages PR — publish is removed
        Changesets-->>GH: PR created
    end

    GH->>Canary: Publish browse canary
    Canary->>Canary: git checkout HEAD
    alt Browse CLI files changed
        Canary->>Canary: Check if browse version changed in this push
        alt Version changed (browse was released)
            Canary->>Canary: Skip canary (real version already published)
        else Version unchanged
            Canary->>Canary: Build and publish canary version
            Canary->>NPM: npm publish browse@x-canary-hash
            NPM-->>Canary: publish success
        end
    else No browse changes
        Canary->>Canary: Skip canary
    end
Loading

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant