# Model picker capture matrix — corrected pins and evidence redo

2026-10-23. Original source predictions are preserved below. Evidence redo now proves 11/11 rows: M2 has both genuine cached-to-initial-live variants in before/after x11grab recordings; M4 includes actual custom web numbered shortcuts. See evidence.md, redo-narrative.md and manifest.json. No product edits/commits/push/watch.

Original [#21727](https://github.com/pingdotgg/t3code/pull/21727), fork [yordis/t3code branch](https://github.com/yordis/t3code/tree/yordis/fix-model-picker-reopens-last-tab). Capture replacement `/home/ubuntu/wt/pr-21727`, branch `takeover/21727`, pinned after [ddb8df4ab5](https://github.com/pingdotgg/t3code/commit/ddb8df4ab57a37ae145983eb18fba44d3345019a); before/merge-base [71a283aed2](https://github.com/pingdotgg/t3code/commit/71a283aed253f23be1860a31d4ea48f1c06e0b1c). Do not capture original fork head as after.

## Diff boundary and corrected expectations

Local `main` is stale at [07d38b8d17](https://github.com/pingdotgg/t3code/commit/07d38b8d17167c8d17fba1184dbe13a307fada74). Literal `main...HEAD` spans 3,464 files of accumulated history; saved locally as `main-full.diff` with `main-diff-inventory.tsv`. That entire historical diff was not reviewed line by line. The complete focused `origin/main...HEAD` diff was read: only `apps/web/src/components/chat/ModelPickerContent.tsx`, `apps/web/src/providerInstances.ts`, and its test file (182 additions, 31 removals). No CSS changes. This matrix covers that replacement change, not unrelated history from stale main.

Resolver priority: explicit chosen tab → active account when locked/setup/selectable-unavailable forces it → remembered account if enabled AND ready or included in the selectable-unavailable set → Favorites when nonempty → active account. A remembered Favorites value follows the same Favorites-or-active fallback. Merely enabled is insufficient. The exception set includes the active retained unavailable model and accounts offering setup when the caller supplies setup navigation. Sidebar reachability is the relevant criterion; forced lock priority is resolved first.

First star and last unstar pin the CURRENT open tab before mutating favorites, when there is no explicit choice and no forced active tab. They do not persist a preference by themselves. They must not cause the open tab to jump. Genuine initial settings loading without user interaction still allows active → Favorites; explicit tab choice prevents that jump. These are separate branches, not interchangeable evidence.

Storage `t3code:model-picker-last-tab:v1` is a JSON string, read on content mount. Successful non-search model picks persist the selected TAB, including additive selection. Search picks preserve memory. A forced active tab's model pick also preserves memory until the user explicitly chooses a tab (sidebar or provider navigation shortcut). Explicitly choosing even that same active tab allows its subsequent non-search pick to persist. Star toggles while forced do not count as explicit choice. Whitespace-only search is non-search. Disabled/unresolvable picks return before the write. Explicit chosen tabs are not subsequently revalidated; dynamic catalog removal while already open is not a new capture requirement.

## Synthetic fixture contract

Evidence must show the real web app, its production picker, storage path, settings subscription, and services. All test data is explicitly authorized synthetic data. NEVER inspect, open, copy, migrate, snapshot, or mutate a real database; never use `~/.t3/userdata`. Use fresh homes `/tmp/ev-21727/homes/{before,after}`, project `/tmp/ev-21727/project`, and evidence-only browser profiles. Launch with explicit evidence home and seed disabled (`T3CODE_DEV_SEED=0 vp run dev --home-dir <evidence-home> --no-seed`); verify resolved home before use. Do not set VITE_HTTP_URL/VITE_WS_URL.

Base S: synthetic project and unsent multi-model draft; ready A=Personal and B=Work accounts of the same driver, distinct IDs and labels; one different-driver C for the lock control; at least two selectable models per ready account, including long labels. Start with Favorites containing an A and a B model except where a row specifies empty/one favorite. Reuse this fixture with small resets, not a separate fixture per assertion. No legacy models or ten-row catalog needed.

Build through UI, valid settings/RPC, or a temporary seed script calling production services/commands against the fresh evidence home. Synthetic provider fixtures, including a test CLI with valid provider configuration, are permitted to reproduce ready, setup, locked, and unavailable states. Label them SYNTHETIC in manifest/sidecar and save their configuration and protocol script. Use production discovery/adapters and service semantics; do not replace product behavior, inject component props/client atoms, intercept RPC/WS replies, or render a reconstructed picker. A test CLI can return controlled discovery/readiness responses; it need not be a real authenticated paid account. A synthetic stopped thread may be seeded via production commands. Never obtain it from a real DB. No paid turn is required.

Reset only synthetic settings/state and the named storage key between chapters. Use real model picks to establish memory for core persistence evidence; direct key seeding is acceptable for guard variants, labeled in manifest. Copy only our own stopped synthetic fixture between version homes if useful.

## Minimum behavioral matrix

Each row is a chapter, not another app install. Record actions and observable milestones; assertions below are after expectations, not claimed passes. Reuse S across G1–G4.

| ID / group | Minimal fixture and actions | Expected after / evidence |
|---|---|---|
| M1 / G1 account and Favorites memory | S, no key: open; choose B, pick B, reopen; browse A then Escape/reopen; reload/reopen. Then Favorites, pick its B model, reopen. | Clean defaults Favorites. Real B pick saves B and reopens B despite Favorites; browsing alone preserves B; reload retains B. Favorites pick saves Favorites, not owning account B. Show account labels/IDs and cross-account favorite rows. |
| M2 / G2 actual loading | S persisted favorites, key absent or Favorites. Delay genuine initial environment settings delivery using network throttling/gating, open while unresolved; release. Repeat with explicit A choice before release. | No user action: active A → Favorites when settings arrive. Explicit A: stays A. Record actual subscription/loading transition; star mutations are not evidence for this row. No fabricated settings payload. |
| M3 / G2 first star and last unstar | Empty favorites, no key; open A with no explicit choice, star first row. Reset to exactly one favorite/no key; open default Favorites, unstar last row. Close/reopen after each. | Open tab stays A on first star and stays Favorites on last unstar. Star actions leave key unchanged. With no model pick, reopening recalculates default: Favorites after first star, A after last unstar. Show both live and remount behavior. |
| M4 / G1 additive and keyboard | S unsent multi-model draft active A; B tab Shift-pointer add then remove B model, reopen after each. Repeat additive via Shift-Enter; ordinary Enter pick and one rendered numbered model shortcut. Use provider next/previous shortcut to choose B then pick. | Add/remove retain active A where applicable; both remember B. Picker toggle behavior and selected marks remain correct. Enter/numbered route persist visible tab and target correct visible row. Provider navigation is explicit choice and enables persistence. Use resolved/rendered keybindings, not guessed OS shortcuts. |
| M5 / G3 search | Establish B by real pick; search A-only result, ordinary pick/reopen. Repeat one Shift-Enter additive search pick. Clear query; choose A, enter spaces only, pick/reopen. | Nonempty search spans accounts and hides sidebar; ordinary and additive picks leave key B. Reopen B even if selected model belongs to A. Spaces-only pick saves A. Show query cleared on actual reopen; do not treat stale query as tab proof. |
| M6 / G4 remembered reachability | Active A ready/unforced, key B. Reset B among: ready; enabled unavailable with no setup/selectable exception; same unavailable with production setup action reachable; hidden/disabled; missing/deleted ID. Favorites nonempty; repeat fallback once with empty favorites. | Ready B restores. Unreachable unavailable B falls back Favorites; reachable setup B restores. Hidden/missing B fall back Favorites, and empty-favorites fallback is A. Show sidebar enabled/disabled/absent and setup notice as applicable; enabled alone is not enough. Missing-ID reset covers deleted without requiring a separate deletion movie. |
| M7 / G4 forced states and write guard | Key B or Favorites; synthetic locked thread active A with incompatible C. Open, pick valid compatible A row without explicit tab, read key; explicitly choose A, pick again/read key. Reset active account to setup-needed, then to retained selectable-unavailable OpenCode/Antigravity saved model. | All three forced states open active account despite memory. Locked implicit successful pick preserves key; explicit same-tab pick saves A. Incompatible C cannot pick/write. Setup notice is visible. Retained unavailable model remains visible/selectable under production rules; if selectable, repeat implicit/explicit pick guard there. Do not manufacture a pick in a setup-only empty list; locked fixture proves shared write condition. Show star on forced tab does not alter memory or enable later implicit persistence where star control exists. |

M6's unavailable remembered exception is setup reachability in a real caller with setup callback. M7 separately covers active retained unavailable models and forced priority. Do not substitute a generic disabled account for either unavailable state. The same unavailable provider fixture can supply both chapters with valid setting/thread resets.

## Capture matrix and artifact minimum

Only `apps/web` applies under the dispatcher's file-path surface rule. Desktop and native mobile are not additional requirements. 390px is responsive web. No server/provider adapter changes to certify independently; synthetic providers exercise the real web integration.

Four chaptered before/after recordings (8 videos), plus four before/after still pairs (8 PNGs). No fixture × theme × viewport Cartesian product. Frames may be extracted from recordings if dimensions/state match.

| Group | CSS viewport / theme | Chapters |
|---|---|---|
| G1 core | 1440×900 light | M1, M4 |
| G2 loading and stars | 1440×900 light | M2, M3; loading and star chapters explicitly separate |
| G3 search | 390×844 dark | M5 |
| G4 guards | 1440×900 dark | M6, M7 with short named resets |
| S1–S4 still pairs | 1440×900 light; 1440×900 dark; 390×844 light; 390×844 dark | M1 B-reopen milestone, long account/model labels, badges, selected tab, trigger/popup fit and list/fades |

For before, use identical fixtures/actions against the pinned merge-base; expected bug differences are legitimate. Do not force identical final tabs to hide the fix. G2 star pinning is already present before in some cases; record it as a regression control, not an invented before failure. Before initial loading may stay A while after follows Favorites. Before has no memory write: treat key evidence accordingly. Each final artifact gets version hash, fixture reset inputs, viewport/theme/DPR, chapter timestamps and observed result; never label a source prediction as runtime proof.

No separate demand for legacy expansion/numbering exhaustion, every Settings form, browser policy denial/storage exceptions, all provider drivers, cross-tab synchronization, or live account deletion while open. None is needed to prove these changed branches. One applicable setup caller and the primary composer cover the required paths; use another existing caller only when needed to produce a genuine guard state. Existing resolver tests support fallback logic but do not replace runtime proof for writes/loading/star pinning.

## Later capture workflow

This pass does not execute the following. Keep all scripts, synthetic provider CLI/config inputs, sanitized logs and captures in `/tmp/ev-21727`; never commit them. Record HEAD/base/status and changed-file hashes first. Before capture may temporarily restore only the three changed files from pinned base, preserving/restoring pinned after contents with an exit trap; do not reset branch/index. Stop captured server PID before version swap to avoid mixed HMR evidence. Keep synthetic homes and browser profiles isolated; use same origin with chapter storage resets for comparability. Save restoration verification.

Measure inner viewport/DPR and verify theme. Drive real app controls; DOM/ARIA/storage reads can assert observations. Observe settings delivery to substantiate M2. Use actual rendered shortcut labels. No fake DOM overlays. Record at modest frame rate, finish video trailers, inspect outputs, then upload with `ghdrop upload -m`. Track only PIDs spawned by capture; never kill by pattern. Do not upload credentials, pairing links, profiles, DBs, or unrelated raw history. Publish artifact manifest mapping M1–M7 and S1–S4 to URLs/timestamps and exact gaps.

## FRICTION

- No browser/server/capture ran in this update. Fixture implementation and runtime results remain unverified; this is the revised capture plan.
- Literal local `main...HEAD` includes unrelated historical work. Complete focused replacement diff reviewed against `origin/main`; full stale-main diff saved locally but not fully reviewed. Capture pinned base/after above, not stale main.
- Actual loading requires delaying real initial settings delivery while picker remains mounted. If throttling also blocks opening, report M2 uncaptured with the exact obstacle; M3 cannot stand in for it.
- Setup and selectable-unavailable states may need the authorized synthetic test CLI plus production service seeding. This is permitted, not a prerequisite for real provider accounts. Save exact scripts and label synthetic; report a concrete unsupported service/protocol path only if encountered.
- No storage-policy-denial or unrelated legacy/Settings coverage is an acceptance gap for this matrix. Surface scope is web only.

## Evidence redo outcomes

M2 is now proven: cached empty-Favorites production config mounts Personal while the genuine initial live config is gated. Separate synthetic settings RPC updates Favorites while disconnected. Releasing identical frame bytes changes after to Favorites; baseline remains Personal. Explicit Personal before release stays Personal in both. The same input DOM object stays mounted. Both variants have narrated paired recordings and frame-content measurements.

M4 numbered visible-list behavior is proven via supported custom keybindings.json rules, with rendered Ctrl+2 labels: Work row2 selects Work long model; Favorites row2 selects Work Atlas. No fake desktop API. S1–S4 explicitly include independent-audit >8/255 masks alongside raw and 8x amplified diffs. G3 corrected frame cues: ordinary Work remount 3.1–3.7s, additive Work remount about5.8s; other original cues remain approximate.
