# Proof audit pass 1 — fixture matrix

Scope: `/home/ubuntu/wt/issue-17034`, branch `fix/issue-17034`. Complete committed diff audited: [a50cd989ae](https://git.cafe/pingdotgg/t3code/commit/a50cd989ae) → [4eb9032d54](https://git.cafe/pingdotgg/t3code/commit/4eb9032d544f1156686b7d2bbb748f62b5b80676). Two changed files: `apps/web/src/components/ServerUpdateAction.tsx` and its existing browser test. Uncommitted `ServerEnvironment.ts` descriptor fixture excluded. No PR, no previous proof pass. This is a prospective capture specification, not completed runtime proof.

Read repository and global AGENTS, complete committed diff, component implementation, every direct caller and relevant ChatView/session/storage/version-skew gates. `t3code-ops/docs/EVIDENCE.md` could not be found in accessible local filesystem (bounded directory searches plus a completed full-path search); its file contents remain unverified. User supplied the operational EVIDENCE standard during this pass; that supplied standard governs this matrix and the missing checkout is friction, not a blocker. No browser/server launched, captures taken, repository files edited, forge comments made, or pushes performed by this audit. Only this requested /tmp artifact and its public upload are written.

## Capture contract

Every A row below requires actual base/head matched captures at **1440×900 light, 1440×900 dark, 390×844 light, 390×844 dark** (CSS pixels, DPR 1, browser zoom 100%). Each is a baseline/head pair: 8 assets per independent row, unless one asset explicitly demonstrates multiple rows with identical state. Static rows use stills; **every interaction or time row uses a recording**, including tooltip, focus, touch, re-pairing and async transitions. Recordings must show the starting control, action and result, not only an endpoint. For touch rows use touch emulation at both widths; width alone does not prove touch. Stop and settle the pointer for static stills. Name assets with row ID/revision/width/theme. Same data, labels, scroll, route, browser settings, frozen clock and target version on both revisions. Record rendering browser/version, DPR, font scale, and exact viewport for each group; show the whole viewport, not just cropped controls. Every recording needs written steps plus timestamps for each relevant milestone. Keep original frames and two image-diff outputs: zero-threshold amplified diff and a second diff with its stated threshold. Report dimensions, counts and thresholds. Compare matching milestone frames for recordings. Expected changed regions are the hint/tooltip/toast and denied bulk enabled state. Explain every other difference. Do not count synthetic standalone component pages as actual-app proof.

A = affected by changed component/control or new permission behavior. U = unaffected or caller excludes changed path; no mandatory extra capture. H = harness-only scenario; must be labelled **HARNESS**, never presented as a real reachable app state. Harness capture variants use the same four width/theme combinations when a visual result is asserted. Existing identical visuals collapse; one operation can satisfy several IDs if timestamps and states are indexed explicitly. The matrix is valid for the reported pending atom-helper/test-matcher simplification only if its rendered behavior stays unchanged; evidence must identify the final committed head, not assume this pinned SHA still contains final code.

## Seed recipes

**R0 — real app and isolation.** A committed seed fixture/script is required by the user-supplied evidence standard; the current uncommitted descriptor hardcode alone does not satisfy it. Lead owns existing web 8431 / backend 16471 and remote 16472. Do not kill/restart these from a child. Have lead arrange actual baseline and final-head app builds with the *same* descriptor fixture and isolated copied DB. Existing temporary metadata reports an older version and boot-service capability; that is an **actual-app descriptor fixture**, not a historical binary or proof of an installed boot service. Keep fixture source out of implementation commits, but provide an explicitly reviewable reproducible fixture/seeding recipe or dedicated approved test fixture. Record both revisions and fixture provenance. Do not reconstruct the base UI in HTML. Never touch live userdata read-write.

**R1 — real sessions.** Lead/capturer privately mint scoped sessions or one-time pairing links against each isolated T3 home, using the actual scoped CLI. Source-verified command template: `node apps/server/src/bin.ts auth session issue --base-dir <isolated-home> --scope orchestration:read --scope orchestration:operate --scope terminal:operate --scope relay:read --label proof-denied --json`. Repeated `--scope` REPLACES defaults. Allowed version adds `--scope environment:maintain`; add separately required settings/access permissions only when needed by setup. `pair --base-dir <isolated-home> --scope ...` is the corresponding actual browser-pairing route. Keep tokens/links private; do not put command output or URLs in public evidence. Verify the resulting session is authenticated and its effective `permissions` omit/include maintain, rather than inferring from a legacy scope. Existing auth semantics prioritize `permissions`; absent modern scope metadata can invoke legacy fallback. Use real scoped modern sessions, not just a token named legacy. CLI seeding is preferred for primary/saved credentials; use actual Connections add/pair flow for saved registrations if needed. Browser catalog is IndexedDB `t3code:connection-runtime`, catalog/document; a guessed localStorage target is not a valid seed.

**R2 — actual routes/settings.** `/settings/connections` for primary version/saved list/bulk; `/settings/appearance` for explicit light/dark. Existing seeded non-scratch project/thread for composer, with activeThreadEnvironmentId set by actual thread selection, version mismatch undismissed and automatic selection off. Create/open a new draft for auto-balance: >1 logical-project environments, same project associated across environments, client loadBalancingEnabled true, no attachment, branch or worktree, unlocked draft, not promoted and selection not manual. Clear only isolated version-dismissal state or use a fresh profile; reopen real app to confirm the banner. More than one composer banner requires the actual stack expand affordance before inspecting a hidden update action.

**R3 — target sets and lengths.** Need three distinct saved environment IDs A/B/C for one permitted + two denied. Existing remote16472 can supply one; lead needs two additional isolated real environment identities (or already-running isolated servers), NOT three aliases/tokens to the same environment. Connection rows must be enabled, connected, compatible, idle/failed and older than client with selfUpdate boot-service. Set labels `Office`, `Laptop`, and a 96-character label (including a 48-character unbroken segment); set them through supported app/server configuration. Include primary-only composer label `server`, multi-environment `<label> server`, saved icon `<label> server`, bulk bare labels. Distinct UUIDs matter for permission subscriptions. Seed denied-only 1 and 3, mixed 1+1 and 1+2, allowed-only 1+; restore same seed between revisions. Manual/null and desktop-managed/no-update targets are ineligible for bulk. Do not make fake IDs pointing to identical descriptors.

**R4 — controlled failure and pending.** Use only expendable isolated update targets. Metadata claiming boot-service does not install a service; invoking Update can fail, and that genuine failure can seed Retry. Record the actual failure; do not claim upgrade success from a descriptor. For pending/reentrancy/race, desktop confirmation and unreachable session-result combinations, use a deterministic component/service harness with explicit resolved/deferred atoms and mocked update result; label HARNESS. If an actual safe target can produce these naturally, prefer real app and document it. Never update/restart the lead's production environment for proof.

## Fixture table

| ID | Affected / surface | Fixture, props and conditional branches | Seed / reachable route | Evidence and required observable result |
|---|---|---|---|---|
| C1 | A composer | One old boot-service server; settled authenticated denied; button `Update`, ghost/xs; no other banner | R0–R2; real thread, auto off | **Still**, closed hint: baseline/head geometry and disabled control; no persistent extra copy outside tooltip/toast |
| C2 | A composer | C1; primary label `server` then multi-environment long `<label> server`; pointer hover and keyboard Tab to wrapper, blur/Escape | R1–R3; actual app | **Recording**: new re-pair tooltip readable and contained at both widths; focus can reach wrapper; no update RPC. Base shows original unexplained disabled state. Long text shares this row, not a separate count permutation |
| C3 | A composer | C1 touch/click wrapper, legacy toast first dismissed; repeat tap | R1–R2 actual app | **Recording**: `Pair again to update` warning names target and pairing permission; no server-update RPC; inspect wrapping, repeated-toast behavior and dismissal |
| C4 | A composer failed | Failed update with mismatch retained, label `Retry`, error description; permission subsequently denied | R4 actual safe failure + R1 re-pair; H if directly injecting state | **Still**: failed banner + disabled Retry. **Recording** for hover/tap explanation (can share C2/C3 sequence only if failed state visibly reached) |
| C5 | A composer stack | Two or more banners; update control initially stacked; expanded with keyboard/touch; long label | R2 real stack; H only if no legitimate second banner can be seeded | **Recording**: expand → reach denied wrapper → explanation; no clipping/z-index/focus regression; collapse/restore |
| P1 | U primary denied / required negative gate | Connections canManageLocalBackend = !disabled && canMaintain; denied session removes entire Version row/control | R1 primary denied; `/settings/connections` | **Still** optional combined with S1. Do NOT fabricate an actual primary denied Version button; that combination is H |
| P2 | U primary allowed | Allowed maintain session, old boot-service, Version `Update to <clientVersion>` outline/sm; failed label `Retry update` | R1 allowed, R2 Connections; R4 safe failure for retry | No additional captures required. New denied branch is bypassed; allowed Update-to / Retry-update rendering is unchanged |
| S1 | A saved icon | One enabled connected old saved server; denied; appearance icon, ghost-muted/icon-xs, idle | R1–R3 Connections | **Still**: disabled arrow stays aligned beside switch/menu, narrow label truncation stable; no forced full-width wrapper |
| S2 | A saved icon | S1 hover, keyboard focus, tap; short and long server labels | R1–R3 actual app | **Recording**: new tooltip/toast names server and says pair again; icon accessible name stays `Update for <label> server`; existing generic Update tooltip replaced. No RPC |
| S3 | A saved retry icon | Failed saved update, still connected/mismatch, then denied; icon name `Retry update for …` | R4 real failure + R1; H if state injection needed | **Still** for error/progress layout; **Recording** for reachable wrapper tooltip/tap. Error text does not obscure hint |
| B1 | A Connections bulk | Exactly 1 eligible denied target; then 3 denied including long label; label Update all ghost-muted/xs | R1–R3 Connections | **Still**: disabled head bulk vs enabled base; icon rows remain aligned. 1 vs 3 differ in popup text only, share closed still |
| B2 | A Connections bulk denied | B1 hover/focus/touch click with 1 and 3 denied; joined comma-separated labels | R1–R3 actual app | **Recording**: all named, long popup/toast wraps within viewport; no update RPC. Same closed button visuals collapse, 1 vs many explanation content remains covered |
| B3 | A mixed bulk one skipped | Two eligible targets: A maintain, B denied `Office`; Update all remains enabled | R1–R3 actual app, R4 safe allowed target | **Recording**: hover explanation before click; click yields `Office skipped`, message says pair; only A update request; pending → settled/failed on safe fixture. Base lacks skipped explanation |
| B4 | A mixed bulk many skipped | Three eligible targets: A maintain, B/C denied with long label | R1–R4 actual app | **Recording**: `Some servers skipped`, both denied labels and pairing advice; only A updated; inspect stacked warning/error toasts at 390. This is distinct from singular B3 title |
| B5 | U shared helper allowed-only | All permitted, one or many eligible; no denied wrapper; one target already pending | R1 allowed; actual safe app for normal state; pending duplicate H | No additional captures required for allowed-only settled/success/failure/pending visuals; unchanged. Mixed-denial pending branch is covered by H3 |
| A1 | A auto-balance bulk | Idle mismatches; all machines connected managed; 1 then >1 targets; denied-only, label Update all ghost/xs | R2 auto draft + R3 | **Still**: collapsed banner title singular/plural and disabled bulk; **Recording**: hover/focus/tap explanation, open machines popover, dismiss/restore using actual UI/state reset. Run only legitimate 1 mismatched of >1 logical environments for singular |
| A2 | A auto-balance subset | At least one connected managed denied target plus manual or disconnected mismatch: label `Update 1 machine`, then `Update 2 machines`; manual count description | R2–R3; make subset via actual connection/manual fixture | **Still** each distinct label/description, **Recording** for hint and machines popover. Remote idle machines show Ready/Reconnect text; they do NOT render per-machine ServerUpdateAction in this popover |
| A3 | A auto-balance Retry | One failed managed target, none running; denied-only then mixed permitted; bulk label Retry, banner error style | R2–R4; real failure preferred | **Still** error banner, **Recording** hover/tap and mixed click skipped notice; error styling remains readable in both themes |
| T1 | A permission transitions | Denied → maintain-granted re-pair → denied, same environment ID; bulk membership changes without remount; single/icon and bulk subscribers | R1 real re-pair; reset private auth after profile reset; no fixture DOM mutation | **Recording**: hint removed/control enabled after grant refresh, returns after denial; direct update remains guarded. Record actual session revalidation milestone, not arbitrary sleep |
| H1 | A HARNESS session Initial/Failure | Single/icon without manualCommand: disabled with no new hint. Bulk eligible targets all Initial or Failure: head remains enabled, handler does zero allowed updates and no denied warning | H, controlled AsyncResult atoms; source permits this branch though normal connected configs may be absent | **Still** for Initial vs Failure if output differs, otherwise collapse. **Recording** for bulk click/no-op and resolving session → denied. Do not label these settled denial or silently promise loading is fixed |
| H2 | A HARNESS unauthenticated Success | Connected config held but AuthSessionState authenticated false: canUpdate false and isUpdatePermissionDenied true; same hint as denial | H; real session loss normally changes connection/auth page | **Still** can reuse denied visuals explicitly; **Recording** for session-loss transition if asserted |
| H3 | A HARNESS pending + denial | Mixed batch in progress with denied sibling; isPending disables button while denied hint remains; duplicate click; grant changes between render and invocation | H deterministic Deferred/update spy; use real safe target only if milestones controlled | **Recording**: warning once per operation, no duplicate update, skipped targets determined at click, session never grants update implicitly; pending spinner is NOT added by this diff |
| H4 | A HARNESS desktop permitted filter | Eligible desktop-managed/desktopAppUpdate true, denied desktop excluded from available before confirmation; allowed desktop confirmation accept/cancel; long labels | H desktop service or real isolated desktop app if available; web-only descriptor is not desktop proof | **Recording**: prompt names only allowed desktops; all denied yields hint/no dialog; cancellation has no update. Single denied supported desktop is visually same C1/S1, so reuse denial capture with explicit capability branch transcript |
| U1 | U manual / desktop guidance | selfUpdate null + npm-global vs relaunch command; manualCommand non-null bypasses denial. desktop-managed without desktopAppUpdate returns guidance before permission hint | R0 descriptor variations; component harness acceptable negative branch check | No additional captures required for unchanged paths. Existing copy command behavior, guidance, and auto popover manual per-machine actions unaffected |
| U2 | U absent controls / empty counts | No mismatch, zero saved targets, off/disconnected/running/desktop-local saved target filtered; auto machines 0 or dismissed → no banner; any auto running → no bulk action | Actual route/state; H only for empty raw targets component (disabled no hint) | No changed-path captures required. Can share route overview/negative state with above. ServerUpdateProgress downloading/installing/resuming labels unchanged; do not add redundant stills per stage |
| U3 | U other entry points/clients | Sidebar Update Everything uses unchanged useServerUpdate/canUpdateServer; OutdatedServerUpdateAction unsupported protocol path unchanged; command palette/keybindings add no direct caller | Source reachability audit | No extra visual evidence. Web and Electron renderer share changed component; Electron shell/IPC unchanged. Native mobile imports none of these changed web components and has no changed render path. Provider adapters, MCP and scheduler have no committed changes |

## Exact outstanding fixture needs / handoff

1. Ops checkout remains unavailable. Follow the user-supplied operational standard above; no permission question or missing-doc block remains. This audit does not claim to have read the absent file.
2. Re-pair privately after browser profile reset. Capturer must open its own tab, not reuse the lead's root-owned tab_j; default profile has fresh lead pairings but independent tab lifecycle still matters. Never publish pairing credentials. Startup admin privileges would conceal the bug: verify effective denied permissions after every pairing.
3. Provide baseline actual app at the base revision and final committed head with matched reproducible descriptor metadata. Existing 8431/16471/16472 can be reused only under lead coordination. Reported later refactor (existing environmentSessionStatesAtom/environmentIdsKey plus linear matcher) is not in this audited pinned head; recheck final diff before capture acceptance.
4. Seed three distinct saved targets for mixed-many case, scoped sessions, predictable labels and protocol-compatible old descriptors; two extra distinct isolated remote identities beyond current remote16472 are needed unless suitable isolated servers already exist. Do not duplicate registrations for the same identity. Seed the same logical project across >=2 environments plus an automatic draft and load-balancing setting for A1–A3.
5. Supply a **committed seed fixture/script** capable of selecting descriptor version/capability/installation and state sets above; currently only the uncommitted single old/boot-service descriptor fixture is known. Do not commit that accidental production-source hardcode. Need deterministic explicit harness cases for transient session atoms, pending race and desktop prompt filtering; never substitute those for actual-app denied/mixed rows.
6. Lead reports preliminary 1280/light real-app check: denied-only bulk disabled; after dismissing legacy toast, wrapper click opens named `Pair again to update` warning; saved-icon description/layout present. Useful lead observation, not this auditor's runtime observation, and not the required width/theme or baseline/head evidence. No final captures yet.
7. Existing red/green logs read only: red file records 3 permission regressions (one assertion later corrected) and 6 pass; green log records 9/9 at 03:00:54, 46.86s. These are supporting logs, not fresh test execution or visual proof. In particular the new explanation helper reads sr-only/aria text; it does not prove real hover/focus/touch reachability. Captures must close that gap.

## FRICTION

- tool: no browser/capture tools used by design; browser profile reset requires capturer-owned tab and private fresh auth. ghdrop is the explicitly requested artifact publishing mechanism.
- brief: ops repo path absent; user supplied the standard and instructed no blocking on it. Final committed head will differ after reported nonvisual simplification; pin final capture provenance.
- runbook: required t3code-ops/docs/EVIDENCE.md not located/read. Full-path search completed with no accessible result; user supplied its operational standard directly, which is applied above. Missing file is not blocking.
- infra: current servers are lead-owned; only one remote identity known, while mixed-many fixture needs three saved identities. Historical boot-service install and Electron runtime unverified.
- forge: origin verified git.cafe; no PR exists and no forge state commands/comments were needed. Artifact upload only.
- policy: strictly read-only worktree audit; requested /tmp markdown + upload are explicit exceptions. No source edits, live-state writes, server/browser launches or captures.
- model: no delegation/model switching; this pass performed by gpt-6.1-sol in Codex. No runtime assertions inferred from source alone.
- other: primary denied Version action is gated out in the real app; presenting it as reachable would be false proof. Native mobile is outside the changed render paths.
