fix: correct appPaths sort order for parallel routes with route groups (#91160)
### What?
Fixes webpack dev 404s when parallel routes have children nested inside
a route group (e.g. `@slot` + `(b1)/page`) and when a parallel route has
`page.tsx` directly inside it (e.g. `@slot/page.tsx`).
### Why?
Two separate issues caused 404s for parallel routes with route groups:
1. **Sort order**: The three `appPaths` sort sites used bare `.sort()`
(lexicographic ordering). `renderPageComponent` relies on
`appPaths[appPaths.length - 1]` being the children/root page. Without
route groups this works because `@` (0x40) sorts after lowercase letters
— `/@slot/page` comes before `/page`. But when the children page is
inside a route group, `(` (0x28) sorts before `@` (0x40), flipping the
order: `/(b1)/page < /@slot/page`. Now the last item is the slot page
instead of the children page, so the manifest lookup fails and a 404 is
returned.
2. **Double `__PAGE__` segment**: When a parallel route like `@slot` has
`page.tsx` directly inside it, `resolveParallelSegments` returns
`[PAGE_SEGMENT]` (an array) to signal that the loader should recurse
into the slot directory to pick up layout/default files. However, the
segment key normalization was mapping `PAGE_SEGMENT` to
`PAGE_SEGMENT_KEY` (`__PAGE__`), while the recursion would also produce
a `__PAGE__` for children — creating a double `__PAGE__` nesting (`slot:
['__PAGE__', { children: ['__PAGE__', ...] }, ...]`).
### How?
**Sort order fix**: Adds a `compareAppPaths` comparator in
`packages/next/src/shared/lib/router/utils/app-paths.ts` that sorts
paths containing `/@` segments before paths without them, ensuring the
children page is always last. Replaces the three bare `.sort()` calls
with `.sort(compareAppPaths)` in:
- `packages/next/src/build/entries.ts`
- `packages/next/src/server/lib/router-utils/setup-dev-bundler.ts`
-
`packages/next/src/server/route-matcher-providers/dev/dev-app-page-route-matcher-provider.ts`
**Loader tree fix**: Maps `PAGE_SEGMENT` to `'(slot)'` in the segment
key normalization (same as `PARALLEL_VIRTUAL_SEGMENT`), instead of
`PAGE_SEGMENT_KEY`. By the time this code is reached,
`parallelSegmentKey === PAGE_SEGMENT` only occurs for the array case
(the string case is handled by the early return), so this is safe. The
actual `__PAGE__` is correctly created by the recursion.
**Before:** `slot: ['__PAGE__', { children: ['__PAGE__', ...] }, ...]`
**After:** `slot: ['(slot)', { children: ['__PAGE__', ...] }, ...]`
Also adds an e2e test that verifies the fix across all modes (Turbopack
dev, Turbopack start, webpack dev).