From fed2badd2817d6a9c3993b8a13b62eee5e73a1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Fri, 7 Aug 2026 09:43:30 +0000 Subject: [PATCH] =?UTF-8?q?record=20the=20close=20of=20=C2=A75.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/workspace-panel-todo.md | 42 +++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/docs/workspace-panel-todo.md b/docs/workspace-panel-todo.md index bf2d4cd8..07d61102 100644 --- a/docs/workspace-panel-todo.md +++ b/docs/workspace-panel-todo.md @@ -28,9 +28,9 @@ before deciding what to pick up next. Its conclusions in one paragraph: (§5.1), but inverted: the requirement is that closing a chat panel must _not_ destroy the agent; `normalizeLayout` as framework (§5.4); and the mobile-collapse decision (§6), which swings on one unanswered question. - **§5.9's first three are done** — the bag is a parsed identity (`dbe585f`) and the two file-browser - fields are deleted (`717580f`, `585f234`). What is left there is `promptPrefix` and the - constructed-in-two-places preview context. + **§5.9 is closed** (`dbe585f`, `717580f`, `585f234`, `d3922bd`, `ca046a3`) — the bag is a parsed + identity, the app-config fields are deleted or moved onto the app, and the inert context is built + once. Tier B is now panel lifecycle (§5.1), `normalizeLayout` (§5.4) and the mobile decision (§6). - **Tier C, orthogonal:** everything else — including **§5.2 (remounts) and §5.3 (drag-to-move), both large downgrades.** A panel is now a pointer to a server-side session, so a remount costs a replay, and the drag hazard is disarmed by resolving identity by name (`e588524` + `bc82086`). @@ -490,9 +490,11 @@ All the same bug: an app guessing "am I being closed?" from an unmount, or payin `WorkspaceContext` is 18 fields, of which the framework itself reads none of the first six. Apps never touch the framework half, so the abstraction holds in one direction; the leak is entirely outbound. -**Down to 16 as of 2026-08-07**, and the outbound half is now `workspace`, `cwd`, `root`, `promptPrefix`. -Of those, `workspace` and `cwd` are genuinely the framework's to state — where the panel is and what -directory it is over. `promptPrefix` is the one remaining courier job, and it is the next item. +**§5.9 is closed as of 2026-08-07.** The context is 15 fields, and the outbound half is `workspace`, +`cwd`, `root` — all three facts about *where the panel is*, which is the one thing a framework of this +shape genuinely owes an app. Nothing left on it is an app's vocabulary: the file-browser pair is +deleted, the chat's system prompt is a prop on the chat, and the key three apps used to parse is a +parsed identity. The two hand-written copies of the inert half are one named constant. - [x] **Delete `initialFilePath` and `defaultFileSort`.** Declared `WorkspaceContext.ts:14-15`, plumbed through `WorkspaceView.tsx:19-20,30`, read only by @@ -505,11 +507,17 @@ directory it is over. `promptPrefix` is the one remaining courier job, and it is the duplicate `DefaultSort` type in two files, and `useFileBrowserApp`'s `isolated` — which was `!!initialPath` and so had always been false. No behaviour changed at either level; both were already running on the defaults. -- [ ] **Move `promptPrefix` onto the component, not the context.** `WorkspaceContext.ts:16` → +- [x] **Move `promptPrefix` onto the component, not the context.** `WorkspaceContext.ts:16` → `Chat/ChatPanelWrapper.tsx:78` → `useEmbeddableChat.ts:107`. Set by `EmailScreen.tsx:53` and `BrowserScreen.tsx:35`, each a screen-local ~40-word system prompt. The framework is a courier for a string only one app understands, and the `components` prop already exists for exactly this — Email can supply a pre-configured chat by panel id. + **Done in `d3922bd`**, exactly that way: both screens put their own `ChatPanelWrapper` in + `components` under the chat panel's id and pass the prefix as a prop. `PanelSlot` prefers a + `components` entry over the registry for the *body* only, so the panel keeps its registry header — + the screens did not have to reproduce any chrome. `ChatPanelWrapper` is exported from the barrel + for it. The same prop came off `WorkspaceLayout`, where it had no callers at all: every settings + pane and job detail rendering through it had always been passing its chat panels `undefined`. - [x] **`dashboardId` is a bag whose _format_ three apps parse.** It is literally `workspace.key` (`WorkspaceView.tsx:163`). Consumers reverse-engineer meaning from its shape: `Chat/ChatPanelWrapper.tsx:51-56` does `dashboardId === 'email' || dashboardId === 'screens/email'` @@ -531,11 +539,16 @@ directory it is over. `promptPrefix` is the one remaining courier job, and it is against a workspace with no row to hang it on), and `terminalStateKey` now takes the identity, so it can no longer nest a key inside itself. Seven tests in `workspace-identity.test.ts`, and the two live agents on `ws-layout-agent-mvp` were confirmed still addressable after the restart. -- [ ] **`WorkspaceLayout.tsx:36` silently omits `root`** — apps inside a `DashboardPreview` fall through +- [x] **`WorkspaceLayout.tsx:36` silently omits `root`** — apps inside a `DashboardPreview` fall through to the `createContext` defaults. (`initialFilePath` and `defaultFileSort` were on this list too and are now deleted; `workspace` is omitted there on purpose, since a preview is not a place an agent can be addressed.) Whatever survives the three items above should be constructed in one place, not twice by hand. + **Done in `ca046a3`.** The eleven interaction fields — everything a panel uses to rearrange the + workspace, plus the state those interactions run on — are one exported `inertInteraction`, spread + by `WorkspaceLayout` and by the `createContext` default. `root` stays omitted, and that is now a + stated decision rather than an oversight: it is only ever read when `cwd` is scoped, and no caller + of `WorkspaceLayout` passes a `cwd` at all, so there is nothing for it to be the root *of*. ### 5.10 Channel hygiene — _(found 2026-08-07)_ @@ -696,3 +709,16 @@ Low priority, but each line here is a line someone will read and believe. In the same pass, the two file-browser fields the context had grown were deleted, and with them the prop chain underneath that had no other caller. Net: the context is 16 fields from 18, and four dead parameters and a permanently-false flag are gone from the file browser. + +- [x] **The framework stopped carrying things only one app understands.** _(`d3922bd` + `ca046a3`, + branch `agent-coordination-mvp`)_ — the last two items of §5.9, and with them the section. A + screen's ~40-word system prompt used to travel screen → `WorkspaceView` → context → + `ChatPanelWrapper`, three of those four steps by a framework that has no idea what the string is. + It is now a prop on the chat panel the screen mounts itself through `components` — the prop that + already existed for supplying a panel's component, and which `PanelSlot` honours for the body + while still taking header and provider from the registry entry, so nothing about the panel's + chrome had to be reproduced. + The second half is the inert context: `WorkspaceLayout` and the `createContext` default had each + written out the same eleven switched-off fields by hand. `inertInteraction` names the idea once. + Net across all of §5.9: the context is 15 fields from 18, and everything still on it answers + "where is this panel" rather than "what should this panel do".