* feat(codex): read the account email with app-server usage
The Codex-harness usage snapshot now carries the account identity: the
usage fetch runs account/rateLimits/read and account/read over one
app-server session (new withCodexAppServerJsonClient seam, which the
single-request helper now delegates to), so the email is guaranteed to
belong to the same account as the windows. Identity stays best-effort;
rate limits survive an account read failure.
* style(test): scanner-safe app-server marker fixture
* test(codex): keep scanner-neutral hunks around app-server marker literals
* fix(codex): bound the best-effort account read within the usage deadline
Review P2: account/read shared the outer usage deadline, so a slow or hung
identity read could reject the whole snapshot with a timeout instead of
returning the already-fetched rate-limit windows. Race the account read
against a local timer bounded to min(4s, usageTimeoutMs/3) and drop the
identity on timeout; a regression test hangs account/read and asserts the
windows still return.
* fix(codex): send account/read params and bound identity by the remaining deadline
Second review round: account/read (GetAccount) requires a params object per
the app-server protocol, so send an empty {} (refreshToken defaults false);
without it a real app-server rejects the request. Bound the best-effort
identity read by the time left before the shared usage deadline (minus a
margin) instead of the original budget, so a slow rate-limit read can no
longer let the identity read trip the outer timeout and discard the
already-fetched windows.
* fix(codex): reserve the isolated shutdown budget in the usage deadline
Third review round: withCodexAppServerJsonClient awaits the isolated
client's closeAndWait inside the outer timeout, so a hung account/read
could reach the deadline during force-kill/exit cleanup and discard the
already-fetched windows. The usage read now passes a cheap isolatedShutdown
(force-kill 200ms + exit 300ms) and the identity bound reserves that plus a
250ms margin (750ms) of the remaining deadline, so cleanup always finishes
before the outer timeout.
* style(codex): rename scoped-request generic to avoid shadowing
* feat(codex): scope app-server rate limits to the physical client
Replace the process-global rate-limit cache with a WeakMap keyed by the
physical app-server client, tracking per-limitId revisions. Rolling
account/rateLimits/updated notifications merge sparsely per the protocol
contract (credits/individualLimit/planType survive nulls), and
usage-limit errors only trust a snapshot for auth-profile blocking when
the same client observed a primary update during the failing turn's
startup. Fixes cross-client rate-limit bleed in usage-limit error
messages. A new client-runtime module installs the
account/chatgptAuthTokens/refresh handler and the rate-limit observer
once per physical client, replacing per-start inline handlers in
shared-client, run-attempt, and side-question.
* refactor(codex): split thread/resume subscription safety into thread-resume
Move the thread/resume request out of thread-lifecycle into a dedicated
thread-resume module that retires the exact physical client when resume
acceptance is indeterminate: only a structured RPC rejection proves
Codex holds no subscription, so any other failure abandons the client
instead of returning it to the shared pool. Resume responses naming a
different thread now fail closed (assertCodexThreadResumeSubscription),
and the fresh-thread fallback requires a released subscription unless
the resume was a proven RPC rejection.
* refactor(codex): replace client-factory positional DI with shared-client factory
Delete the lazy positional-argument CodexAppServerClientFactory and use
the options-object factory type exported from shared-client. Callers in
run-attempt, compact, bounded-turn, provider-capabilities, and the
web-search provider now default to getLeasedSharedCodexAppServerClient
directly; the lazy indirection was ineffective because those modules
already import shared-client statically.
* feat(codex): route app-server turn traffic through a keyed turn router
Install one turn router per physical app-server client and replace the
broad per-attempt notification/request fanout with explicit per-thread
routes. Attempt startup reserves the thread route (before thread/resume
on the resume path, so early notifications buffer instead of racing),
run-attempt activates it with receive-time, queued, and request
handlers, arms the route before turn/start, binds the accepted turn id
to flush buffered traffic in wire order, and releases the route on
cleanup. Requests for a pending turn wait for binding instead of being
auto-declined, native turn completion waits use route state instead of
scanning buffered notifications, and correlation readers now match the
canonical v2 wire shapes only (top-level threadId, nested turn.id). The
unscoped response-delta lease-count attribution and its client API are
deleted along with the retired correlation predicates.
* test(codex): reset the shared binding store between thread-lifecycle tests
SQLite bindings are keyed by session identity rather than the per-test
temp dir, so earlier tests leaked resumable threads into fresh-start
expectations. The old silent resume-failure fallback masked the leak;
subscription safety surfaces it.
* test(codex): reset the binding store between delivery-hint iterations
The loop reuses one session identity across iterations, so the previous
iteration's thread would resume against a harness that cannot serve it.
* feat(openai): add GPT-5.6 series support
* docs: refresh map for GPT-5.6
* fix(openai): preserve GPT-5.6 thinking metadata
* fix(codex): sync managed app server version
* fix(codex): sync managed app server version
* fix(openai): account for GPT-5.6 cache writes
---------
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
Restores the Codex/OpenAI usage line in status by routing Codex-harness usage through the Codex app-server provider hook. Preserves configured app-server startup options, selected OpenAI/Codex auth profiles, weekly-window cadence, and Codex credit wording while skipping unsupported API-key usage probes. Fixes#91694.