[PR #1089] feat(router): expose route graph manifest read model #1088

Open
opened 2026-05-06 13:11:55 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1089
Author: @NathanDrake2406
Created: 5/6/2026
Status: 🔄 Open

Base: mainHead: nathan/726-graph-02-route-manifest


📝 Commits (1)

  • e04749e feat(router): expose route graph manifest read model

📊 Changes

6 files changed (+504 additions, -13 deletions)

View changed files

📝 packages/vinext/src/routing/app-route-graph.ts (+264 -2)
📝 packages/vinext/src/routing/app-router.ts (+35 -9)
📝 tests/app-route-graph.test.ts (+190 -2)
📝 tests/cache-proof.test.ts (+1 -0)
📝 tests/entry-templates.test.ts (+1 -0)
📝 tests/routing.test.ts (+13 -0)

📄 Description

What this changes

Implements #726-GRAPH-02/03 for issue #726 by exposing root-boundary identity from the App Router route graph and adding a minimal RouteManifest read model.

The route graph now includes:

  • RootBoundaryId on graph-minted semantic route IDs
  • deterministic graphVersion
  • RouteManifest with a StaticSegmentGraph
  • semantic lookup maps for routes, pages, route handlers, layouts, templates, slots, and root boundaries

Bonk: please read issue #726 before reviewing so the big-picture route manifest and navigation planner architecture is fresh.

Why

Issue #726 is moving route meaning out of transport keys and scattered runtime observations. The graph already minted semantic IDs for route entries, but callers still only received the raw routes array, with root-boundary identity implicit in layoutTreePositions[0].

That makes future planner, compatibility, and cache-proof work depend on incidental route array shape rather than an owned graph read model.

Approach

This keeps the current route matching behavior intact and adds the thinnest read model on top of the existing route graph output.

The manifest is derived after route validation and sorting, uses only stable semantic facts for its version input, and fails fast if generated layout/template IDs ever lose their matching tree-position metadata. It deliberately does not add a transition automaton, planner ownership, cache dependency graph, skip transport, or runtime compatibility semantics.

appRouteGraph() is exposed as the Layer 4 handoff point for the future #726 navigation planner while appRouter() remains backward-compatible for current callers.

Correctness oracle: Vinext internal invariant for issue #726. The read model must expose stable graph facts without changing current App Router routing behavior.

Rebase note

This branch also includes a one-line tests/app-elements.test.ts expectation update after rebasing onto current main: upstream added artifactCompatibility to AppElementsWire.readMetadata(), and the PR's Vitest unit CI failed until the legacy metadata assertion matched the current codec read model. This is test-only and does not change runtime behavior.

Validation

  • vp test run tests/app-elements.test.ts tests/routing.test.ts tests/app-route-graph.test.ts tests/entry-templates.test.ts
  • vp check packages/vinext/src/routing/app-router.ts packages/vinext/src/routing/app-route-graph.ts tests/app-elements.test.ts
  • commit hook: vp check --fix, knip --no-progress, vp pack
  • vp run vinext#build

vp run vinext#build and the commit hook pack still emit the existing virtual-module external warnings for generated entry placeholders.

Risks / follow-ups

This PR intentionally does not promote any planner decisions or cache authority. It only exposes the minimal graph read model needed by later #726 work.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/1089 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 5/6/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `nathan/726-graph-02-route-manifest` --- ### 📝 Commits (1) - [`e04749e`](https://github.com/cloudflare/vinext/commit/e04749e4c6ab35f22172d615a37aac54a2b71c57) feat(router): expose route graph manifest read model ### 📊 Changes **6 files changed** (+504 additions, -13 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/routing/app-route-graph.ts` (+264 -2) 📝 `packages/vinext/src/routing/app-router.ts` (+35 -9) 📝 `tests/app-route-graph.test.ts` (+190 -2) 📝 `tests/cache-proof.test.ts` (+1 -0) 📝 `tests/entry-templates.test.ts` (+1 -0) 📝 `tests/routing.test.ts` (+13 -0) </details> ### 📄 Description ## What this changes Implements #726-GRAPH-02/03 for issue #726 by exposing root-boundary identity from the App Router route graph and adding a minimal `RouteManifest` read model. The route graph now includes: - `RootBoundaryId` on graph-minted semantic route IDs - deterministic `graphVersion` - `RouteManifest` with a `StaticSegmentGraph` - semantic lookup maps for routes, pages, route handlers, layouts, templates, slots, and root boundaries Bonk: please read issue #726 before reviewing so the big-picture route manifest and navigation planner architecture is fresh. ## Why Issue #726 is moving route meaning out of transport keys and scattered runtime observations. The graph already minted semantic IDs for route entries, but callers still only received the raw `routes` array, with root-boundary identity implicit in `layoutTreePositions[0]`. That makes future planner, compatibility, and cache-proof work depend on incidental route array shape rather than an owned graph read model. ## Approach This keeps the current route matching behavior intact and adds the thinnest read model on top of the existing route graph output. The manifest is derived after route validation and sorting, uses only stable semantic facts for its version input, and fails fast if generated layout/template IDs ever lose their matching tree-position metadata. It deliberately does not add a transition automaton, planner ownership, cache dependency graph, skip transport, or runtime compatibility semantics. `appRouteGraph()` is exposed as the Layer 4 handoff point for the future #726 navigation planner while `appRouter()` remains backward-compatible for current callers. Correctness oracle: Vinext internal invariant for issue #726. The read model must expose stable graph facts without changing current App Router routing behavior. ## Rebase note This branch also includes a one-line `tests/app-elements.test.ts` expectation update after rebasing onto current `main`: upstream added `artifactCompatibility` to `AppElementsWire.readMetadata()`, and the PR's Vitest unit CI failed until the legacy metadata assertion matched the current codec read model. This is test-only and does not change runtime behavior. ## Validation - `vp test run tests/app-elements.test.ts tests/routing.test.ts tests/app-route-graph.test.ts tests/entry-templates.test.ts` - `vp check packages/vinext/src/routing/app-router.ts packages/vinext/src/routing/app-route-graph.ts tests/app-elements.test.ts` - commit hook: `vp check --fix`, `knip --no-progress`, `vp pack` - `vp run vinext#build` `vp run vinext#build` and the commit hook pack still emit the existing virtual-module external warnings for generated entry placeholders. ## Risks / follow-ups This PR intentionally does not promote any planner decisions or cache authority. It only exposes the minimal graph read model needed by later #726 work. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1088
No description provided.