From 66be240123ca1fa07ae3d157b7fc3095026db9ff Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Thu, 10 Sep 2026 14:09:35 -0700 Subject: [PATCH 1/3] Hold the Workspace registry in Rust and make dor refs stable Each webview's store sees only its own Workspaces, so nothing could route a dor request naming a sibling window's, and workspace: was a strip position that a reorder renumbered. Rust now holds the union: every window reports its list on change and the union is broadcast with a revision. Ids are minted only in Rust, workspace- off one counter seeded above every id on disk and handed to webviews in blocks, so the ref workspace: is the id's number and never changes; a host with no registry (VS Code, an older snapshot) still numbers by position. A dor request naming a Workspace or Window is routed to the window holding it, ahead of the caller's own Surface; one the registry cannot place falls through to the caller's window to be refused by name. The browser harness answers the same three commands for its one window. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01PkPyEFCxiPo5UFeju5Ya9u --- docs/specs/dor-cli.md | 43 ++-- docs/specs/glossary.md | 2 +- docs/specs/standalone.md | 30 ++- dor/src/commands/list.ts | 2 +- dor/src/commands/workspace.ts | 2 +- dor/test/snapshots/help/list.md | 2 +- dor/test/snapshots/help/workspace.md | 2 +- lib/src/lib/workspace-store.test.ts | 45 +++- lib/src/lib/workspace-store.ts | 72 +++++-- scripts/spec-word-budgets.json | 4 +- standalone/scripts/dev-agent-browser.mjs | 30 +++ standalone/src-tauri/src/lib.rs | 86 ++++++++ standalone/src-tauri/src/routing.rs | 86 ++++++++ standalone/src-tauri/src/workspaces.rs | 237 ++++++++++++++++++++++ standalone/src/browser-sidecar-adapter.ts | 17 ++ standalone/src/tauri-adapter.ts | 8 + standalone/src/workspace-registry.test.ts | 81 ++++++++ standalone/src/workspace-registry.ts | 105 ++++++++++ 18 files changed, 805 insertions(+), 49 deletions(-) create mode 100644 standalone/src-tauri/src/workspaces.rs create mode 100644 standalone/src/workspace-registry.test.ts create mode 100644 standalone/src/workspace-registry.ts diff --git a/docs/specs/dor-cli.md b/docs/specs/dor-cli.md index a0bfaced0..5bda51fa4 100644 --- a/docs/specs/dor-cli.md +++ b/docs/specs/dor-cli.md @@ -143,11 +143,15 @@ Control direction: `dor` → sidecar JSON-lines net socket → Rust command/even bridge → `TauriAdapter` `CustomEvent("dormouse:control-request")` → Wall handler, and back along the same hops. -**A request is routed to the window that owns its `DORMOUSE_SURFACE_ID`**, and -one naming no Surface goes to the focused window. **A Surface no window owns -fails** — `No Dormouse window owns surface ''` — rather than being handed to -a sibling, which would act on the wrong terminal. **A cancel follows its own -request** to the window holding it (`docs/specs/standalone.md` → Routing). +**A request naming a Workspace or a Window is routed to the window holding +it**, whichever window the caller sits in; one naming neither goes to the +window that owns its `DORMOUSE_SURFACE_ID`, and one naming no Surface to the +focused window. A target the registry cannot place — an unknown ref, or a name +two windows use — reaches the caller's own window, which refuses it by name. +**A Surface no window owns fails** — `No Dormouse window owns surface ''` — +rather than being handed to a sibling, which would act on the wrong terminal. +**A cancel follows its own request** to the window holding it +(`docs/specs/standalone.md` → Routing). ### VS Code @@ -289,14 +293,16 @@ Invariants: - Text list output defaults to refs; commands that list handles accept `--id-format refs|ids|both` (`uuids` is a compatibility alias for `ids`). JSON list output always includes both refs and stable ids. -- `workspace:` selects a container and is **positional**, so a strip reorder - renumbers it; `workspace:` is the stable handle and **resolves only when - exactly one Workspace carries that name**, else the error lists the - candidates. Both are accepted bare (`2`, `build`), and **a ref that reads as a - number is positional**, never a name. **A Window is `window: