Conversation
Adds diffState/applyStateDelta/mergeStateDelta/selectBaseline under state/stream plus a hydrateReducer that three-way merges streamed server state into the live store, keeping slots the client changed and ignoring deltas after a client reset. Exposed through __INTERNAL__ for the React SSR adapters. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…of its script tag ServerData wrote JSON.stringify output directly into a <script>, so a string containing </script> ended the tag early. Escape <, >, &, U+2028 and U+2029 as JSON unicode escapes, which keeps the payload valid JSON. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
createServerStore builds the redux-style store, controller and manager wiring once so the Express and Next.js adapters stop duplicating it. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…ive state useCacheState now uses useSyncExternalStore's getServerSnapshot in the browser so a Suspense boundary that hydrates after the store has already changed (manager updates, streamed data) still matches the server HTML. Updates keep flowing through StateContext, so transitions remain non-blocking. DataProvider provides the snapshot through the internal ServerSnapshotContext; React 16/17 and React Native keep the plain context read. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…et window The Next.js DataProvider decided the server store was complete after a fixed 10ms without in-flight fetches, so any async Server Component that resolved later left #data-client-data empty and the client refetched everything it had just received as HTML. The provider now registers useServerInsertedHTML: the shell carries the state so far as an inert JSON baseline and every later flush prepends a delta script describing what changed since. The client folds these into the hydration snapshot and merges them into the live store (HYDRATE) as they arrive, so each Suspense boundary hydrates against exactly what it was rendered from. Also: nonce prop for CSP, managers accepted as a factory so each request gets its own instances (arrays are ignored on the server with a warning), and a local next/navigation declaration under typings/ that is not shipped. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…gnored typings/ directory Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…er streaming hydration in jsdom A boundary whose data the server never sent (a delta lost to a serialization failure, or arriving after its boundary hydrated) would suspend on every hydration retry because the snapshot alone never gains that data. The hydration view now overlays the server snapshot on the live store, so such boundaries hydrate after exactly one client fetch while everything the server did send still wins. Adds jsdom coverage for both the plain DataProvider (late boundary hydrates against server state, StrictMode, transitions, legacy branch) and the Next.js client (deltas streaming into dehydrated boundaries, queued deltas, client reset, missing baseline, document still loading, managers factory). Test fixtures under __tests__/fixtures are no longer collected as suites. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…e and limitations Also exports NextDataProviderProps, lists react-dom as an optional peer for the nextjs entry, and makes the Next.js example exercise a Server Component that resolves after the shell. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…caping Co-authored-by: Nathaniel Tucker <me@ntucker.me>
🦋 Changeset detectedLatest commit: ffed9ea The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
Benchmark Spread
Details
| Benchmark suite | Current: ffed9ea | Previous: 38dbb52 | Ratio |
|---|---|---|---|
setOneEntity in 10k entity store |
151 ops/sec (±0.55%) |
153 ops/sec (±0.97%) |
1.01 |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
Benchmark React
Details
| Benchmark suite | Current: ffed9ea | Previous: 3fa47c8 | Ratio |
|---|---|---|---|
data-client: getlist-100 |
145.99 ops/s (± 5.5%) |
137.94 ops/s (± 4.5%) |
0.94 |
data-client: getlist-500 |
44.25 ops/s (± 5.8%) |
44.05 ops/s (± 3.8%) |
1.00 |
data-client: update-entity |
416.67 ops/s (± 10.0%) |
384.62 ops/s (± 9.3%) |
0.92 |
data-client: update-user |
408.33 ops/s (± 9.6%) |
333.33 ops/s (± 8.6%) |
0.82 |
data-client: getlist-500-sorted |
50.51 ops/s (± 8.3%) |
43.11 ops/s (± 9.4%) |
0.85 |
data-client: update-entity-sorted |
370.37 ops/s (± 9.7%) |
312.5 ops/s (± 7.9%) |
0.84 |
data-client: update-entity-multi-view |
392.31 ops/s (± 8.7%) |
327.96 ops/s (± 7.5%) |
0.84 |
data-client: list-detail-switch-10 |
11.35 ops/s (± 7.7%) |
9.9 ops/s (± 9.4%) |
0.87 |
data-client: update-user-10000 |
81.63 ops/s (± 13.5%) |
72.2 ops/s (± 14.8%) |
0.88 |
data-client: invalidate-and-resolve |
38.54 ops/s (± 6.2%) |
37.67 ops/s (± 5.6%) |
0.98 |
data-client: unshift-item |
232.56 ops/s (± 5.2%) |
219.81 ops/s (± 6.0%) |
0.95 |
data-client: delete-item |
312.5 ops/s (± 4.9%) |
285.71 ops/s (± 3.8%) |
0.91 |
data-client: move-item |
188.68 ops/s (± 9.9%) |
177.01 ops/s (± 7.9%) |
0.94 |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: ffed9ea | Previous: 93555f8 | Ratio |
|---|---|---|---|
normalizeLong |
448 ops/sec (±3.65%) |
447 ops/sec (±4.75%) |
1.00 |
normalizeLong Values |
397 ops/sec (±1.10%) |
408 ops/sec (±1.51%) |
1.03 |
normalizeLong Scalar |
355 ops/sec (±3.39%) |
352 ops/sec (±3.69%) |
0.99 |
normalizeLong Scalar update |
857 ops/sec (±1.17%) |
895 ops/sec (±0.68%) |
1.04 |
denormalizeLong |
229 ops/sec (±6.46%) |
233 ops/sec (±6.00%) |
1.02 |
denormalizeLong Values |
221 ops/sec (±5.51%) |
213 ops/sec (±4.94%) |
0.96 |
denormalizeLong donotcache |
1068 ops/sec (±1.00%) |
1002 ops/sec (±0.64%) |
0.94 |
denormalizeLong Values donotcache |
759 ops/sec (±0.20%) |
737 ops/sec (±0.59%) |
0.97 |
denormalizeLong Scalar donotcache |
1176 ops/sec (±0.26%) |
1073 ops/sec (±0.13%) |
0.91 |
denormalizeShort donotcache 500x |
1352 ops/sec (±0.08%) |
1437 ops/sec (±0.29%) |
1.06 |
denormalizeShort 500x |
590 ops/sec (±6.71%) |
639 ops/sec (±6.97%) |
1.08 |
denormalizeShort 500x withCache |
7223 ops/sec (±1.02%) |
6834 ops/sec (±5.52%) |
0.95 |
queryShort 500x withCache |
3363 ops/sec (±0.72%) |
3206 ops/sec (±0.97%) |
0.95 |
buildQueryKey All |
51329 ops/sec (±1.52%) |
58478 ops/sec (±1.39%) |
1.14 |
query All withCache |
5993 ops/sec (±2.78%) |
5828 ops/sec (±2.46%) |
0.97 |
denormalizeLong with mixin Entity |
211 ops/sec (±8.08%) |
209 ops/sec (±7.50%) |
0.99 |
denormalizeLong withCache |
7450 ops/sec (±0.22%) |
7517 ops/sec (±0.32%) |
1.01 |
denormalizeLong withCache (Scalar churn) |
7368 ops/sec (±0.89%) |
7491 ops/sec (±0.24%) |
1.02 |
denormalizeLong Values withCache |
6511 ops/sec (±1.19%) |
5132 ops/sec (±1.60%) |
0.79 |
denormalizeLong Scalar withCache |
7374 ops/sec (±0.38%) |
7648 ops/sec (±0.98%) |
1.04 |
denormalizeLong Scalar update withCache |
5510 ops/sec (±1.04%) |
4074 ops/sec (±0.24%) |
0.74 |
denormalizeLong All withCache |
6130 ops/sec (±0.28%) |
6058 ops/sec (±0.18%) |
0.99 |
denormalizeLong Query-sorted withCache |
6234 ops/sec (±2.10%) |
6098 ops/sec (±1.48%) |
0.98 |
denormalizeLongAndShort withEntityCacheOnly |
1581 ops/sec (±1.64%) |
1748 ops/sec (±0.19%) |
1.11 |
denormalize bidirectional 50 |
4138 ops/sec (±10.27%) |
4498 ops/sec (±10.41%) |
1.09 |
denormalize bidirectional 50 donotcache |
44486 ops/sec (±0.22%) |
42385 ops/sec (±1.43%) |
0.95 |
getResponse |
5075 ops/sec (±4.54%) |
4418 ops/sec (±4.05%) |
0.87 |
getResponse (null) |
10275618 ops/sec (±0.41%) |
10236651 ops/sec (±0.70%) |
1.00 |
getResponse (clear cache) |
204 ops/sec (±9.23%) |
203 ops/sec (±7.07%) |
1.00 |
getSmallResponse |
3810 ops/sec (±1.20%) |
3543 ops/sec (±0.24%) |
0.93 |
getSmallInferredResponse |
3023 ops/sec (±0.32%) |
2852 ops/sec (±1.79%) |
0.94 |
getResponse Collection |
4661 ops/sec (±5.99%) |
4306 ops/sec (±4.05%) |
0.92 |
get Collection |
2826 ops/sec (±0.32%) |
2707 ops/sec (±0.19%) |
0.96 |
get Query-sorted |
5889 ops/sec (±2.54%) |
5052 ops/sec (±1.47%) |
0.86 |
setLong |
448 ops/sec (±0.27%) |
467 ops/sec (±0.60%) |
1.04 |
setLongWithMerge |
257 ops/sec (±0.23%) |
257 ops/sec (±0.45%) |
1 |
setLongWithSimpleMerge |
268 ops/sec (±0.42%) |
272 ops/sec (±0.80%) |
1.01 |
setSmallResponse 500x |
873 ops/sec (±1.42%) |
926 ops/sec (±1.48%) |
1.06 |
This comment was automatically generated by workflow using github-action-benchmark.
Co-authored-by: Nathaniel Tucker <me@ntucker.me>
Manager instances cannot be shared between server requests, so the array form only ever applied to the browser while the server kept its defaults. The prop now takes a function, called once per request on the server and once in the browser; an array throws with a migration hint. BREAKING CHANGE: @data-client/react/nextjs DataProvider managers prop changes from Manager[] to () => Manager[]. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
…kfile The nextjs managers change ships as a minor, so @data-client/img and @data-client/test must accept 0.19.x; also records the optional react-dom peer in yarn.lock. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
CHANGE_THIS_PR The streaming handoff design is the right shape for this problem — baseline + deltas via What blocks Ready (adversarial pass kept these):
Not asking in this PR: managers factory (array was already unused for the server store; warn + factory is an improvement), soft-nav / Draft is fine; Ready needs green |
|
Size Change: +778 B (+0.96%) Total Size: 81.8 kB 📦 View Changed
ℹ️ View Unchanged
|
- a delta that ends the baseline wait before DOMContentLoaded no longer lets the stale load listener clear the receiver installed later; the pending wait is cleared once settled - the client managers factory result is cached on the per-document snapshot store so StrictMode's double useMemo cannot run it twice - Controller is honored on the server store and SSR controller; gcPolicy is documented as browser-only; store providers no longer receive props consumed at store creation - only StateDelta and StateBaseline are public; createServerStore drops its unused managers return Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
CHANGE_THIS_PR (updated for Prior note raced this push. Cleared on this head:
Still blocks Ready (adversarial pass kept these; CircleCI
Not asking: soft-nav streaming, Express 10ms path, CodeQL on the double-stringify / test regexes (false positives), website GHA Draft is fine; Ready needs green |
|
CHANGE_THIS_PR (updated for
Still blocks merge (adversarial pass kept these; CircleCI
Not asking: soft-nav streaming, Express 10ms path, CodeQL / GHA website typecheck (unrelated; CircleCI typecheck green), or redesign of overlay/merge/ Ready needs green |
Lazy-require react-dom/client after the LegacyReact gate so describe.skip can run. Gate DOM-preserving / no-recoverable-warning asserts to React 19 and check reset-vs-delta and mid-hydration Probe via the live store. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
On 18, setResponse while a sibling is dehydrated is deferred, and a client reset can remount from the snapshot. Gate those live-store claims to React 19; keep data, refetch, and stream liveTitle asserts. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #4090 +/- ##
==========================================
- Coverage 97.84% 97.59% -0.25%
==========================================
Files 156 167 +11
Lines 3057 3243 +186
Branches 612 661 +49
==========================================
+ Hits 2991 3165 +174
- Misses 18 21 +3
- Partials 48 57 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Drop the unused-generality id helper; R19 probe covers the late-update store read, and reset asserts getState() inline. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Prior matrix CHANGE_THIS_PR items are cleared on this head:
Adversarial pass on the R18 re-spec: KILL as CHANGE_THIS_PR — honest React 18 hydration scheduling, not a missing product path. Optional FOLLOW_UP only if we ever need stronger R18 guarantees around reset-during-streaming vs remount/snapshot fold — not this PR. Hold squash for Bugbot success. GHA “Typecheck website” / CodeQL remain the prior unrelated / false-positive set; CircleCI typecheck is green. No further changes requested on this PR. |
Staff review — LGTM / FOLLOW_UP only @
|
d7ecc8c to
f123190
Compare
|
Staff LGTM (updated after second force-push back to
CHANGE_THIS_PR cleared
Prior LGTM at
Hold squash for
Optional FOLLOW_UP only (not this PR): browser No further changes requested on this PR. |
|
CHANGE_THIS_PR (updated for Prior Staff LGTM at Blocks Ready
Not asking: GHA website Ready needs green |
Once-per-mount via useRef is correct. StrictMode 17/18 discards a render/useRef pass so the factory runs twice; React 19 keeps one. Assert stability across re-renders within a mount and keep init/cleanup pairing on the live instance. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
The browser DataProvider now accepts a factory; arrays are transitional. Drop the stale "unchanged / Manager[] only" line so release notes do not contradict the sibling changeset. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Prior CHANGE_THIS_PR at
Prior LGTM still stands for the streaming/hydration design (baseline + deltas, three-way Hold squash for
No further changes requested on this PR. Optional FOLLOW_UP only if we later want stronger R18 remount-from-snapshot guarantees — not this PR. |
Rename escapeJsonForHtml to escapeJsonForScript: CodeQL treats any callee named like an HTML sanitizer as producing output unsafe for code construction, hiding the actual \u003c/U+2028 escaping behind the name. Test regexes that parse generated <script> tags are now case-insensitive and tolerate whitespace before the closing bracket. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Prior CHANGE_THIS_PR at
No CHANGE_THIS_PR. Architecture LGTM unchanged: baseline + deltas, three-way Hold squash for
GHA No further changes requested on this PR. Optional FOLLOW_UP only if we later want stronger R18 remount-from-snapshot guarantees — not this PR. |
|
CHANGE_THIS_PR — real Next 16 consumer validation found a client handoff race on I tested packed artifacts from this exact head in the order-book app that originally reproduced the 10 ms bug:
Server side passes: production build is clean; 8 concurrent mixed-symbol requests each returned 87 data cells and a route-isolated cache. The baseline is the 101-byte initial state and 3–5 streamed deltas reconstruct the expected Client side does not meet the zero-refetch claim on this head. On a clean hard navigation, browser
(The later direct depth request from this app's Binance sequence synchronizer is expected and separate.) No hydration warning was required to trigger this; useful SSR HTML remained visible, but the Data Client requests were duplicated. The raw response ordering is correct: each delta script precedes its dependent Fizz HTML. The failing assumption is that this also precedes Client Component execution. In Next 16, Flight can start that client work before the inserted HTML delta script executes and before I validated the conservative fix below: const element = document.getElementById(BASELINE_ID);
-if (!element && document.readyState === 'loading') {
+if (document.readyState === 'loading') {
throw (queue.pending ??= new Promise<void>(resolve => {
- // whichever fires first wins; the loser must not clobber the receiver
const done = () => {
document.removeEventListener('DOMContentLoaded', done);
- if (queue.onDelta === done) queue.onDelta = undefined;
queue.pending = undefined;
resolve();
};
document.addEventListener('DOMContentLoaded', done);
- queue.onDelta = done;
}));
}In other words: while the initial document is still parsing, wait through all streamed deltas; do not let the first delta end bootstrap. At With only that runtime refinement:
The regression test needs the baseline installed before If preserving progressive interactivity is required, the alternative is a larger endpoint-aware client wait: missing I would not merge the current head with the zero-client-request claim unchanged. The |
Rewrite the SSR guide, changeset, blog, Next example README, and agent skills around baseline-plus-delta hydration. Inline the sequence once via the existing diagrams MDX extract. Keep Open questions honest: waiters and fold-on-script are the remaining client clock, not this commit. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
Rewrite the streaming test HTML parser so CodeQL does not treat a </script> regex as a bad tag filter. Type homepage SVGs from the SVGR import to avoid dual @types/react conflict in website typecheck. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
CHANGE_THIS_PR (adversarial re-check @ Tip Verified on this SHA:
Release surfaces still overclaim the unfinished contract (changeset, Before Ready — pick one:
Do not treat DOMContentLoaded-always as the required sole fix (validated progressive tradeoff elsewhere; not the intended contract). Soft LGTM of hygiene while changelog/guide claim zero-refetch is not acceptable for a minor. Architecture already on tip (baseline+deltas, three-way |
Lane B honesty pass: changeset, blog, SSR guide, Next example README, skill, and JSDoc now match the tip. Wire (G0 + StateDelta + HYDRATE) ships; per-key waiters, zero-refetch, and generic Fizz incremental emission do not. A DOMContentLoaded interim is not forbidden. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (Lane B @ CHANGE_THIS_PR at
Runtime race remains known/documented — Lane A is follow-up after this lands, not a blocker for Lane B honesty. Bugbot SUCCESS on this HEAD. Nathaniel HOLD on squash stands — no merge from Staff. |
Split the SSR hydration sequence into an overview with black boxes and one zoom per box. Replace Fizz/Flight jargon with renderToPipeableStream and RSC in the guide, skill, changeset, blog, example README, and Next adapter comments. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Lane B LGTM at
Non-blocking nit: Bugbot SUCCESS on this HEAD. Nathaniel HOLD on squash stands — no merge from Staff. Lane A (waiters + fold-on-script + RSC-first tests) remains follow-up after merge. No CHANGE_THIS_PR. Coding: no spawn for this tip. |
Co-authored-by: Nathaniel Tucker <me@ntucker.me>
SSR is a reference inside data-client-react, not a standalone skill. Decision trees include an SSR column only where behavior differs; otherwise they are the same as client (streamed baseline+deltas instead of one initialState). Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Lane B LGTM at
Lane A (waiters + fold-on-script) remains follow-up after merge. HOLD squash until Nathaniel clears merge. |
Revert the previous fold (per-row "Same" tables and intended-behavior claims in SKILL.md). SSR now lives in references/ssr.md inside data-client-react and documents only what differs from the browser: entry per host, streamed baseline + StateDelta on Next.js App Router vs one initialState elsewhere, and what is not shipped (per-key waiters, fold-on-script, streamed generic renderToPipeableStream). No standalone data-client-ssr skill. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
|
Staff LGTM (updated for Lane B LGTM at
No CHANGE_THIS_PR. Architecture LGTM unchanged (baseline + deltas, three-way Hold squash for
Lane A (waiters + fold-on-script + RSC-first fetch-count tests) remains follow-up after merge. Coding: no spawn for this tip. |
Add RSC as a trigger term in the data-client-react description, drop the docs-terminology rule from references/ssr.md (not a host difference), and state the SUBSCRIBE caveat without restating browser behavior. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
Co-authored-by: Nathaniel Tucker <me@ntucker.me>
Motivation
A streaming HTML response is a sequence of committed revisions. A store serialized once — after a quiet window, or after
useReadyCacheState()— cannot describe that sequence. Late islands arrive as markup whose endpoint/meta never landed in the browser, souseSuspense()takes the fetch branch on an empty seed.PR 4090 already replaced the Next 10 ms
createPersistedStoreServersnapshot on the wire: an inert baseline plus per-flushStateDeltas. That is not the remaining bug. Head still folds into the live store only fromStreamedStateReceiver’s layout effect, has no per-key waiter, and letsgetSnapshotStore()return from the empty baseline while RSC runsuseLive(). GenericrenderToPipeableStream/ Anansi still emit onedataclientJSON blob.Lane B (this tip): stop claiming zero-refetch / per-key waiters as shipped behavior. The Next 16 RSC-first race remains open and is out of Lane B scope. Do not ship Lane A (fold-on-script + per-key waiters + event-order tests) in this PR.
Secondary defects, same PR: hydration reads must overlay the server snapshot so a late boundary does not mismatch the live store (Gap B);
</script>in API data must be escaped; Nextmanagersmust be a per-request factory.Solution
This tip ships: the wire (inert baseline +
StateDelta+HYDRATE), three-way merge, server-snapshot overlay, Nextmanagersfactory, and honest release surfaces. Per-key waiters, fold-on-script-arrival, and genericrenderToPipeableStreambaseline+delta are not in this release.Wire format (
@data-client/core).StateDelta,diffState/applyStateDelta/mergeStateDelta/selectBaseline/overlayState, andHYDRATE(hydrateReducer: ignore after client reset;resetopcode for server resets). Three-way merge: a slot the client changed keeps the client value. No React, Next, or Anansi imports here.Next transport (
@data-client/react/nextjs).useServerInsertedHTML()emits the baseline then deltas into the HTML stream. LiveHYDRATEruns fromStreamedStateReceiver’s layout effect.initialStateis the one-time seed. Keepnonce, escaped JSON, andmanagers={() => Manager[]}(array throws on this entry).Hydration reads. Browser
useCacheStateusesuseSyncExternalStorewith a server snapshot overlay so a boundary whose piece is late hydrates against what the server rendered, then converges to live state. React 19 is the DOM-preserving target; React 18 may client-render a still-dehydrated boundary when the store updates.managersfactory. Function form is the long-term API. Next entry: function only. BrowserDataProvider: function supported, array transitional.Docs honesty (Lane B). Changeset, blog, SSR guide, Next example README, the
data-client-reactSSR reference (no standalonedata-client-ssrskill), and JSDoc describe what this tip does. They do not claim a per-key waiter or zero-refetch. The intended client clock (waiters + fold-on-script) is labeled as future work. The skill does not forbid aDOMContentLoadedinterim. Figures: an overview with black boxes, then one zoom per box (docs/core/diagrams/_streamed_hydration.mdx). Labels are RSC andrenderToPipeableStream.The intended coordinator (fold-on-script, per-key
useSuspensewaiters, genericrenderToPipeableStreambaseline+delta, event-order tests) is Lane A / future client-clock work, not this tip.Open questions
StreamedStateReceiver’s layout effect), and genericrenderToPipeableStream/ Anansi baseline+delta emission are intended, not shipped. Release surfaces now match this tip.1dd5bfd). Out of Lane B scope. A document-wideDOMContentLoadedwait is an acceptable interim, not the required sole fix.initManagerdisposers remain discarded (no request-end hook). Server managers stay inert.managers={array}(@data-client/test/ Vue still construct arrays).