Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Claude handoff — Next multi-runtime / nested instance selection parity

## Repo / branch

- Repo: `/Users/hta218/Documents/work/workspace/weaverse`
- Branch: `feat/next-multi-runtime-selection`
- Base: `main` at `3738e484 Release @weaverse/next 0.1.0-alpha.7`
- Tracker: https://github.com/Weaverse/builder/issues/2659

## Context

Continuing Next Productionization Epic 2663 after publishing `@weaverse/[email protected]` for pageAssignment/save payload parity.

Next requested slice from the parity roadmap: **multi-runtime / nested Weaverse instance behavior spec + tests**.

Hydrogen/Builder reference behavior:

- `packages/hydrogen/src/WeaverseHydrogenRoot.tsx::createWeaverseInstance()`:
- stores every runtime in `window.__weaverses[pageId]`;
- reuses only when `pageId + requestInfo.pathname + requestInfo.search` match;
- same page on a different URL creates a fresh instance and overwrites that pageId registry key;
- design mode calls `window.weaverseStudio.refreshStudio(normalizedParams)` for the live page.
- Builder Studio active-instance selection is in the Builder repo, not this package:
- `builder/studio/utils/instance-binding.ts::resolveEditingInstance()` filters `window.__weaverses` to current `pathname + search` and then picks the editor-intended pageId or the DOM leaf instance.
- `builder/studio/index.ts::init()` keys initialization by both pageId and requestInfo.
- Therefore SDK-side Next must primarily guarantee the same runtime registry/reuse contract and give Builder enough request/root-element data to select the right runtime.

Current Next code:

- `packages/next/src/runtime.ts`
- `getRuntimeKey(pageId, requestInfo) => pageId:pathname:search`
- `window.__weaverses[pageId] = runtime`
- `window.__weaverse = runtime`
- same request key reuses existing runtime;
- design-mode reuse does not clobber live draft tree but updates latest payload/internal data.
- `packages/next/src/renderer.tsx` mounts `<WeaverseRoot context={weaverse} />` and `<WeaverseNextStudio runtime={weaverse} />`.
- `packages/next/__tests__/next-adapter.test.tsx` already covers single runtime create/reuse, but not multi-runtime/nested contract explicitly.

## Goal

Add narrow package-level tests and docs/work-log for Next multi-runtime parity. Prefer tests first. If tests expose a real bug, fix the smallest SDK-side issue. If existing implementation already passes, this PR can be tests/docs-only.

Expected test coverage (likely in `packages/next/__tests__/next-adapter.test.tsx`):

1. **Co-located multi-runtime registry**
- Create two design-mode runtimes with the same `pathname + search` but different page IDs and distinct root/item IDs.
- Assert `window.__weaverses` contains both keys.
- Assert each runtime keeps its own `pageId`, `requestInfo`, `data.rootId`, `internal.pageAssignment`, and `project`.
- Assert the runtimes are not reused across page IDs.

2. **Same page + same URL reuse**
- Existing coverage likely already exists; strengthen only if needed.
- Assert same pageId + same requestInfo returns the same runtime and updates internal payload fields.

3. **Same page + different URL does not reuse the stale runtime object**
- Create page `page-1` at `/collections/a` then page `page-1` at `/collections/b`.
- Assert the second call returns a different runtime object and `window.__weaverses['page-1']` points to the new runtime.
- This mirrors Hydrogen's "reuse only while browser stays on same URL" comment.

4. **Studio bind calls init per runtime without collapsing registry**
- Stub `window.weaverseStudio = { init: vi.fn(), refreshStudio: vi.fn() }`.
- Bind both co-located design-mode runtimes.
- Assert `init` is called for each runtime object.
- Do **not** reimplement Builder's `resolveEditingInstance()` in the SDK tests; just verify Next passes both candidates through.

5. **Root element compatibility for Builder leaf selection** (only if feasible without jsdom)
- The test env is Node, so don't add jsdom. You can directly set mocked refs or item `_element` values if simple.
- If awkward, document that DOM leaf-selection is Builder-owned and covered there, while SDK ensures each runtime has distinct root item stores when item IDs are distinct.

## Non-goals

- Do not modify Builder Studio selection logic in this PR.
- Do not add new public API surface unless tests reveal an SDK bug that needs one.
- Do not solve translation/static-text, global sections, markets/i18n, or redirect helpers.
- Do not publish npm or update POC in this slice; Hermes will handle release flow after review/merge.
- Leave changes uncommitted; Hermes commits/pushes after review.

## Files to inspect/change

- `packages/next/src/runtime.ts`
- `packages/next/src/renderer.tsx`
- `packages/next/__tests__/next-adapter.test.tsx`
- `.specs/2026-06-21--next-studio-bridge/work-logs.md`

## Verification commands

Run at least:

```bash
pnpm --filter @weaverse/next test -- __tests__/next-adapter.test.tsx
pnpm --filter @weaverse/next typecheck
pnpm --filter @weaverse/next build
pnpm exec biome check packages/next/src packages/next/__tests__ packages/next/README.md --diagnostic-level=error
git diff --check
```

Report exact commands/results. If the test runner executes extra package tests despite the file arg, report the actual count.
83 changes: 83 additions & 0 deletions .specs/2026-06-21--next-studio-bridge/work-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,86 @@ git diff --check
### Notes

Claude started the SDK implementation from the handoff and timed out after touching the package source. Hermes completed the missing tests/work-log and ran verification. No Builder database/save endpoint changes were needed for this package-level contract slice.

## 2026-07-10 — multi-runtime / nested instance selection parity

Slice branch: `feat/next-multi-runtime-selection`
Tracker: https://github.com/Weaverse/builder/issues/2659

Continuing Epic 2663 after `@weaverse/[email protected]`. This slice codifies the
multi-runtime / nested Weaverse instance contract as package-level tests so
`@weaverse/next` provably matches Hydrogen's `window.__weaverses` registry/reuse
semantics and hands Builder Studio every runtime candidate.

### Outcome: tests-only (no SDK bug found)

Audited `createWeaverseNextRuntime` / `bindWeaverseNextStudioRuntime` against the
Hydrogen reference behavior in `packages/hydrogen/src/WeaverseHydrogenRoot.tsx`
(`createWeaverseInstance()`) and Builder's `resolveEditingInstance()` /
`init()` selection. The existing Next implementation already satisfies the
contract, so no source change was needed — this is a tests + work-log slice.

### Scope

Added a `multi-runtime / nested instance selection` describe block to
`packages/next/__tests__/next-adapter.test.tsx` (5 tests):

1. **Co-located multi-runtime registry** — two design-mode runtimes at the same
`pathname + search` but different page/root IDs both land in
`window.__weaverses` under their own keys, are not reused across page IDs, and
each keeps its own `pageId` / `requestInfo` / `data.rootId` /
`internal.pageAssignment` / `internal.project`. Also asserts
`window.__weaverse` tracks the last-created candidate — Hydrogen's
single-pointer + full-registry split. Builder owns deciding which co-located
instance is the editable leaf.
2. **Same page + same URL reuse** — same `pageId` + same `requestInfo` returns
the same runtime object, the registry key still points at it, and internal
payload fields (`pageAssignment`, `project`) refresh from the latest loader
pass.
3. **Same page + different URL** — `page` at `/collections/a` then `/collections/b`
returns a fresh runtime object and overwrites `window.__weaverses[pageId]`,
mirroring Hydrogen's "reuse only while the browser stays on the same URL".
4. **Studio bind per runtime** — with `window.weaverseStudio = { init, refreshStudio }`
stubbed, binding both co-located design-mode runtimes calls `init` for each
runtime object and leaves both registry keys intact. Builder's
`resolveEditingInstance()` is intentionally NOT reimplemented in the SDK test;
the SDK only verifies both candidates pass through.
5. **Distinct root item stores / element refs** — co-located runtimes with
distinct item IDs own distinct root item stores, each carrying its own element
ref (set directly, since the Node test env has no jsdom). Documents that the
actual DOM leaf-selection walk is Builder-owned and covered there.

Item IDs are globally unique per test (prefixed `mr-*`) to avoid the process-wide
`Weaverse.itemInstances` static map leaking item stores across tests (the pitfall
flagged in the 2026-07-09 root-theme-provider entry).

### Non-scope

- No Builder Studio selection-logic changes (`resolveEditingInstance()` stays
Builder-owned).
- No new public API surface — the existing runtime already satisfies the contract.
- Translation/static-text, global sections, markets/i18n, redirect helpers untouched.
- No npm publish / POC update — Hermes handles release flow after review/merge.

### Verification

```bash
pnpm --filter @weaverse/next test -- __tests__/next-adapter.test.tsx
# 5 files, 88 tests passed (83 → 88). NOTE: the `-- <file>` arg did not filter;
# vitest ran the whole package suite (all 5 files). +5 tests = the new block.

pnpm --filter @weaverse/next typecheck # passed (exit 0)
pnpm --filter @weaverse/next build # passed (tsup ESM/CJS/DTS all succeeded)
pnpm exec biome check packages/next/src packages/next/__tests__ packages/next/README.md --diagnostic-level=error
# Checked 33 files. No errors.
git diff --check # clean (exit 0)
```

### Remaining risk

- Package-level unit coverage only. It does not exercise a real browser DOM or
Builder's `resolveEditingInstance()` leaf pick — that path is Builder-owned and
covered in the Builder repo. Full nested-instance Studio E2E in the POC (two
co-located instances, confirm Builder edits the intended leaf) remains a
manual/E2E step.
- Changes left uncommitted per the handoff; Hermes commits/pushes after review.
Loading
Loading