# Claude nested proxy cooldown: real app comparison

Base: 13f89ae0a7fcecbdcd06ac1551d5ff549bb76926
Head: 1f88524e9df7a08957360652f1aa1105d30e6779

The scenario runner documentation excludes provider-specific usage-limit state. This proof uses the real Claude CLI, adapter, orchestration, and web client, with a deterministic local HTTP proxy. No mock adapter or replay provider is used.

For each side, install dependencies with `vp i`, create a fresh home using the accompanying seed.py, and start proxy.py once. The proxy responds to every POST with HTTP 429 and JSON containing:

    All credentials for model claude-opus-5-5 are cooling down (last error: rate_limit_error (reset after 1h))

It sends no rate-limit headers and no outer pool reset deadline. The synthetic API key is valid only for this stand-in; no provider account is required.

Start each checkout using this command, substituting the generated home and the side's ports:

    T3CODE_DEV_SEED=0 T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD=0 T3CODE_PORT_OFFSET=13028 node scripts/dev-runner.ts dev --home-dir HOME --port 18762 --dev-url http://127.0.0.1:18761 --no-seed -- --host 127.0.0.1

For head use offset 13038, server port 18772, and web port 18771. Keep these commands in tracked terminal sessions and stop them after capturing. Add the synthetic project through the live server:

    node apps/server/src/bin.ts project add PROJECT --title 'Cooldown demo' --base-dir HOME

The seed enables the same setting as Settings -> Threads -> Resume after usage limits. It sets Claude Agent as the provider and claude-opus-5-5 as the model. Each side has its own isolated Claude config and fresh SQLite database. No production database is copied.

Browser driver on both sides (Chromium, Linux, 1280x800 CSS viewport, DPR 2, light theme):

1. Open the side's startup pairing link and complete pairing.
2. Open a new thread in Cooldown demo. The initial base setup also had one earlier CLI-created thread for diagnosis; the captured thread is a new UI-created thread with no history.
3. Hide the thread details and main sidebar using their toolbar buttons before recording, so machine labels are excluded and both captures have the same layout.
4. Start recording. Fill `[contenteditable="true"]` with `Say hi`, then press Enter.
5. Wait for `Usage limit reached`. Both sides display exactly the same API-error message from the real CLI.
6. Base displays `Resumes 11:18 AM`, `Cancel auto-resume`, and `Snooze until reset`. Head displays `Reset time unavailable; retry manually` and has neither scheduled-recovery action.
7. Stop recording after the terminal state is visible. Click blank conversation space to remove focus. Before saving each final still, obtain two screenshots at least 500ms apart and verify their decoded pixels are identical. Inspect final stills and video contact sheets before upload.

The attached observed-state.json extracts only synthetic failure and recovery fields from read-only SQLite connections. Base terminal failure resetAt is one hour after receipt; head resetAt is null and limitRecovery is null. There is no scheduled recovery for the head's unknown deadline.

Native rejected rate_limit_event combinations were not attempted: they require first-party Claude OAuth, unavailable in this environment. No conclusion about those branches is based on these recordings.
