From 19d75b10b6951342af10f2570bee7afb684f0672 Mon Sep 17 00:00:00 2001 From: Brenley Dueck Date: Tue, 4 Aug 2026 19:51:26 -0500 Subject: [PATCH] Adopted claims derive their prefix from the wire id, not the call address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The identity split (bcbe7e5b) rebound adopted frames to the call's address — function id + args hash — but the document producer stamps _hk keys and region fids under the bare wire id. ctx.frame falls back to the frame id when no claimScope is given, so every adopted claim on an args-bearing call derived a ':hash'-suffixed prefix, missed the registry, and re-rendered fresh clones; their inserts then moved the adopted {$frame} region elements (server-rendered interiors) into the discarded detached tree — streamed content flashed on screen and went blank at hydration. Argless calls (address === id) masked the break. claimScope is the runtime's existing seam for exactly this — region frames already thread the root boundary's scope down — so adoptBoundary now passes the wire id through it, alongside the other unpublished FrameOptions in the spread-cast. Co-Authored-By: Claude Opus 5 --- .changeset/adopt-claim-scope-wire-id.md | 5 +++++ packages/solid-web/frames/src/client.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .changeset/adopt-claim-scope-wire-id.md diff --git a/.changeset/adopt-claim-scope-wire-id.md b/.changeset/adopt-claim-scope-wire-id.md new file mode 100644 index 000000000..9224fa8a0 --- /dev/null +++ b/.changeset/adopt-claim-scope-wire-id.md @@ -0,0 +1,5 @@ +--- +"@solidjs/web": patch +--- + +Thread the document wire id down as the adopted frame's claim scope. The identity split binds the frame to the call ADDRESS (function id + args hash), but the document producer stamps `_hk` hydration keys and region fids under the bare wire id — so every adopted claim on an args-bearing call (e.g. a note list keyed by search text) derived a `:hash`-suffixed prefix, missed the registry, and re-rendered fresh clones whose inserts moved the server-rendered `{$frame}` regions into a discarded detached tree: streamed content flashed and went blank. `claimScope` is the runtime's existing seam for exactly this (nested region frames already thread the root's scope down); adoptBoundary now passes the wire id through it. diff --git a/packages/solid-web/frames/src/client.ts b/packages/solid-web/frames/src/client.ts index 445a6ad9e..bf98449b0 100644 --- a/packages/solid-web/frames/src/client.ts +++ b/packages/solid-web/frames/src/client.ts @@ -689,7 +689,14 @@ function adoptBoundary( const hy = (globalThis as any)._$HY; return !!(hy && hy.fr && hy.fr.pending()); }, - drainRecords + drainRecords, + // The identity split binds the frame to the call ADDRESS (id + args + // hash), but the document producer stamped `_hk` keys and region fids + // under the wire name — the bare function id. Hydration-claim prefixes + // must derive from what the producer wrote, so thread the wire id down + // as the claim scope; without it every adopted claim misses and the + // occurrence re-renders fresh clones that cannibalize the server DOM. + claimScope: id } as {}) }); if (binding) followBinding(frame, binding);