fw-08 — Analysis
The single invariant
Only the most recent navigation may commit.
Every stale-data bug in a router violates it. Stating it this way collapses four separate bugs — stale loader, back-during-load, redirect race, double submit — into one.
Required invariants
- Only the most recent navigation commits.
- A superseded navigation's loaders are cancelled and their results discarded.
- A redirect during loading prevents the original navigation from committing.
- Scroll restoration happens after the content determining page height exists.
- Navigation blocking cannot silently swallow a browser back navigation.
The three fixes, and where each stops working
| Fix | Stops the work? | Correct with a server side effect? |
|---|---|---|
| Render-time guard | no | no — the effect already happened |
| Sequence number | no | no |
AbortController | best-effort | closest — the server may still have acted |
Ship AbortController plus a sequence guard: cancellation is best-effort, so late responses
must still be ignored.
The question that separates seniority levels: what if the loader has a server side effect? No client-side fix suffices. You need idempotency keys, or the operation does not belong in a loader. That is an architectural answer, not a code fix.
Platform constraints you cannot engineer around
| Reality | Consequence |
|---|---|
popstate does not report direction | track indices yourself |
pushState does not fire popstate | handle your own navigations explicitly |
| The history stack is unreadable | no "can I go back?" without bookkeeping |
| Back cannot be cancelled | unsaved-changes guards only work for router-controlled navigation |
The last is a deliberate platform decision — trapping the back button would be user-hostile — which
is why beforeunload is limited to a browser-controlled dialog. The Navigation API exists to give
back a principled version of the capability.
The recurring anchoring problem
Restoring scroll before async content resolves scrolls to a position that does not exist and clamps.
This is the same problem as fw-10's virtualized list and the browser's own scroll anchoring
(bi-08): you cannot restore a position in a document whose size you do not yet know.