diff --git a/docs/workspace-panel-todo.md b/docs/workspace-panel-todo.md index cf73d5d8..f9e657fb 100644 --- a/docs/workspace-panel-todo.md +++ b/docs/workspace-panel-todo.md @@ -481,17 +481,31 @@ work disagree permanently about the roster, with neither told — a direct contr and `refetchOnWindowFocus` gated on a module-level in-flight count plus a 2 s quiet period. - [ ] **Preserve sibling sizes on split.** `splitInner`/`insertPanel` redistribute evenly (`100 / newChildren.length`), so one split discards carefully tuned proportions. -- [ ] **`tpl-N` panel ids collide across dashboards.** `DashboardPreview.tsx:25-26` — +- [x] **`tpl-N` panel ids collide across dashboards.** `DashboardPreview.tsx:25-26` — `let tplCounter = 0; const tplUid = () => \`tpl-${++tplCounter}\`` — module-level, no entropy, resets every page load. Two dashboards created from templates after a reload hold panels with **identical ids**, and panel id keys `terminal-conn-${panelId}`and`file-viewer:${panelId}`. - Use the core's `uid()` (`layout-utils.ts:4`), which stamps `p-${Date.now()}-${n}`. One line. + **Resolved `6fd60e5`** — the templates now call the core's `uid()`, which is exported from the + Workspace barrel for the first time so that there is exactly one way to mint a panel id. The + duplicate minter is deleted rather than fixed: a second implementation of "make me an id" is how + this happened, and the collision was no longer only a settings mix-up — `agent_panels` addresses a + panel by `(dashboardId, panelId)`, so two dashboards built from templates in the same page load + could hand two different agents the same address. ### 5.6 Registry -- [ ] **No duplicate-key guard.** `metasToRegistry` is `Object.fromEntries` - (`state/src/useAppRegistry.ts:19`) — a collision silently last-wins and one app just disappears. - All 44 keys are unique today. Throw in dev. +- [x] **No duplicate-key guard.** `metasToRegistry` is `Object.fromEntries` + (`AppRegistry/useAppRegistry/useAppRegistry.ts:19`) — a collision silently last-wins and one app + just disappears. + **Resolved `6fd60e5`**, but not by throwing, which is what this item asked for. A duplicate key is + an authoring mistake made at edit time; throwing punishes the owner at runtime for it, by taking + down every dashboard rather than one app. So it is a **test over the real meta list** + (`AppRegistry.test.ts`) plus a `console.error` at runtime — the mistake is caught before it ships + and named if it somehow does. Confirmed: all 44 keys are unique today, and the test says so. + Getting the real list into a test needed one thing beyond exporting it: `test-setup.ts` was not + providing `localStorage`, and `MusicPlayer/useLyricsOpen.ts` reads it at *import* time, so the + whole app graph was unimportable from a test. That is now fixed, which unblocks testing anything + else that pulls in a panel app. - [ ] **Seeding depends on undocumented mount ordering.** Three call sites call `useAppRegistry()` with no argument, defaulting to `[]`. It works only because `` sits at `frontend.tsx:32`, above `` at `:34`. Mount a `WorkspaceView` above that and every panel renders empty.