# Sticky-traits proof contract — audit1

Read-only proof plan for [#24619](https://git.cafe/pingdotgg/t3code/pulls/24619). This document is expected behavior derived from source, not captured runtime proof. Auditor: GPT-6.1 Sol / Codex in T3 Code. No servers, browsers, tests, source changes or live userdata access.

## Revisions

Recommended baseline: [8525000dce](https://git.cafe/pingdotgg/t3code/commit/8525000dcecdf738c26c12f15b38b43082b9701f), the immediate parent of [ef56e48934](https://git.cafe/pingdotgg/t3code/commit/ef56e4893417afe46c309b39f17a8bb23991ad6a). Candidate: [39f1493f0d](https://git.cafe/pingdotgg/t3code/commit/39f1493f0de9f170ddd857eb5beb469a04857883). Candidate composerDraftStore.ts is unchanged from the fix commit. This parent isolates the two guarded sticky mutations; it already has the preceding displayed-model precedence fixes.

The candidate/current-main merge base is [91ea0e18eb](https://git.cafe/pingdotgg/t3code/commit/91ea0e18ebe2db81752bad7f0d4fa70a66d7562b). Do not use it as the primary isolated comparison: it also lacks earlier PR fixes and can display A rather than started B. Historical baseline eea9895 and earlier screenshots cannot establish this correction. Parent versus final candidate includes unrelated main merge changes; disclose that fact, and use raw store assertions to isolate this block.

## Clean fixture recipe (future authorized capture; not executed)

1. Work only in /home/ubuntu/wt/pr-24619. Coordinator must arrange sequential revision selection/builds without disrupting other readers; auditor changes no checkout. Pin full SHA and record git rev-parse HEAD for every run. Do not infer revision from inherited archive root files.
2. Use a NEVER previously used absolute home /tmp/ev-24619/<run-id> for EACH baseline/candidate/theme/viewport/branch run, e.g. baseline-light-1440-set-<unique>. Future startup command: `T3CODE_DEV_SEED=0 vp run dev --no-seed --home-dir /tmp/ev-24619/<run-id>`. Verify startup's resolved home and actual ports. Never access, copy, migrate, seed from or symlink ~/.t3/userdata. Do not run migrate-dev-db. Do not set VITE_HTTP_URL/VITE_WS_URL.
3. A fresh server home is insufficient: use a new browser profile/storage partition per run, and a fresh origin or cleared origin-scoped storage. Composer persistence key is `t3code:composer-drafts:v1`; record its initial absence BEFORE opening the app and hydration. No previous service worker/session/localStorage may seed B options. Do not publish credentials, pairing URLs, runtime logs containing secrets, or raw browser storage.
4. Provision synthetic environment/project and a stopped started thread S through existing isolated fixture/service mechanisms. No vendor execution is required. Save the exact seeder/payload with evidence; this audit does not certify an existing runtime seeder. S must have persisted history (run or items), model B, Low reasoning, no active turn. Project/server model defaults must not override sticky A. Use one enabled Codex instance P and two distinct offered models with reasoningEffort low/high/xhigh supported. Suggested prior fixture: A=GPT-6.1-Sol, B=GPT-6-Sol; resolve actual slugs from the run's catalog, not display labels. Record catalog and IDs. Avoid Fast/priority and all other options; use reasoning only so a clear can truly be empty.
5. Harness initialization is permitted ONLY before each independent sequence. Set sticky selection P/A with reasoningEffort=xhigh using store.setStickyModelSelection, seed A per-model memory to the same value, and assert B per-model memory is ABSENT. Ensure stickyActiveProvider=P. S has NO draft selection entry, no explicit bit, no active draft provider overriding P; give it a synthetic unsent prompt for persistence. Inspect effective composer B/Low and raw thread B/Low before any actions. Use actual option selection schema/builders, not invented JSON. Keep server S unchanged throughout.
6. Record all initialization as synthetic/harness setup. No further reseeding, hydration injection, direct DOM writes or store repairs between interaction checkpoints. Capture raw state after every action: S draft, sticky selection, A/B per-model memory, fresh destination draft, effective composer model/options and immutable server S. Save a redacted structured assertion result, not all localStorage.

Notation: X=xhigh/Extra High, H=high/High, L=low/Low, empty=no explicit options. M[A]/M[B] are stickyOptionsByModelByProvider[P] entries. Sticky is stickyModelSelectionByProvider[P]. Draft is draftsByThreadKey[resolved environment/thread key]. Options are semantic decoded values; absent and empty are distinguished in raw assertions. Catalog defaults may render a label even for empty options; record exact catalog default label before capture.

## Exact interaction rows

Run SET sequence and CLEAR sequence independently from the clean fixture. CLEAR deliberately starts with the same real SET action so it exercises deletion of a populated B memory entry. Never reset sticky A after that action: baseline corruption is expected to remain observable.

| Row | Real action / endpoint | Baseline EXPECTED | Candidate EXPECTED | Required raw assertions |
|---|---|---|---|---|
| S0 / C0 | Open stopped started S; show composer and picker/traits | B/L; sticky A/X | B/L; sticky A/X | S started B/L; no explicit draft; Sticky=A/X; M[A]=X; M[B] absent. If unequal, reject fixture. |
| S1 / C1 | Open actual Traits menu on displayed B; choose High; reopen to show checked High | Composer B/H; Sticky becomes A/H (DEFECT) | Composer B/H; Sticky remains A/X | Draft B/H, explicit=true, activeProvider=P; M[B]=H on BOTH; M[A]=X unchanged; Sticky exact expected above; server S remains B/L. |
| S2 | Enter genuinely fresh no-model thread F through real no-model prompt-link entry (no provider/model params), in project without model defaults; show composer and picker | A/H (DEFECT) | A/X | F unstarted, no run/items/runtime; no source carry; F seeded from Sticky; Sticky unchanged; S draft B/H retained. A new destination ID required. |
| S3 | Navigate back to existing S through actual sidebar/navigation | B/H | B/H | Same S ID, draft B/H explicit, M[B]=H; Sticky remains baseline A/H or candidate A/X. No picker selection during navigation. |
| C2 | After C1, clear ALL explicit B traits through a verified UI unset action; reopen menu | Composer B with catalog defaults; Sticky A loses options (DEFECT) | Composer B with catalog defaults; Sticky A/X retained | Draft B with NO options, explicit=true; M[B] key absent; M[A]=X unchanged; Sticky baseline A/no options versus candidate A/X; server S B/L unchanged. |
| C3 | Enter genuinely fresh no-model thread G through same non-carry entry | A with catalog defaults (DEFECT) | A/X | New destination ID; unstarted; seeded from Sticky; no source carry/default override. S explicit B/no options retained. |
| C4 | Navigate back to existing S through actual sidebar/navigation | B with catalog defaults | B with catalog defaults | S still explicit B/no options; NOT inherited server B/L; M[B] absent; sticky remains baseline A/no options or candidate A/X. |

Required configurations for EVERY row: light 1440x1000, dark 1440x1000, light 390x844, dark 390x844. CSS pixels, DPR=1, zoom=100%, explicit theme, same catalog and layout conditions across paired runs. SET has 4 checkpoints and CLEAR has 5: 9 × 4 × 2 revisions = 72 indexed checkpoint cells. Shared S0/C0 and S1/C1 are independently initialized in their respective sequences. Eight independent runs per revision (two sequences × four configurations), sixteen total. Could package as eight full videos with two explicitly separated fresh runs each, but never reuse state across sequences/revisions.

A complete full-viewport recording must show each sequence's real interactions; eight matched baseline/candidate sequence pairs. Index checkpoint timestamps and extracted endpoint stills with exact revision, run-id, resolved home, storage partition, theme, viewport, catalog, IDs, setup provenance and pass/fail assertions. Generate matched before/after and amplified differences for endpoints, especially S2/C3; identical-looking B edit endpoints alone do not prove sticky correctness. Keep unrelated timestamps stable where feasible; do not edit application DOM to equalize them.

Optional per-model restoration extension: from fresh F explicitly PICK B and show H restored from M[B]; after CLEAR use a separate fresh destination to pick B and inspect absence of remembered B traits. This is different from navigating back to S. Picker choice changes the sticky model to B and contaminates later A assertions, so do it only AFTER required A/fresh/return checkpoints or in another fresh run. Report both actions accurately.

## Clear affordance limitation / pitfalls

TraitsPicker.tsx selects descriptor radio values; a catalog option bearing the Default badge is still a value. Selecting Medium/default, Fast Off or toggling a checkbox does NOT prove empty options. Inspect serialized selections before crediting C2. Source inspection here does not establish that the current Codex Traits UI exposes an all-options unset action. If none exists, report interactive-clear proof BLOCKED; do not manufacture an interaction or call it complete. A separately labeled harness `setProviderModelOptions(S, codex, null, {instanceId:P, model:B, persistSticky:true})` proves the clear state transition and resulting UI only, not a native unset interaction. Record that limitation even if all harness-clear rows pass. Existing unit test covers set and clear but cannot replace these recordings.

The ordinary contextual New thread action may carry B and is unsuitable for S2/C3. A no-model prompt link can still reuse a draft or receive project defaults: assert a fresh destination, no explicit query selection, and actual sticky source. Preserve S's unsent prompt so reuse cannot silently replace the source. Never explicitly choose B before the sticky-A fresh-thread observation.

Implicit Fast options can prevent empty clear; disable that fixture behavior or disclose and inspect all remaining options. Fresh server homes without fresh browser state caused the previous baseline contamination. Expect corruption immediately at S1 on parent baseline: if baseline Sticky is still A/X after a genuine B/H edit with persistSticky=true, stop; wrong revision, stale bundle or invalid fixture is likely.

## Existing proof status

Read PR body through cafe only and read the linked [prior focused audit](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/4eae24ae2cea990c/sticky-proof-review-audit.md) and [original matrix](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/230e9005e941ccb0/matrix.md). Prior accepted desktop/light candidate shows set/fresh-A/B restoration. Its baseline did not demonstrate the expected immediate mutation; baseline final checkpoints, three other configuration pairs and actual clear action were missing. Existing broad A/B/C/D evidence and its sufficient verdict do not cover this new block. No archive recapture or new runtime proof is claimed by audit1.

No repo writes, commits, pushes, PR comments/body edits or evidence-ledger edits. All new work product is this file outside the worktree. This plan requests no server/browser launch and grants no such authorization.
