# Proof audit, pass 1

## Findings

1. **Proof is insufficient.** [#32569](https://git.cafe/pingdotgg/t3code/pull/32569) contains a text table of active-element results and no attached captures. Focus restoration, portal traversal, and delayed unmount are interactions; a still cannot establish their sequence. All required recording rows F01–F22 below are missing. These are evidence findings, not reproduced implementation defects.
2. **The reported environment is missing from the evidence.** [#32538](https://git.cafe/pingdotgg/t3code/issues/32538) reports macOS desktop and Cmd+Alt+B. The body describes Linux Chromium at 1280×800, explicitly excludes desktop and the Pull Requests page, and does not show native browser shortcut forwarding.
3. **The existing manual transcript does not identify the audited revision.** It names [e455200077](https://github.com/pingdotgg/t3code/commit/e455200077) as main and [70734da198](https://github.com/pingdotgg/t3code/commit/70734da198), with [75be918823](https://github.com/pingdotgg/t3code/commit/75be9188233dedd281a7cf7027d14c62c67bcdad), as the PR. This audit is pinned to [c5c4a2170e](https://github.com/pingdotgg/t3code/commit/c5c4a2170efc9cc606f6ffabee30851ee6a48968) against [ac5e48c612](https://github.com/pingdotgg/t3code/commit/ac5e48c612061895511f549d363a2186a6a005ea). The shell and its new tests are unchanged since the earlier head, but the merged workspace focus controller changed; integrated recordings should identify the current head and this explicit baseline.

The GitCafe metadata confirms the requested head, target main, source branch fix/issue-32538, and observed base. The worktree was clean at the start. No source, PR body, review, or comment was changed. No server, browser, capture process, provider turn, or test was started by this audit. The eight test cases listed below were inspected, not rerun. CI and old bot approvals do not substitute for recordings.

## Render and interaction inventory

Sources are pinned to the audited head. Four production JSX call sites exist in three caller components, plus the browser-test fixtures.

| Path / owner | Every relevant input and branch | Consequence for fixture selection |
|---|---|---|
| [PreviewPanelShell entry](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanelShell.tsx#L35) | Supplied inlineSize goes straight to the frame; absent inlineSize uses ResizablePreviewPanelShell. The internal hook is enabled for inline and not maximized. widthStorageKey/defaultWidth affect only the internally created sizing object. | Chat exercises injected sizing. The Pull Requests page exercises internal sizing and its own storage/default width. |
| [Frame modes and layout](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanelShell.tsx#L65) | Modes inline, sheet, sidebar, embedded. Only inline with open explicitly supplied is collapsible. open omitted means true. Collapsed is explicit open=false on that path. Normal inline has left border and resize handle; maximized inline flexes to 100% with neither. Other modes are full width. Collapsible normal content is pinned to the right with a fixed inner width and overflow clipping; maximized content is not. Closed host becomes inert, unavailable, and pointer-inaccessible. | F01/F02 contrast immediate unmount versus retained collapse. F15 covers maximized close. F18/F19 cover real sheet. Sidebar and inline-without-open are supported type shapes with no current production caller; X01 labels them as harness-only controls. |
| [Frame metadata](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanelShell.tsx#L147) | workspaceArea true adds panel region, order, tabindex and label; false omits them. workspaceLabel defaults to Workspace panel; workspaceFocusKey is optional. children is opaque ReactNode, including empty/null and multiple nodes. | Outer RightPanelTabs is a workspace area with a key per environment/surface. Nested PreviewPanel and DevicePanel are not their own workspace area. The test helper deliberately omits the outer panel workspace flag but supplies an external composer area. |
| [Focus capture and return](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanelShell.tsx#L52) | relatedTarget=null or equal to lastBlurred is ignored; an external HTMLElement becomes origin; a different non-HTMLElement clears it. Internal moves and React-owned portals update blur history without replacing origin. Child ref autofocus can precede host ref attachment. A return is attempted only if collapse holds focus, or eligible unmount cleanup later finds body active. No restoration if someone else holds focus. Collapse clears origin; reopen resets returnedFocus. | F03–F09 and F22. React-owned portals and focus entering from an unrelated external area are distinct sequences. A menu that still owns focus is not the same fixture as dismissing it and returning inside the panel. |
| [Return eligibility](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/lib/workspaceFocus.ts#L28) | Origin must be connected, outside host, in a workspace area, visible, in view of every vertical auto/scroll ancestor, and able to accept focus. Visibility rejects hidden/inert/data-closed/aria-hidden, maximized-away chat, collapsed sidebar, unavailable workspace, display none, visibility hidden, zero-sized rectangles, and invisible shadow host. Partial vertical intersection passes; fully above or below fails. No scroller passes. Shadow-root area lookup recurses to host. Disabled or otherwise unfocusable origins fail the activeElement confirmation. Missing/unfocusable toggle cannot falsely report success. | F10–F14 and F22. Invalid-origin mechanisms with the same observable toggle result are labelled chapters of one harness row, rather than a Cartesian product of UI captures. |
| [Width and animation](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/hooks/usePreviewPanelInlineSize.ts#L15) | Normal default 540 px; minimum 360 px; maximum is max(360, min(floor(0.7×viewport), container width−360)). Persisted width may override default. Width/maximized changes without open change suppress the transition; open/close changes enable it. App animations are duration>0, no reduced motion, and no navigation suppression. Animated presence retains then unmounts after duration; disabled/reduced-motion presence removes immediately. Reopen cancels removal. | F01/F02/F03/F15/F16. Use 0 and 400 ms; reduced motion and route suppression collapse into the immediate-removal branch. F02 includes a close/reopen before exit completes. No need to repeat every duration. |
| [RightPanelTabs call site](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/RightPanelTabs.tsx#L1319) | Forwards mode/maximized/open/width props; workspace label depends on selected surface and preview/terminal labels. Zero surfaces or activeSurfaceId=null renders launcher; a non-null id renders children. Zero/one/many tabs; enough tabs or long titles overflow, show left/right scroll controls, and scroll active tab into view. open=false closes launcher menu and removes its trigger. Menus include Browser profile submenu, availability/disabled reasons, optional Side chat, rename-device input and native/HTML context menus. Surface status may be pending; titles, favicon/theme, audio, PR state/draft decorate tabs. | Empty, one terminal, many overflowing tabs, and portalled menu are the distinct focus-relevant classes. Status decoration and title lengths are combined with overflow in F16. Closing last surface also removes outer shell; closing one of many keeps it. |
| [ChatRightPanel and ChatView callers](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/chat/ChatRightPanel.tsx#L19) | Thread/draft chat passes injected sizing with per-thread key. ChatView only renders panel when present, activeThreadRef exists, and chat is not embedded. At width ≤980 px, non-maximized chat uses RightPanelSheet; maximized uses inline. Sheet controls move inside; inline controls are at workspace root. Sheet width min(42vw,28rem), min 320 px; at ≤760 px width min(88vw,24rem), no minimum. | F01–F16, F18/F19. Exactly 980 and 760 are branch boundaries; representative 900 and 390 px capture both sheet layouts without multiplying every fixture by width. Thread switching/route removal also exercises unmount guards, F22. |
| [PullRequestsPage caller](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/pullRequest/PullRequestsPage.tsx#L1469) | Separate RightPanelTabs inline caller, explicit open, own maximized state, no supplied inlineSize, key t3code:pull-request-panel-width, default floor(viewport/2), server fallback 640. Requires capable environment, selected PR, retained presence, environment id. PR query loading/error/empty produces list/detail variants; list area can become inert while maximized. No chat sheet breakpoint here. | F17 needs this actual page, not a chat PR tab. One loaded PR and a visible list/search origin are enough for the changed return path; absence of any selected PR means no shell to close. Loading/error descendants do not add a restoration algorithm, X02. |
| [PreviewPanel two call sites](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanel.tsx#L36) | No preview operate permission OR runtime unavailable gives a shell with a permission/unavailable message. Otherwise shell wraps PreviewView. Its sole production caller is RightPanelSurfaceContent preview branch, lazy/Suspense null, mode embedded; no open prop, no collapsible cleanup. PreviewView includes empty, navigating/loading, loaded, unreachable/error, native browser content and controls. | Nested shell must not independently return focus. F21 uses the available native path; unavailable text can be forced via an app driver, but is equivalent at the enclosing shell. Catalogue X02, not a demand to capture every browser page. |
| [DevicePanel call site](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/device/DevicePanel.tsx#L180) | Its only production caller is RightPanelSurfaceContent device branch, embedded and lazy/Suspense null. Loaded and onboarding incomplete OR host disabled returns setup Dialog with no shell. Otherwise embedded shell: active device/session → DeviceWorkspace; else pending/busy/not loaded → loading/error/retry; else zero device groups → empty/failed text, or ≥1 iOS/Android groups → list/start/open/refresh. Optional diagnostics, updates, bootingDevices count>0 and operation-error notices alter top region. No open prop. | All are caller branches inventoried, but none adds shell collapse restoration. Host/device data is not deterministic on a fresh database; label frozen device-state captures as harness if used. No need to boot/lease a device for this focus fix. X02. |
| [Other surface data](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/chat/RightPanelSurfaceContent.tsx#L82) | All nine kinds: preview, terminal (one/multiple ids, horizontal/vertical split), diff, pull-request, pull-requests, side-chat, device, files, file (path or attachment, reveal line/request, folder trail). Null surface → no content. File without project/root → no content. Lazy surfaces may temporarily have empty fallback. PR capability unknown → ghost; unsupported → unavailable. Side chat embeds another composer and does not recursively render its own right panel. Files may use shadow DOM; HTML/PDF may use iframe focus. | Opaque children do not change frame layout policy. The minimum uses empty, self-focusing terminal, ordinary files, PR page, and native browser; X02 records the remaining equivalent data states. Arbitrary HTML or native shortcut routing is outside a claim that the shell can fix a chord that never reaches it. |
| [Tests changed by PR](https://github.com/pingdotgg/t3code/blob/c5c4a2170efc9cc606f6ffabee30851ee6a48968/apps/web/src/components/preview/PreviewPanelShell.browser.test.tsx#L10) | Workspace(open, present default true, optional children) has simple input composer, outside toggle, inline shell and focusable region. Variants: missing host; autofocus child ref; createPortal button; 100 px timeline/2000 px spacer; drawer whose workspace marker is removed. Eight assertions cover collapse, unmount, autofocus mount, menu round-trip, offscreen origin, closing drawer, earlier-open reset, toggle-origin. | These are labelled component fixtures, not screenshots of the product. The simple portal fixture does not prove real menu focus-trap restoration; the new test file does not drive actual Cmd/Ctrl+Alt+B. |

### Entry points, clients, and collapse scope

The keyboard chord is mod+alt+b. Header toggle calls the same visibility action. Opening a surface, selecting a tab, and maximizing can request panel focus through the global workspace controller; terminal mounts can focus through the terminal registry. Closing a surface (mod+w where supported), last-tab close, context-menu close-all, store close, or route teardown can remove the same shell. Use one of these in F16/F22 instead of treating all close buttons as the toggle.

No right-panel toggle command is exposed by the inspected CommandPalette item list, and Settings configures appearance/keybindings rather than rendering this shell. F6 can move focus to/from workspace areas and is useful to seed F07/F09. Desktop adds native browser shortcut/menu forwarding and draggable titlebar controls. Native mobile does not import the changed web shell; mobile app captures are not required. Mobile-width web is required as sheet regression coverage. Provider adapters, contracts, RPC schemas, and local/relay/tunnel transport are unchanged; repeating every row for every provider or connection adds no distinct focus branch.

## Capture and seeding contract

All seeds below are plans for the lead to execute, not claims of execution in this pass.

**Fresh real app.** Start the lead's dedicated dev server with T3CODE_DEV_SEED=0 and an explicitly unused home directory. For example, from the audited worktree:

    T3CODE_DEV_SEED=0 vp run dev --home-dir /tmp/lead-32569-r1/proof-audit-1/capture-state-head

Use a different unused home for the baseline. Disabling seeding does not erase an existing database. Do not point at the running developer's home, delete existing state, start another server against a lead's active database, or set VITE_HTTP_URL/VITE_WS_URL. This sub-agent starts none.

Pair to the actual logged origin using the Browser panel. Add a disposable project through the app. Create a stopped thread through the free Replay (dev) showcase scenario: after adding a project, execute window.t3dev.replay("showcase"), and wait for the turn's visible settled state. It navigates to /<environmentId>/<threadId>. Use the composer with content already typed so the caret and continuation can be shown without sending another turn. For files use a disposable project containing short text and, if needed, long named files. For the actual PR-page row, add the read-only audited repository as a project instead and use its existing forge connection; no forge mutation is needed.

**Settings and store driver.** Use /settings/appearance for built-in dark/light theme and panel duration 0 or 400 ms. The actual exported updateClientSettings({panelAnimationDurationMs: ...}) can also be called by a dev-browser script imported from /src/hooks/useSettings.ts. Disable OS reduced motion for animation recordings; use reduced motion only for a labelled immediate-removal check.

A driver may import /src/rightPanelStore.ts, then call useRightPanelStore.getState().show(ref), close(ref), open(ref,"files"), openFile(ref,path), activateSurface(ref,id), closeSurface(ref,id), or setMaximized(ref,true). ref is the current route's environmentId/threadId pair. These are the app's actual state actions, not a fake shell. Do not set raw React props or replace document markup and call it a real-app capture. For the PR page use exported PULL_REQUESTS_PANEL_REF and openPullRequest with real environmentId, projectId, repository, host git.cafe, and an existing PR number; then navigate /pull-requests with the matching selected query fields. The UI selecting that PR is equally valid.

**Focus visibility.** Every recording must show a non-focusable, pointer-transparent overlay containing row id, Before/After and revision, current document.activeElement tag/id/accessible label, workspace area, and panel mode/open state. Include a short event trail of focus from/to; for shadow/iframe content include the deep active element when readable and at least the iframe/native-page label otherwise. Put this overlay inside the captured frame, not only in a console log. Keep a composer caret/focus ring visible and type a harmless suffix after restoration where useful. Keep scrollTop in the overlay for F10/F11. Never let the overlay itself take focus.

Begin before the opening interaction. Show panel focus entry, any menu/tab/drawer transition, close, and the final settled state. For animated close show the 400 ms exit and the state after unmount; include about 1.5 s of visible settled observation to catch delayed focus stealing. A still of the final state is insufficient. Do not fake expected focus by calling focus() after the close. Driver focus() before opening, or for explicit re-entry, must be labelled as seeding.

**Revision pairing.** Rows marked Before/After need equivalent recordings of the explicit baseline and audited head with identical data/settings. Control rows may use audited-head recordings. One recording may contain multiple clearly labelled rows/chapters; matrix entries are not a requirement for 22 separate files. Adjacent final-state stills may help scanning, but do not replace the recording.

## Fixture matrix

D = changed restoration destination. G = guard/regression path through changed focus bookkeeping or eligibility; expected outcome can match the baseline. U = unchanged restoration owner, checked as a surface control. All required rows are **recording** because they depend on interaction or time. No capture exists in pass 1.

Tuple A = 1280×800, built-in dark, Chromium web. B = 1280×800, built-in light, Chromium web. C = 900×800, light, web sheet. D = 390×844, dark, web sheet. E = 1280×800, dark, macOS Electron. H = 1280×800, dark, labelled browser component harness. These are representative viewport/theme tuples, not a cross product; no theme-specific logic was added.

| ID / fixture | Diff | Required data, seed and route | Interaction and visible acceptance criterion | Minimum capture | Status |
|---|---|---|---|---|---|
| F01 Empty / immediate removal | D | Fresh stopped thread route; panel surfaces empty, composer text; duration 0. | Composer → Ctrl+Alt+B → focus in launcher → same chord. Baseline toggle; head composer and caret. Type suffix without clicking. Host disappears immediately. | A, Before/After, recording | MISSING |
| F02 Empty / retained collapse and reopen | D/G | Same thread and empty panel; duration 400. | Open from composer, close while inside. Head returns before host is inert and stays there through timed unmount. Then repeat with reopen before exit finishes; panel stays usable and next close returns to the current origin. | A, Before/After normal close; head rapid-reopen chapter, recording | MISSING |
| F03 Terminal mount takes focus | D | Same thread; Add panel surface → Terminal. One actual terminal, duration 0 and 400 as labelled chapters; composer text. | Hide terminal panel, click composer, keyboard open, verify terminal textarea/caret took focus without an intermediate click, close by chord. Head returns to composer through immediate and delayed removal. Include first creation/remount path if it autofocuses. | B, Before/After, recording | MISSING |
| F04 Toggle is origin | G | F01 or F03 state. | Click header toggle to open; after content takes focus close with chord. Final focus is the surviving toggle, not an older composer origin. | A, head, recording | MISSING |
| F05 Pointer close keeps chosen toggle focus | G | Open from composer; panel owns focus. | Click header close/toggle. Pointer deliberately moves focus outside first; closing must preserve that toggle focus instead of pulling it back to composer. | A, head, recording | MISSING |
| F06 Focus already outside / no stealing | G | Open panel; another visible workspace control, e.g. composer or sidebar row. | Move focus to outside control, close via chord or labelled store close without clicking elsewhere. Final focus remains that exact control, through delayed unmount. | A, head, recording | MISSING |
| F07 Latest external origin replaces earlier one | D/G | Open panel plus composer and a visible conversation/sidebar/details control. | Enter from composer; leave to another workspace control; re-enter panel via keyboard/F6 or labelled focus driver; close. Return to the most recent external control, not composer. | A, head, recording | MISSING |
| F08 Per-open reset / null origin | G | Same thread, two sequential opens. Real app store driver can blur composer to body before second show. | First open/close returns composer. Blur to body, open with actual store show/refocus logic, close. Do not reuse first open's composer; no eligible new origin means toggle fallback. Overlay must show second entry's origin. | A, head real-app driver; H if exact null transition cannot be produced, recording | MISSING |
| F09 Internal and real portal round-trip | D/G | F03 panel with at least one control plus Add panel surface menu; optional Browser profile submenu on Electron. | Open from composer, visit two in-panel controls, open actual portalled menu, keyboard-navigate, Escape back to trigger/content, then close panel. Original composer survives all internal visits. Also show closing while focus was intentionally left outside does not steal it. | B, Before/After portal return; head internal-control chapter, recording | MISSING |
| F10 In-view timeline origin | D | Showcase/long thread with a visible message action; enough content to scroll, stable visible origin. | Focus that actual action without changing scroll, open panel, close. Restore that exact action with preventScroll; scrollTop is unchanged. An area container is also a valid labelled origin if actual controls are hover-only. | B, Before/After, recording | MISSING |
| F11 Timeline origin scrolled out | G | F10 plus enough content to scroll origin fully above/below viewport while panel focused. | Enter panel from timeline action, scroll conversation with wheel/driver without taking focus, then close. Toggle fallback; show identical pre-close/post-close scrollTop. Partial visibility remains eligible and can be a short chapter in F10. | B, head, recording | MISSING |
| F12 Still-open drawer origin | D | Open bottom terminal drawer with actual terminal focus; empty or files right panel. | With drawer textarea focused, open right panel by chord, then close while panel owns focus. Restore drawer textarea, not main composer/toggle. | B, head, recording | MISSING |
| F13 Closing drawer origin | G | F12; duration 400. Import /src/terminalUiStateStore.ts and call setTerminalOpen(ref,false) while focus remains in right panel. | Close right panel while drawer is retained for exit but no longer a workspace area. Toggle fallback. Show drawer marker removal and final focus so animation visibility cannot be mistaken for eligibility. A single driver evaluation can close both stores to hit the same commit without racing a manual gesture. | B, head real-app driver; existing drawer component fixture H if unavailable, recording | MISSING |
| F14 Origin rejected / cannot accept focus | G | H extends existing Workspace fixture with external workspace button/input and real Shell. Separate labelled segments: detached, disabled, no workspace area, hidden/inert/unavailable/zero rect, fully out-of-scroll-view. | Capture valid entry first, make origin invalid while inside, then collapse. Every variant uses toggle fallback. Also record non-HTMLElement/null relatedTarget when deliberately supplied by harness; label synthetic focus-event delivery. No raw DOM change may be presented as a product user action. | H, head, recording | MISSING — labelled harness |
| F15 Maximized inline | D/G | Real thread and panel, composer origin, 400 ms. | Open from composer; maximize without an extra outside focus visit (keyboard command or actual store driver), then close with chord. Chat/composer becomes available again and eligible focus returns there. Include restore-size then close as a chapter. Overlay identifies whether a click on Maximize intentionally became a new origin. | A, head, recording | MISSING |
| F16 Many tabs / width / last surface | G | Same thread; files + several actual files with long titles and terminal; enough tabs to overflow. Injected chat sizing; resize normal panel to minimum/cap; duration 400. | From composer enter panel, switch/scroll tabs, resize, then close. Origin survives internal controls and width transitions. Close one of many: panel stays open. Close final ordinary file surface via shortcut/close control: shell removes and preserves eligible external origin or explicit outside focus. Record any confirmation separately; do not count surface close as toggle close. | B, head, recording | MISSING |
| F17 Pull Requests page / internal sizing | D/G | Real /pull-requests; add audited repo to fresh database, existing forge auth, loaded selected PR and visible list row/search origin. Actual UI selection or openPullRequest(PULL_REQUESTS_PANEL_REF,target) plus matching route query. | Select/open PR, focus a visible list/search control, enter panel, close by Ctrl+Alt+B. Restore most recent eligible list/search control; show 0 and 400 ms chapters and maximized/unmaximized control. Independent width key/default is visible. If no read-only forge access, use labelled PR-page provider/contract fixture, not an empty page. | A, Before/After return; head timing/maximize chapters, recording | MISSING |
| F18 Medium-width sheet | U | Real thread at 900×800, light, nonmaximized, terminal or launcher; 400 ms. | Open by chord, close by supported chord; repeat by Escape/backdrop. Observe sheet/dialog's focus restoration and relocated controls; no hidden panel focus after close. This is a control for the separate dialog owner, not proof of inline shell cleanup. | C, head, recording | MISSING |
| F19 Compact-width sheet | U | Same at 390×844, dark, nonmaximized. | Same sheet interactions with ≤760 px popup sizing; controls remain reachable, focus returns to a visible external target. Show compact header and no lingering overlay trap. | D, head, recording | MISSING |
| F20 Reported macOS desktop | D/G | macOS Electron client loading isolated dev server; stopped thread, composer and terminal/empty panel. Built-in dark; Cmd+Alt+B. | Reproduce issue exactly on desktop, then show head composer restoration and continued typing. Capture titlebar controls and focus before/after 400 ms exit. Use actual macOS; Linux web with Meta event emulation is not equivalent proof of app-level routing. | E, Before/After, recording | MISSING |
| F21 Native browser / nested embedded shell | D/G | Electron from F20; one actual Browser surface in an available permitted preview runtime, simple harmless page. | Open from composer, focus page content, close via native-forwarded chord. Show active native page plus app focus overlay/bridge trace where DOM focus alone is ambiguous. Returns to composer if forwarding reaches close and a valid origin was captured. Then repeat from URL/toolbar control to distinguish native routing from ordinary DOM controls. A native shortcut failure is reported separately, not silently replaced by a fake input. | E, head; Before/After if asserting this path is fixed, recording | MISSING |
| F22 Guarded unmount / no usable fallback | G | H using actual Shell and toggle; origin button/input. Separate segments: unmount with focus inside/body; unmount with another control focused; synchronous focus handoff before queued microtask; no toggle or disabled toggle. | After removal queued cleanup restores eligible origin only if body still owns focus. It must not override another committed focus owner. With no eligible origin and no usable toggle, record the resulting body/remaining focus rather than calling it restored. Include a direct unmount rather than only open=false, since the app's 0 ms path can skip a collapsed render. | H, head, recording | MISSING — labelled harness |
| X01 Noncollapsible / unused mode shapes | U | H only for sidebar or inline with open omitted; real app provides sheet and embedded. | Noncollapsible shell does not run return-on-collapse/unmount policy. Inline without open still has border/handle; sidebar/sheet/embedded are full-width. Invalid combinations, e.g. maximized=true with open=false, are not independently produced by current app callers. | No additional minimum; F18/F19/F21 plus code inspection cover live owners. Optional H recording if demonstrated. | INVENTORIED — no separate capture required |
| X02 Opaque content states and no-shell branches | U at nested shell; outer policy covered | Preview allowed, unavailable, permission denied; Device setup (no shell), loading/error, zero/multiple groups, active session and notices; files missing root/attachment/iframe; diff loading/empty/error; PR capability ghost/unavailable; side-chat composer; Suspense null. | These alter children or remove nested shell, not the changed return algorithm. Ordinary non-native children share the same outer frame; no theme/count/error cross product is needed. If illustrating a state unavailable in a fresh app, explicitly label a frozen provider/child harness and list its data; never imply a real device or forge request was run. | No additional minimum beyond representative F01/F03/F16/F17/F21. New evidence exposing a distinct focus boundary can promote a subcase. | INVENTORIED — equivalent or outside the changed policy |

### Minimum recording set

The minimum uses six viewport/theme/client tuples, A/B/C/D/E/H, distributed across eight practical recording groups so data stays stable:

1. A chat: F01/F02/F04–F08/F15; before/after chapters for F01/F02.
2. B terminal/menu/tabs: F03/F09/F16; before/after chapters for F03/F09.
3. B timeline/drawer: F10–F13; before/after chapter for F10.
4. A /pull-requests: F17; before/after restoration plus head controls.
5. C medium sheet: F18.
6. D compact sheet: F19.
7. E macOS desktop: F20/F21; before/after F20.
8. H labelled component harness: F14/F22, exact F08/F13 only if real-app driver cannot seed them.

Different chapters and before/after streams may live in one montage as long as labels, viewport, theme, revision, and row id are visible. No full light×dark×viewport×row cross product is justified by this diff. Light B/C and dark A/D/E/H make the focus indicator legible in both theme classes.

Coverage in the new browser test file is source-inspected for F01, F02, the autofocus part of F03, F04, F08, the synthetic portal part of F09, F11, and F13. It is not real-app recording evidence. No supplied capture contradicts a row because none exists. No runtime correctness claim is made for the missing rows.

Cleanup: no processes started; no files outside this scratch directory were created or removed; worktree and forge were left unchanged. Evidence is retained for the lead.

FRICTION:
tool | Several exploratory rg invocations named guessed files that do not exist; subsequent searches used actual directories and found the intended definitions. No coverage remains blocked. | Discover filenames with rg --files before naming speculative paths.

VERDICT: INSUFFICIENT F01–F22 recordings missing
