# Proof audit pass 1 — minimal visibility fixture matrix

Scope: issue 25194; base fd71ddc223091093d172a431f4080772fa41c2a9 → head 8cb07b3d6f7deae991f9951ff45048d527de5c2a, read-only source audit. No PR. This is a proposed proof plan, not executed verification.

Fixture: reuse default browser profile at http://localhost:7825 and the parent's running isolated dev server. Use the existing project action (`echo started; sleep 300; echo finished`) and one saved thread as navigation target. Do not send a provider turn. Keep one draft D with an empty composer and one project P. A second project Q is needed only for the exclusion filter. Reuse D through states rather than creating a fixture per cell.

## Affected render paths and rows

- Web SidebarDraftBlock: unpromoted draft selection, active frozen-composer path, inactive live-composer path, terminal-label fallback, active/inactive row styling, project label/favicon, truncation, discard affordance, and trailing divider. Terminal existence, not running status, is the new visibility condition.
- Sidebar: matching scoped draft count drives empty-state suppression and list-motion layout/animation eligibility. Include a scope with no saved threads so an existing row cannot mask count defects.
- Terminal metadata hook: readable environment metadata → first terminal by numeric terminal-ID ordering → environment/thread-keyed label. Running, idle shell, and exited summaries all count; absence does not. No new running indicator is introduced.
- Shared web render serves desktop Electron and responsive web. At 390px use the web sidebar drawer, not the separate native mobile client. Native mobile, provider adapters, contracts, saved-thread row implementation, Settings, and command palette are unchanged; no separate fixture for them.
- Project filter gates both rows and counts. Thread search replaces the normal list entirely; it does not search these draft rows. Promotion excludes a draft before either visibility branch.

## Minimal matrix

Every row involving an action is marked **RECORDING**. Expectations refer to normal list mode unless explicitly searching. All drafts are unpromoted and terminal-readable unless stated.

| ID | Fixture/state and interaction | Expected proof | Evidence |
| --- | --- | --- | --- |
| A | D active, composer missing/empty, no terminal. Start project script. | Initially no D row; terminal creation adds exactly one active D row immediately, labelled with terminal label rather than `0 attachments`; output shows `started`. No send required. | **RECORDING** |
| B | Same empty D with running script: click saved thread, then click D sidebar row to return. | D remains visible while inactive; clicking it restores the same draft and terminal output. Row changes active styling correctly. Browser Back is not used as the return mechanism. | **RECORDING** |
| C | Same D: let script finish (or stop only this fixture's script through app controls); navigate away and return via row. Retain exited terminal. | D stays reachable active and inactive after subprocess completion; exited output retained. A running flag is not required. | **RECORDING** |
| D | Same empty D with retained terminal but no running subprocess (idle shell if distinct from exited); then remove/close the last terminal through supported UI, navigate away. | Existing terminal keeps row; after actual metadata removal, empty D disappears and divider disappears if last draft. If scope has no saved rows, normal empty-state returns. Closing drawer alone is not terminal removal. | **RECORDING** |
| E | Reuse D with terminal: add short prompt, navigate away/back; replace with one attachment and navigate away/back; clear content, navigate away/back. | Inactive preview precedence: prompt > attachment count > terminal label. Returning preserves existing frozen active-composer behavior; no duplicate rows. Clearing leaves terminal-labelled row. A no-terminal content draft remains visible after navigation; clearing it and leaving hides it. | **RECORDING** |
| F | Empty terminal-backed D in P; filter All → P → Q → P. Use P with no saved threads where feasible. | Included for All/P, absent for Q; draft count and empty-state agree; restoring P restores row and navigation. Filter is allowed to intentionally hide it. | **RECORDING** |
| G | Same visible D: enter thread search, clear search. | Search uses existing saved-thread results, not a duplicate draft row; clearing restores D. Do not infer loss from intentional search replacement. | **RECORDING** |
| H | Same running/retained-terminal D: keyboard focus row and Enter (Space is equivalent handler); open context menu, dismiss; discard a disposable copy only if already available, otherwise perform last on D. | Row keyboard navigation reaches same terminal; existing context menu remains usable. Discard removes row without accidental row activation. Do not assert process shutdown semantics from this visibility diff. | **RECORDING** |

A–D cover active/inactive × no terminal/running/idle/exited without multiplying states. E uses two representative composer shapes, not every attachment type. Missing composer is the new null fallback; an explicit empty composer is covered after clearing. F covers include/exclude scope. G is one search boundary control, not a search suite. H checks existing interactions on the newly reachable row.

Source-only boundary checks (no new app fixtures): promoted drafts remain excluded; environment key prevents cross-environment thread collisions; unreadable terminal scope supplies no terminal-derived visibility. Multi-terminal ordering, every provider, relay/tunnel combinations, all attachment kinds, and native mobile are outside this one-branch capture matrix.

## Minimum capture set — 1440/390, light/dark

- Four short **RECORDINGS**, one per 1440-light, 1440-dark, 390-light, 390-dark (CSS-pixel widths; use consistent height, e.g. 900). Each records A → B: start from empty draft/no row, run script, expose sidebar, navigate to saved thread, expose sidebar again, click D, verify same output. At 390, explicitly record opening/closing the responsive sidebar drawer. These prove the actual interaction at each requested appearance/width without a fixture cross-product.
- Four after stills, extracted from those recordings: sidebar open with inactive running D visible, one per width/theme. Include project identity and readable terminal-label truncation. Use a deliberately long script label on this same fixture if available; do not create another draft just for width.
- One supplemental **RECORDING** at 1440-light covers C–H sequentially with the same D, including the no-saved-thread scoped empty-state check and last-terminal removal at the end. Run content/filter/menu checks before destructive removal/discard. H discard can be omitted from capture if it would require an unrelated new fixture; report that omission.
- Before comparison: reuse the existing reproduction's light running/after-navigation captures and recording. They are 1280px, not matching-width/theme baselines; label that limitation. If matched before/after evidence is required, parent must capture base at 1440/390 light/dark separately. No such captures were made in this audit.

Total proposed minimum: 5 recordings + 4 extracted after stills; reuse existing before evidence. All matrix interactions must be present in recordings, not represented by stills alone. No need to replay C–H across all four appearance/width combinations.

## Proof gaps / FRICTION

- **FRICTION:** Browser/capture/edit/push/merge/watch were prohibited. I only read source/reproduction, wrote this matrix outside the worktree, and uploaded it. No behavior or captures are claimed as verified. Parent dev server was untouched.
- Added browser test mocks terminal labels and checks two rows (running/exited) with route rerender. It does not prove actual metadata subscription, terminal creation/removal, sidebar count/empty-state, filter, real navigation, responsive drawer, or themes. The real-app plan closes those evidence gaps.
- Active content snapshots are intentionally frozen, but an initially empty terminal-backed active row uses live composer data until navigation. E should observe this boundary rather than require all active edits to update identically.
- `threadContexts` counts as user content but is absent from the row's attachment count, an existing preview limitation. Do not expand this visibility fix into a composer-preview cleanup.
- If the app has no terminal-removal control, record what closing actually does and mark D's removal assertion unverified; do not edit stores/databases or kill arbitrary processes to manufacture it. If an idle shell cannot be reached through the current script terminal, source establishes status independence; flag idle as not runtime exercised.


Capture status and limitations: see index.md. This matrix is the original proposed scope, not a claim every assertion passed.
