# Codex model-request hook runtime evidence

This is a manual real-app proof, not a unit-test result. The scenario replay provider uses ACP and cannot exercise the Codex JSON-RPC decoder.

Both commits ran their own real T3 server (`node apps/server/src/bin.ts serve`) and Vite web client (`vp run --filter @t3tools/web dev`) in separate installed worktrees, on Linux with Node v26.12.1 and Chromium 151. The browser viewport was 1440x900, light theme. Published media crops the same left 1120x900 conversation area from both sides, excluding environment details. No content was edited. Final stills were sampled more than 500 ms apart and byte-identical before cropping.

The executable `codex-fixture.mjs` substitutes only for the external Codex process. The production typed client, Codex adapter, orchestrator, persistence, WebSocket connection, and web rendering are unmodified. This checks delivery of controlled provider frames, not actual execution of a user's Codex hooks or a live model request.

## Reproduce on each checkout

Install with `vp i`. Choose a fresh HOME_DIR, an OUTPUT_DIR, and separate free SERVER_PORT and WEB_PORT. These are task-specific paths, not the user's T3 home. Make `codex-fixture.mjs` executable. Write HOME_DIR/userdata/settings.json with:

```json
{"providerInstances":{"codex":{"driver":"codex","enabled":true,"config":{"binaryPath":"ABSOLUTE_PATH_TO/codex-fixture.mjs"}}},"enableProviderUpdateChecks":false}
```

From the checkout:

```sh
T3CODE_DEV_SEED=0 node apps/server/src/bin.ts serve --base-dir HOME_DIR --host 127.0.0.1 --port SERVER_PORT
T3CODE_SINGLE_ORIGIN_DEV=1 T3CODE_PORT=SERVER_PORT PORT=WEB_PORT HOST=127.0.0.1 vp run --filter @t3tools/web dev
```

In another terminal:

```sh
python3 capture-live.py CHECKOUT HOME_DIR OUTPUT_DIR start
```

Pair the browser with this server using its startup token, at the web client's origin. Open the thread in OUTPUT_DIR/thread.json. Collapse the sidebar, use a 1440x900 viewport and light theme. Start a browser recording, then:

```sh
python3 capture-live.py CHECKOUT HOME_DIR OUTPUT_DIR finish
```

The script creates a synthetic git project through the actual CLI and runs three real orchestrated turns. The first sends `preCompact` (control). While recording, the next two send `preModelRequest` and `postModelRequest`. Each prompts the fixture to emit `hook/completed` with a stopped run and a stop entry containing `Checkpoint required before continuing.`, followed by `turn/completed` with status interrupted. Frames use the active native thread and turn ids. The same ordering and fixture run on both commits. The interrupted terminal notification supplies an end-to-end processing barrier; this is not the original in-memory unknown-notification barrier.

Read OUTPUT_DIR/runtime.txt for the real server's persisted `run_interrupt_result.message` values (read-only SQLite query after CLI --wait). Stop recording after the third row is visible. Blur the composer, then confirm two stills more than 500 ms apart are identical. Crop both sides identically if environment details are visible.

Observed base: control reason retained; both model-request reasons replaced by `Stopped by the provider`.
Observed head: all three hook names and stop reasons retained and rendered.

No live Codex login/model, desktop, mobile, or hook/started notification was exercised.
