Skip to content

[WRONG BRANCH] release: promote 2.59.0 to main - #5074

Merged
lidge-jun merged 117 commits into
mainfrom
release/2.59.0
Sep 18, 2026
Merged

lidge-jun merged 117 commits into
mainfrom
release/2.59.0

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

Promote the frozen 2.59.0 candidate from dev to main so it can be published. The candidate
is ecd3adae75, which is dev as it stood before the pre-release version move; dev itself has
since gone to 2.60.0 in #5072 so the release gate that requires dev to outrank the published
version is satisfied.

This is 116 first-parent commits against 2.58.0. The bulk is provider and transport
stabilization rather than new surface: send-budget accounting that stops counting a withheld
recovery as a physical send (#5056), configured attempts that subtract sends already spent
(#4925, #4947), admission lifetime separated from response-body inactivity (#4753, #4751),
fresh-connection policy applied at the fetch and dispatch boundary that actually runs (#4977,
#5022), and Antigravity session anchoring corrected to the parent and child pair after the first
attempt anchored on the child alone (#5054, then #5062).

The last change in the candidate is #5070, which closed the two compatibility gaps a release
audit found in this tree: freeform tool-argument streaming read its wrapper grammar differently
from the completion path, so a wrapper written with whitespace streamed as raw JSON and then
completed as the unwrapped body; and the SOCKS5 transport surfaced content-coded bodies
unchanged, so a gzip response reached the caller as bytes its parser could not read.

Verification

No local suite was run. The candidate commit ecd3adae75 has a green push-event Cross-platform
CI run on dev: four Linux shards, both macOS shards, keyring on three platforms, npm-global on
three platforms, gates, structure gate, docker smoke, api usage and storage policy, aggregating
to ci: success.

Two things are recorded rather than hidden. The unsharded macos control lane did not complete
within its 75-minute budget on the preceding tip, and its evidence is on #4997. The sharded
macos 2/2 leg failed twice on this candidate before passing, with a different timing-sensitive
test each time; that is the same class, and the newly observed sharded occurrence is recorded on
#4997 with the unhandled-fixture case split out as #5073. Neither is a failure of the candidate:
the third run passed with no code change, and #5070's own head was green on macOS first time.

A repository integrity check at this commit reports GUI locale parity clean across all nine
locales against 2818 keys in en.ts, and no file over its size-ratchet cap with 37 of 51 entries
sitting exactly at theirs.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

github-actions Bot and others added 30 commits September 18, 2026 02:39
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* docs: remove remote runner access details from historical offload notes

* docs(devlog): scope redaction note to this document and qualify remote gate coverage

Address CodeRabbit review: state that runner details are not recorded in this document rather than asserting they are absent from the public repository, and state that the remote run was limited to the four listed gates instead of implying full prepush coverage.

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…me (#4753)

* fix(server): retain raised body admission through HTTP response lifetime

Reimplement the concurrency protection from luvs01#482 at the admitted HTTP boundary. Keep the reservation through downstream work and response consumption, preserve protocol-specific retryable overload responses, and avoid early release during asynchronous stream cancellation.

Preserve current request-copy accounting and the configured image/search/count_tokens limits. Add 38 isolated lifecycle regressions, a real-server route integration test, and user/architecture documentation.

Validation: 38 Web-stream/reader cases passed under Node v22.16.0 using TypeScript 5.8.3 transpilation of the actual helper and unchanged upstream reader. All four deliberate guard mutations failed. This is not a Bun repository-suite or full-typecheck claim; hosted Bun tests and documentation/structure/privacy checks remain pending.

Co-authored-by: luvs01 <luvs01@hanmail.net>

* refactor(server): move the admitted body call site out of the server facade

* test(server): classify every loopback route for inbound body admission

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…4919)

* fix(web-search): replay executed bridge searches to the destination

The web-search passthrough bridge runs an intercepted web_search proxy-side and
shows the caller a hosted web_search_call cell. The caller replays that cell on
every later turn, so the destination received an item type it never produced,
carrying a query and sources but no result, and usually searched again.

Record each executed search in a process-local memo scoped to the upstream
destination and keyed by the cell id, then restore the destination's own
function_call and function_call_output in the cell's place before the next
turn's first leg is dispatched. The memo stores exactly what a continuation leg
would have sent, so a replayed turn and a continued turn show the destination
one consistent conversation.

A miss leaves the replayed item untouched: no second search is billed and no
result text is invented.

Closes #4587

* docs(devlog): record the lane's closure evidence for #4429 and #3719

Both issue bodies predate the commits that changed the answer, so each claim is
re-judged against the current source with the delivering commit named.
…evidence (#4906) (#4921)

A pool holding Plus and Free Codex accounts keeps sending gpt-5.6-sol and
gpt-6-astra to a Free account and taking the upstream unsupported-model 400,
after a quota refresh and a catalog sync, with no alternate attempt.

The ordering rules #4797 added are present and correct; they just have no
evidence to act on. Both read cachedDeniedCodexAccountIdsForModel, which is
cache-only by contract, and the roster cache it reads expires five minutes
after a catalog sync fills it. Nothing on the flagship request path refills
it, because resolveCodexModelEntitlements is awaited only for
ACCOUNT_GATED_NATIVE_OPENAI_MODELS, which holds Daybreak alone since the
2026-09-04 owner decision. So for most requests the denial set is absent,
withoutModelDeniedAccounts and preferModelEntitledAccount are the identity
function, and the pool selects on quota alone.

The refusal itself was the missing evidence. A 400 whose body is exactly
"The '<model>' model is not supported when using Codex with a ChatGPT
account." is authenticated, account-specific and model-specific. It was spent
on one retry and discarded, so the next request repeated the same selection.

It is now recorded per account and model in a bounded six-hour store and
unioned into cachedDeniedCodexAccountIdsForModel. It stays evidence rather
than a gate: consumers treat it exactly like a roster denial, so
restore-on-empty and the pin exemption still hold, no model is hidden from any
catalog, and nothing is refused before dispatch. A confirmed roster grant for
the same pair outranks it, a successful response clears it, and a credential
identity change discards it. Availability is never inferred from a plan name
or from remaining quota.

Detection now reads the model upstream actually named instead of rebuilding
the sentence from route.modelId. applyCodexAccountGatedWireNormalization
rewrites Daybreak to gpt-5.6-sol before dispatch, so upstream names Sol while
the route still says Daybreak; the comparison never matched, which silently
disabled both the alternate-account retry and the eight-rung same-account
ladder that exists for exactly that model.
* fix(devin): forward the selected model's input ceiling

Resolve the exact account/model UID's input ceiling and preserve smaller
configured hints instead of silently serializing the 128k default. Keep
output limits, entitlement preflight and unknown-window fallback unchanged.
Add cached-catalog-to-wire regression cases and a scoped review record.

Validation: 48 isolated Node/TypeScript checks passed; the original adapter
reproduced 128000 against a 262000 expectation. Full Bun tests, repository
typecheck and live Devin inference were not run in this environment.

* docs(structure): cross-link the Devin input-ceiling review in the adapter owner

* fix(devin): reuse the turn's single catalog read in the chat preflight

getCachedCatalog returns null without caching when fetchCatalog fails, so each same-turn caller retried the request: resolveWireModelUid, the runTurn preflight read, and the streamChatEvents preflight could each pay the catalog fetch timeout before a valid turn started.

runTurn now performs the one catalog read and threads the result through resolveWireModelUid (new optional parameter; the test seam still falls back to its own lookup) and streamChatEvents (new optional CloudChatRequest.catalog field). An explicit null is passed through deliberately so a failed lookup is not retried inside the turn; the null fallback and the 499 abort handling are unchanged, and cancellation during the read is now abort-responsive.

Regression: devin-prompt-cache asserts exactly one metadata request per turn when the catalog endpoint fails.

* docs(structure): clarify the no-evidence wire-field fallback

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…dation (#4723)

* fix(providers): admit canonical Antigravity fake-IP on config writes

* test(routing): cover Antigravity config-write fake-IP scope

* test(routing): keep Antigravity negative cases literal

Co-authored-by: cubebox <58514883+juzijia@users.noreply.github.com>

---------

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
Five opencode-go ids (qwen3.8-max, qwen3.8-flash, deepseek-v4.1-flash, glm-5.3-flash, muse-spark-1.3-contributor) have no jawcode bundle row and no vendor-level fallback, so the Usage estimated-cost column and per-model breakdown rendered an em dash for every request through them. Add exact provider/model expected-price overlays reusing each vendor published list price as a verified-derived estimate (Go itself is subscription-billed).

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…get (#4903) (#4927)

A combo target whose gateway cannot serve response_format ends the chain
instead of trying the target behind it. comboFailureDecision reaches the
generic invalid_request_error stop, because isRequestLocalTargetIncompatibility
refuses at its first guard: the gateway reports invalid_parameter_error, which
is not in the generic code set, and none of its three accepted shapes describes
a response_format refusal.

A second blocker explains the reported text. The gateway answers inside a
single SSE frame, so normalizeUpstreamErrorText cannot parse it, the raw
data: {...} survives as the classification text, and the structured code
arrives undefined.

Neither obvious option was taken. Hopping on every 400 replays a genuinely
malformed request at every remaining target, and dropping response_format
changes the output contract the caller asked for. The verdict is narrowed to a
capability claim: the message must name response_format and say it is
unavailable or unsupported, so an invalid-schema complaint stays terminal.

The envelope keeps the existing discipline: HTTP 400, intact provider JSON,
type invalid_request_error, a three-envelope depth budget and a 16,384
character bound. Its code set is the shared generic one plus
invalid_parameter_error, held separately so the user and image branches are not
widened. One data: prefix is unwrapped, and only on a single-line body, so a
multi-event body still fails closed.

The next target receives the same request with response_format intact.
Traversal stays finite because combo excludes each attempted target, and the
verdict records no cooldown because a capability gap says the target is healthy.
)

* docs(devlog): plan the Lane B provider-reliability round

* fix(cursor): seed Muse Spark 1.3 so live discovery can surface it

Cursor live discovery filters the configured roster instead of unioning live ids into it, so a family with no capability base stays invisible no matter what GetUsableModels returns. Six advertised muse-spark-1.3 effort variants therefore produced no Cursor row (#4820).

Seed the capability base and its ladder. The ladder stops at xhigh although the roster also advertises muse-spark-1.3-max: Meta publishes no max rung for Muse Spark and an independent probe rejected it, both already recorded on META_MUSE_REASONING_EFFORTS, so publishing it would invent a capability against two sources. A request at max clamps to xhigh.
…odels (#4913)

Claude Code CLI (v2.1.200+) injects an internal billing header
(`x-anthropic-billing-header: cc_version=...`) as the first line of its
system prompt. Cloud Code Assist / Google Antigravity inspects
`systemInstruction` and rejects requests containing this header with
HTTP 429 RESOURCE_EXHAUSTED.

Strip `x-anthropic-billing-header:` at the start of Cloud Code Assist
system prompt while preserving non-leading occurrences, leading
whitespace, all other instructions, and non-CCA requests.

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
#4929)

* fix(cursor): stop grok-4.6 tool-result echo from poisoning later turns

Grok-4.6 through Cursor often writes a real sentence and then pastes the replayed
[Tool Result] envelope. The prefix sniffer only watches the opening bytes of a turn, so the
echo reaches Codex, is stored as assistant text, and the next turn replays it — which primes
the model to echo again.

Strip whole-line echo envelopes from assistant root replay, remint the conversation for the
next turn after a mid-stream echo on its own bounded allowance, prefer the retained thread
remint override over a stale stored conversation id, and name Write as an unavailable
neighboring-agent tool.

The current send is never retried: the echo has already reached the client, and resending
would be an uncertain replay. Conversations already poisoned still need a new task.

Carries the work in #4900 onto current dev. That branch holds a pre-squash copy of #4875,
which landed as ee28833 with review hardening the copy
predates, so dev's version is authoritative for every shared file and only the increment is
reapplied here.

Co-authored-by: MerryEcho <xx59623633@163.com>

* test(cursor): prove the echo strip is reached from root replay

The unit test covers the filter; this covers the wiring. It also pins the bounded-strip behaviour end to end: the prose before AND after the echoed envelope survives into rootPromptMessagesJson while the envelope body does not.

Placed in cursor-tool-continuation.test.ts because cursor-blob.test.ts sits exactly at its file-size-ratchet cap of 3657 lines and cannot take another line.

* test(cursor): include Write in the neighboring-agent guidance assertions

Adding Write to NEIGHBOR_AGENT_TOOL_NAMES changes the generated guidance note, and these three assertions pin that note verbatim. Line-neutral replacements; no assertion is weakened and the negative cases still hold.

* fix(cursor): keep a compaction turn off the parent thread override

Preferring the retained thread override over a stored _cursorConversationId is right for a stale
id from a second Responses chain, but a compaction turn also carries a thread owner and its own
conversation id while never setting the isolate flag. Unconditionally preferring the override
pulled compaction onto the parent conversation, which
"compaction storage isolation preserves the stable thread override without relying on the isolate
flag" in cursor-adapter.test.ts exists to prevent.

Exclude compaction from the override lookup and pin the interaction with its own case.

* test(cursor): exercise the echo strip through a real tool continuation

Root replay only carries history on a tool-continuation turn, so the previous shape sent a plain
user message and produced a system-only root prompt: the assertions could never have seen the
assistant text they were checking. Give the turn a tool result so the assistant message is
actually replayed.

It also now asserts the GENUINE replayed envelope survives. The strip must remove the copy the
model pasted into its own text without touching the tool-result envelope the adapter builds.

---------

Co-authored-by: MerryEcho <xx59623633@163.com>
…ly (#4676)

* feat(oauth): rank Antigravity failover by Gemini vs Claude quota family

Co-authored-by: chilung <b0423031@gmail.com>

* fix(responses): restore non-replayable replay-refusal guards dropped in rebase

The quota-family rebase lost upstream isNonReplayableResponse guards and wire-scoped enforceDeclaredToolNames in the 429 recovery arms (CodeRabbit Major on PR #4676). A replay-refused 429 must never enter same-target retry, key rotation, or OAuth failover. No behavior change besides the restored guards.

---------

Co-authored-by: chilung <b0423031@gmail.com>
Co-authored-by: jun <bitkyc08@gmail.com>
Add Cache-Control headers when serving static files from the GUI distribution:
- Content-hashed bundles under 'assets/' receive 'public, max-age=31536000, immutable'
  so browsers can cache bundles without redundant re-downloads over slow
  networks and SSH tunnels.
- Unhashed files under 'assets/' (e.g. runtime-config.js) and other static files
  receive 'no-cache' so updates are picked up promptly.
- 'index.html' continues to be served with 'no-store' to guarantee immediate
  bootstrap and script hash updates.

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…#4805)

* fix(gajae): export working loopback credentials without an env prerequisite

* docs(clients): record Gajae loopback credential ownership

* fix(gajae): address keyless export review findings

* docs(gajae): translate loopback credential table entries

* docs(gajae): clarify Traditional Chinese placeholder wording

---------

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
* fix(streams): cancel response bytes before an aborted read

* fix(oauth): bound OrcaRouter key-exchange responses

* docs(structure): record bounded OrcaRouter login contract

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…ead (#4935)

* fix(codex): key pool affinity on the conversation cohort, not the thread (#4780)

Upstream keys its prompt cache on something the whole tree shares.
prompt_cache_key is responses_metadata.session_id, or {source}:{parent_thread_id}
for an internal session, and one AgentControl whose session_id is the root
thread id is shared with every sub-agent spawned from that root. The upstream
suite asserts root and child carrying different thread ids while sending the
same promptCacheKey, and openai/codex#44862 went further on 2026-09-11 by
making an ephemeral fork inherit its parent's session id.

While the proxy keyed per thread, a tree could split across pool accounts while
every member kept sending one cache key. The split member asserted a warm
prefix that was deterministically cold on its account, so the prompt was
replayed in full. Nothing failed; only tokens burned, which is why no log line
reports it.

The binding unit is now the cohort. A request carrying session-id resolves to
HMAC(session, session) and every root, child and grandchild of that tree lands
on it. Without a session the cohort is read from the parent's lineage record,
falling back to HMAC(parent, parent) when this scope has not seen that parent,
which is the same key that parent derives for itself, so a chain of parent-only
turns converges instead of splitting at every depth. Which requests bind at all
is unchanged.

This is not a revert of #4546 wp8. wp8 fixed a child binding under the RAW
parent id, an identity unrelated to the root's own binding, so siblings shared
an entry the root was not on and a grandchild landed on a key nobody had bound.
A cohort key cannot produce that incoherence, because the root's own binding IS
the cohort key. The orphan property is pinned as a regression rather than left
as an argument. What wp8 additionally gave each thread, a binding of its own, is
what this deliberately gives up.

The cost is explicit: a tree gains cache locality and loses per-thread placement
independence. All members share one binding, so a fan-out cannot spread across
accounts and an exhausted account moves the whole tree. First placement is
largely subsumed and its hook is now gated on the parent's key actually
differing from the request's own.

* fix(codex): repair cohort-keying fixtures that assumed per-thread keys

Three CI failures, all in test fixtures rather than in the derivation.

The bounded-table test varied only the thread id under one session, so every
record landed under a single cohort key and the eviction probe read the newest
record back through the oldest key. Each index now gets its own session, so the
record cap and the scope cap are probed as before.

The preview test asserted that an eligible preview leaves no lineage record,
probing through the child's key. That key is now the root's, and the root was
recorded earlier in the same test, so the probe answered from the root's entry
rather than from anything the preview wrote. It now probes a cohort nothing has
recorded, which restores the original meaning.

A comment rewrite pushed tests/codex-integration/codex-auth-context.test.ts one
line past its file-size cap. The comment is shortened rather than the cap
raised, since updateBaseline only lowers caps.
…#4593)

* fix(audio): bind stored direct account identity

* fix(auth): clear caller account header on async Direct substitution

* test(auth): cover Direct identity on both Responses endpoints

* docs: link stored Direct identity from all source owners

* refactor: split changed contracts to respect the file-size ratchet

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(auth): cover synchronous stored Direct identity isolation

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
* fix(config): track recovery backups without suppressing recovery

* fix(config): track the OAuth recovery backup without suppressing recovery

Splits out the half of this change that could not ship. The
src/oauth/store.ts hunk is unchanged: backupLegacyOnce registers the
auth.json.pre-multiauth copy it just created, and a registration failure warns
and leaves the copy intact, so recovery wins and registration is best-effort.

What is removed is the matching registration in src/config/salvage.ts.
backupInvalidConfig mints a timestamp-unique path on every invalid-config load,
and recordOwnedConfigPath appends without a bound, deduping only on an identical
string that a timestamped name never is. isManifest rejects a manifest whose
paths exceed MANIFEST_MAX_PATHS (1024) at read time, so past that threshold
loadOwnership returns null permanently: createOwnership will not replace it
because the directory is not empty, and nothing self-heals.

The consequence inverts this change's own goal. removeOwnedConfigState then
takes its refusal branch, "config ownership metadata is missing or invalid", so
uninstall stops deleting auth.json and config.json and leaves refresh tokens and
API keys on disk. A service restarting against a persistently broken
config.json reaches that, one manifest slot and one backup file per load.
backupLegacyOnce does not have the problem because it is guarded once-only and
registers a fixed name, which is also true of every pre-existing caller;
salvage.ts would have been the first unbounded one.

The two salvage-specific tests are removed with it, and structure/config.md now
records why invalid-config copies are not registered, plus the shape that would
work: sweep them by name pattern at removal time, so ownership stays a
fixed-size manifest and cleanup stays complete. That is a separate change.

bun test tests/config/config-ownership-uninstall.test.ts
tests/oauth/oauth-store-multi.test.ts: 51 pass / 0 fail.
bun run structure:check: pass.

Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

* fix(oauth): warn when recovery backup registration is refused

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: JUN <bitkyc08@gmail.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
* fix: pin Union Alpha wire and namespace Go sessions

* fix(tests): correct the Claude-metadata Go session vectors

The Claude metadata lane is not the hashed metadata.user_id. claude-messages.ts turns
prompt_cache_key into a UUID through uuidFromHex and normalizes THAT, so the lane is
sha256(uuidFromHex(sha256(user_id)[:32]))[:32]. The three metadata vectors were computed without
that step.

Derived independently of the production helpers and validated against the unchanged v1 values
these tests carried before the namespace change: the same reconstruction reproduces both of the
previous metadata vectors exactly, which is what shows the lane is right rather than merely
self-consistent. The other eight vectors were already correct and are untouched.

* fix(tests): use the per-model session vectors the loop already supplies

The loop lists CHAT_SESSION_VECTORS for glm-5.2 and RESPONSES_SESSION_VECTORS for the Muse model
but destructured only [model, url], so every case in it read whichever sessionVectors binding was
in scope instead of its own. Muse settles on the Responses wire, and these vectors are now
protocol-scoped, so each model needs the table the loop names for it.
…4523)

* fix(config): validate provider send paths before management writes

* refactor: split changed contracts to respect the file-size ratchet

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(config): isolate provider send-path validation from schema initialization

Move the shared shape validator into an import-free config leaf and retain the schema export. The management boundary no longer enters config initialization through the schema before the facade can initialize its dependencies.

A fresh-process regression fails with the runtimeRoleSchema TDZ before this fix. The management, import and layout checks pass: 155 tests, 1649 assertions. Typecheck, structure, privacy and file-size checks pass. Full hosted CI remains a separate publication gate.

* docs(providers): add the missing chatCompletionsPath row to localized tables

Every localized provider table documented responsesPath but not chatCompletionsPath, although each page's nearby prose already names both keys. Add the row to all seven locales (fr, ja, ko, ru, tr, zh-cn, zh-tw) in each document's own language and table style, matching the English relative-path contract.

* docs(providers): document merged-path validation on provider PATCH

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…failures (#4594)

* fix(gui): keep failed reauth cancellation retryable

* fix(gui): settle failed reauth cancellation responses

* docs: link reauth cancellation from GUI source owners

* fix(gui): announce reauth cancellation failures

* fix(gui): release expired main reauth flows

* fix(gui): fence device reauth responses across flows

* fix(gui): retain polling after retryable cancellation

* fix(gui): retain cancel retry across polling HTTP races

* fix(gui): keep cancellation available before DELETE settles

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(gui): make reauth ownership explicit to React Doctor

Capture the accepted flow identity as a const for polling and queued state updaters. Keep intentional API error-body reads at three narrowly documented React Doctor exception sites; HTTP status and flow ownership still gate all successful outcomes.

Add POST, GET and DELETE regressions where non-2xx responses contain success-shaped JSON. Focused GUI validation passes 40 tests and 461 assertions, lint, TypeScript and production build. React Doctor 0.9.11 against the exact CI base goes from one compiler error plus three response-body warnings to a complete clean scan with those three local exceptions. Structure, privacy and file-size checks pass.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(gui): add the reauth cancellation screenshot for review

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <bitkyc08@gmail.com>
…rough lane (#4925)

* fix(responses): honor the provider transient-5xx policy on the passthrough lane (#4893)

A provider's transientRetryOn5xx never reached the Responses passthrough
lane. Configuring it on a key-auth provider whose adapter is openai-responses
changed nothing in either direction, while the same provider on openai-chat
honored it.

Two things had to change together. transientRetryPolicyFor rejected every
adapter but openai-chat, and the lane never called it: core.ts returns into
executePassthroughResponse on the adapter's passthrough flag before the three
call sites that read the policy are constructed, and passthrough-dispatch.ts
passed the constant TRANSIENT_RETRY_MAX_ATTEMPTS at four dispatch sites and
asked sendBudgetExhausted at that same constant twice more. Widening the gate
alone leaves the reproduction at three sends, which is why PR 4800 is carried
here rather than merged on its own.

The ladder now resolves from the provider row at every leg: the initial send,
the OAuth-401 replay, the same-target 429 replay, and the validated rebuild.
sendBudgetExhausted takes the cap as a parameter so it asks at the same value
the sends use, defaulted so every other caller is unchanged.

The configured value is a cap on the ladder, intersected with the request-wide
base allowance by remainingBaseSends. Configuring below that allowance narrows
the ladder exactly, so attempts 1 sends once. Configuring above it does not
raise the bound that exists to stop per-request amplification. authMode stays
fail-closed, so the ChatGPT forward pool still gets a null policy and keeps the
ladder it has always had, and isNonReplayableResponse is unaffected by attempts
so a higher value cannot obtain a resend that marker forbids.

Co-authored-by: Yum-wu <118118663+Yum-wu@users.noreply.github.com>

* fix(responses): measure a configured transient ladder against the request total

remainingBaseSends(cap) bounds what REMAINS, not what a request may spend in
total. That is the right reading for the fixed constant, but
transientRetryOn5xx.attempts is documented as the total sends for one request
including the first, so passing the configured value straight through turned it
into a per-leg ceiling: a provider configured at one send could still reach
upstream again on a recovery leg.

transientSendCapFor reduces the configured total by what the request has
already sent before it is intersected with the base allowance. An absent policy
returns the constant unchanged, so a provider that configures nothing is
unaffected at every call site.

Caught by the regression added in the previous commit, which asserted the
intended contract rather than the implemented one.

Co-authored-by: Yum-wu <118118663+Yum-wu@users.noreply.github.com>

---------

Co-authored-by: Yum-wu <118118663+Yum-wu@users.noreply.github.com>
Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
* feat(usage): show API list-price in breakdowns

* fix(usage): distinguish unpriced estimates

* docs(usage): clarify list-price coverage fields

* fix(usage): keep unavailable list prices explicit

* fix(usage): omit empty exclusion captions

* fix(usage): make exclusion captions count-neutral

* fix(usage): pluralize excluded request caption

* fix(usage): clarify French exclusion caption

* docs(usage): qualify exclusion counts for older proxies

Co-authored-by: HarryZhou <2373256746@qq.com>

---------

Co-authored-by: lidge-jun <bitkyc08@gmail.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
…4958)

* fix(catalog): explain a suppressed Luna Reserve row in the sync log

The Luna Reserve projection is account-qualified, so it cannot be written
without a selector that targets the main Codex account. A fresh authless
install has an empty codexAccountNamespaces map, so no selector exists, the
projection returns undefined, and the operator gets no row and no reason.

An omission has no row to carry an explanation, so catalog sync now emits one
warn-once line naming the cause and the action that restores it, in the same
place and the same shape as the account-gated native suppression warning.

Scoped to an install where authless Codex Desktop routing is effective: a
default install wants no Reserve row and is never told about one.

Also documents codexAccountPickerEnabled and codexAccountNamespaces, which
were absent from the configuration reference entirely.

* fix(catalog): keep the reserve warning off the catalog facade

The facade re-export pushed src/codex/catalog/sync.ts from 52 to 58 lines,
past its file-size ratchet cap in tests/fixtures/file-size-baseline.json.
The ratchet only moves downward by design, so the cap cannot be raised.

The re-export was never load-bearing: retained-sync.ts imports the warning
directly from ./reserve-warn, and the reserve tests already import the
projection helpers from ./reserve rather than through the facade.
A connected client runs the machine listener, which binds the same address a
standalone proxy would (port ?? config.port ?? 10100) and identifies as
opencodex on /healthz. CLI liveness parsed that body but discarded its
role: "client" discriminator, so every management-backed ocx subcommand on such
a machine resolved a base URL for a listener that serves only /api/machine/*
and died on its opaque JSON 404
({"error":"not_found","method":"PUT","path":"/api/custom-models/<id>"}) — one
character away from the management handler's own unknown-id {"error":"not found"}.

Carry the role through liveness and refuse it where a management plane is
actually required:

- proxy-liveness.ts parses role into HealthzIdentity and carries it on
  LiveProxy. isOpencodexHealthz still accepts a client-role body, because stop
  and orphan cleanup must keep finding that process.
- runtimeBaseUrl refuses a client-role listener with RuntimeApiError 503 (exit
  1, not the misleading exit 4) and names the port, the machine-only route set,
  the hub, and the on-machine alternative.
- responseMessage renders a 404 carrying method and path as the route the
  listener does not serve.
- ocx models edit narrows a genuine handler 404 to name the id and
  ocx models list-custom.

Closes #4662
…alling back to 128k (#4962)

* fix(catalog): publish OpenCode Go context windows for live-only ids

OpenCode Go's /v1/models returns id/object/created/owned_by and no context
field, so a live-discovered row reaches the catalog with no contextWindow and
no contextCap. applyCatalogMetadata is the only writer that can still supply a
window on that path; it reads the generated registry keyed by provider and
model id and returns early when the table has no row. Nine served ids were
missing, so ensureStrictCatalogFields stamped its 128000 routed default and
1M-class models silently advertised 128k while chained clients compacted at
roughly 121k.

Refresh the vendored snapshot with the eight ids models.dev publishes for this
provider and regenerate the committed table. Capability fields only: the new
records carry no cost block, so every pricing path resolves exactly as before.

Closes #4944

* fix(catalog): complete the OpenCode Go context-window snapshot refresh

Adds the remaining ids models.dev publishes for this provider that the vendored
snapshot still lacked: glm-5.3-flash (1,000,000), muse-spark-1.2-contributor
(1,048,576) and ox-alpha-free (1,000,000). Same record shape as the first pass,
with the same deliberate omissions: no cost block, so every pricing path in
resolveMatchedPriceExact resolves exactly as before, and no thinking block.

deepseek-v4.1-flash and deepseek-v4-flash-vision-exp are deliberately left out.
models.dev publishes 1,000,000 for both, but entries-core.ts already declares
1_048_576 for each on this provider, citing DeepSeek's official Codex setup
script and calling the 1,000,000 figure a rounded approximation. The registry
hint wins wherever it applies, so copying the lower number in would fix nothing
and would lower the window on any row that receives no provider hints. A test
now pins that as an invariant rather than as an absence: these ids may be added
later, but only carrying a window at least as large as the registry promises.
lidge-jun and others added 22 commits September 18, 2026 17:07
…#5040)

Issue #5035 reopens #4903 against deepseek/deepseek-v4-pro. The reported build is 2.58.0, which was tagged two hours before #4927 landed, so the capability classifier is in no published release. On dev the reported envelope already hops, in every form the pipeline produces.

This vendor spells its code invalid_request_error rather than invalid_parameter_error, at both the outer and the inner level. That is the code the generic terminal list stops on, so the ordering inside comboFailureDecision is load-bearing here in a way the first gateway never exercised. Pin it, and keep a malformed-schema complaint terminal.
A `workflow_dispatch` against `dev` landed in the same concurrency group as
the `push` runs on `dev`, because the group was keyed on `github.ref` alone
and `cancel-in-progress` was unconditionally true. The next merge therefore
cancelled the dispatch. Run 35318264610 was cancelled in the same second its
job started, three minutes after it was queued.

The lane this hurt is `macos control`, the longest job in the workflow at
roughly fifty minutes, so on a branch under active development the odds that
no merge landed inside its window were close to zero. A maintainer
dispatching it for release evidence usually got nothing back and had no
reason to notice, because a cancelled job reports neither pass nor fail.
Those cancellations were read as runner capacity for months; raising the
budget from 30 to 75 minutes in #5028 did not change them.

Supersession is still what `push` and `pull_request` want, so they keep it.
A dispatch is keyed on `github.run_id` instead, which is unique per run, so
each dispatch is a group of one: it cancels nothing and nothing cancels it,
including a second dispatch of the same ref.

Closes #5037.
…failover (#4926)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
* test(ci): warm a spawned child's module graph before it is timed

Eighteen files spawn a real Bun child and bound it with INTERNAL_DEADLINE_MS,
so the first child of a module graph is measured with its cold load inside the
assertion. Pay that load once in setup instead, through a shared helper.

Refs #4956 (cold-start class only).

* test(ci): survive a shebang and a module that will not settle

Run 35318878762 failed shards test 2/4 and windows 8/9 identically: the scan
prepends module context, which moved src/cli/index.ts's shebang to line 2 and
died with a syntax error before warming anything. Strip it first.

The warm-up child also keeps its own budget now, so one module that never
settles at import cannot consume the whole warm-up.
* fix(service): bind service start to the installed environment

* test(service): return service.test.ts to its size cap and keep the start guard

The branch added five lines to `tests/service/service.test.ts`, which sits at
its committed cap of 4106 in `tests/fixtures/file-size-baseline.json`, so the
file-size ratchet failed the run. Caps only move down, so the fix is to move
the new assertion rather than to raise the cap.

The start-case ordering check now lives in a sibling,
`tests/service/service-start-environment.test.ts`, and asserts the same
property plus one more: the guard is imported, so a local stub of the same
name cannot satisfy it.

This also restores three lines the branch had reindented from four spaces to
three. They are the `repair`/`restart` assertions and were unrelated to the
change.

Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: JUN <bitkyc08@gmail.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
…pable on CommandCode (#5039)

Move the id from COMMAND_CODE_TEXT_ONLY_MODELS to COMMAND_CODE_IMAGE_MODELS.
The gateway route was unverified when #4505 classified it text-only; the
upstream probe that issue asked for is now run end to end:

- A 3x3 random-color grid (180x180 PNG, six candidate colors) delivered as a
  user-message image and as a tool_result image both came back 9/9 correct
  (~1e-7 by guessing), with no vision-sidecar call in either request window.
- Both requests: HTTP 200, adapter command-code, on an existing 2.58.0 install.

Update the pinned regression tests for the new classification; opencode-go's
route keeps its text-only declaration (no probe evidence) and the text-only
mechanism stays in place for the next route that measures text-only.

Co-authored-by: xinzhihong-ship-it <254184831+xinzhihong-ship-it@users.noreply.github.com>
…tations (#4994)

* fix(client): fence loopback-bootstrapped GUI sessions from machine mutations

A connected-client listener mints GUI sessions to any loopback caller, and the bootstrap hands out the session token, browser origin, and CSRF value together. Any local process can replay those values and pass the Origin/CSRF checks, so the credentialless session authorized durable machine mutations (sync, shim install/uninstall, disconnect plus scheduled recycle). Treat the bootstrapped session as proof of possession rather than user presence: keep status and diagnostic GET reads working but refuse non-GET/HEAD calls under /api/machine/* with 403. Machine changes remain available through the explicit CLI commands, which invoke the same operations directly rather than over the listener.

* fix(client): route HEAD and unsupported methods through the machine policy

---------

Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
A pull request touching only `structure/` ran no test or gate leg at all, so
`tests/ci-workflows/structure-ssot.test.ts` never executed — and that test is
the only place CI runs `bun run structure:check`. The aggregate `ci` check
reported success over a change nothing had read.

The cause is the `changes` job's `ci` path filter, which does not list
`structure/**`. On #4999, a pure doc split, every expensive leg reported
`skipped`: windows, macos, macos control, test 1/4 through 4/4, gates,
npm-global, docker smoke, keyring, api usage, storage policy and docs site
build.

This adds a `structure` filter and a narrow `structure gate` job that runs the
check alone, rather than adding `structure/**` to `ci`. Widening `ci` would
also close the hole, and would start nine Windows shards and two macOS shards
for a check that takes seconds — the cost this workflow's own comments argue
against for `docs-site`.

The gate is pull-request scope, like `docs-site-build`, because the push
trigger's `paths:` is pinned to mirror the `ci` filter exactly. That costs
nothing: `dev`, `main` and `preview` are protected to require a pull request.

Closes #5001.
…tions (#5042)

* fix(local): fail closed DNS bind names for credential-bearing destinations

probeHostname returns a DNS bind name unchanged, and the credential-bearing destination composers (localInferenceDestination, localManagementOrigin, resolveApiAccessBaseUrl) then embed that name in a URL the client dials with credentials attached. A hostname that re-resolves at dial time is a DNS-rebinding exfiltration path: the credential leaves for whatever the name resolves to then, not what it resolved to at compose time.

localCredentialDestinationHostname keeps literal IPs as-is and fails closed to 127.0.0.1 for DNS names, so credential-bearing destinations only ever target a literal address. Display-only hosts keep the resolved name. Tests pin the fail-closed behavior for inference, management-origin, and API-access base URLs, plus the literal non-loopback IP path.

* fix(local): keep localhost out of the DNS fail-closed branch

The fail-closed branch treated every non-literal bind name as a DNS bind,
including `localhost`, and rewrote it to 127.0.0.1. That failed
`ocx claude management discovery destination > a loopback or wildcard install
keeps asking 127.0.0.1 on the public port`, which pins that a `localhost`
install keeps writing `http://localhost:<port>` into its exported client
configuration.

The rewrite also bought nothing. RFC 6761 reserves `localhost` to loopback, so
a second lookup cannot select a peer off this machine — the only outcome the
fail-closed branch exists to prevent. `isLoopbackHostname` is already the
encoding of "this name is loopback" in this module, so the carve-out reuses it
rather than growing a second list.

Also rebased onto current `dev`.

Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: JUN <bitkyc08@gmail.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
)

`resolveCodeModeHelperName` decides a code-mode `exec` body is an apply-patch
call by reading `unwrapFreeformToolInput` under the wire tool name, which
strips an outer Markdown fence and accepts that name's fallback fields (#4983).
Compilation kept a narrower unwrap that saw only `input` and `patch`, so a body
accepted through a fence or through a field like `content` reached
`tools.apply_patch` still wrapped. The host then rejected the JSON text or the
fence instead of applying the patch.

Both halves now read one canonical body, produced by one unwrap under the name
the body actually arrived on. That name is not always the helper: the
name-based path arrives as `apply_patch`, whose fallback fields are `patch` and
`content`, while the body-based path arrives as `exec`, whose fields are the
code-carrying ones. `{"patch": ...}` is meaningful for the first and is
correctly refused by the second, so reading it under `exec` would compile a
body recognition had declined.

Closes #5046.
…n principal (#4928)

* fix(responses): scope compact handoff cache to authenticated admission principal

The compactHandoffRoutes map is process-global but was keyed only by the caller-supplied lane header, so any two admitted clients sending the same lane header shared one fallback route. Namespace the lane by the admitted principal (contextPrincipalId when minted, configured key id or environment kind otherwise); loopback and missing admissions have no authenticated identity and are ineligible rather than trusted.

* fix(responses): fail closed when an admission mints no context principal

compactHandoffRouteKey substituted "configured:" plus the key id, or the
constant "environment", when contextPrincipalIdOf returned nothing. Both
substitutes reintroduce the collision the key exists to prevent: a key id
survives rotation, so a replaced secret inherited the previous holder's
route, and every identity-less environment admission shared one bucket.
Production admission always mints a principal for configured and
environment holders, so refusing the cache without one costs no real
caller anything.

The new test file was also missing from both test-layout registries, which
tests/test-layout-tooling.test.ts asserts independently. Register it, and
replace the different-key intruder with a same-key-id rotation so the case
the old fallback collapsed is the one under test.

* test(responses): include the minted principal in the routed-handoff admission fixture

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
…n 429 failover (#4954)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…5041)

* fix(devin): wait out a stated rate-limit reset and replay the turn

Cognition free-tier caps answer resource_exhausted trailers that name their own recovery delay ("Your limit will reset in 35 seconds"). The delay was never parsed: clients got the synthetic 2s Retry-After and combo cooldowns fell back to the 60s default, so a retry fired straight back into the live cap and the turn died inside a window it could have waited out.

parseRetryAfterFromMessage now reads "reset in N <unit>" phrasing plus minute/hour units on the existing hints, so the stated delay drives the client Retry-After and the cooldown metadata. streamChatEventsWithResetRetry waits the stated delay and replays the identical request, but only while the stream has yielded zero events — after any output a replay could double billable side effects, so those failures keep their terminal path. Waits are bounded by a replay cap and a per-wait ceiling; longer stated windows surface with the parsed delay intact.

* fix(devin): bound cumulative reset waits and preserve server cooldowns

Parse complete and compound retry durations without treating milliseconds as minutes. Keep the errors.ts local parser binding as well as its public export.

Bound scheduled waits cumulatively within a stated-reset wrapper invocation; preserve explicit refusal errors, cancellation, zero-wait opt-out and the no-output replay boundary. Store explicit Retry-After cooldowns without truncating them to the local ten-minute fallback.

Add regression coverage for parser integration, cumulative waits, abort races, post-output refusals and authoritative numeric/HTTP-date cooldowns.

Validation in this environment: 90 offline core checks; 43 proposed regression cases executed via a Node/TypeScript module harness with external routing/state/RPC dependencies stubbed; strict typecheck of errors.ts and retry-delay.ts. Full Bun/repository typecheck and live Devin validation remain pending. Long-lived SSE/preflight and cross-layer send/wait budgeting are not implemented by this commit.

* test(layout): register the new Devin and combo reset test files

`tests/test-layout-tooling.test.ts` failed its membership oracle: three of the
new test files resolve through neither the explicit map nor a regex seed, so
nothing placed them. `combo-authoritative-reset.test.ts` collides with the
`combo-` seeds, which point at `routing`, and the `devin-stated-reset-*` pair
has no seed at all.

Registered in both `scripts/test-layout/layout.json` and
`tests/fixtures/test-layout-expected.json`, which the oracle compares against
each other as well as against the tree.

Also rebased onto current `dev`.

Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: JUN <bitkyc08@gmail.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
…5053)

#4983 widened what counts as a freeform wrapper at completion. Partial input
streaming still knew only the compact `{"input":"` form, so a wrapper such as
`{"code":"const x = 1"}` streamed as raw JSON through
`response.custom_tool_call_input.delta` and then finished with the unwrapped
body. Concatenated deltas no longer equalled the authoritative input, and a
client that renders or accumulates tool input mid-stream had to rewind.

`input` stays progressive: `unwrapFreeformToolInput` returns it whenever the
key is present, whatever else the object carries, so its value is decidable
from the prefix and can never be retracted.

A fallback key is not decidable that way. It unwraps only when it is the single
string field, and a second key can still arrive, so a value emitted early would
have to be taken back. Those buffers are held until the object closes and then
published once. The routed passthrough in `responses-custom-tool-repair.ts`
already holds any object prefix for the same reason.

The streaming side also drops the tool name for a namespaced tool that does not
own the apply-patch grammar, because `repairFreeformToolInput` drops it at
completion; streaming under a vocabulary the completed item does not use is the
same disagreement in the other direction.

Closes #5047.
)

`antigravitySessionId` anchored on `_clientThreadId`, which carries
`x-codex-parent-thread-id`. Every parallel child of one parent presents the
same parent id, so concurrent Codex children collapsed onto a single upstream
Cloud Code Assist session instead of getting one each.

`codexConversationIdentity` already keys on parent AND thread for exactly this
reason: a thread id is only unique within its parent. This surface needs the
narrower half, so the anchor now prefers the request's own `thread-id` and
falls back to the parent id for clients that send only that.

Deliberately not the general lane key. `codexConversationKeyFor` is an HMAC
under a process-random secret, so it changes across a proxy restart — and
instability, not sharing, is the failure mode this derivation must avoid,
because the replay cache observes thought signatures on turn N and re-injects
them on turn N+1. `thread-id` is Codex's own value and survives compaction and
restart alike.

A root turn presents `thread-id` equal to its parent id, so its anchor is
byte-identical to what it was. Only a child's anchor moves, and it moves once.

Closes #5033.
* fix(quota): make the account-switch warning agree with routing

The manual account-switch warning could report an exhausted account as usable
while the router refused it. Three boundaries diverged, each locally plausible:

The dashboard compared a stored reset against `Date.now()` without normalizing
units. Both Unix seconds and milliseconds reach storage, and read as
milliseconds a seconds-form instant lands in 1970, so every future reset looked
elapsed there and live in routing.

The dashboard accepted a fresh observation even when an elapsed reset was
present. Routing treats a reset as authoritative once it exists and uses
freshness only for a reading that has none.

`providerQuotaFromCodexQuota` dropped `shortObservedAt`, and the Free/Go
projection dropped the whole burst window. Routing counts that window on every
plan, so a Free/Go account could be refused upstream while the dashboard had
neither a governing window nor terminal evidence and returned no opinion.

`isTerminalShortWindow` and `resetAtToMs` now live on `src/codex/quota-types`,
the dependency-free leaf the dashboard already imports, and both sides call the
same function instead of keeping two copies of the rule.

Closes #5045.

* fix(quota): import the shared resetAtToMs, not only re-export it

`export { resetAtToMs } from "./quota-types"` re-exports the binding without
introducing the name into this module's scope, and two call sites here use it.
Import it and re-export the local binding instead.

* fix(quota): keep the Free/Go carve-out on the server DTO

The burst-window carve-out for 30-day plans belongs to the server DTO, not to
the GUI normalizer — `tests/gui/rate-limit-reset-credits.test.ts` says so in
the #1791 case it pins, and `normalizeQuotaForPlan` is not on the
account-switch warning's path at all: the modal scores `confirm.quota`
directly.

So the projection fix stays where it belongs, in
`providerQuotaFromCodexQuota`, and the parity test now exercises that DTO
instead of the GUI normalizer.
…4751)

* fix(responses): bound pending body reads without premature shared abort

Reimplement the combined response-body inactivity scope from luvs01#176 and luvs01#339 on current dev. Guard direct native bodies after classification and scope initial/continuation adapter parsers. Preserve native SSE ownership, backpressure, terminal ordering, and nonblocking cancellation cleanup.

Add 29 regression cases and document the body-lifetime contract. Node behavior/component/HTTP checks passed; repository Bun, typecheck, full-suite and policy gates remain unrun in this environment. Keep upstream submission in draft.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(responses): keep the lease-owner structural check on the wrapped return

* fix(responses): classify body stalls before signal state and yield on discarded empty chunks

* fix(responses): map the initial stream body stall to a 504 upstream error

A ResponseBodyInactivityError thrown by the guarded initial stream reached the bridge catch and surfaced as a 500 proxy_error. Wrap the initial stream so the stall yields the same 504 upstream_error terminal the continuation and buffered paths already emit, and cover the direct passthrough guard with a plain successful body case.

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
When the send budget refused a retry or an account-rotation hop, the runtime
returned the upstream response it already had and recorded nothing. A log with
one physical send was therefore ambiguous: it could mean no recovery was
eligible, or that one was and the budget withheld it. Those need opposite
follow-ups, and only the first was visible.

`recoveryWithheld` is a bounded per-attempt vocabulary recorded beside
`recoveryKinds` and separately from `sendCount`. Nothing was sent, so the count
that means "requests this proxy actually made" does not move. The four states
the issue asks to distinguish fall out of the pair: neither field set means
nothing was eligible, a withheld reason means something was and the budget
refused, and a recovery kind means one was dispatched.

Recorded at the four places that previously fell through silently: the Google
retry ladder when it holds a retryable response, and the generic OAuth rotation
in the run-turn, passthrough and adapter-continuation loops.

The adapter seam is `onRecoveryWithheld`, a sibling of the existing
`onPhysicalSend` rather than a new argument to it, so an adapter cannot report
a refusal as a send.

Closes #5044.
…5057)

The Anthropic surface published `usage.input_tokens: 0` on `message_start`
whenever the upstream had not reported usage before the first content frame.
Third-party clients read the prompt size there — Paseo's context meter takes
input from that frame and output from `message_delta` — so a turn whose own
`/context` reported ~97k rendered as a nearly-empty ring.

#4891 fixed the destinations that report usage up front. The internal bridge
attaches `usage: null` to its lifecycle frames, so those paths had nothing to
publish and kept sending zero.

`responsesSseToAnthropicSse` now accepts an input-token floor: the count this
proxy made of the prompt it forwarded, published only when no confirmed
upstream usage arrived first. `claude-messages.ts` supplies it from
`estimateClaudeRequestTokens`, the same estimate the usage log already trusts
as a floor, computed at most once per request and shared with the log path.

This narrows a recorded decision rather than ignoring it. The pinned case said
zero is the honest placeholder and an estimate must not replace it. Zero is not
honest about a prompt that exists — it asserts an empty one — and the Anthropic
schema makes the field required, so the choice is between a false measurement
and a real one of the request side. The second half of that decision stands:
the first content frame is still never delayed to await usage, and
`message_delta` remains authoritative.

Closes #4857.
)

#5054 fixed same-parent sibling sharing by anchoring on the request's own
thread id, and got two things wrong.

A thread id is only unique WITHIN its parent, so keying on the child alone
relocated the collision rather than removing it: two parents can each have a
child of the same id. The anchor is now the pair, joined by a NUL so the
encoding is injective.

And a parentless root does not present `thread-id` equal to its parent, which
is what #5054 claimed. `src/server/context-history.ts` says the opposite in as
many words: root model requests use (session-id=root, thread-id=root) and do
not fabricate a parent key. So #5054 moved every root's anchor on upgrade, and
durable Antigravity replay state is keyed by model plus session id, which
strands the signatures stored under the old root session. A parentless root now
keeps the pre-#5054 anchor.

Parent-only clients are unchanged in both revisions.

Closes #5058.
…d decode SOCKS5 content-codings (#5070)

* fix(transport): match freeform streaming to its completion grammar and decode SOCKS5 content-codings

The bridge decided whether a freeform argument buffer was a wrapper by comparing it with the compact literals {"input":" and {"code":", while the completion path reads the same text with JSON.parse. A wrapper written with spaces or newlines matched no prefix, so it streamed as raw JSON and then completed as the unwrapped body - the disagreement #5047 closed for compact wrappers, reached through a different spelling. The same applies to a Markdown-fenced body, which stripMarkdownCodeFence removes at completion for exec and apply_patch.

socks5Fetch assembles the response from a raw socket, so new Response(body, headers) surfaced a coded body unchanged: .json() threw SyntaxError on the gzip magic number. The request now asks for identity unless the caller chose otherwise, gzip and deflate are decoded, and any other coding is refused by name.

The keep-alive socket-close tests asserted that close propagation is observable within a fixed 50ms, which failed in the unsharded control lane and passed everywhere else; they now wait for the state the contract promises under a bounded deadline.

* fix(transport): correct the streaming JSON escape set, hold undecidable prefixes, and keep bodyless SOCKS5 responses out of the decoder

Typecheck: DecompressionStream declares its writable side as WritableStream<BufferSource>, which TypeScript measures as invariant, so the pair needed an explicit conversion to reach pipeThrough.

Review findings: the streaming decoder mapped every unlisted escape to its own suffix, so a valid backslash-b streamed as the letter b; an escape JSON does not define now stops the preview because such a wrapper never parses and completion returns the raw text. A lone high surrogate is held until its pair arrives. A decorated apply_patch envelope is held because normalizeApplyPatchDelimiters rewrites it at completion. A bodyless response no longer has its content-encoding decoded or refused, and the deflate fixture now states zlib framing through node:zlib rather than relying on a runtime default.

* test(bridge): pin what a wrapper that turns invalid mid-stream is allowed to do

A valid prefix is already published when an undefined escape arrives, and no mechanism takes a delta back. The guarantee is that nothing further is invented: the preview stops at the last decodable character and the completed item carries the raw text. Holding the whole wrapper instead would mean never streaming a canonical wrapper progressively, which the neighbouring test requires.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 18, 2026 16:25
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-18T16:26:20.912345Z ecd3ada PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 586 files, which is 286 over the limit of 300.

To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: b6d00e1b-fa3a-41d5-8254-0f12b2cc20fa

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe4cd0 and ecd3ada.

⛔ Files ignored due to path filters (8)
  • .github/pr-assets/4823-opper-provider-catalog.png is excluded by !**/*.png
  • .github/pr-assets/4823-opper-provider-note.png is excluded by !**/*.png
  • .github/pr-assets/fast-rows-setting-toggle.png is excluded by !**/*.png
  • assets/pr-screenshots/main-reauth-cancel-retryable.png is excluded by !**/*.png
  • docs/pr-assets/usage-api-list-price.png is excluded by !**/*.png
  • gui/public/provider-icons/crusoe.svg is excluded by !**/*.svg
  • gui/public/provider-icons/opper.svg is excluded by !**/*.svg
  • src/generated/model-metadata.ts is excluded by !**/generated/**
📒 Files selected for processing (586)
  • .dockerignore
  • .github/workflows/ci.yml
  • AGENTS.md
  • Dockerfile
  • README.md
  • compose.yaml
  • devlog/_fin/260731_pr_merge_round/022_remote_test_offload.md
  • devlog/_fin/260908_openai_chat_compat/000_implementation_report.md
  • devlog/_plan/260914_cost_guard_stabilization/100_dev_tip_closure_assessment.md
  • devlog/_plan/260914_cost_guard_stabilization/110_spend_ceiling_configuration.md
  • devlog/_plan/260917_devin_input_ceiling/000_review.md
  • devlog/_plan/260918_2580_release_train/040_release.md
  • devlog/_plan/260918_lane_a_bug_train/010_roadmap.md
  • devlog/_plan/260918_lane_a_bug_train/030_transient_passthrough_policy.md
  • devlog/_plan/260918_lane_a_bug_train/040_combo_response_format.md
  • devlog/_plan/260918_lane_a_bug_train/041_combo_response_format_second_vendor.md
  • devlog/_plan/260918_lane_a_bug_train/050_cohort_pool_affinity.md
  • devlog/_plan/260918_lane_b_provider_reliability/000_roadmap.md
  • devlog/_plan/260918_lane_i_catalog_visibility/010_lane_record.md
  • devlog/_plan/260918_ld_search_bridge_and_thinking_replay/010_roadmap.md
  • devlog/_plan/260918_ld_search_bridge_and_thinking_replay/020_closure_evidence.md
  • docker/verify-compatibility.ts
  • docs-site/src/content/docs/fr/getting-started/installation.md
  • docs-site/src/content/docs/fr/getting-started/quickstart.md
  • docs-site/src/content/docs/fr/guides/claude-code.md
  • docs-site/src/content/docs/fr/guides/codex-integration.md
  • docs-site/src/content/docs/fr/guides/codex-prompt.md
  • docs-site/src/content/docs/fr/guides/integrations.md
  • docs-site/src/content/docs/fr/guides/providers.md
  • docs-site/src/content/docs/fr/guides/remote-hub.md
  • docs-site/src/content/docs/fr/guides/web-dashboard.md
  • docs-site/src/content/docs/fr/reference/cli.md
  • docs-site/src/content/docs/fr/reference/cli/agents.md
  • docs-site/src/content/docs/fr/reference/cli/lifecycle.md
  • docs-site/src/content/docs/fr/reference/configuration/providers.md
  • docs-site/src/content/docs/fr/reference/configuration/server.md
  • docs-site/src/content/docs/getting-started/installation.md
  • docs-site/src/content/docs/getting-started/quickstart.md
  • docs-site/src/content/docs/guides/claude-code.md
  • docs-site/src/content/docs/guides/codex-app-models.md
  • docs-site/src/content/docs/guides/codex-integration.md
  • docs-site/src/content/docs/guides/codex-prompt.md
  • docs-site/src/content/docs/guides/integrations.md
  • docs-site/src/content/docs/guides/native-main-profiles.md
  • docs-site/src/content/docs/guides/providers.md
  • docs-site/src/content/docs/guides/remote-hub.md
  • docs-site/src/content/docs/guides/web-dashboard.md
  • docs-site/src/content/docs/ja/getting-started/installation.md
  • docs-site/src/content/docs/ja/getting-started/quickstart.md
  • docs-site/src/content/docs/ja/guides/claude-code.md
  • docs-site/src/content/docs/ja/guides/codex-integration.md
  • docs-site/src/content/docs/ja/guides/codex-prompt.md
  • docs-site/src/content/docs/ja/guides/providers.md
  • docs-site/src/content/docs/ja/guides/remote-hub.md
  • docs-site/src/content/docs/ja/guides/web-dashboard.md
  • docs-site/src/content/docs/ja/reference/cli.md
  • docs-site/src/content/docs/ja/reference/cli/agents.md
  • docs-site/src/content/docs/ja/reference/cli/lifecycle.md
  • docs-site/src/content/docs/ja/reference/configuration/providers.md
  • docs-site/src/content/docs/ja/reference/configuration/server.md
  • docs-site/src/content/docs/ko/getting-started/installation.md
  • docs-site/src/content/docs/ko/getting-started/quickstart.md
  • docs-site/src/content/docs/ko/guides/claude-code.md
  • docs-site/src/content/docs/ko/guides/codex-integration.md
  • docs-site/src/content/docs/ko/guides/codex-prompt.md
  • docs-site/src/content/docs/ko/guides/providers.md
  • docs-site/src/content/docs/ko/guides/remote-hub.md
  • docs-site/src/content/docs/ko/guides/web-dashboard.md
  • docs-site/src/content/docs/ko/reference/cli.md
  • docs-site/src/content/docs/ko/reference/cli/agents.md
  • docs-site/src/content/docs/ko/reference/cli/lifecycle.md
  • docs-site/src/content/docs/ko/reference/configuration/providers.md
  • docs-site/src/content/docs/ko/reference/configuration/server.md
  • docs-site/src/content/docs/reference/cli.md
  • docs-site/src/content/docs/reference/cli/agents.md
  • docs-site/src/content/docs/reference/cli/lifecycle.md
  • docs-site/src/content/docs/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/reference/configuration.md
  • docs-site/src/content/docs/reference/configuration/providers.md
  • docs-site/src/content/docs/reference/configuration/server.md
  • docs-site/src/content/docs/reference/inbound-body-admission.md
  • docs-site/src/content/docs/ru/getting-started/installation.md
  • docs-site/src/content/docs/ru/getting-started/quickstart.md
  • docs-site/src/content/docs/ru/guides/claude-code.md
  • docs-site/src/content/docs/ru/guides/codex-integration.md
  • docs-site/src/content/docs/ru/guides/codex-prompt.md
  • docs-site/src/content/docs/ru/guides/providers.md
  • docs-site/src/content/docs/ru/guides/remote-hub.md
  • docs-site/src/content/docs/ru/guides/web-dashboard.md
  • docs-site/src/content/docs/ru/reference/cli.md
  • docs-site/src/content/docs/ru/reference/cli/agents.md
  • docs-site/src/content/docs/ru/reference/cli/lifecycle.md
  • docs-site/src/content/docs/ru/reference/configuration/providers.md
  • docs-site/src/content/docs/ru/reference/configuration/server.md
  • docs-site/src/content/docs/tr/getting-started/installation.md
  • docs-site/src/content/docs/tr/getting-started/quickstart.md
  • docs-site/src/content/docs/tr/guides/claude-code.md
  • docs-site/src/content/docs/tr/guides/codex-integration.md
  • docs-site/src/content/docs/tr/guides/codex-prompt.md
  • docs-site/src/content/docs/tr/guides/integrations.md
  • docs-site/src/content/docs/tr/guides/providers.md
  • docs-site/src/content/docs/tr/guides/remote-hub.md
  • docs-site/src/content/docs/tr/guides/web-dashboard.md
  • docs-site/src/content/docs/tr/reference/cli.md
  • docs-site/src/content/docs/tr/reference/cli/agents.md
  • docs-site/src/content/docs/tr/reference/cli/lifecycle.md
  • docs-site/src/content/docs/tr/reference/configuration/providers.md
  • docs-site/src/content/docs/tr/reference/configuration/server.md
  • docs-site/src/content/docs/zh-cn/getting-started/installation.md
  • docs-site/src/content/docs/zh-cn/getting-started/quickstart.md
  • docs-site/src/content/docs/zh-cn/guides/claude-code.md
  • docs-site/src/content/docs/zh-cn/guides/codex-integration.md
  • docs-site/src/content/docs/zh-cn/guides/codex-prompt.md
  • docs-site/src/content/docs/zh-cn/guides/providers.md
  • docs-site/src/content/docs/zh-cn/guides/remote-hub.md
  • docs-site/src/content/docs/zh-cn/guides/web-dashboard.md
  • docs-site/src/content/docs/zh-cn/reference/cli.md
  • docs-site/src/content/docs/zh-cn/reference/cli/agents.md
  • docs-site/src/content/docs/zh-cn/reference/cli/lifecycle.md
  • docs-site/src/content/docs/zh-cn/reference/configuration/providers.md
  • docs-site/src/content/docs/zh-cn/reference/configuration/server.md
  • docs-site/src/content/docs/zh-tw/getting-started/installation.md
  • docs-site/src/content/docs/zh-tw/getting-started/quickstart.md
  • docs-site/src/content/docs/zh-tw/guides/claude-code.md
  • docs-site/src/content/docs/zh-tw/guides/codex-integration.md
  • docs-site/src/content/docs/zh-tw/guides/codex-prompt.md
  • docs-site/src/content/docs/zh-tw/guides/integrations.md
  • docs-site/src/content/docs/zh-tw/guides/providers.md
  • docs-site/src/content/docs/zh-tw/guides/remote-hub.md
  • docs-site/src/content/docs/zh-tw/guides/web-dashboard.md
  • docs-site/src/content/docs/zh-tw/reference/cli.md
  • docs-site/src/content/docs/zh-tw/reference/cli/agents.md
  • docs-site/src/content/docs/zh-tw/reference/cli/lifecycle.md
  • docs-site/src/content/docs/zh-tw/reference/configuration/providers.md
  • docs-site/src/content/docs/zh-tw/reference/configuration/server.md
  • gui/.react-doctor-ignores.md
  • gui/public/provider-icons/README.md
  • gui/src/App.tsx
  • gui/src/api-targets.ts
  • gui/src/codex-quota-utils.ts
  • gui/src/components/AccountPoolStrategyControls.tsx
  • gui/src/components/CodexAccountPool.tsx
  • gui/src/components/CodexPoolStrategySetting.tsx
  • gui/src/components/FastRowsSetting.tsx
  • gui/src/components/ModelCatalogSettingsPanels.tsx
  • gui/src/components/NativeMainProfiles.tsx
  • gui/src/components/QuotaBars.tsx
  • gui/src/components/apikeys-workspace/ClientConfigDialog.tsx
  • gui/src/components/codex-account-pool-main-card.tsx
  • gui/src/components/codex-account-switch-modal.tsx
  • gui/src/components/login-url-block.tsx
  • gui/src/components/native-main-profiles-view.tsx
  • gui/src/components/provider-workspace/ProviderCapacityQuota.tsx
  • gui/src/components/use-main-device-reauth.ts
  • gui/src/hooks/useCodexAccountPool.ts
  • gui/src/i18n/catalogs.ts
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/fr.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/lab-translations.ts
  • gui/src/i18n/log-guard-labels.ts
  • gui/src/i18n/log-guard-operation-labels.ts
  • gui/src/i18n/log-guard-state-labels.ts
  • gui/src/i18n/native-main-copy.ts
  • gui/src/i18n/native-main-translations.ts
  • gui/src/i18n/routing-compatibility-labels.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/shared.ts
  • gui/src/i18n/tr.ts
  • gui/src/i18n/vi.ts
  • gui/src/i18n/vision-reasoning-labels.ts
  • gui/src/i18n/zh-TW.ts
  • gui/src/i18n/zh.ts
  • gui/src/main.tsx
  • gui/src/native-main-profile-session.ts
  • gui/src/native-main-profiles.ts
  • gui/src/own-record-value.ts
  • gui/src/pages/Models.tsx
  • gui/src/pages/Usage.tsx
  • gui/src/pages/models-catalog-state.tsx
  • gui/src/provider-icons.ts
  • gui/src/status-codes.ts
  • gui/src/styles-codex-set.css
  • gui/src/styles/fast-rows-setting.css
  • gui/tests/account-pool-strategy.test.tsx
  • gui/tests/api-targets.test.ts
  • gui/tests/client-config-panel.test.tsx
  • gui/tests/codex-account-pool-behaviour.test.tsx
  • gui/tests/fast-rows-setting.test.tsx
  • gui/tests/fixtures/native-main-profiles.webp
  • gui/tests/i18n-locales.test.ts
  • gui/tests/login-url-block.test.tsx
  • gui/tests/logs-cost-plain-dollar.test.ts
  • gui/tests/main-device-reauth-ownership.test.tsx
  • gui/tests/main-device-reauth.test.tsx
  • gui/tests/models-empty-provider.test.tsx
  • gui/tests/models-status-toast.test.tsx
  • gui/tests/native-main-profile-session.test.ts
  • gui/tests/native-main-profiles.test.ts
  • gui/tests/native-main-translations.test.ts
  • gui/tests/subagent-surface-warning.test.tsx
  • gui/tests/usage-layout.test.ts
  • package.json
  • readme/README.fr.md
  • readme/README.ja.md
  • readme/README.ko.md
  • readme/README.ru.md
  • readme/README.tr.md
  • readme/README.zh-CN.md
  • readme/README.zh-TW.md
  • readme/i18n-manifest.json
  • scripts/ci/docker-smoke.ts
  • scripts/file-size-ratchet.ts
  • scripts/generate-compatibility-version.ts
  • scripts/model-metadata.source.json
  • scripts/privacy-scan.ts
  • scripts/test-layout/layout.json
  • skills/ocx/references/01_management_surface.md
  • src/adapters/base.ts
  • src/adapters/cursor.ts
  • src/adapters/cursor/catalog.ts
  • src/adapters/cursor/effort-map.ts
  • src/adapters/cursor/envelope-echo.ts
  • src/adapters/cursor/message-mapper.ts
  • src/adapters/cursor/protobuf-request.ts
  • src/adapters/cursor/request-builder.ts
  • src/adapters/cursor/thread-continuity.ts
  • src/adapters/cursor/tool-guidance.ts
  • src/adapters/devin.ts
  • src/adapters/devin/cloud-direct/chat.ts
  • src/adapters/devin/cloud-direct/index.ts
  • src/adapters/devin/cloud-direct/stated-reset-retry.ts
  • src/adapters/google-antigravity-wire.ts
  • src/adapters/google-http.ts
  • src/adapters/google.ts
  • src/adapters/openai-chat.ts
  • src/adapters/openai-chat/response-events.ts
  • src/adapters/openai-responses/passthrough.ts
  • src/adapters/openai-responses/tool-output-recovery.ts
  • src/adapters/openai-responses/tool-schema.ts
  • src/adapters/responses-tool-schema.ts
  • src/adapters/run-turn-queue.ts
  • src/bridge/response-json.ts
  • src/bridge/sse.ts
  • src/claude/context-windows.ts
  • src/claude/outbound.ts
  • src/cli/account-api.ts
  • src/cli/account-extended.ts
  • src/cli/account-orca-import.ts
  • src/cli/account.ts
  • src/cli/capabilities.ts
  • src/cli/claude.ts
  • src/cli/codex-cli-update.ts
  • src/cli/dispatch.ts
  • src/cli/doctor.ts
  • src/cli/help.ts
  • src/cli/index.ts
  • src/cli/models-runtime.ts
  • src/cli/registry.ts
  • src/cli/runtime-api.ts
  • src/cli/start-args.ts
  • src/cli/system-command.ts
  • src/client/machine-api.ts
  • src/client/machine-listener.ts
  • src/clients/config-export.ts
  • src/clients/config-export/constants.ts
  • src/codex/account-store.ts
  • src/codex/auth-api/pool-quota-probe.ts
  • src/codex/auth-api/routes.ts
  • src/codex/auth-context.ts
  • src/codex/catalog/build-entries.ts
  • src/codex/catalog/derive-entry.ts
  • src/codex/catalog/effort.ts
  • src/codex/catalog/gather-capture.ts
  • src/codex/catalog/model-hints.ts
  • src/codex/catalog/parsing.ts
  • src/codex/catalog/reserve-warn.ts
  • src/codex/catalog/retained-sync.ts
  • src/codex/catalog/routed-gather.ts
  • src/codex/cli-installation-identity.ts
  • src/codex/cli-installation-targets.ts
  • src/codex/convergence.ts
  • src/codex/history-provider.ts
  • src/codex/history-state-open.ts
  • src/codex/inject.ts
  • src/codex/inject/config-toml.ts
  • src/codex/lineage.ts
  • src/codex/loopback-target.ts
  • src/codex/main-account-hard-lock.ts
  • src/codex/main-account.ts
  • src/codex/main-device-reauth.ts
  • src/codex/model-entitlements.ts
  • src/codex/observed-model-denials.ts
  • src/codex/orca-auth-source.ts
  • src/codex/orca-import.ts
  • src/codex/prompt-text-probe.ts
  • src/codex/quota-401-recovery.ts
  • src/codex/quota-types.ts
  • src/codex/quota.ts
  • src/codex/routing.ts
  • src/codex/routing/cooldown-math.ts
  • src/codex/routing/pin-drain.ts
  • src/codex/subagent-model-fallback.ts
  • src/codex/windows-installation-files.ts
  • src/combos/failover.ts
  • src/config/diagnostics.ts
  • src/config/load-degrade.ts
  • src/config/pending-teardown.ts
  • src/config/process-state.ts
  • src/config/provider-relative-send-path.ts
  • src/config/proxy-env.ts
  • src/config/schema/config-schema.ts
  • src/config/schema/leaf-validators.ts
  • src/lib/bounded-body.ts
  • src/lib/destination-policy.ts
  • src/lib/errors.ts
  • src/lib/local-destinations.ts
  • src/lib/provider-outbound.ts
  • src/lib/proxy-env.ts
  • src/lib/request-execution-budget.ts
  • src/lib/response-body-inactivity.ts
  • src/lib/retry-delay.ts
  • src/lib/socks5-fetch.ts
  • src/lib/spend-reservation-ledger.ts
  • src/lib/workflow-budget.ts
  • src/oauth/account-quota-rank.ts
  • src/oauth/generic-account-failover.ts
  • src/oauth/orcarouter.ts
  • src/oauth/store.ts
  • src/providers/codex-capacity.ts
  • src/providers/devin-provider-merge-migration.ts
  • src/providers/free-directory.ts
  • src/providers/key-failover.ts
  • src/providers/model-rename-migration.ts
  • src/providers/openai-sidecar.ts
  • src/providers/opencode-go-transport.ts
  • src/providers/quota/report-cache.ts
  • src/providers/registry/entries-extended.ts
  • src/providers/registry/model-seeds.ts
  • src/responses/apply-patch-envelope.ts
  • src/responses/bridge-search-replay-cache.ts
  • src/responses/code-mode-helper-compat.ts
  • src/responses/custom-tool-compat.ts
  • src/responses/hosted-tool-policy.ts
  • src/responses/schema.ts
  • src/server/auth-cors.ts
  • src/server/chat-completions.ts
  • src/server/chat-native-sse.ts
  • src/server/chat-native.ts
  • src/server/claude-messages.ts
  • src/server/gui-static.ts
  • src/server/inbound-body-admission.ts
  • src/server/index.ts
  • src/server/management/api-access.ts
  • src/server/management/config-routes.ts
  • src/server/management/provider-capability-config.ts
  • src/server/management/provider-routes.ts
  • src/server/proxy-liveness.ts
  • src/server/relay.ts
  • src/server/request-log.ts
  • src/server/responses-custom-tool-repair.ts
  • src/server/responses/adapter-continuation.ts
  • src/server/responses/adapter-delivery.ts
  • src/server/responses/adapter-dispatch.ts
  • src/server/responses/compact.ts
  • src/server/responses/core-codex-account.ts
  • src/server/responses/core-normalize.ts
  • src/server/responses/fetch-helpers.ts
  • src/server/responses/passthrough-delivery.ts
  • src/server/responses/passthrough-dispatch.ts
  • src/server/responses/passthrough-execution.ts
  • src/server/responses/request-prepare.ts
  • src/server/responses/request-send-budget.ts
  • src/server/responses/request-sidecar-auth.ts
  • src/server/responses/request-spend.ts
  • src/server/responses/request-transport.ts
  • src/server/responses/run-turn-execution.ts
  • src/server/responses/sidecar-execution.ts
  • src/server/responses/ws-upstream.ts
  • src/server/sse-frame-buffer.ts
  • src/server/sse-payload-rewrite.ts
  • src/server/system-env-shell.ts
  • src/server/system-env.ts
  • src/server/workflow-refusal.ts
  • src/service/cli.ts
  • src/service/guards.ts
  • src/service/health.ts
  • src/service/state.ts
  • src/types/accounts.ts
  • src/types/config.ts
  • src/types/provider.ts
  • src/types/request.ts
  • src/types/wire.ts
  • src/usage/expected-prices.ts
  • src/usage/log.ts
  • src/web-search/passthrough-bridge.ts
  • structure/INDEX.md
  • structure/adapters/registry.md
  • structure/catalog.md
  • structure/clients/claude-desktop.md
  • structure/clients/integrations.md
  • structure/codex-home.md
  • structure/config.md
  • structure/data-planes/images.md
  • structure/data-planes/inbound-compat.md
  • structure/data-planes/search.md
  • structure/design-methodology.md
  • structure/gui-and-management-api.md
  • structure/manifest.json
  • structure/ops/docs-and-release.md
  • structure/ops/service-and-sidecars.md
  • structure/overview.md
  • structure/providers-and-adapters.md
  • structure/providers/chat-compat.md
  • structure/providers/cursor.md
  • structure/providers/kiro.md
  • structure/providers/openai-tiers.md
  • structure/providers/xai-grok.md
  • structure/runtime.md
  • structure/subagents.md
  • structure/transports/byte-accounting.md
  • structure/transports/inventory.md
  • structure/transports/responses.md
  • structure/transports/streaming-health.md
  • tests/adapters/bridge.test.ts
  • tests/adapters/google/google-adapter.test.ts
  • tests/adapters/google/google-antigravity-wire.test.ts
  • tests/adapters/google/google-vertex-http.test.ts
  • tests/adapters/key-failover.test.ts
  • tests/adapters/openai/openai-chat-hardening.test.ts
  • tests/adapters/run-turn-queue.test.ts
  • tests/ci-workflows/ci-concurrency-groups.test.ts
  • tests/ci-workflows/ci-structure-gate.test.ts
  • tests/ci-workflows/ci-workflows.test.ts
  • tests/ci-workflows/cold-spawn-warmup.test.ts
  • tests/ci-workflows/file-size-ratchet.test.ts
  • tests/ci-workflows/privacy-scan-ssh-endpoint.test.ts
  • tests/ci-workflows/test-runner.test.ts
  • tests/claude-integration/claude-cli.test.ts
  • tests/claude-integration/claude-outbound.test.ts
  • tests/cli/cli-account-orca-import.test.ts
  • tests/cli/cli-account-pin-drain.test.ts
  • tests/cli/cli-codex-cli-update.test.ts
  • tests/cli/cli-connect-readiness.test.ts
  • tests/cli/cli-dispatch.test.ts
  • tests/cli/cli-dto-fidelity.test.ts
  • tests/cli/cli-headless-parity.test.ts
  • tests/cli/cli-help.test.ts
  • tests/cli/cli-models.test.ts
  • tests/cli/cli-ready.test.ts
  • tests/cli/cli-status-json.test.ts
  • tests/cli/cli-transport-honesty.test.ts
  • tests/cli/start-args.test.ts
  • tests/clients/client-connect.test.ts
  • tests/clients/client-machine-listener.test.ts
  • tests/clients/integrations-writer.test.ts
  • tests/codex-integration/catalog-free-pricing-status.test.ts
  • tests/codex-integration/catalog-opencode-go-context-window.test.ts
  • tests/codex-integration/codex-auth-context.test.ts
  • tests/codex-integration/codex-catalog-ladders.test.ts
  • tests/codex-integration/codex-cli-installation-identity.test.ts
  • tests/codex-integration/codex-cli-installation-targets.test.ts
  • tests/codex-integration/codex-cli-update-zero-effect.test.ts
  • tests/codex-integration/codex-cli-windows-installation-files.test.ts
  • tests/codex-integration/codex-history-lock.test.ts
  • tests/codex-integration/codex-history-provider.test.ts
  • tests/codex-integration/codex-history-worker.test.ts
  • tests/codex-integration/codex-inject-integration.test.ts
  • tests/codex-integration/codex-inject.test.ts
  • tests/codex-integration/codex-lineage-placement.test.ts
  • tests/codex-integration/codex-model-denial-evidence.test.ts
  • tests/codex-integration/codex-pin-drain-projection.test.ts
  • tests/codex-integration/codex-prompt-text-probe.test.ts
  • tests/codex-integration/codex-retained-root-serialization.test.ts
  • tests/codex-integration/codex-v2-gate.test.ts
  • tests/codex-integration/codex-write-lock.test.ts
  • tests/codex-integration/combo-authoritative-reset.test.ts
  • tests/codex-integration/doctor.test.ts
  • tests/codex-integration/main-account-hard-lock-auth.test.ts
  • tests/codex-integration/main-account-hard-lock-policy.test.ts
  • tests/codex-integration/main-device-reauth.test.ts
  • tests/codex-integration/main-quota-provenance.test.ts
  • tests/codex-integration/native-model-toggle.test.ts
  • tests/codex-integration/native-profile-manager.test.ts
  • tests/codex-integration/orca-import.test.ts
  • tests/codex-integration/reserve-catalog.test.ts
  • tests/codex-integration/reserve-dispatch.test.ts
  • tests/config/client-config-export-new-clients.test.ts
  • tests/config/client-config-new-clients.test.ts
  • tests/config/config-spend-ceilings.test.ts
  • tests/config/settings-fast-rows.test.ts
  • tests/fixtures/crusoe-models.json
  • tests/fixtures/file-size-baseline.json
  • tests/fixtures/provider-outbound-mihomo.ts
  • tests/fixtures/test-layout-expected.json
  • tests/gui/alibaba-intl-token-plan.test.ts
  • tests/gui/gui-codex-usage-score-parity.test.ts
  • tests/gui/gui-static.test.ts
  • tests/helpers/cold-spawn-warmup.ts
  • tests/helpers/held-response.ts
  • tests/helpers/management-relative-send-paths.ts
  • tests/helpers/stored-direct-identity.ts
  • tests/lib/abort-idle-deadline.test.ts
  • tests/lib/local-destinations.test.ts
  • tests/lib/socks5-fetch.test.ts
  • tests/lib/spend-ceiling-enforcement.test.ts
  • tests/lib/workflow-budget.test.ts
  • tests/oauth/adapter-event-oauth-failover.test.ts
  • tests/oauth/generic-oauth-failover.test.ts
  • tests/oauth/oauth-account-quota-rank.test.ts
  • tests/oauth/oauth-refresh-lock-multiprocess.test.ts
  • tests/oauth/oauth-store-multi.test.ts
  • tests/oauth/pool-kernel-generic-sweep.test.ts
  • tests/providers/crusoe-provider.test.ts
  • tests/providers/cursor/cursor-call-id.test.ts
  • tests/providers/cursor/cursor-discovery.test.ts
  • tests/providers/cursor/cursor-effort-suffix.test.ts
  • tests/providers/cursor/cursor-envelope-echo-retry.test.ts
  • tests/providers/cursor/cursor-request-builder.test.ts
  • tests/providers/cursor/cursor-tool-continuation.test.ts
  • tests/providers/cursor/cursor-tool-definitions.test.ts
  • tests/providers/devin-prompt-cache.test.ts
  • tests/providers/devin-provider-merge-migration.test.ts
  • tests/providers/devin-stated-reset-hardening.test.ts
  • tests/providers/devin-stated-reset-retry.test.ts
  • tests/providers/flash-route-image-modalities.test.ts
  • tests/providers/minimax-reasoning-split.test.ts
  • tests/providers/opencode-go-session-header.test.ts
  • tests/providers/openrouter-quota-reset-cooldown-4024.test.ts
  • tests/providers/opper-provider.test.ts
  • tests/providers/orcarouter-provider.test.ts
  • tests/providers/provider-outbound.test.ts
  • tests/providers/provider-registry-parity.test.ts
  • tests/providers/upstream-transient-retry.test.ts
  • tests/providers/xai/grok-lifecycle.test.ts
  • tests/responses/apply-patch-envelope.test.ts
  • tests/responses/chat-native-lenient-finish.test.ts
  • tests/responses/fresh-connection-optout.test.ts
  • tests/responses/responses-code-mode-patch-compile.test.ts
  • tests/responses/responses-compact-handoff-admission.test.ts
  • tests/responses/responses-compaction-routing.test.ts
  • tests/responses/responses-console-go-upload-retry.test.ts
  • tests/responses/responses-core-modules.test.ts
  • tests/responses/responses-fetch-helpers-boundary.test.ts
  • tests/responses/responses-hosted-tool-declaration.test.ts
  • tests/responses/responses-native-main-refresh.test.ts
  • tests/responses/responses-passthrough-transient-policy.test.ts
  • tests/responses/responses-spend-ledger-wiring.test.ts
  • tests/responses/sse-client-frame-bounds.test.ts
  • tests/responses/sse-payload-rewrite.test.ts
  • tests/responses/ws-upstream-socks5.test.ts
  • tests/routing/destination-policy-resolved.test.ts
  • tests/routing/router-combo-failover-classification.test.ts
  • tests/routing/subagent-model-fallback.test.ts
  • tests/server/adapter-resolve.test.ts
  • tests/server/api-access-endpoints.test.ts
  • tests/server/audio-transcriptions.test.ts
  • tests/server/bounded-body.test.ts
  • tests/server/management-provider-pinsless-validation.test.ts
  • tests/server/management-provider-proto-override.test.ts
  • tests/server/management-provider-synthetic-max.test.ts
  • tests/server/management-provider-validation.test.ts
  • tests/server/provider-send-path-import.test.ts
  • tests/server/proxy-env.test.ts
  • tests/server/proxy-liveness.test.ts
  • tests/server/retry-after-429.test.ts
  • tests/server/retry-delay-hardening.test.ts
  • tests/server/server-combo-failover-e2e.test.ts
  • tests/server/server-combo-held-response.test.ts
  • tests/server/server-key-failover-e2e.test.ts
  • tests/server/server-request-body-size.test.ts
  • tests/server/terminal-guard-server.test.ts
  • tests/service/container-bootstrap.test.ts
  • tests/service/launchd-repair.test.ts
  • tests/service/process-state.test.ts
  • tests/service/service-sqlite-home.test.ts
  • tests/service/service-start-environment.test.ts
  • tests/service/stop-deferred-teardown.test.ts
  • tests/usage/quota-401-recovery-runtime.test.ts
  • tests/usage/quota-401-recovery.test.ts
  • tests/usage/usage-cost.test.ts
  • tests/usage/usage-log.test.ts
  • tests/web-search/web-search-bridge-replay.test.ts
  • tests/web-search/web-search-passthrough-bridge.test.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lidge-jun
lidge-jun merged commit 134c92a into main Sep 18, 2026
78 of 83 checks passed
@lidge-jun
lidge-jun deleted the release/2.59.0 branch September 18, 2026 16:25
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot changed the title release: promote 2.59.0 to main [WRONG BRANCH] release: promote 2.59.0 to main Sep 18, 2026
@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • wrong target branch (main); retarget to dev. UI screenshot required.

What to do

  • Retarget this PR to dev — all contributions go to dev.
  • Add a screenshot of the UI change to the PR description.

Its title has been prefixed with [WRONG BRANCH].
Automatic draft conversion failed (token cannot change draft status). Please convert this pull request to a draft manually. The required enforce-target check will keep failing until every issue above is resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.