Add per-slot error attribution for instant validation using slot markers and config depth preference (#91610)
When a validation boundary spans multiple parallel slots, errors were
previously attributed to whichever unstable_instant config was found
first during tree iteration — which varied between turbopack and
webpack. This made the "Caused by: Instant Validation" source
non-deterministic and sometimes pointed to the wrong slot's config.
This adds a SlotMarker client component that wraps each slot's content
at fork points (where parallel routes > 1). The marker's
dynamically-named inner function appears in the SSR component stack,
allowing resolveInstantStack to identify which slot an error belongs to
and look up that slot's config. When a slot has no config, it falls back
to slotStacks[0] (the root config).
The root config is now selected by config depth preference rather than
first-found. configDepth tracks how many URL-consuming segments deep a
config was found, with deeper configs preferred as more specific. At
equal depth, the children slot is preferred over named slots. This
ensures deterministic attribution regardless of bundler iteration order.
Key changes:
- SlotMarker component in boundary-impl.tsx takes a name prop and lazily
creates named inner functions cached by name
- slotStacks array replaces the singleton createInstantStack on
InstantValidationState (index 0 = root config, 1+ = per-slot)
- configDepth on TreeResult only counts URL-consuming segments —
synthetic segments like (__SLOT__), __PAGE__, and route groups don't
contribute
- resolveInstantStack parses component stacks for slot markers and maps
to the correct config
- wrapSlotsWithMarkers called at every fork in both
buildSharedTreeSeedData and buildNewTreeSeedData