Skip to content

Build: Narrow only quarantined ranges when generating sandboxes - #35775

Merged
valentinpalkovic merged 3 commits into
nextfrom
valentin/sandbox-age-gate-narrow-ranges
Aug 6, 2026
Merged

valentinpalkovic merged 3 commits into
nextfrom
valentin/sandbox-age-gate-narrow-ranges

Conversation

@valentinpalkovic

@valentinpalkovic valentinpalkovic commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

What I did

We generate sandboxes with a 7 day npm minimum age gate now, so a package published within the last week never ends up in a sandbox. When a declared range has no release old enough to clear that gate, the install cannot resolve at all, and our recovery path upgraded every dependency of the template to its newest allowed version.

That recovery is pretty much the broadest thing we could have done. yarn up ignores the ranges in your manifest per default, it is basically the counterpart to yarn upgrade --latest. So one single blocked package rewrote the whole manifest, 154 files in the last publish:

  • The Angular sandboxes moved from TypeScript 6 to TypeScript 7. Compodoc bundles TypeScript 6 and crashes when it parses a TS 7 project, which is exactly why the Angular sandbox builds are red right now.
  • The Angular 21 template got upgraded to Angular 22, so its dependencies are identical to the Angular 22 template. It has not been testing Angular 21 since that run.
  • In a bunch of other templates exact pins were loosened to ranges and tilde ranges became carets.

Solution: only narrow the ranges that Yarn actually reports as quarantined, and hand yarn up an explicit range anchored at the major the template already declared. Yarn respects a range you give it, so it then picks the newest allowed version inside that range, and every other dependency keeps whatever its own scaffolder generated. Regenerating the Angular sandbox now keeps TypeScript on 6 and only moves the Angular packages, which is the minimum needed to get a resolvable lockfile.

Two cases fail loudly now instead of quietly publishing a wrong sandbox: a package pinned to a prerelease (every stable release sorts above it, so any narrowing would land on stable) and a package that only its parent can move off. Both are solved by adding the package to that template's age gate exemption list.

Worth knowing: the currently published sandboxes are already mangled, so they need a regeneration once this lands. The failing tanstack jobs are unrelated to this PR, though, that one is an upstream @tanstack/react-router release and I am handling it separately.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Check what we publish today, it has "typescript": "^7.0.2":
    curl -s https://raw.githubusercontent.com/storybookjs/sandboxes/next/angular-vite/default-ts/before-storybook/package.json
  2. Regenerate the same template with this branch checked out:
    cd code && yarn generate-sandboxes --templates angular-vite/default-ts --debug
  3. Open repros/angular-vite-default-ts/before-storybook/package.json and compare:
    • typescript stays on ~6.x, it must not be ^7
    • @types/node stays on ^20.x
    • express, rxjs, tslib and prettier keep the ranges from step 1's pre-gate state
    • only the @angular/* entries moved, and they stay inside ^22
  4. The log prints which ranges were touched, so you can check the blast radius directly:
    ⚠️ narrowed 11 range(s) with no release older than the 10080min age gate: @angular/build@^22.0.0, ...
  5. To confirm the deliberate old pins survive, regenerate angular-vite/21-ts as well and verify it is still on Angular 21.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

This only touches our own sandbox generation tooling, so there is no user facing surface to document.

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>

The age-gate recovery path ran `yarn up '*'`, which is documented as the
counterpart to `yarn upgrade --latest`: it ignores the declared ranges and
moves every dependency to its newest allowed release. One template failing
to resolve therefore rewrote the template's whole manifest.

Hand `yarn up` only the packages Yarn reported as quarantined, anchored at
the bottom of the major they already declared, so a workaround for one
dependency cannot upgrade the rest of the template.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The lockfile refresh now handles Yarn age-gate failures through targeted dependency upgrades. It preserves declared version bounds, rejects unsafe prerelease ranges, retries bounded rounds, handles failure cases, and adds comprehensive tests.

Changes

Lockfile refresh

Layer / File(s) Summary
Quarantine detection and range narrowing
scripts/sandbox/utils/yarn.ts, scripts/sandbox/generate.ts
The refresh parses YN0016 failures, derives bounded descriptors from manifest ranges, preserves version constraints, rejects unsafe prerelease ranges, and updates the failure guidance.
Iterative targeted installation
scripts/sandbox/utils/yarn.ts, scripts/sandbox/utils/yarn.test.ts
The refresh accumulates quarantined packages across retries, handles unsupported failures, enforces retry limits, performs a final plain install, and tests each outcome.

Sequence Diagram(s)

sequenceDiagram
  participant refreshBeforeStorybookLockfile
  participant Yarn
  participant PackageManifest
  refreshBeforeStorybookLockfile->>Yarn: Run lockfile installation
  Yarn-->>refreshBeforeStorybookLockfile: Return YN0016 package failures
  refreshBeforeStorybookLockfile->>PackageManifest: Read dependency ranges
  PackageManifest-->>refreshBeforeStorybookLockfile: Return bounded descriptors
  refreshBeforeStorybookLockfile->>Yarn: Run targeted retry
  Yarn-->>refreshBeforeStorybookLockfile: Return installation result
Loading

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/sandbox/utils/yarn.test.ts`:
- Around line 111-119: Update failResolveSteps so it only stores the supplied
errors for the test, without calling mockImplementation. Add a beforeEach block
that installs the single runCommand mock implementation, consuming the queued
errors for resolve steps while preserving the existing successful response
behavior.
- Around line 17-18: Update the generate module mock in yarn.test.ts to use a
spy mock via vi.mock('../generate.ts', { spy: true }). Move runCommand’s
mockImplementation from failResolveSteps into beforeEach, and leave
failResolveSteps responsible only for configuring the error queue consumed by
that implementation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0948e7d4-a2ee-43f6-9fd6-2ff51671ccdf

📥 Commits

Reviewing files that changed from the base of the PR and between c88236e and 9366c06.

📒 Files selected for processing (3)
  • scripts/sandbox/generate.ts
  • scripts/sandbox/utils/yarn.test.ts
  • scripts/sandbox/utils/yarn.ts

Comment thread scripts/sandbox/utils/yarn.test.ts
Comment thread scripts/sandbox/utils/yarn.test.ts
@valentinpalkovic valentinpalkovic added the build Internal-facing build tooling & test updates label Aug 5, 2026
@ndelangen ndelangen self-assigned this Aug 6, 2026
@ndelangen ndelangen added patch:yes Bugfix & documentation PR that need to be picked to main branch ci:normal Run our default set of CI jobs (choose this for most PRs). qa:skip Pull Requests that do not need any QA. (e.g. documentation) labels Aug 6, 2026
@ndelangen ndelangen moved this to In Progress in Core Team Projects Aug 6, 2026
@valentinpalkovic
valentinpalkovic merged commit 98fb332 into next Aug 6, 2026
33 of 41 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Core Team Projects Aug 6, 2026
@valentinpalkovic
valentinpalkovic deleted the valentin/sandbox-age-gate-narrow-ranges branch August 6, 2026 07:42
ndelangen pushed a commit that referenced this pull request Aug 6, 2026
…narrow-ranges

Build: Narrow only quarantined ranges when generating sandboxes
(cherry picked from commit 98fb332)
@github-actions github-actions Bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Aug 6, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Aug 13, 2026
3 of 9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Internal-facing build tooling & test updates ci:normal Run our default set of CI jobs (choose this for most PRs). patch:done Patch/release PRs already cherry-picked to main/release branch patch:yes Bugfix & documentation PR that need to be picked to main branch qa:skip Pull Requests that do not need any QA. (e.g. documentation)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants