# Proof audit pass 1 — composer chip order

Read-only source audit; no browser, server, capture, test execution, or production data access. Capture instructions below are for the next agent, not actions performed here.

[GitCafe #17892](https://git.cafe/pingdotgg/t3code/pulls/17892) · [GitHub #17892](https://github.com/pingdotgg/t3code/pull/17892).
Audited entire `origin/main...HEAD`: replacement `takeover/pr-17892` [c772f425b1](https://git.cafe/pingdotgg/t3code/commit/c772f425b12ab22d7455d5de616370ece0d2a295), base main [eea9895368](https://git.cafe/pingdotgg/t3code/commit/eea989536849e5b5049987ee24318b5a77326542). Original supplied: [NikitaMGrimm/t3code](https://github.com/NikitaMGrimm/t3code), `fix/composer-compact-chip-order`, [263670f223](https://github.com/NikitaMGrimm/t3code/commit/263670f2239d6118a60b4413c571fe8446d48627). Original is provenance, not the comparison base. Clean worktree confirmed.

## Exact affected scope and acceptance

Three changed files, 106 additions / 83 deletions. Attach moves from the ChatComposer right-action parent into FooterPrimaryActions, whose Attach + meter fragment is passed as `leadingActions` into PrimaryActions. Every PrimaryActions return now has fragment slots `(chip, leadingActions, action)`. The former chip+send flex wrapper is removed. Stable attachment/focus callbacks are added at the caller.

Expected order: chip (if eligible), Attach (if supported), meter (or reserved blank), existing primary action/group. Without chip: Attach, meter, existing action/group. Primary buttons inside their groups retain order. For a fixed viewport, action group, and meter state, Attach x/y must remain fixed when Compact ↔ Full or chip absent ↔ present. Do not compare geometry across a meter enable/disable, action width change, sidebar resize, or resting/expanded transition and call it a chip regression.

The change affects sibling spacing, reconciliation/mount identity, keyboard order and overlays. It does not change compaction eligibility, action choice, labels, submission/interrupt handlers, attachment count logic, token formatting, or provider contracts. Code review is not visual proof; geometry remains unverified until captures.

## Practical minimum: 40-minute capture budget

Use actual web app at viewport widths exactly 1440 and 390 CSS px (suggest height 1000 and 844). 390 means responsive web, not native mobile. Keep browser zoom 100%, fixed sidebar state, and record viewport dimensions. Before = main eea989536849e5b5049987ee24318b5a77326542; After = candidate c772f425b12ab22d7455d5de616370ece0d2a295. Build/run both in the real app under identical fixture, viewport, theme and frozen clock. Every affected row requires a before/after pair and zero-threshold amplified plus stated-threshold diff images. Toggle recordings are required for both builds; record the same script and narrate steps/timestamps above each pair. Counts below are PER BUILD, so double for full before/after evidence.

| ID | Required real-app fixture | Still output | Recording output / assertions |
|---|---|---|---|
| C1 | 1440, light; expanded existing Claude thread, eligible chip, Attach visible, real meter | Compact and Full: 2 stills | One recording: pause before Compact → Full → Compact, pause after; then remove/retype draft in resumable thread for present → absent → present. Attach visible at every checkpoint. Log Attach/send/meter rects and original DOM node identity. |
| C2 | 1440, dark; same data, meter disabled | Compact and Full: 2 stills | Same recording sequence; proves meter absent and constant Attach geometry without meter. |
| C3 | 390, light; expanded/focused composer, real meter | Compact and Full: 2 stills | Same sequence. Keep focus/expanded state through text removal (avoid blur collapsing mobile composer). Include real Tab traversal and chip tooltip once. |
| C4 | 390, dark; expanded composer, meter disabled | Compact and Full: 2 stills | Same sequence; show no clipping/overlap with left controls or viewport. |
| S1 | 1440 light, actual resting existing-thread composer, real meter, chip eligible | No additional still required: extract checkpoint if useful | One short recording: overflowing timeline, scroll away from end into true resting layout; toggle chip both ways; return to end/expanded. Check Attach geometry within resting state, editor focus, timeline overlay and last-row clearance. Actual resting predicate must be true, not just `compact=true`. |
| S2 | 1440 light, started thread loading detail, meter enabled and reporting capability true/unknown | No additional still required | One short recording: reserved blank → real meter as detail arrives; Attach/input identity stable. If natural load is too fast, delay the actual detail response in the collaborative browser. Do not substitute an all-empty loaded thread for reservation. |
| S3 | 1440 light proposed-plan follow-up, Attach + real meter, chip absent | One Implement closed-menu still | One short recording: open Implementation actions menu, show unclipped “Implement in a new thread”, Escape; type feedback → Refine; clear → Implement. Do not launch a new provider turn just for evidence. |

Minimum mandatory core per build: **8 stills + 4 recordings**. Scope supplements: **1 plan still + 3 short recordings**, for **9 stills + 7 recordings per build**, with branch checkpoints folded into these clips where production fixtures already exist. No theme/width Cartesian product for unchanged branch labels. Record interaction/time rows; stills alone cannot prove stationary geometry, focus, mount identity or overlay continuity.

Suggested allocation: 0–12 min isolated setup + usable Claude fixture; 12–25 min C1–C4; 25–31 min S1/S2; 31–36 min S3 and branch checkpoints; 36–40 min upload and manifest. If provider setup prevents the real core, report the blocker immediately; do not spend the budget on a harness claiming real-app completion.

## Rendering paths and collapsed branch decisions

Source links use audited head. Local line numbers aid navigation.

- [ChatComposer](https://git.cafe/pingdotgg/t3code/blob/c772f425b12ab22d7455d5de616370ece0d2a295/apps/web/src/components/chat/ChatComposer.tsx): attachment predicate 1256; responsive direct caller 3836; footer layout 3868–3960; stable callbacks 2748. Only production ChatComposer JSX caller found: ChatView at 3493. CommandPalette holds a composer handle, not a second rendered composer.
- [ComposerFooterControls](https://git.cafe/pingdotgg/t3code/blob/c772f425b12ab22d7455d5de616370ece0d2a295/apps/web/src/components/chat/ComposerFooterControls.tsx): FooterPrimaryActions 151 onward; Attach/meter/placeholder fragment 196–213; forwards all action props. Other exports in this file are unchanged and need no independent capture.
- [ComposerPrimaryActions](https://git.cafe/pingdotgg/t3code/blob/c772f425b12ab22d7455d5de616370ece0d2a295/apps/web/src/components/chat/ComposerPrimaryActions.tsx): shared fragment 135; return branches 170, 220, 234, 279, 374, 378. Only JSX callers: FooterPrimaryActions and narrow-web pending-answer direct caller in ChatComposer.

| Path / data and props | Affected decision and minimal proof |
|---|---|
| Ordinary submit, chip eligible; `compactBeforeSendTokens != null`, not Resume or queued edit | Core C1–C4. `keepFullHistory=false/true` gives Compact/Full, warning/muted styles, changed chip width; both required. `compact` prop means action label density, not presence of compaction chip. |
| Ordinary submit without chip (`compactTokens=null`) | Affected fragment return; record removal/reappearance in each core clip. Resume empty draft → nonempty draft is reachable and keeps a same-sized primary button; do not use running state, which disables compaction eligibility upstream. |
| Resume empty, queued-message editing | Same chipless submit wrapper. Resume play icon appears in core removal sequence. Queued edit check icon is unchanged; one static checkpoint only if a real queued message already exists, no separate theme/width set. Chip is explicitly suppressed in both. |
| Pending question: 0 vs >0 index, Next vs final Submit, Previous, optional Stop; responding/disabled | Changed wrapping, unchanged group contents. One desktop static checkpoint at index >0 with Previous and Stop, if reachable within budget; this is the widest group. Index 0 removes Previous, final/responding change text/disabled appearance, no distinct new ordering; source-only collapse, not a claim all were visually tested. Attach exists only for custom-answer-capable supported questions. |
| Responsive pending question direct caller | At 390, `showMobilePendingAnswerActions` is true; footer is `hidden sm:flex`; direct PrimaryActions gets no leadingActions and no chip, `compact=true`, no Stop. One real narrow checkpoint if pending fixture exists; explicitly unchanged visual order, changed fragment shape only. Cannot demand Attach in this branch: production deliberately does not pass it. |
| Plan Refine (`showPlanFollowUpPrompt && promptHasText`) | Affected early return; S3 type/clear records Refine and Implement. Loading text Sending and disabled styles unchanged; collapse with generic busy state. |
| Plan Implement (`showPlanFollowUpPrompt && !promptHasText && !canResume`) | Distinct split button/menu geometry; S3 mandatory. Menu portal/floating scope unchanged but relocation merits actual opening. Chip cannot occur here because upstream plan follow-up disables compaction. |
| Stop-only (`canInterrupt && !hasSendableContent && !isEditingQueuedMessage`) | Affected early return, same fixed-sized stop button. One static checkpoint if running fixture exists; otherwise source-only explicit decision. No chip upstream while running. |
| Running with content: Queue / Steer, alternate Ctrl/Meta; queued edit suppresses dispatch mode | Same ordinary submit wrapper, icon changes internally. One static running-content checkpoint, optionally paired with Stop in same real thread; modifier behavior is unchanged and does not justify separate capture matrix. Do not claim a frozen harness dispatch is a real provider interaction. |
| Connecting / send busy spinner, worktree preparing, offline, missing provider/project, permission or validation error, empty prompt | All unchanged internal submit-status / disabled precedence. Empty prompt no-Resume gives disabled send. One chipless disabled checkpoint can stand for geometry; no new overlay or order per error string. Spinner/time demonstration, if requested beyond this pass, must be a recording. Offline/worktree states cannot have eligible chip upstream because compactDisabled/isWorking gates it. |
| Meter real / reserved / absent | All affected as relocated siblings: real in C1/C3, absent C2/C4, reserved S2. Reserved is `meterEnabled && detailLoading && threadStarted && reportsContextWindow !== false` with active usage null. Loaded no usage is absent, not reserved. Percent/cost/max/overloaded combinations are unchanged popover internals; one real popover suffices. |
| Attach hidden | `fileStagingLimit=null` (known capability unsupported/no max) or unsupported/choice-only pending question. Unknown upload capability still permits Attach. Use a real capability/question fixture if available; one static chipless checkpoint is enough. No full matrix for hidden Attach: target geometry is absent. |
| Attach data counts 0 / 1 / many, upload failure / preparation, images vs files | Attach visibility itself does not depend on attachment count. Core starts at 0; add one benign text file once to verify hidden input survives and clears, and focus returns. Counts >1, media preview overflow and failure labels are unchanged strips; collapse, no independent captures. Preparation/errors can force expanded layout: do not call them resting fixtures. |
| Actual resting / expanded desktop; collapsed / expanded narrow web | S1 proves actual resting. 390 must be focused or forced expanded for core: collapsed mobile omits footer entirely. A final blur/collapse/reopen segment in C4 covers narrow overlay entry/exit; no requirement to show Attach while footer is absent. |
| Theme / environment artwork / platform | Required light/dark in core. Artwork button decoration changes background only, unchanged; no extra capture. Desktop wraps same web renderer; no Electron IPC or native mobile changes, so no separate platform captures. Local/relay/tunnel have same renderer/contracts; no independent remote matrix. |

Static branch checkpoints above are supplemental, not an unbounded mandate to synthesize every state. If real pending/running fixtures cannot be created within the timebox, list them as source-reviewed, uncaptured with exact reason. A harness may demonstrate a genuinely unreachable prop combination but cannot replace core, resting, real Tab, or plan production proof. No harness is necessary for the proposed minimum. Running+eligible-chip and plan+eligible-chip are unreachable upstream; do not create these fixtures.

## Capture observations bundled into core/supplements

Each core recording must hold Attach and the action visible before and after toggling. Collect rects after settled layout for Compact, Full, absent and reappeared; accept only subpixel rounding (suggest <=1 CSS px). Compare to same-state baseline; retain chip/action/meter rectangles and viewport alongside video, not just an assertion. Pointer moving onto Send can scale it on hover, so park pointer away before measurements.

Retain references to Attach button, its hidden file input, and real meter trigger before toggling; check `isConnected` and strict node equality afterward. Do not write DOM/style mutations as proof. Check actual editor focus before/after pointer toggles on 390 and resting: those callers preserve focus. In expanded desktop chip focus can normally move on pointer; do not invent a stronger invariant. Attach always prevents pointer focus loss. Select a benign file once; input value clears and handler remains usable. Record this interaction.

Use actual keyboard Tab/Shift+Tab events, not `.focus()`, for one core clip: chip → Attach → meter (when present) → primary, with the correct disabled controls skipped. Show visible focus and tooltip. Hover/open real meter, then trigger a safe chip state change while observing popover and node continuity where feasible; record popup behavior, do not assume that closing on outside interaction means remount. S3 covers the separate plan menu. Log clipping/hit target/overlap at 390 and actual resting separately. No continuously animated demo is required.

## Fresh-home seeding handoff (never production data)

All commands must begin with explicit `cd /home/ubuntu/wt/pr-17892`. Keep evidence, drivers, SQL and notes under `/tmp/pr17892-proof`; runtime home is **/tmp/ev-17892**. Do not read, copy, migrate, or even inspect `~/.t3/userdata`. Do not run migrate-dev-db. No secrets or pairing URL in uploaded files.

Launch when capture is authorized:

```bash
cd /home/ubuntu/wt/pr-17892
T3CODE_DEV_SEED=0 vp run dev -- --home-dir /tmp/ev-17892 --no-seed
```

If the script runner treats the extra `--` as a positional argument, use the exact direct package-script equivalent:

```bash
cd /home/ubuntu/wt/pr-17892
T3CODE_DEV_SEED=0 node scripts/dev-runner.ts dev --home-dir /tmp/ev-17892 --no-seed
```

Both explicit home and seed-off controls are intentional. Read actual ports and pairing URL from output. Start once for migrations; use collaborative Browser skill workflow and private pairing URL. Never set VITE_HTTP_URL/VITE_WS_URL. Retain own process session/PID; stop it before SQL writes. No process-pattern kills.

1. Create a synthetic project rooted at an empty fixture repo under `/tmp/ev-17892/project` through the real app; create an existing Claude thread and a benign completed conversation (one user item whose text is not just /compact). Use a provider available in the isolated environment; credentials/provider health are unverified by this audit. Do not import personal data to make setup faster. For present/absent recording, use an interrupted resumable thread with no active work and type a short draft; emptying draft chooses Resume, retyping returns eligible chip. Confirm actual canResume and upstream eligibility before filming.
2. Settings: light/dark per core, `contextWindowMeterEnabled=true` for C1/C3 and false for C2/C4 (default is false); idle compaction `onReturn` globally and ensure selected Claude instance override is default/onReturn, not off. Keep one model, no held queue, no plan/pending approval/question, no compaction/revert/setup/upload in progress, permission to operate. Selected provider must be available and expose slash command `compact`. Blank draft without Resume is only disabled-send proof, not chip disappearance proof.
3. For synthetic token age, use app-written linked V2 rows as templates. Stop own server, inspect `PRAGMA table_info` for `orchestration_v2_projection_provider_turns` and `orchestration_v2_projection_provider_threads` with `node apps/server/scripts/t3-sqlite-state.ts query --base-dir /tmp/ev-17892 --sql '...'`. Never assume a schema from old examples. Enumerate fixture-only rows, choose current provider thread's latest turn; update its `payload_json.tokenUsage` to `{usedTokens:240000,maxTokens:1000000,promptCacheTtlMs:3600000,updatedAt:<ISO two hours ago>}`. This is valid `OrchestrationV2ProviderTurnTokenUsage`; preserve every other field and relational ID. Update via helper `exec --base-dir /tmp/ev-17892 --file /tmp/pr17892-proof/seed.sql`, one statement per invocation. Do not create an orphan provider turn: app-written thread/node/providerThread/run links matter. Latest tokenUsage wins over providerThread.contextUsage, so modifying only providerThread can be ineffective. Restart and reopen the actual environment/thread route `/<environmentId>/<threadId>` (TanStack `_chat` is pathless). Route values must come from the app, not guesses.
4. Eligibility source: ChatView 2487–2549 requires compactable conversation, server thread/project, available manual compaction provider, idle detail-loaded thread, no held queue/multimodel/dismissal; ContextWindowMeter.logic 64 requires provider `claudeAgent`, >=200000 tokens, age >= promptCacheTtlMs or 70-minute fallback. Full preference is per-thread React state, initially false; click chip to obtain Full, do not persist a guessed setting. Meter-off preserves active usage for eligibility.
5. Long timeline for S1: create multiple harmless synthetic messages/turn items in isolated data (or several app turns) until timeline actually overflows. The predicate in composerFooterLayout requires existing server thread, desktop viewport, scroll-collapse true, no multiline prompt, no expanded chrome. Scroll away from end and verify actual resting DOM/layout. A compact label or small viewport alone is insufficient. Pending inputs/plan drawer, errors, drag/upload and menus force expanded chrome.
6. S2 loading reservation is reachable transient state: started thread, meter enabled, known reporting provider, usage null during detail loading. Navigate from another thread with its real detail response delayed, then release response. Observe actual request before adding delay; do not invent an endpoint. If natural controls cannot hold the state, label an isolated component harness reserved-state illustration; report S2 real-app gap instead of claiming it passed. Real+reserved combination chooses real meter first, so it is not a fourth fixture.
7. S3 create a real proposed plan through provider/app commands, or seed schema-valid plan/run/turn items from app-written examples while stopped. Preserve related IDs; do not infer a complete plan fixture from a single flag. If fresh-home provider cannot supply this within budget, report missing production plan proof. Harness only when a combination is genuinely unreachable, with label and exact props; unavailable credentials do not make a production state unreachable.

Direct projection fixtures are visual-only; leave event log unchanged and do not claim backend behavior. Use live app commands for turn execution, queues, questions and plans where practical. This audit created no driver or seed, only this matrix. The capture agent must upload **every** scratch driver/seed/SQL it creates with `ghdrop upload -m` (redact secrets first), never commit them. Include URLs in final evidence manifest with fixture labels, head, viewport, theme and actual-vs-harness provenance.

## Friction

| Category | Happened | Avoidance |
|---|---|---|
| State safety | Worktree dev runner can auto-seed real data by default; not executed here | Explicit /tmp/ev-17892 plus --no-seed and T3CODE_DEV_SEED=0; never migrate or inspect live userdata |
| Eligibility | A generic high-token thread alone does not show chip; >=200k, Claude, old cache and compaction gates required | Use exact seed/settings checklist; verify gate before core captures |
| Responsive paths | 390 blur can remove footer; pending-answer direct caller intentionally has no Attach | Keep expanded/focused for mandatory core; label collapsed and pending paths separately |
| False equivalence | Compact action-density prop and actual resting layout differ | Verify resting predicate/overflow/scroll state; capture S1 separately |
| Fixture precision | Real tokenUsage overrides providerThread contextUsage; loading placeholder is not loaded-empty meter | Patch latest linked turn template, delay actual detail response for S2 |
| Tooling | One broad rg glob referenced absent apps/web/src/settings*; source was found in contracts/hooks instead | Use rg --files or known paths; no operational impact |
| Proof status | No capture executed in pass 1; provider availability and seed recipe not runtime validated | Treat matrix as actionable plan; report actual gaps, do not certify geometry from source |
| Scope | EVIDENCE.md absent per dispatcher; not searched | Follow supplied operational constraints and this bounded matrix |

Audit used test-t3-app SKILL.md + sqlite-fixtures reference and ghdrop SKILL.md. No code regression claimed or disproved by captures in this pass. Reviewers' no-code-regression conclusions are supplied context, not independent visual verification.
