record §5.4's first item as landed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 10:07:33 +00:00
co-authored by Claude Opus 5
parent 1de1d925a5
commit 99ee9dbb88
+26 -3
View File
@@ -32,8 +32,10 @@ before deciding what to pick up next. Its conclusions in one paragraph:
identity, the app-config fields are deleted or moved onto the app, and the inert context is built
once. **§5.1's first two items are closed too** (`04371a9`, `198dc71`, `c92b51c`) — panels have a close
signal that fires on a real close and on nothing else, and the terminals use it; the chat panel
deliberately does not, which is the inversion above. Tier B is now the pty backstop (the third item of
§5.1), `normalizeLayout` (§5.4) and the mobile decision (§6).
deliberately does not, which is the inversion above. **§5.4's first item is closed** (`1de1d92`) — the
allow-list is a `WorkspaceView` prop and the fourteen copies are gone. Tier B is now the pty backstop
(the third item of §5.1), the default-layout collapse (the second item of §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`).
@@ -384,7 +386,21 @@ the whole table:
### 5.4 Make `normalizeLayout` framework, not convention
- [ ] **One `makeLayoutNormalizer(allowed, fallback)` applied inside `WorkspaceView`.**
- [x] **One normaliser applied inside `WorkspaceView`.** _(`1de1d92`)_ — it landed as a prop rather
than a factory: `<WorkspaceView appTypes={{ allowed, fallback }} />`, with `normalizeLayout` in
`layout-utils.ts` and the persist-back inside `WorkspaceView`. All fourteen copies are deleted;
QrTransfer gained the persist-back it never had. Two notes for whoever reads this next. The
framework normaliser **drops `config`** when it replaces an app — the copies kept it, which left
the old app's config on a panel the new app now owns, the opposite of `setApp`. And Headscale
keeps a local `useMemo`, because its check is "is the server picker present at all", which is
about a panel being _missing_ and no allow-list can see that.
Still open from this item: deriving the allow-lists from the AppRegistry (they are still
hand-written literals, so a type still allow-listed but deleted from the registry passes and
reaches the unrecoverable empty box at `PanelSlot.tsx:311-317`), and the nine locked screens
that still pass no `appTypes` at all — now a one-line fix each rather than fifty.
The original text follows.
**One `makeLayoutNormalizer(allowed, fallback)` applied inside `WorkspaceView`.**
The guard currently exists **14 times, character-identical except for the allow-list and the
fallback**, plus a matching `useMemo`/persist-back `useEffect` pair 13 times — ~150 duplicated
lines. Consequences of it being convention: - **10 `WorkspaceView` consumers have no guard at all**, including `screens/HomeScreen.tsx:11`,
@@ -635,6 +651,13 @@ Cheap to fix, and prerequisites for the 5.8 migration rather than alternatives t
_(move items here with the commit and a one-line resolution)_
- [x] **The appType allow-list is a prop, not a convention.** _(`1de1d92`, branch
`agent-coordination-mvp`)_ — closes the first item of §5.4. Fourteen character-identical
normalisers, each with its `useMemo` and persist-back `useEffect`, collapse to
`appTypes={{ allowed, fallback }}`. 402 lines deleted for 215 added, most of the additions being
the seven tests that pin the normaliser — including idempotence, because a normaliser that does
not normalise to itself turns the persist-back into an infinite write loop.
- [x] **Panels can carry per-panel settings, and keep them through a move.** _(`e588524`, branch
`agent-coordination-mvp`)_ — `LayoutPanel.config`, opaque to the framework, exposed as
`usePanelConfig(panelId)`. The substantive half is in `layout-utils.ts`: `swapPanels` and