# Copilot ACP model and effort proof

AI-assisted; verified with the tests and tools listed above.

## Environment

Real web client, separate dev servers and fresh unseeded T3 homes on each commit. Copilot CLI 1.0.109, authenticated using the GitHub CLI token. Chromium viewport 1280×800, device scale 2, dark appearance. Synthetic git project titled “Copilot proof”. No application source changes.

Model A is the default model advertised by Copilot session/new. Model B is the next concrete model in its model option list; both supported reasoning in this run. Their identifiers are discovered at runtime by prepare-proof.py, so no private identifier or private mapping is needed to repeat the setup. Catalog changes may change which concrete models these aliases denote.

copilot-wrapper.py changes only human-readable names and descriptions on ACP output, and redacts its scratch wire log. It leaves protocol IDs, option values, requests, responses, and native usage behavior unchanged. Native usage evidence is extracted separately from Copilot’s own events.jsonl.

## Setup each side

Install @github/copilot@1.0.109 in a private scratch directory. Save the four Python files from this evidence bundle together. Set ROOT to a private scratch root, SIDE to base or head, WORKTREE to that side’s checkout, and COPILOT_BINARY to the installed executable. Do not point WORKTREE at an existing live installation.

```bash
python3 prepare-proof.py "$ROOT" "$SIDE" "$WORKTREE" "$COPILOT_BINARY"
cd "$WORKTREE"
vp i
T3CODE_DEV_SEED=0 vp run dev
```

Create an empty synthetic git repository and add it through `t3 project add --base-dir .t3 --title 'Copilot proof' <directory>`. Create a thread titled “Effort setup” using the Copilot provider and its advertised Model A. Send `Reply with the single word OK.`. In its model picker choose high effort and send the same prompt. This establishes a real existing Model A session.

Set the native stored default to Model B, without changing T3’s default model:

```bash
python3 prepare-proof.py "$ROOT" "$SIDE" "$WORKTREE" "$COPILOT_BINARY" --stored-default
```

In the existing setup thread, select low effort and send the same prompt, await completion, then select high and send it again. Await completion. These actual low→high writes republish high as the provider’s live default; merely viewing an existing thread whose stored selection is high does not republish it.

## Capture the same interaction on both sides

1. Set dark appearance, dismiss the GitHub star prompt, and hide the sidebar and thread details.
2. Use the project breadcrumb to start a new thread. Leave Model A and its inherited high effort untouched. Do not open or change the new thread’s model picker.
3. Type `Reply with the single word OK.`. Both composers show Model A high immediately before sending. Capture the stable before-send state.
4. Record clicking Send through completion. Capture the stable completed state. The new threads’ persisted modelSelection contains only the provider instance and model; there are no explicit effort options.
5. Inspect the ACP request stream and the corresponding Copilot native session. Base sends no configuration writes, runs Model B/medium, and ends showing Model A/medium. Head sends Model A and reasoning_effort=high before session/prompt, runs Model A/high, and retains Model A/high.

The final recordings correspond to base native session 24b447c3-5837-44fe-86ce-9bdb3b8ac2a2 and head native session 10dc915e-4591-4af5-b8e1-bff139a7b493. The uploaded wire and native logs contain only these sessions. Wire exports omit MCP credentials, filesystem paths, unrelated options, and prompt scaffolding; usage exports retain model and effort. observations.json includes the persisted option-free model selections.

## Capture processing

Two stills at least 500 ms apart were pixel-identical before each selected still. Screenshots and videos are scaled from physical 2560×1600 to CSS 1280×800 and cropped identically below the 52 px application header, yielding 1280×748. This excludes unrelated generated titles. No composer or conversation content is masked or replaced. The same prompt, response, theme and framing appear on both sides; only the effort suffix differs in the completed stills. Recordings are trimmed to the first 15 seconds, retaining the pre-send state, send, complete turn, and settled result. Video timing differs because the real provider runs independently.

## Independent fresh-home authentication check

The prepare script was also run against a third empty scratch home. Its dynamically discovered aliases matched those of the app run. After setting its stored default to Model B, `python3 verify-provider.py "$ROOT" head` sent explicit Model A/high and successfully completed a real authenticated prompt. fresh-home-verification.json is that result. This is a reproducibility/authentication check, separate from the two real-app captures.
