Future-Readiness — What would have to break for an external state-read primitive to exist
Framing
The absence is not an oversight; it is a load-bearing boundary. Three invariants would each have to break — and they are not equally reversible.
Seam 1 — the render-only dispatcher gate (large, additive, partially reversible)
Every read funnels through ReactSharedInternals.H, live only between renderWithHooks and finishRenderingHooks (ReactFiberHooks.js:511,656,664). A read-from-outside API needs a render-independent read path. First safe step: never expose raw fiber reads — expose committed-tree snapshots built on the existing useSyncExternalStore consistency machinery, never in-flight WIP state.
Seam 2 — concurrency makes 'the state' multi-valued (IRREVERSIBLE)
Double buffering (fiber.alternate — ReactInternalTypes.js:174; createWorkInProgress — ReactFiber.js:327-355) plus the scheduler's interruptible lanes mean committed and in-flight values are simultaneously live. Any external read must choose committed-vs-in-flight semantics or tear. This is the load-bearing wall — it is the same property that makes time-slicing, Suspense, transitions, and Offscreen safe. Exposing uncontrolled reads would forfeit React's ownership of when reads happen, and could not be walked back.
Seam 3 — positional hook identity (epic, breaking, but local)
Hooks are addressed by call order, not by key (ReactFiberHooks.js:194-200,263-266). There is no name to read by. Keyed identity would mean changing the hook model itself. Don't retrofit hooks — the keyed, addressable path already exists as useSyncExternalStore.
The safe seam already exists and points the other way
useSyncExternalStore (:1633) is React's expand-contract bridge: snapshot per render + checkIfSnapshotChanged forcing a sync re-render on tearing (:1846-1850). react-cache was an earlier experiment in the same spirit. The reversible evolution is to keep state outside the tree and enrich the doorway (selectors, derived snapshots, transition-aware reads) — not to drill a hole into fiber internals.
Ranked roadmap (by reversibility)
| Seam | Effort | Reversibility | Verdict |
|---|
| Hook identity (keyed) | Epic | Irreversible (local API) | Avoid — use external stores |
| Dispatcher gate (2nd read path) | Large | Partially reversible (additive) | Only as committed-snapshot reads |
| Concurrency read-ownership | — | Irreversible (global) | Do not break — it is the foundation |
Suggestion
Add an explicit dispatcher-bridge edge react ⇒ react-reconciler to the board. The two packages have no direct import edge — they are joined only by the mutable ReactSharedInternals.H slot during render. Making that runtime bridge visible explains at a glance why reads are render-gated and why an external primitive has nowhere to attach.