[PR #1061] [MERGED] feat(app-router): track visible commit versions for browser operations #1060

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

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1061
Author: @NathanDrake2406
Created: 5/5/2026
Status: Merged
Merged: 5/5/2026
Merged by: @james-elicx

Base: mainHead: nathan/726-core-01-operation-record


📝 Commits (1)

  • 28ed7a0 feat(app-router): track visible commit versions for browser operations

📊 Changes

5 files changed (+313 additions, -70 deletions)

View changed files

📝 packages/vinext/src/server/app-browser-entry.ts (+22 -0)
📝 packages/vinext/src/server/app-browser-navigation-controller.ts (+12 -0)
📝 packages/vinext/src/server/app-browser-state.ts (+111 -20)
📝 tests/app-browser-entry.test.ts (+159 -46)
📝 tests/prefetch-cache.test.ts (+9 -4)

📄 Description

What this changes

Implements #726-CORE-01 from #726 by adding the first browser-visible lifecycle spine to the App Router browser state. Browser router state now carries visibleCommitVersion and the operation that produced the currently visible router-state commit.

Why

Issue #726 calls out that activeNavigationId is not enough lifecycle authority for same-URL refresh and server-action races. Before this PR, browser-visible router state changed without a versioned commit baseline or a typed operation record, which made later stale-result gates impossible to express cleanly.

visibleCommitVersion intentionally names the router lifecycle commit baseline from #726. It advances when the reducer accepts a new visible router-state commit; it is not a React DOM paint signal.

Approach

  • Add OperationRecord types with explicit lanes for navigation, refresh, traverse, server-action, and HMR work.
  • Add visibleCommitVersion and activeOperation to AppRouterState, initialized at hydration version 0.
  • Make pending navigation commits capture their lane and starting visible commit version when the RSC payload resolves into a pending commit.
  • Route reducer commits through one helper, commitVisibleRouterState, which is the only owner that increments visibleCommitVersion and stamps the committed operation.
  • Thread explicit lanes through cached navigation, fetched navigation, same-URL server actions, and HMR replacement without changing current merge/replace/root-layout behavior.
  • Harden the prefetch-cache unit test that CI exposed as timing-sensitive by waiting for the async router.prefetch() fetch side effect instead of assuming one timer tick is enough.

Non-goals for this PR: it does not introduce ApprovedVisibleCommit, NavigationPlanner, broad cache coherence, or the stale same-URL server-action rejection planned for later #726-CORE-04. This PR intentionally creates the versioned ownership data those later gates need.

Validation

  • vp check packages/vinext/src/server/app-browser-state.ts packages/vinext/src/server/app-browser-navigation-controller.ts packages/vinext/src/server/app-browser-entry.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts
  • vp test run tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts
  • vp test run --project unit
  • git diff --check
  • Commit hook: vp check --fix plus knip --no-progress

Risks / follow-ups

The known same-URL server-action stale commit race is still deliberately left in place and documented in code. The observable behavior is unchanged here; follow-up #726-CORE-04 should use startedVisibleCommitVersion to reject or reroute stale same-URL commits.


🔄 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/1061 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 5/5/2026 **Status:** ✅ Merged **Merged:** 5/5/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `nathan/726-core-01-operation-record` --- ### 📝 Commits (1) - [`28ed7a0`](https://github.com/cloudflare/vinext/commit/28ed7a074d3cf12e6110b475fb5837e1841c8bf0) feat(app-router): track visible commit versions for browser operations ### 📊 Changes **5 files changed** (+313 additions, -70 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/app-browser-entry.ts` (+22 -0) 📝 `packages/vinext/src/server/app-browser-navigation-controller.ts` (+12 -0) 📝 `packages/vinext/src/server/app-browser-state.ts` (+111 -20) 📝 `tests/app-browser-entry.test.ts` (+159 -46) 📝 `tests/prefetch-cache.test.ts` (+9 -4) </details> ### 📄 Description ## What this changes Implements `#726-CORE-01` from #726 by adding the first browser-visible lifecycle spine to the App Router browser state. Browser router state now carries `visibleCommitVersion` and the operation that produced the currently visible router-state commit. ## Why Issue #726 calls out that `activeNavigationId` is not enough lifecycle authority for same-URL refresh and server-action races. Before this PR, browser-visible router state changed without a versioned commit baseline or a typed operation record, which made later stale-result gates impossible to express cleanly. `visibleCommitVersion` intentionally names the router lifecycle commit baseline from #726. It advances when the reducer accepts a new visible router-state commit; it is not a React DOM paint signal. ## Approach - Add `OperationRecord` types with explicit lanes for navigation, refresh, traverse, server-action, and HMR work. - Add `visibleCommitVersion` and `activeOperation` to `AppRouterState`, initialized at hydration version `0`. - Make pending navigation commits capture their lane and starting visible commit version when the RSC payload resolves into a pending commit. - Route reducer commits through one helper, `commitVisibleRouterState`, which is the only owner that increments `visibleCommitVersion` and stamps the committed operation. - Thread explicit lanes through cached navigation, fetched navigation, same-URL server actions, and HMR replacement without changing current merge/replace/root-layout behavior. - Harden the prefetch-cache unit test that CI exposed as timing-sensitive by waiting for the async `router.prefetch()` fetch side effect instead of assuming one timer tick is enough. Non-goals for this PR: it does not introduce `ApprovedVisibleCommit`, `NavigationPlanner`, broad cache coherence, or the stale same-URL server-action rejection planned for later `#726-CORE-04`. This PR intentionally creates the versioned ownership data those later gates need. ## Validation - `vp check packages/vinext/src/server/app-browser-state.ts packages/vinext/src/server/app-browser-navigation-controller.ts packages/vinext/src/server/app-browser-entry.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts` - `vp test run tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts` - `vp test run --project unit` - `git diff --check` - Commit hook: `vp check --fix` plus `knip --no-progress` ## Risks / follow-ups The known same-URL server-action stale commit race is still deliberately left in place and documented in code. The observable behavior is unchanged here; follow-up `#726-CORE-04` should use `startedVisibleCommitVersion` to reject or reroute stale same-URL commits. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:47 +02:00
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#1060
No description provided.