Skip to content

[pull] canary from vercel:canary - #1326

Merged
pull[bot] merged 7 commits into
code:canaryfrom
vercel:canary
Aug 21, 2026
Merged

[pull] canary from vercel:canary#1326
pull[bot] merged 7 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented Aug 21, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

aurorascharff and others added 7 commits August 21, 2026 16:01
## Summary

Dogfooding the Partial Prefetching adoption skill on v0 exposed two
preservation checks that should be part of the main workflow:

- trace custom Link wrapper consumers and distinguish declarative
prefetch props from imperative hover or touch prefetching
- treat existing instant() assertions as preservation contracts, and
expand caching only to the smallest coherent rendered subtree when a
data-only cache does not restore the prefetched UI

## Verification

- pnpm prettier --with-node-modules --ignore-path .prettierignore
--check skills/next-partial-prefetching-adoption/SKILL.md
- Commit hook lint-staged formatting passed
- Not run: quick_validate.py because PyYAML is unavailable in the local
skill validator runtime

<!-- NEXT_JS_LLM -->
## Summary

Turbopack currently builds an App Router page without a root layout,
leaving the problem to surface later at runtime. Report it while
building the app structure instead:

`route/page.js doesn't have a root layout. To fix this error, make sure
every page has a root layout.`

The check uses the layouts already inherited during directory-tree
traversal, so route groups and apps with multiple root layouts keep
working. Route handlers are unaffected.

Webpack behavior is intentionally unchanged in this PR.

## Verification

- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/create-root-layout/create-root-layout.test.ts`
- `HEADLESS=true pnpm test-start-turbo
test/e2e/app-dir/create-root-layout/create-root-layout.test.ts`
- `HEADLESS=true pnpm test-dev-webpack
test/e2e/app-dir/create-root-layout/create-root-layout.test.ts`
- `HEADLESS=true pnpm test-start-webpack
test/e2e/app-dir/create-root-layout/create-root-layout.test.ts`
- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/root-layout/root-layout.test.ts`
- The `brower.eval(callback)` version was a bit weird, use
beforePageLoad as we do everywhere else
- Properly parse the URL and match against the pathname, to not break
with `?dpl`
…llows more work to be discovered (#95974)

## What

Adds `scope_unbounded `, a parallel scope to turbo-tasks: jobs run on a
shared work-queue, any job may enqueue more, and the pool is drained by
the runtime worker threads plus the calling thread until empty.

## Why

The garbage collector (later in this stack) needs to process a pool of
work that *discovers more work as it runs* — collecting a task cascades
into collecting newly-parentless children. A fixed `parallel::for_each`
can't express that. `scope_self_feeding` is the general primitive for
"parallel pool where jobs spawn jobs".

## Design notes

- **Deadlock-safe on thread-limited / contended runtimes.** Helper
workers are a pure optimization: the calling thread always makes
progress on the shared queue on its own, so the pool completes even when
no worker threads are available.
- Supports growing/shrinking the set of workers pulling from the queue
based on the amount of work available.
- Supports a simple mostly lock free way to aggregate data from the
tasks
- Supports a way for tasks to abort the whole queue, which is important
for making GC interruptible

## Testing

There are a fair number of new unit tests and i have done some runs
under miri
This is everything except `turbo-tasks-[backend]`

Using ast-grep replacement:

- search: `|$$$ARGS| async move {$$$BODY}`
- replace: `async |$$$ARGS| {$$$BODY}`

This also made it obvious in some places that we don't actually need
async-await,
e.g. `.map(async |v| v.to_resolved.await)`
Adds discriminated error messages for `unstable_navigation()` used
outside of Suspense.

Previously we only had to discriminate two kinds of errors in each
validation flow:
- App Shell -- 1. link data (if it resolves in `Runtime`) or 2. dynamic
data (if it resolves in `Dynamic`)
- Static Shell -- 1. runtime data (if it resolves in `Runtime`) or 2.
dynamic data (if it resolves in `Dynamic`)

However, with `navigation()` (96908), the App Shell flow needs to
distinguish three kinds: 1. link data, 2. navigation (if it resolves in
`NavigationRuntime`), and 3. dynamic data. This complicates the
validation code a bit, because we can no longer get away with one retry.
To accommodate this, i restructured the validation code to no longer
recurse as a method of retrying. We just loop over an array that defines
what order we should try the stages in + what kind of hole shows up in
each stage.

I've also removed `hasAmbiguousErrors` and the associated logic. since
we're no longer mixing Static+Runtime segments in a runtime prefetch,
this is no longer relevant -- all segments used for validation use one
stage, so whether or not the error is ambiguous only depends on the
stage.

For ease of reviewing, this is split into two commits:
1. updating the (many) places that need a new `DynamicHoleKind` in our
error messages. This one has a lot of pretty mechanical changes, and was
also machine-reviewed for consistency already, but the messages
themselves are worth looking at (we'll also need to update docs --
leaving that for a follow-up)
2. the actual instant validation changes, i.e. using the new
`DynamicHoleKind` and adding the new pass
@pull pull Bot locked and limited conversation to collaborators Aug 21, 2026
@pull pull Bot added the ⤵️ pull label Aug 21, 2026
@pull
pull Bot merged commit 43273a1 into code:canary Aug 21, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants