record the first three items of §5.9

This commit is contained in:
2026-08-07 09:36:27 +00:00
parent 585f234b5b
commit b1e0bac1e0
+41 -5
View File
@@ -28,6 +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.
- **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`).
@@ -487,18 +490,27 @@ 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.
- [ ] **Delete `initialFilePath` and `defaultFileSort`.** Declared `WorkspaceContext.ts:14-15`, plumbed
**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.
- [x] **Delete `initialFilePath` and `defaultFileSort`.** Declared `WorkspaceContext.ts:14-15`, plumbed
through `WorkspaceView.tsx:19-20,30`, read only by
`apps/FileBrowser/FileBrowserApp/FileBrowserPanelWrapper.tsx:7,9,10` — and **set by zero callers**.
`DefaultFileSort` (`{field: 'name'|'size'|'type'|'date'}`) is file-browser vocabulary living in the
framework's type file, and it is re-exported from the barrel (`Workspace/index.ts:27`). Pure leak,
no payoff, entirely deletable.
**Gone in `717580f`**, along with the two barrel re-exports. Deleting them orphaned the props they
were feeding, so `585f234` took out the layer below: `FileBrowserApp`'s `initialPath`/`defaultSort`,
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` →
`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.
- [ ] **`dashboardId` is a bag whose _format_ three apps parse.** It is literally `workspace.key`
- [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'`
→ email context, and `!startsWith('screens/')` → dashboard context — **so renaming a screen key
@@ -509,9 +521,21 @@ touch the framework half, so the abstraction holds in one direction; the leak is
`TerminalWrapper.tsx:13-16` regexes it;
`HostTerminalWrapper.tsx:12` doesn't (§2). Give the context the parsed facts
(`{ kind: 'screen'|'dashboard', id }`) instead of the raw key, and the three parsers collapse.
- [ ] **`WorkspaceLayout.tsx:36` silently omits `root`, `initialFilePath`, `defaultFileSort`** — apps
inside a `DashboardPreview` fall through to the `createContext` defaults. Whatever survives the
three items above should be constructed in one place, not twice by hand.
**Done in `dbe585f`.** `workspace: WorkspaceIdentity | null` replaces `dashboardId`, parsed once in
`WorkspaceView` by `parseWorkspaceKey` and memoised on the key — the identity lands in
`useAgentPanel`'s query key, and a fresh object per render there is the `useClient()` trap that
disabled the Jellyfin playback reports. The identity carries `key` as well as `kind`/`id`, because
the raw key is the address `agent_panels.dashboard_id` stores: parsed halves are for deciding, the
key is for storing. Two behaviours tightened deliberately — an unrecognised key is no longer
treated as a dashboard (the old `!startsWith('screens/')` would have let a panel register an agent
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
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.
### 5.10 Channel hygiene — _(found 2026-08-07)_
@@ -660,3 +684,15 @@ Low priority, but each line here is a line someone will read and believe.
the day it changes: a move drops `zoom` and `fitContent` (§5.3).
**Still untested:** the other eleven files of the framework — `WorkspaceView`, `WorkspaceRenderer`,
`PanelSlot`, `normalizeLayout`. §5.5's debounce lost-updates live there, not in `layout-utils`.
- [x] **A panel is told where it is, instead of being handed a key to reverse-engineer.** _(`dbe585f` +
`717580f` + `585f234`, branch `agent-coordination-mvp`)_ — the first three items of §5.9. The
context field `dashboardId: string` — which was never an id, always the whole `workspace.key` —
is now `workspace: WorkspaceIdentity | null`, parsed once by `parseWorkspaceKey` and memoised on
the key. Three apps had been parsing the format independently, each with its own idea of what a
non-dashboard looks like; they now read `kind` and `id`. The raw `key` rides along because it is
the address `agent_panels.dashboard_id` stores, and a stored address must not depend on which
feature wrote it.
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.