Skip to content

[WRONG BRANCH] release: promote the verified 2.60.0 tree to main - #5249

Merged
lidge-jun merged 97 commits into
mainfrom
release/2.60.0
Sep 20, 2026
Merged

lidge-jun merged 97 commits into
mainfrom
release/2.60.0

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

Verification

  • Promotion only; the tree is the reviewed dev head, with no additional commits on this branch.
  • Per-PR exact-head hosted CI covered each integrated change on dev. Local suites, typecheck, builds and installs were not run in this lane by explicit maintainer instruction; hosted CI on this promotion is the execution evidence.
  • Publication follows through release.yml with expected-sha pinned to the merge commit.

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 19, 2026 01:24
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…t inventories (#5075)

The regex seeds place a conventionally named file, so a regression test can sit in the tree, run in CI, and still be absent from the authoritative table. That is how the regression tests for #5050, #5051 and #5055 landed without ever entering scripts/test-layout/layout.json or tests/fixtures/test-layout-expected.json (#5059).

The two inventories are two copies of one table and the membership oracle already compares them, so both sides get the same three entries. A new test names the three files so they cannot fall out again silently, and checks that each one actually sits in the directory its registration claims.

No repository-wide explicit-registration policy is introduced here; the seeds keep carrying brand-new files as designed.
…tself on every boot (#5077)

* fix(providers): stop the Antigravity rename migration re-announcing itself

The rename migration and the OAuth preset reconciliation disagreed about
nine retired Antigravity Flash ids, and startServer runs both, in that
order. ANTIGRAVITY_MODEL_CONTEXT_WINDOWS derives a window for every
compatibility alias, so the google-antigravity preset carries a
modelContextWindows key for each retired id. The migration renamed those
keys and persisted, applyOAuthPresetCatalog copied the preset's record
back over them in the same boot, and the next start found them again:
nine [model-rename-migration] lines on every ocx start, for a user who
never selected any of those nine models.

Skip a field the registry's own seed still publishes keyed by the retired
id. Those entries are deliberate (a request naming gemini-3.6-flash routes
to 3.7 and needs a window under the id it asked for), and reconciliation
owns that record anyway, so the migration has nothing to repair there.
Every field the user owns (models, selectedModels, retainModels,
defaultModel, disabledModels) is still renamed and still reported once.

Closes #5066

* fix(providers): only skip registry residue, not a value still to carry

The first cut skipped any field the registry seed published keyed by the
retired id, which also skipped a row that saved only the retired key. That
row needs the value carried onto the supported id, and dropping it blanks
the record instead of moving it (test 4/4 caught it at
gemini-37-flash-migration.test.ts:211).

Require both conditions now: the registry seed still publishes the retired
id in the field, AND the saved field already carries the supported id, so
the rename would only delete a key reconciliation puts straight back. The
reporter's post-reconcile row satisfies both for all nine ids; a row with
just the retired key does not, and is still migrated and still reported.
…nts (#5008) (#5079)

* diag(google): project the structure of an Antigravity wire request (#5008)

Adds a pure, content-free projection of the compiled Google wire body so a reporter can describe a failing request without pasting a conversation into a public issue.

* test(google): pin the wire-shape projection and record the upstream contract (#5008)

* diag(google): name the signature facts the projection can actually prove (#5008)

Adversarial review found the two signature booleans claimed more than the call site knows: replayedCallIds conflates a client-supplied signature with a durable-store hit and misses the Antigravity session cache entirely, and a bound replay scope is not a complete one. They are now counts and a presence flag with the names they earn, and a call turn after an unrecognized role no longer reports a model turn.

* test(google): stop a fixture thread id from shadowing the anchor class name (#5008)

The leak assertion planted the parent thread id 'parent-a', which is a substring of the anchor class literal 'parent-and-own' the same line asserts is present. The diagnostic never carried the id; the marker collided with the class name. Both shards reported only this one failure.

* diag(google): make the wire-shape projection unable to reach the request path (#5079 review)

Four review defects. The projection was evaluated in argument position, so a throw inside it would have rejected buildRequest; it now goes through a lazy provider diagnostic that gates first and evaluates the builder inside its own try/catch. The item ceilings alone let a worst case serialize past the debug buffer's per-line cap, which cut the JSON while the retained prefix still claimed truncated:false; a serialized budget at half that cap now trims turn detail and the flag stays honest. The send-count assertion counted fetches around buildRequest, which never fetches, so it is replaced by a real fetchResponse exercise under a controlled executor, a send budget and onPhysicalSend. The timing claim is corrected rather than engineered away: with debug on the walk is synchronous on the dispatch path and linear in history length, and the docs say so. Also shares the session-anchor decision, the bypass sentinel and the two upstream error predicates instead of keeping second copies.

* test(google): let the tighter of the two ceilings win in the long-session assertion (#5079 review)

The serialized budget trims the long-session case below the turn ceiling, so pinning the retained detail to the turn ceiling alone was wrong once both bounds existed. The assertion now fixes what actually matters: exact totals, a head-anchored remainder, and a summary that fits a debug line. The dispatch comparison also stops claiming more than it checks and now compares the whole outbound body with only the per-build request id normalized out.
* test(ci): split phase timing for the four #4997 budget overruns

The four cases in #4997 exceed their own budgets only when the suite runs unsharded, and pass in the sharded lanes running the same files. Three control dispatches produced three disjoint failing sets, so a per-test duration cannot say whether the time went to cold fixture setup, to a wait the assertion needs, to slow contended execution, or to a teardown still reaping a child.

This records those phases from inside the fixtures. tests/helpers/phase-timing.ts emits monotonic performance.now() boundaries plus exponential progress ticks, so a log truncated by a budget kill still distinguishes slow-but-advancing execution from a stall. The heartbeat case moved to a sibling file because web-search.test.ts sits exactly at its recorded cap.

* test(ci): make the #4997 phase record say something a reader can act on

Review of the first commit found the progress signal unwired in two of the three instrumented files, so every tick would have reported no movement and the hang-versus-slow distinction the record exists for would have been unavailable. The web-search case now probes its send count and the provider spine its observed-capture count; the image cases already probed the encode counter, but the per-build reset sat inside the measured segment and zeroing a probe mid-phase reports movement that did not happen. The spine also claimed to separate the server bind and did not. A phase now stops reporting after two minutes rather than after forty ticks, which is nine.
…windows (#5082)

Three of the four cases spend most of their budget on work the assertion is not about. The image file builds the same 1000x1000 noise PNG seven times, once inside each of the two windows that overran; it is now built once per size and shared, which no case can observe because nothing writes to the result. The provider-option spine asked the host service manager who owns its sandboxed homes, which on macOS is up to four synchronous launchctl children at two seconds apiece, and it now uses the seam that exists for exactly this. Its WebSocket and migration child were reachable only from the success path and are now released on the failure path too.
* fix(tests): judge cold-spawn warm-up registration structurally

The coverage guard recorded a file as warmed when its text contained the substring helpers/cold-spawn-warmup, so a comment, a string literal, or an import left behind after the beforeAll call was deleted all satisfied it while the measured child paid the cold module-graph load again (#5060).

tests/helpers/warmup-registration.ts replaces the substring with a structural judge over the file tokens: it follows the import binding from the exact helper module through aliases, finds the bun:test beforeAll registration and the scope of its inline callback, requires the call on that callback direct path, and requires the promise to reach the hook by await or return. A file it cannot read is reported unreadable rather than answered.

Parsing uses the scanner from typescript/unstable/ast, the same entry point tests/responses/responses-fetch-helpers-boundary.test.ts already uses, because TypeScript 7.0.2 is the native port and publishes no in-process parser.

* fix(tests): close the scopes a warm-up registration can hide in

Four gaps the first pass left, each of which accepts a file that pays the cold load anyway: a namespace import warms without binding a name the judge follows, so an unwarmed disposition now requires no helper import at all rather than no binding; a hook registered in an uncalled helper or behind a false condition registers nothing, so a registration must sit at the top level or in a describe callback, unconditionally; a callback parameter of the same name shadows the import with no declaration keyword to find; and a warm-up that is one operand of the returned expression leaves the hook settling on something else.

* fix(tests): end a guarded statement without needing its semicolon

A semicolonless guarded registration left the conditional flag set for the next line, so the unconditional hook after it was refused too. Statement level now also ends at a line break after a token a statement can end on, with the token that begins a guarded statement exempted so if (false) on its own line still guards what follows it.

* fix(tests): keep a guarded statement that the next line continues

A line break only ends a statement when the next line cannot continue the previous expression. A line opening with a paren continues it, so drawing the boundary on the line break alone read the second half of one conditional consequent as unconditional and accepted it.

* fix(tests): judge four warm-up shapes exactly and refuse the rest

The token walker reconstructed scoping, statement and expression grammar by hand, and the gaps were false passes: an expression-bodied arrow created no scope, so a hook registered inside one read as top-level work, and a shadowed beforeAll took a correctly awaited callback while nothing ran.

It now recognises four shapes - an awaited or returned statement in a beforeAll callback, a beforeAll expression body, and a module-level await - and every other occurrence of a warm-up binding is one refusal naming its line and its scope chain. Provenance is required for beforeAll and describe as well as for the warm-up name. TypeScript 7.0.2 publishes no in-process parser (typescript/unstable/ast exports the node FACTORY, and parsed trees come from the tsgo client), so the alternative to an exact accept-set is more hand-written grammar, where each wrong guess is a false pass.

Refusing a legitimate file no longer blocks it: a disposition records the construct in unmodeled, and the judge must still see the warm-up and still refuse it for that reason, so deleting the call or dropping the await fails again.

* fix(tests): require a suite call this judge can see running

braceLayer read a block as a describe body from the callee name alone, so describe.skip and a describe behind a false condition both produced a suite scope and a hook inside one was recorded as a registration while nothing ran. A suite now counts only for a plain statement call of the bare imported name, and the refusal says which of the two it was. Adds fixtures for both, and one for warmColdSpawn, which no fixture pinned.

* fix(tests): pin the member-call suite without tripping the focused-test gate

The fixture named describe.skip in a string, which PR hygiene reads as a focused test in the diff. describe.each takes the same path through the judge - a callee that is not a bare identifier - so it pins the same property without the literal.
…5078)

* test(ci): give the Windows nested live-lock case its own lock owner

The nested live-lock regression registered only when OCX_TEST_NO_QUEUE was
not 1, and the hosted Windows batch leg sets exactly that, so the case was
skipped on the only platform it applies to.

A controller child now owns the lock instead of borrowing the lane's: it runs
with the opt-out removed for itself alone, resolves the user-scoped path
through the ordinary safe path, acquires it for its own run id, and spawns the
nested Bun children that must inherit it. The outer environment, the real
home, and any pre-existing owner are left untouched.

Closes #4991

* test(ci): bound the nested live-lock controller and harden its receipt

Adversarial review of the first commit found three real weaknesses. The
controller could spend more than the caller's 45s hard kill across four child
spawns, so a failure path could terminate it inside a spawn with the lock
still held and its teardown never reached. It is now handed an absolute
deadline 10s short of that kill and bounds every child by what is left of it,
minus a cleanup reserve.

A join failure inside registerMember can carry a member filename, and that
path runs before the controller learns its own token, so a redactor keyed on
that token was blind exactly where a leak was possible. Diagnostics now strip
every UUID-shaped substring, and receiptRedacted scans for one instead of
being vacuously true on the green path.

Two other receipts were weak: the acquire-timeout probe accepted the message
without waiting, and release checked only that our own owner file was gone.
They now require the elapsed floor and the planted foreign owner intact after
release. childrenReaped requires the full spawn count so a skipped scenario
cannot pass. lockOwned is renamed lockHeld because the controller joins an
existing owner when a wrapped run already published one.

* test(ci): keep the nested case's child deadline where the guard can see it

Moving the per-child timeout into the controller removed this file's only
spawn-options INTERNAL_DEADLINE_MS, so the cold-spawn warm-up guard stopped
matching it and its disposition became an orphan. That failed test 3/4 on
Linux and windows 7/9.

The deadline that bounds four cold Bun starts belongs to the case that owns
them, not to the helper, so the test now declares the child spawn options and
hands them over; the controller only narrows them to what its own deadline
still allows. The guard's inventory and its scan agree again, and the helper
no longer re-derives a budget constant.
)

* fix(codex): keep routed rows from inheriting experimental context

Routed catalog rows are cloned from a native template, so they inherited
supports_experimental_context from the account's native models. Codex reads that
flag as "this model accepts experimental context history" and drives its
context-management cadence from it, which on a routed third-party provider turns
into a compact-after-every-step loop: a routed DeepSeek row compacted 1,600+ times
in a single thread.

Strip the field in normalizeRoutedCatalogEntry, next to the existing strips for
supports_websockets and supports_reasoning_summaries.

Validation:
- bun run typecheck: clean
- bun test tests/ci-workflows/file-size-ratchet.test.ts tests/e2e-style/phase100-native-parity.test.ts tests/codex-integration/codex-catalog.test.ts: 349 pass, 0 fail
- bun run privacy:scan: pass
- bun run structure:check: pass

* docs(routing): note the native-only flags stripped from routed rows

AGENTS.md asks src/ behavior changes to update docs-site/. Record the delivery flags a routed row
never inherits, including supports_experimental_context and what inheriting it looked like.

Validation: cd docs-site && bun install --frozen-lockfile && bun run build (465 pages built).
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
* fix(gui): keep file clients unknown on a failed-cold client read

clientsSettled counted a failed-cold read as an answer, so the overview dropped the file-client rows as a server-side omission and showed the 'No installed clients were detected' panel next to the load error. Settle on the payload itself: undefined covers pre-response and cold failures while failed-with-stale keeps its real rows.

* docs(pr): add the failed-cold integrations screenshot

---------

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

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

* fix(gui): validate Claude Desktop status payloads before trusting them

The status poll accepted any JSON and cached it as DesktopStatus, so an error-shaped or malformed OK payload reached the render path where status.health dereferences crashed the page. Guard the wire response and the cached entry with isDesktopStatus: a non-conforming fetch now records a cold failure and shows the existing failure presentation, and a non-conforming cache entry is treated as absent.

* docs(pr): add the malformed-status Desktop screenshot

---------

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

A routed Command Code Muse turn reached Codex App carrying
{"type":"function_call","name":"default.view_image"} and the same item for
default.apply_patch. Codex has no handler for either name, answered
"unsupported call", and stored both. Every later request that replayed that
history was then refused before it could run:

  Invalid 'input[877].name': string does not match pattern '^[a-zA-Z0-9_-]+$'.

A side chat opened from an 11h43m parent task hit it through automatic
compaction, and no upgrade helps once the item is in stored history.

The cause is two resolvers disagreeing, not a missing mechanism.
undeclaredNameInItem resolves an emitted name through
normalizeDeclaredToolName, which maps a default.-prefixed code-mode helper onto
the declared exec (#4412) as well as a default.-prefixed bare tool (#4176), so
default.view_image was ADMITTED as exec. The emit-side rewrite,
normalizeDefaultNamespaceInItem, implemented only the bare-tool half, so it
forwarded the name unchanged. The guard's own conclusion never reached the
client.

Fall back to the resolver in the rewrite, so a name good enough to admit is the
name the client receives. Gated on isSchemaValidResponsesToolName rejecting the
emitted name, so a name the upstream accepts cannot be reshaped by this branch
no matter what the resolver would say about it. The routed-custom-tool and
namespace restores run earlier in the same rewrite chain and keep owning the
shapes they convert; this is the boundary check for names no restore claimed.

A dotted name that resolves to nothing declared is left alone here and stays
refused by the #1700 guard, which is the pre-existing behaviour and the right
one: an unresolvable invalid name must end the turn visibly rather than enter
stored history. A dotted name the caller itself declared is a real identity and
passes through byte-identical.

No local suite was run.

Refs #5095
)

Stopping the emission is only half the report. Codex stores what it received, so
a conversation that already contains a default.-prefixed function_call name is
refused on EVERY later request that replays it:

  Invalid 'input[877].name': string does not match pattern '^[a-zA-Z0-9_-]+$'.

The task cannot be compacted or continued, and upgrading does not reach it. That
is the part of the report that actually hurts: a side chat opened from an 11h43m
parent hit it on a plain OpenAI model, from history a routed provider had
damaged.

repairLegacyDottedToolCallNames repairs the replayed item on the way out, in
buildRequest beside backfillWebSearchQueries and again in compact.ts, which
forwards the caller's body directly. It runs before the canonical-destination
split, because the destination that refused the request was plain OpenAI.

What resolves is bounded on purpose:

- a dotted spelling the caller's own catalog declares is a real tool identity and
  is never stripped; rewriting it would change which tool the history says was
  called;
- a suffix claimed by two declared identities is ambiguous and is left alone;
- a suffix naming exactly one declared tool resolves to it;
- otherwise, only the code-mode helper spellings in CODE_MODE_HELPER_WIRE_NAMES
  resolve, because a code-mode catalog never declares them -- they exist solely
  as nested tools.* helpers inside exec, so a recorded call under one of those
  names can only be a provider echoing the helper.

There is deliberately no "strip everything before the first dot" rule. A
legitimate tool name may contain a dot in another provider's vocabulary, and a
replayed item names a call that already happened, which is the worst possible
place to guess. Anything unresolved is left exactly as it is; the upstream still
refuses it, which is the pre-existing outcome rather than a new one.

Only replayed input items are eligible. The caller's tool catalog is never
rewritten, call_id is untouched so a repaired call still pairs with its stored
output, and a body with nothing to repair is returned by reference.

No local suite was run.

Refs #5095
…ansports (#5125)

* fix(transport): return null bodies for 204 and 205 on raw outbound transports

Both raw outbound transports build a Response from a socket, so each applied the
Fetch null-body rule on its own and the two disagreed. The SOCKS helper excluded
204 but not 205; the pinned direct helper attached a streaming body to every 2xx.
A 204 or 205 therefore either raised a TypeError inside the response handler or
waited for a peer that was entitled to keep the connection alive.

The status set now lives in one place and both owners read it. Representation
headers survive untouched: a 205 that advertises a coding it never sent is
neither decoded nor refused, because there are no coded bytes to act on.

* docs(transport): correct the null-body note on 101 and 103

The comment claimed an upgrade is refused before the shared predicate is
consulted. It is not: the SOCKS helper stops its interim-response loop on 101 and
carries that status into response construction. Describe 101 and 103 as statuses
outside the final Response set these helpers support, which is what is actually
true, without changing any runtime behavior.

* test(transport): prove the SOCKS 205 case releases its tunnel

The case was named for a release it did not check. It asserted status and body
and then force-closed every socket in teardown, so the name claimed more than the
assertions did. It now waits, under a bounded deadline rather than a fixed sleep,
for the keep-alive peer's connection to be observably destroyed, which is the
release the transport actually owes.
* fix(gui): do not offer retry for the Grok coupon reset POST

A transport rejection after the redemption POST is dispatched has an unknown outcome: the request may still reach the server and spend the coupon. Classifying it as a retryable network error let the operator re-submit an irreversible redemption with the same operation id. Return the aborted outcome for any post-dispatch rejection so the UI stops posting and forces a re-read of account state.

* docs(pr): add the unknown-outcome coupon dialog screenshot

---------

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

Single-key pools cannot fail over, so a burst 429 on the Go destination surfaces immediately. Six 10s-paced attempts absorb a short burst window; Retry-After is still honored and capped, and an explicit retryOn429 always overrides.
The server-configuration table in English and all seven locale copies
claimed generated apiKeys are accepted by management and data-plane
auth. Runtime rejects data-plane credentials as management tokens
(src/server/management-auth.ts). Correct each row to describe
data-plane admission only, link the locale management reference, and
record the row contract in the docs structure owner.

Closes #5120
…5131)

tests/providers/cursor/cursor-stream-health.test.ts asserted that meaningful
frames keep resetting both stream-health deadlines by running a synthetic
HTTP/2 server for three times the silence budget and requiring that no
deadline expire. That is an assertion about how busy the machine is. In the
unsharded macOS control lane it fails with "Cursor stream stalled: no inbound
frames for 5s before turnEnded" while the watchdog is behaving correctly:
under contention the fixture's own frames do not arrive inside the window.

The budget is already CI-scaled, and scaling is what makes it worse. With the
silence budget floored at 5s the case needs 15 consecutive seconds during
which no 5s gap in frame decoding occurs, so raising the floor lengthens the
exposure rather than reducing it.

Add a T04-only clock seam (now, setTimeout, clearTimeout), matching
StageLeaseClock in src/cli/account-api.ts. Production omits it and keeps the
globals; the 30s and 90s budgets, the first-frame timer, the turn-ended grace
and the outbound heartbeat are untouched. The test now advances virtual time
by hand between frames whose arrival it awaits, so runner contention can
delay a frame without any deadline passing, and it additionally asserts that
exactly one timer is armed after each frame and none survives turnEnded.

No production timeout changed, no budget widened, no retry added and no
platform skipped.
…ses (#5127)

* fix(transport): settle SOCKS5 uploads on abort and early final responses

The upload loop awaited the caller's body reader before looking at the socket at
all. Aborting destroyed the socket, which does nothing to a read owned by the
caller's own stream, so a stalled body kept the fetch pending - including when
the peer had already answered and the response was sitting in the receive buffer.

One reader now consumes the socket for the whole exchange and starts before the
upload finishes. Each body read and drain wait races the caller's abort and that
pending answer, so an abort rejects with its own reason, an early final response
ends the upload without writing a terminating chunk into a finished conversation,
and a socket failure during a stalled read surfaces as that failure. The request
body is cancelled without being awaited, because a caller's cancel algorithm is
free to never settle; releasing the reader is what frees the pending read.

* fix(transport): type each upload race by its own outcomes

One union covering both races let the compiler accept reading a chunk value off
a drain result, which is the mistake the type exists to prevent. The body race
and the drain race now have separate result types, and the shared answered case
is its own type.

The abort regression also drove its abort from the body stream having produced a
chunk. A caller's stream can be pulled before the tunnel is established, so that
signal did not prove the fetch was parked mid-upload. The fake upstream now
reports the first body byte it actually receives, and the abort follows that.

* fix(transport): preserve a non-Error abort reason on the upload race

AbortSignal.reason is whatever the caller passed, and the socket reader already
hands a string or an object back unchanged. The upload race wrapped anything that
was not an Error, so the same abort surfaced differently depending on which race
won it. It now passes the reason through, with a regression that aborts with a
string and asserts identity.

The abort regression also now waits on the upstream observing the request head
and its first body byte before aborting. Waiting on the caller's stream having
produced a chunk did not prove the fetch was parked mid-upload, because a stream
can be pulled before the tunnel is established.

* fix(transport): give an aborted caller back its own abort reason

The helper preserved a non-Error reason, but that was not the contract the caller
saw. Several waiters inside this transport can win the race that settles an
abort, and they disagree about a reason they consider absent: the socket reader
substitutes an Error for null, others coerce anything that is not an Error. The
same abort(null) therefore surfaced as an Error or as null depending on
scheduling, and the comment claiming otherwise was wrong.

An aborted request now rejects with the exact signal reason, decided in one
place. undefined is left alone so a hand-built signal without a reason still
reaches the underlying cause. The regression covers a string, null and a plain
object, each asserted by identity.
…oute (#5126)

* fix(transport): decode content-coded responses on the pinned direct route

The SOCKS tunnel undoes gzip and deflate; the pinned direct helper returned the
coded bytes unchanged. Provider outbound chooses between the two, so the same
gzip JSON was readable on one route and a SyntaxError on the other depending on
operator egress configuration.

The pinned helper now asks for identity unless the caller chose an
accept-encoding, decodes gzip and deflate, drops the coding and the coded length
once the bytes no longer match them, and refuses any other coding under a named
error instead of handing over bytes no caller can parse. Only the coding the
response actually carries decides this, so a preference list naming an
alternative this code cannot undo is not a refusal.

maxBytes now binds the decoded body as well as the bytes that arrived, because a
ceiling applied only to the coded side admits a body far larger than the caller
agreed to hold. The classifier is shared with the tunnel, which keeps its own
error type and message.

* fix(transport): keep a pinned transport failure out of the decode taxonomy

Review of the content-coding change found the decoded body rewriting every
non-PinnedHttpError from the pipeline into content_decode_failed. A mid-body
reset and a socket error reach a decoder as "the stream failed", so that told the
caller the peer had sent unreadable bytes when the connection had actually died.
The source stream's failure is now recorded as it passes and surfaced unchanged;
only what the decompressor itself rejected is renamed.

The two new error codes also had to be classified everywhere the union is read.
Antigravity quota probing sent every code except the byte cap to "timeout", so an
undecodable response was diagnosed as a timing failure; both new codes now join
the byte cap under "response_unusable". The Lab pinned sender switched over the
four codes that existed when it was written and let anything else fall through to
a raw rethrow. Both consumers now use a total map, which makes a future code a
compile error rather than a silent misdiagnosis. An unsupported coding
deliberately maps to nothing in the Lab taxonomy: it is a deterministic contract
mismatch, and borrowing a timeout or transient code would tell Lab to wait or
retry for a failure that is neither.

Adds regressions for a reset during a valid coded body, cancellation through the
decoder, the socket-side byte ceiling alongside the decoded one, and observed
connection release before teardown.

* fix(transport): classify an unreadable pinned response in the Lab taxonomy

Leaving the unsupported-coding case out of the Lab map was not the same as
leaving it unclassified. The executor turns an unrecognized error into
harness_failure / execution_error, so a response the peer coded in a format this
transport cannot undo was attributed to the runner rather than to the upstream.

Both unreadable answers now carry a new unreadable_response transport code, which
Lab classifies as a protocol failure: deterministic, upstream-owned, and neither
a timeout, a budget, nor a harness fault. The map stays total, so a future pinned
error code cannot inherit the old misattribution by default. The quota and Lab
mappings are now asserted directly.

Two test oracles were also weaker than their names. The byte-ceiling case sat
above both ceilings, so deleting the socket-side counter could still pass through
the decoded one; it now uses a payload whose coded form is larger than its
decoded form, with both sizes asserted, so only the socket-side counter can
refuse it. The cancellation case sent a complete small body, so ordinary
end-of-stream could release the peer; it now promises more than it sends, stays
open, and is cancelled after the pipeline has produced output.

* fix(transport): stop tearing down a decoded body that already ended

Hosted CI showed the success-path assertion failing: the case demanded the peer
connection be destroyed after a complete decoded body, and it was not. The oracle
was wrong, and so was the code it was pinning. A response that ended has nothing
left to release, and destroying it takes a connection the agent is entitled to
reuse. The identity path only closes, so the decode path now does the same.

Teardown stays where a response actually ends early: a decode failure, an
exceeded ceiling, and a caller that cancels. Those three now assert an observed
close rather than only the error they raise, and the success case asserts the
connection is left intact.

* test(transport): assert end of stream, not a pooling decision

The success case asserted the connection was left intact, which pins a mechanism
this transport does not own: Node documents a completed connection as destroyed
or pooled depending on the agent's keepAlive setting, and the runtime's actual
choice is not something a transport test should encode in either direction.

What a completed decoded body owes is that it ends - the decoder flushes, the
stream closes and the caller reads the whole value - so that is what the case now
asserts. The cleanup this path does owe is still asserted where a response ends
early, in the decode-failure, ceiling and cancellation cases.

* test(transport): hold the failing responses open so the close is attributable

The decode-failure and ceiling cases sent their whole declared length, so the
response could complete before the failure surfaced and the connection could then
be pooled rather than closed - the same agent behavior the success case above
deliberately refuses to pin. Both fixtures now promise more than they send and
stay open, so the close each case asserts is the one this path owes for a
response that ended early.

The inventory paragraph is narrowed to match: teardown belongs to responses that
end early, while a completed one is left to the agent.

* test(lab): classify the error the sender actually rejected with

The unreadable-response case asserted the rejection shape and then classified a
separately constructed TransportError. That second assertion would pass even if
the sender raised something else entirely, which is the opposite of what it is
there to prove. Both cases now capture the rejected value, assert it is a
TransportError carrying the expected code, and classify that same instance.
…storation (#5129)

* fix(responses): share one progressive freeform decoder with routed restoration

Routed custom-tool restoration decoded the string inside the input wrapper and
emitted it immediately, while completion strips a complete outer Markdown fence
for exec and apply_patch. A delta consumer could therefore receive fence bytes
that do not belong to the authoritative final input, and no SSE event can take a
published prefix back.

The decoder the bridge already grew for this now lives in
src/responses/progressive-freeform-input.ts and both paths call it. Bridge
behavior is unchanged: the same function with the same arguments at the same call
site, with its separate patch-envelope hold left where it was. Routed restoration
keeps its stricter holds for an unrecognized JSON object and for a code-mode
patch envelope, and keeps owning its retained bytes - the shared decoder is pure
and leases no translator budget.

Duplicate input keys and a wrapper that only becomes invalid after a valid prefix
was emitted stay bounded exceptions rather than an invariant this cannot keep:
completion remains authoritative, and the new sibling test documents both.

* fix(responses): hold a routed apply_patch envelope the way the bridge does

The shared decoder made ordinary raw input progressive on the routed path, which
is the intended behavior and is what the bridge already does. It also exposed a
case the older routed decoder never reached: a raw decorated
`*** Begin Patch ***` envelope now streamed, while completion rewrites those
markers through normalizeApplyPatchDelimiters. The decorated bytes would be
published and then replaced, which is exactly the rewind this path forbids.

The routed hold now covers both reasons completion rewrites an envelope, as the
bridge's does: an exec body that compiles into an apply_patch helper call, and an
apply_patch body whose delimiters are normalized. Namespaced tools are unchanged,
since neither reason applies to a foreign grammar. The regression drives a raw
decorated envelope across every chunk split and asserts no preview alongside
agreeing normalized done, item and terminal input.

* fix(responses): stop previewing a wrapper with a literal control character

A JSON string cannot contain a raw character below U+0020, so a wrapper carrying
one never parses and completion keeps the whole wrapper as the input. The decoder
was appending those characters to the preview, which publishes a decoded value
the authoritative item does not contain - the same disagreement a fenced body
causes, reached through a different invalid spelling. It now stops instead.
…#5130)

* fix(responses): refuse a continuation whose task scope does not match

A task-scope mismatch correctly refused to replay another task's state, then
stripped previous_response_id and continued with whatever input the request
carried. When that input was only a delta, the proxy silently turned a
continuation into a fresh conversation and the model answered without the
history the client believed it had. Missing or corrupt state already asks the
client to replay in full; a mismatch now does the same.

The refusal is the existing generic previous_response_not_found response, byte
for byte, emitted before any upstream send. It is returned even when the input
looks complete, because this process cannot prove that it is; a caller that
really has the whole conversation retries without previous_response_id and
succeeds. The response reveals neither the stored scope nor whether foreign
state exists, and the internal reason stays internal.

Same-scope continuation is unchanged, and two absent scopes remain the legacy
unscoped cohort that still replays together. This is a deliberate change to the
historical fresh-start behavior, recorded in the transport contract and in the
client-facing guides.

* fix(responses): answer a scope mismatch exactly as an unusable id is answered

The refusal was correct but distinguishable. A continuation this process has never
seen records no replay failure and reaches the route-dependent refusals, while a
mismatch answered earlier with a different message. That difference is itself the
disclosure the issue asks to avoid: a caller could tell "state exists and belongs
to another task" from "no state at all".

A mismatch now falls through to those same route-dependent refusals, so both
answers are byte-identical on any given route, and a destination that genuinely
owns the continuation chain keeps behaving as it does today for an unknown id
rather than being rejected for lacking local state. The regressions compare the
two envelopes on the same route and assert neither reaches the model.

* test(responses): cover the WebSocket path for a task-scope mismatch

The existing WebSocket coverage exercises expired and missing replay state. A
scope mismatch is the third way local replay becomes unusable, and the client
has to see the same frame or Codex terminates the task instead of reconnecting
with its full input. The case stores state under one task, reconnects as
another, asserts the generic refusal frame with no upstream request, and then
replays complete input without the id and succeeds.

* fix(responses): refuse a resolved foreign continuation before native forwarding

Letting a scope mismatch fall through to the route-dependent handling was wrong.
An id this process cannot resolve is the destination's business, and a
destination that owns the continuation chain is entitled to receive it. An id
this process CAN resolve, to another task's retained state, is not the same
thing: forwarding it continues that task's conversation for a different caller.

The refusal now happens before that exception, on both the ordinary and combo
paths, and uses the one generic local-unavailable envelope. The paired
regression asserts a resolved foreign id is refused with no upstream request
while an unknown id on the identical native route is still forwarded.

* fix(responses): answer every local replay failure with one envelope

A resolved foreign continuation is still refused unconditionally, before any
route-dependent handling, so another task's conversation is never forwarded. What
changed is the two remaining local-unavailable answers: the canonical forward and
routed-continuation refusals carried their own message text, so which local
failure had occurred was readable from the response even though all three mean
the same thing to a client. They now use the message the early failures already
use.

Genuine upstream-owned continuation is untouched: an id with no local state at
all still reaches a destination that owns the chain. The added case compares
missing and mismatched state on one route and asserts identical status, type,
code and message.

* test(responses): produce all three local replay failures for the equality check

The equality case compared a mismatch against expired state and inferred the
corrupt answer from the source string. It now produces each condition for real on
one route - a spill deleted, a spill overwritten with bytes that do not parse, and
an entry retained under a different task - and asserts byte-identical responses
with no upstream request.

* test(responses): follow the unified local replay failure message

Unifying the local-unavailable answers changed the canonical-forward text this
assertion matched on. It now matches the single message every local replay
failure uses.

* test(responses): state the local replay envelope once

A second assertion matched the retired canonical-forward text through
/continuation state.*expired/i, which is why unifying the message turned shard
four red as well. The expected envelope now lives in one constant that every
local-replay assertion in this file uses, so a future change to that contract
fails one place rather than several written from memory.

Status, error code, upstream-send counts and retention assertions are all
unchanged; nothing was relaxed to a truthy check.
* docs(structure): bind the Lab isolation invariant

Add INV-LAB-01 covering both existing guarantees -- protected core
entrypoints cannot reach optional Lab runtime imports, and gated Lab
activation stays synchronous until startServer returns -- bind it to
the existing core/Lab boundary guard, add the reverse test-side
identifier, and document the contract in the Compatibility Lab
structure owner. No runtime mechanism changes.

Closes #5121

* docs(structure): scope INV-LAB-01 to the guard's actual coverage

Review resolution: the guard walks load-time edges (static, side-effect,
re-export) transitively but deliberately does not follow deferred
dynamic import() specifiers; it separately forbids a protected file
from naming Lab in a direct dynamic import. Restate the invariant and
the Lab contract section to distinguish load-time isolation, the direct
dynamic-import ban, and the sanctioned lazy /api/lab routing pattern,
without broadening the runtime guard.

Also record src/server/index.ts in the Compatibility Lab documents
list (the activation contract lives there) and regenerate
structure/INDEX.md with the canonical generator.
…5073) (#5128)

The reset fixture in tests/server/server-auth.test.ts leaked its stream
controller out of start() and errored it from the test body. Whether that
rejection had a consumer depended on where Bun's server-side response sink
happened to be: between its reads there is no pending read request to reject,
so on a loaded runner the fixture's own error escaped as an unhandled error
and failed the whole file. It fired on four unrelated heads (#4989, #5024,
dev at ecd3ada, and #5085).

Raise it from inside pull() on a stream whose high-water mark is zero
instead. shouldCallPull is then true only while a read request is
outstanding, so pull() runs if and only if a consumer is waiting for the
next chunk, and throwing there rejects that read request. The reset now has
a consumer no matter when the test calls it. What the code under test sees
is unchanged: one SSE chunk, then a mid-stream body error.

Closes #5073
* docs(proxy): align SOCKS5 HTTP/SSE routing documentation

The proxy-format, adapter, provider-configuration, and provider-guide
pages claimed HTTP/SSE never uses ALL_PROXY. Configured outbound fetch
actually selects the built-in SOCKS5 tunnel for an explicit SOCKS5
proxy or a SOCKS5 ALL_PROXY when NO_PROXY does not exempt the target
(src/lib/proxy-env.ts). Correct the four English pages and the seven
translated provider-configuration copies that carry the claim, link
the server configuration reference, and record the alignment contract
in the docs structure owner. Coordinated with open draft #3901, which
owns provider-specific proxy fields untouched here.

Closes #5119

* docs(proxy): correct NO_PROXY and fake-IP gate semantics in SOCKS5 docs

Review resolution on the SOCKS5 documentation alignment:

- A server SOCKS5 proxy configured with config.proxy is written to
  ALL_PROXY at startup (src/config/proxy-env.ts), so both configured
  and inherited SOCKS5 routes honor NO_PROXY; only the per-request
  RequestInit.proxy override skips it. Stop conflating the two.
- The fake-IP accommodation gate counts a SOCKS5 ALL_PROXY because
  effectiveProxyFor selects it; only a non-SOCKS ALL_PROXY does not
  count.

Corrected in all four English pages and all seven locale copies.
DNS/pinning and private-address guard caveats preserved.
* feat(structure): add versioned contract authority to the manifest

Add an optional, versioned contracts registry to structure/manifest.json
so each cross-cutting contract has one authoritative document anchor
while the many-to-many source review map is preserved unchanged. The
checker validates declared topology (unique ids, existing owner
documents/anchors, dependent links) without claiming semantic
correctness, and the generated index publishes the registry.

Migrate the duplicated paginated-history writer paragraph in seven
dependent documents to one authority link, and register the existing
request-copy and stream-buffer accounting contracts. structure/AGENTS.md
now distinguishes mandatory review fan-out from the smaller set of
documents whose content actually changes.

Closes #5116

* fix(structure): validate the manifest before rewriting the index

The --fix path parsed and cast the manifest, then rendered, before any
schema validation: a malformed contracts section crashed the renderer
with a TypeError instead of failing with an actionable diagnostic, and
could write a broken index first. Route generation through
loadManifest and add regression coverage proving the named schema
failure and an unchanged INDEX.md for malformed input.

* test(structure): drive the real --fix CLI in the malformed-manifest regression

The seam-level tests prove writeGeneratedIndex, but the original defect
lived in the CLI tail. Spawn the copied script in the synthetic
scaffold: malformed contracts exit nonzero with the named schema
diagnostic and no TypeError, INDEX.md unchanged; a valid manifest with
a stale index exits zero and regenerates it. Authored for hosted
execution; not run locally per campaign restriction.
)

* feat(devin): admit every inference send through the shared budget

PR #5041 shipped a pre-output replay of a stated rate-limit reset and recorded
what it left undone: those inner sends never reached the request-wide send
budget, the provider fetch wrapper, or physical-attempt accounting. A turn could
therefore make three real inference requests while the shared cap, the pacing
slot and the request log each saw one.

All three now go through the existing shared physical-send primitive, so a permit
is reserved once per actual send, confirmed at the wire boundary, and refunded
when admission succeeded but no request followed. Nothing increments a counter
directly and no second counter exists. The initial send is not double-charged:
the adapter reserves it as ordinal 1, and the request observer already ignores
ordinal 1 because the caller records the entry send itself.

A replay the budget refuses makes no inference request, records why recovery was
withheld, and surfaces the provider's original 429 rather than a local budget
error, so the server-stated reset and any outer cooldown behavior survive.
Reservation still happens after the stated wait, not before it, so a one-hour
wait does not hold a spend booking open for an hour. Catalog and JWT calls are
not inference sends and keep the global fetch.

* test(responses): admit the Devin row so the counted send actually happens

The case asserted one GetChatMessage call and got none, in thirteen milliseconds
with no adapter output: the turn was refused before the adapter ran. The devin
registry entry declares authKind "oauth", and an omitted authMode inherits it, so
the fixture's row demanded an OAuth credential while supplying an apiKey. It now
states authMode "key", which is what the working sibling fixture in this file
does and what the supplied credential actually is.

Both numbers are now asserted together and carry the response status and body in
the failure message, so a turn that never reaches the adapter says so instead of
presenting as an empty URL list.

* test(responses): route the Devin count case through a stored credential

The authMode guess was wrong: the case still recorded no send. Devin is an
OAuth-kind provider, and the key its adapter uses is injected onto the row from
the stored credential, so a config carrying only apiKey never routes and the turn
ends before the adapter. The case now seeds the credential the same way the
working Devin fixture does, which is the path production takes, and the catalog
is keyed to that same value.

The assertion is unchanged: one GetChatMessage call and one recorded send,
reported together with the response status and body so the next failure is
self-describing.

* fix(devin): count the first inference send where it is admitted

Review found the accounting still describing an intention rather than a send.
runTurnAttempt logs the attempt's first send before handing control to the
adapter, which is right for a transport whose sends the caller performs. Devin
now admits its own sends through the shared budget, so that first send can be
refused - and once earlier combo or empty-recovery sends have spent the
allowance, the log claimed a request the wire never made.

An adapter that reports every physical send now says so, and for those the
caller stops pre-logging and the observer counts ordinal 1 at the executor
boundary that actually dispatched it. Every other adapter and call site is
unchanged, including the ordinal-1 skip they rely on. An attempt-level recovery
kind still labels that first send when the adapter supplies none of its own.

* test(devin): pin that a refused first send is neither made nor counted

The accounting fix needs the case that exposed it: an allowance already spent
before this turn starts, which is what an earlier combo fan-out or empty-response
recovery leaves behind. Nothing reaches GetChatMessage, nothing is observed as a
physical send, and the budget records nothing - where the previous ordering would
have logged a send the wire never made.

The admitted case beside it still asserts exactly one call, one observation at
ordinal 1, and one charged send, so the fix cannot be satisfied by counting less.

* test(responses): pin the refused Devin send at the request boundary

The direct-adapter case cannot see the defect it was written for. The phantom
send was logged by executeResponsesRunTurn before the adapter ran, so only a case
that goes through handleResponses with a RequestLogContext can prove the attempt
records nothing.

This one puts Devin last in a failover combo behind a chat target that spends the
allowance first, which is the shape that leaves nothing for Devin's initial send.
It asserts no GetChatMessage request and a Devin attempt sendCount of zero, and
that the members which did send still account for themselves - so the fix removes
a phantom rather than suppressing real counts. The status and body travel in the
failure message.

The direct-adapter case stays for what it does cover, the executor side, and no
longer carries the claim that it pins the outer behavior.

* test(responses): force the refusal instead of arranging it through a combo

Review traced the arithmetic: a two-target combo has five total sends against a
base of four, the first target settles a counted booking leaving three, the
transition books the fourth, and Devin's initial send was still admitted at five.
The case therefore never reached the denied path, and an optional attempt lookup
let an absent attempt satisfy a zero count.

The budget is now handed to handleResponses already spent, built by the real
factory rather than inferred from combo behaviour. The assertions are the ones
that prove a refusal: exactly one attempt, that attempt is Devin's and its
sendCount is zero, no GetChatMessage request, zero total sends, and the response
carries request_send_budget_exhausted. Status and body travel in the failure
message.

This row fails against the eager pre-log it was written for: that path recorded
the attempt's send before the adapter ran, so sendCount would read one.
lidge-jun and others added 22 commits September 20, 2026 06:49
* feat(providers): migrate static policy consumers onto the resolver

Route derive, router merge, catalog hints, gather admission, and adapter
selection through the frozen ResolvedModelPolicy captured at route
construction. Every RouteResult carries staticPolicy; virtual-model
rewrites recapture it atomically with the wire model; credential,
quota, health, and cooldown changes continue to mutate only
route.provider (late binding preserved). Observed limits stay
call-local through clampObservedModelLimits. No persistence serializer
or snapshot format changes.

Closes #5114

* fix(providers): repair four hosted failure classes in the migration

Hosted CI (run 35446350736) fold: the narrow retry route shape now picks
staticPolicy; baseUrl normalization no longer throws before the existing
override validation; virtual-model policy recapture skips only partial
callers without a prior capture, leaving the reasoning merge untouched;
catalog hints restore the configuredInputModalities oracle so exact
declarations override, legacy inference falls back, and clearing the row
returns to inference. No existing assertion changed.

Part of #5114

* fix(providers): complete the policy consolidation in the consumers

Review fold: catalog hints consume the resolved policy's modality field
again — the resolver now reproduces the exact-capability, colon-family,
and case-fold legacy lookups, so consolidation no longer changes
behavior; the legacy helper stays exported for compatibility only. The
virtual-model rewrite resolves identity from the final route.modelId,
with log context reporting-only, and accepts its own mutation marker
only when the wire target matches the current route model.

Part of #5114

* fix(providers): recapture inbound wire policy and honor captured Fast authority

Review RCA fold: request preparation now recaptures staticPolicy with
the actual inboundWire after every initial, fallback, and recovery
route, so translated Chat/Anthropic replays resolve their own adapters
while Responses keeps its captured policy; catalog Fast support derives
solely from the captured fastPolicyForModel authority so an explicit
supportsServiceTier:false cannot be masked by enriched metadata; and
gather capture leaves an explicitly present (even empty)
modelDefaultReasoningEfforts authoritative, with registry fill only when
the field is absent.

Part of #5114

* docs(structure): repair the cascade merge artifact in the catalog contract

The stacked cascade left the parent's "consumer migration is a separate
layer" sentence and a dangling duplicate fragment; this child IS the
migration. One coherent paragraph retains the call-local fill, no-widen,
max-input bound, and frozen gather-flight statements.

Part of #5114

* test(responses): point the passthrough oracle at the captured policy

The migration intentionally resolves terminal-repair policy from the
captured static policy; update the source oracle's anchor to the exact
new capture while preserving the real platform gate and pure native
relay invariant assertions.

Part of #5114

* test(providers): cover gather-captured limits and Anthropic family precedence

Review coverage fold: bounded table cases prove configured low/high
context/output limits survive captureProviderGather into the emitted
catalog rows, and the claude-sonnet-4 family context window outranks
both the provider-wide value and the dated model row. No runtime change.

Part of #5114

* test(providers): cover configured limits below and above the registry

Review fold: the capture table now has both rows with the positive cap
merge fields (modelContextWindows + modelMaxInputTokens) — configured
200000/150000 retained below, and above-registry 1100000/950000 resolving
to the registry 1050000/922000 — asserting both captured maps and the
gathered catalog row. The Anthropic family precedence case is unchanged.

Part of #5114

* test(codex): add fixed-phase startup diagnostics to the inject integration

Diagnostic-only patch (reviewed, authored in campaign coordination):
fixed-phase progress markers at file import, beforeEach, the
unreadable-preimage fixture, and the synchronous spawn return, with
bounded scalars and no env/paths/stdout/stderr content. All assertions
and deadlines are unchanged. Purpose: identify the macOS stall phase;
no root cause is claimed.

Part of #5114

* docs(structure): drop the duplicated exact-only sentence

Review fold: the cascade union left the capability exact-only sentence
twice; one copy removed. No content change.

Part of #5114
…nd (#5223)

Zen gateway stalls-then-drops inference sends; the ambiguous pre-header reset became a synthetic non-replayable 429 that surfaced immediately (and logged as rate_limit_exceeded, hiding the real cause). The Go destination carries subscription inference-only traffic, so the passthrough initial send now opts into bounded reset replays there; recovery legs keep the fail-closed refusal. The log classifier also names the proxy refusal by its message instead of calling it provider throttling.
…rdicts (#5222)

* fix(codex): keep transient pool refresh failures transient and surface stored auth causes

* fix(codex): persist terminal pool reauth verdicts and let stored causes outrank bare marks

A memory-only reauth mark carries no cause of its own, so poolAccountDto no longer names refresh_failed on its behalf: projectCodexAccountHealth then falls back to the persisted verdict, letting a stored http_status:401/403 surface as unauthorized/forbidden while the mark is still present.

Terminal refresh failures found during quota probes (revoked/expired grants) are now persisted through markCodexAccountValidationFailed with terminal: true, the same verdict the token guardian writes - the in-memory mark dies with the process, and only the stored verdict keeps a cached listing from calling the dead grant healthy after a restart. Applied in both recoverPoolQuotaFrom401 and fetchFreshPoolAccountQuota.

Tests: the deferred-validation matrix now expects the stored http status cause whether or not the in-memory mark survives; the pool-reauth-cause helper gains persisted-verdict and restart-simulation assertions for the dead-grant path.

---------

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

* fix(tray): read restart safety through the CLI instead of the admin-gated API

* fix(tray): throttle startup-health probe attempts after launch failure or invalid result

* fix(tray): terminate an active startup-health probe when the tray shuts down

* fix(tray): clean up startup-health probes outside the online branch, on pipe failure, and on shutdown
…ut (#5225)

* test(transports): cover HEAD preservation, interim answers and the response timeout

Three coverage gaps the acceptance audit found in the transports work. No
production change: each case exercises a branch that is already there and was
not asserted.

HEAD (#5109). A HEAD answer carries the headers the GET would have carried,
including the length of a body it will never send. The SOCKS transport now has a
case proving it answers with a null body, keeps the advertised length in the
headers where a caller is entitled to it, and releases a tunnel whose peer asked
to stay alive.

Interim answers (#5110). A peer may answer 100 and 103 before the request body
is finished, and those are not the answer. The new case has the peer send both
mid-upload and asserts the caller receives the final 200, with upload continuity
witnessed by the peer receiving the rest of the body including its terminating
chunk.

The response timeout (#5110). The branch that matters runs while the upload is
parked on a chunk the caller will never produce. Waiting out the real budget
would make this a three-minute test, so the timer is observed as the transport
arms it and its own callback is invoked once the peer has witnessed the stall.
The budget asserted is the transport's, mirrored in the test rather than
exported from the module. Settlement, reader release and socket teardown are
each witnessed.

local checks: NOT RUN

* test(transports): make the interim-answer case prove its own ordering

The case enqueued the whole request body up front, so the upload could finish
before the peer ever sent 100 and 103 and the claim that the rest of the body
went out after them was not causal.

The peer now answers the request head before any body byte, and the caller's
stream withholds its last chunk and the end of the body until that has happened.
Upload continuity is measured against the moment the interim answers were sent
rather than against the whole exchange, so the terminator arriving afterwards
says what it appears to say.

The transport-side receipt is the final answer itself: reading 200 with its body
is only possible for something that consumed both interim heads and went on
reading, where a transport that stopped at the first would have handed the caller
an empty 100. The exchange is also required to end on its own, before the
fixture tears any peer down.

No production change, and every existing assertion is kept.

local checks: NOT RUN

* test(transports): witness the interim answers arriving on this side of the tunnel

The previous version released the rest of the body once the peer had written 100
and 103, which says the bytes were sent, not that the transport had them. The
release now waits until both complete interim heads have arrived on the client
side of the tunnel and the reader has had a native scheduling turn to consume
them, and it records that the fetch is still pending and the body uncancelled at
that moment, which is what says neither head was taken for the answer.

The socket is observed through the timer the transport already arms, with a
passive data listener; the reader is in flowing mode, so it observes the same
chunks and consumes none. No production seam and no sleep.

Upload continuity is still measured from the moment the interim answers were
sent, the final answer and its body are still the receipt that both were read
past, and the exchange must still end on its own before the fixture tears any
peer down.

local checks: NOT RUN

* test(transports): make the interim-answer fixture fail safely

The held tail lived in a stream pull that awaited a receipt which, if it never
arrived, would park the fetch until the runner's own deadline. The finally block
restoring the global Socket prototype would not have run by then, and the data
observer was anonymous, so nothing could remove it either.

The tail is now held by the test body with bounded waits on the receipt, the
outcome and the response, the observer is named and removed, and the fetch is
owned by an AbortController the fixture aborts on the way out. The prototype is
restored first, before anything else in teardown.

Every causal assertion is kept and two more are added: at the moment the
remainder is released, the peer has not yet seen it or the terminator, which
makes the ordering the assertions rely on visible rather than assumed. The
timeout constant and the response and closure checks are unchanged.

local checks: NOT RUN
* fix(codex): recognize boolean native context opt-in

Accept Codex FeatureToml's explicit boolean form as well as the existing
experimental_mode table in the shared injection/runtime predicate.
Keep absent, false and malformed values off and leave admission,
account ownership and upstream forwarding unchanged.

Add opt-in, URL-isolation and runtime-revocation regressions plus
English/Korean guidance for an authenticated native trial profile.
The guide separates source-level feasibility from live-account support.

* docs(guides): list native context guide in the sidebar

Register guides/codex-native-context in the Guides sidebar group so the English and Korean pages are reachable from the left navigation.

---------

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

* fix(vision): let an explicit custom row outrank the provider vision hints

A model added as a manual custom row with inputModalities ["text", "image"] still
had every attachment replaced by the omission marker. The catalog half was
already right: src/codex/catalog/routed-gather.ts copies the custom row's
modalities onto the advertised row, which is why the dashboard showed "text,
image". The request path consulted only providers[].noVisionModels and
modelInputModalities, concluded text-only, and stripped the image before
dispatch. One config, two answers.

The capability predicates in src/vision/eligibility.ts and
src/vision/plan.ts now read the custom row for the exact provider/model
identity through customRowInputModalities. Precedence is modelCapabilities (the
dedicated per-model capability axis, including the ocx provider edit
--text-only write), then the custom row, then noVisionModels, then
modelInputModalities, then registry/vendor metadata. A custom row that declares
no modalities stays silent instead of becoming a text-only claim, and the
provider-only fallback used by legacy unit callers is unchanged.

The new test file pins the request-path seam and the shared predicate, which is
what the sidecar picker and the web-search verbalizer read. Three of its cases
fail without the fix.

* fix(vision): apply the capability precedence in both predicates

CodeRabbit found the order violated in two places. \`isVisionSidecarConsumerWithCache\`
read the custom row before \`modelCapabilities\`, and the native arm of
\`modelAcceptsImageInputWithCache\` ran the sidecar-consumer check before the custom
row, so a \`noVisionModels\` listing the catalog had already overridden still
forced text-only on the request path.

Both predicates now resolve sources highest-first: \`modelCapabilities\`, the
explicit custom row, \`noVisionModels\`, \`modelInputModalities\`, then
registry/vendor metadata. Two tests pin the order at the shared predicate, and
both fail without this change.

* fix(vision): answer "can this model see" the same way in both predicates

Maintainer review on #5163 found the custom-row branch applying a narrower test than
the `modelCapabilities` branch above it. `requiresVisionPreprocessing` asked for
`includes("text") && !includes("image")` while `modelAcceptsImageInput` answers "no
image" for the same declaration, so a row declaring only `audio` or `video` was
image-incapable to one and an image target to the other. Both now use the same rule:
image is absent from the list.

`usableRoutedVisionModel` also ANDed a provider-only `isModelTextOnly` on top of
`modelAcceptsImageInput`. That second predicate never reads a custom row, so a
describer the operator had declared image-capable was refused for the provider hint
that same row overrides; the check could only subtract and is now gone.

`structure/config.md` said the catalog overlay reads the field through
`customRowInputModalities`; it copies `customModels[].inputModalities` directly. Only
the request-path predicates go through the helper, and the note now says so.

Three tests come with it: the audio-only row, the routed describer a custom row
unlocks, and the existing ones stay. The first two fail with the source fix stashed.

* docs-site: state the image-absent rule for custom model rows

The maintainer review noted the public page still described only the text-only case, while
structure/config.md already records that a row declaring only audio or video is
image-incapable in both predicates. The public page now carries the same sentence, so the
two documents agree.
…5164)

* fix(registry): reclassify the Zen Go DeepSeek route as native vision

The OpenCode Go deepseek-v4.1-flash route was declared text-only and listed in
noVisionModels, so every attachment was replaced by the vision-sidecar omission
marker before dispatch. That classification came from jawcode metadata and went
stale: probed 2026-09-19 against the gateway with this proxy's own headers, the
route accepts an image_url part and the model reads it correctly.

Correcting the registry only fixes new installs. enrichProviderFromRegistry
fills noVisionModels all-or-nothing and fills modelInputModalities per-key
beneath the saved value, so a config saved while the stale seed was current
keeps both halves of the claim forever. The new startup projection rewrites
exactly those two saved values, guarded by an exact match on the stale
declaration, in the shared repair pass.

The sibling deepseek-v4-flash still answers HTTP 400 "Model only supports text
input" on the same gateway and keeps its classification. The Zen tiers could not
be probed (HTTP 402), and an unverified tier is not evidence, so they are
unchanged.

* test(providers): rename the migration test out of the service seed

The layout seed regex for the `service` domain matches `stale-`, so the file name
placed the new test in the wrong domain under the seed-only oracle that guards
brand-new files. The name now follows its sibling context-window-seed-repair.

* docs(structure): scope the Zen statement to the unmeasurable tiers

CodeRabbit found both notes still saying "Zen routes are unchanged and unprobed"
directly beside the recorded OpenCode Go probe. Only the Zen tiers
(\`opencode-zen\`, \`opencode-free\`) were unmeasurable (HTTP 402); naming them
removes the contradiction and keeps the note from claiming more than was
verified.

* fix(providers): finish a half-migrated vision row, not just the full stale pair

Maintainer review on #5164 found the repair firing only when `modelInputModalities` was
byte-for-byte the stale `["text"]`. A config whose modalities had already been
corrected but whose id was still in `noVisionModels` was left alone, and the sidecar
predicate reads that list BEFORE the modality list — so the row kept stripping images
with every saved value looking repaired.

The projection now handles both states a running process can be in: the full stale pair
(both values rewritten) and the half-migrated row (the name is dropped, the modalities
are already right). The paired modality declaration stays the guard in both, which is
why a listed name with no declaration beside it is still left alone: that row is either
a half-finished repair or a deliberate operator entry, and the projection does not
guess which. Flagged in the reply as an open question rather than decided here.

Nothing writes `modelCapabilities`. It outranks every source this file touches, so it is
where a deliberate text-only override survives a restart; the module docstring and
`structure/providers-and-adapters.md` now say so.

Tests: the half-repaired row, the listed-name-without-declaration row, and a guard that
the dedicated axis is never rewritten. The old expectation that a corrected modality
value protects the list entry is replaced by the behaviour the review asked for.

* fix(providers): resolve the stale vision repair through the registry transport

providerMatchesRegistryTransport is the rule enrichProviderFromRegistry applies before it
writes registry metadata, so the projection now answers row identity the same way and
inherits the entry's preserveCustomDestination opt-in. Adapter equality stays as an
additional tightening.

The opencode-go entry has no preserveCustomDestination, so for it the helper resolves to the
name check enrichment already relies on; the change follows the shared rule instead of a
hand-rolled one. Two tests pin both directions: baseten, which does opt in, is skipped when a
same-named row points at another host and repaired when it points at the registry destination.

* test(providers): pin the sidecar routing the modelCapabilities axis forces

The maintainer review noted that the modelCapabilities test only asserted the axis itself
was left untouched. It now also asserts the repaired row (modalities rewritten to
text+image, name dropped from noVisionModels) still routes through the vision sidecar,
because requiresVisionPreprocessing reads that axis first.
* fix(codex): hand off affinity in refresh flight

A shared refresh flight deliberately outlives the request that opened it: an aborted owner stops waiting while the detached work still commits G+1. Affinity handoff only ran on the caller path gated by selfRefreshed, so a detached commit stranded thread bindings at the old generation until the next selection released them — losing the prompt-cache affinity instead of advancing it. Register generation-dependent completion with the flight itself so it runs exactly once per committed result, for every waiter including none.

* fix(codex): hand off propagated aliases and contain handoff failures

A dormant same-grant alias commits the rotated credential at its own generation, so handing off only the owner left the alias's thread-affinity entries stranded at the old generation where the exact-generation liveness check fails them. Dispatch the handoff for each propagated alias at (alias.generation - 1, alias.generation).

A throwing handoff listener also rejected the shared refreshPromise after the credential was already persisted: surviving waiters saw a refresh failure that never happened, and plan reconciliation was skipped. Each listener now runs independently inside the flight settlement with failures contained and logged without account ids or token material.

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
* feat(integrations): own value-free mutation planning in a pure seam

An operator confirming apply, overwrite, disable or undo agrees to consequences
nobody has shown them, and the only way to show those consequences safely is to
compute them somewhere that cannot write.

src/integrations/mutation-plan.ts is that place. It owns the closed operation,
change-kind and foreign-edit vocabularies, the bounded plan shape, managed
schema path canonicalization, deterministic ordering with deduplication and a
cap, and a versioned fingerprint over every input a plan's authority rests on.
It holds no IO, takes no lock, and does not import the writer, so the direction
is state/ownership/merge into the planner and the planner into the writer.

Two decisions are load-bearing. A path segment that is not representable in the
managed grammar invalidates its whole path rather than being skipped, because a
skipped segment names a different place than the one being changed, and an
ownership record on disk accepts arbitrary strings and is not a validation
authority. And the fingerprint covers the model snapshot and, for restore, a
digest of the snapshot's actual bytes rather than only its operation id: the
contribution is derived from the models, and the bytes are what would land in
the user's file.

RefusalReason moves here so a plan can report a refusal without depending on
the module that performs writes. The writer re-exports it, so every existing
caller is unaffected and no second vocabulary exists.

No behavior changes: nothing calls the planner yet.

local checks: NOT RUN

* refactor(integrations): share one observation between preview and mutation

A preview that reads the file separately from the mutation it authorizes can
disagree with it, and then the operator confirms one thing while another
happens. The read, parse, contribution build, record selection and
classification now live once in the planner, and the writer consumes that
result instead of performing its own.

The move is behaviour-preserving for mutation, including refusal ordering,
which is load-bearing. What changes is that the two effects a preview must not
have are named rather than implied: pending-prune maintenance and Cline
transaction recovery both write, so they are explicit options with no default.
Mutation passes both; a preview will pass neither. Leaving them defaulted was
the more dangerous option, because a preview would inherit a write while still
being called a read.

Refusals cross the boundary in the planner's own vocabulary, so the planner
keeps no dependency on the writer's result type; the writer translates them
back into WriteRefused, preserving the Cline residual marker. IntegrationWriteInput
moves down with the observation that consumes it and is re-exported, so the
management routes, the Aside adapters and the existing tests are unaffected.

local checks: NOT RUN

* test(integrations): pin the plan projection and fingerprint contract

Covers the three decisions the plan seam exists to guarantee.

A path segment that is not representable in the managed grammar invalidates its
whole path rather than being dropped, because an ownership record accepts
arbitrary strings and a partially dropped path names a different place than the
one being changed. A selected member collapses to a wildcard, so which entry was
chosen is not published.

The fingerprint moves for every input a confirmation rests on, including the
model roster, since the contribution is derived from it, and it distinguishes an
absent file from an empty one because restoring over each is a different
operation. For restore it moves when the snapshot bytes change while the
operation id and snapshot kind stay the same: binding only the id would leave
the bytes that actually land in the user's file outside the confirmation.

Reported changes are deduplicated, ordered and capped, and the result is frozen
so a caller that sorted it in place could not edit shared plan state.

Registered in both test-layout inventories.

local checks: NOT RUN

* fix(integrations): bind install state and admission to the plan fingerprint

Review found that a confirmation could survive two changes it should not. The
fingerprint bound the detect directory's path but not what was actually there,
so an uninstall left every other component identical and the token still
matched. It also bound nothing about admission eligibility, so a config change
that makes the integration an illegal target was invisible to a plan that had
already been shown.

Both are now inputs: the observed kind of the detect directory, which is what
the not_installed refusal is derived from, and whether admission policy blocks
the client, which is the non_loopback refusal's input. A plan is a claim about
a decision, so every input that decision is derived from has to be inside it.

local checks: NOT RUN

* fix(integrations): publish only declared managed paths, as templates

Review found the path rule was an allowlist wearing a grammar's clothes. Any
alphanumeric segment passed, and Kimi writes one fragment per model at
models.<alias>, so a user's model identifier would have been published verbatim.
The same rule accepted any plain path sitting in an ownership record, and a
record on disk is not a validation authority.

Each client now declares where its managed fragments live. A path is published
only when it matches one of that client's templates exactly: static segments
must match literally, a dynamic position accepts any observed segment, and the
string that leaves the planner is the template rather than the observed path.
Publishing a value is therefore structurally impossible rather than merely
unlikely, and a path nobody declared fails closed instead of being described.

The declarations are checked against the client union, so adding a client
without saying where it writes is a type error. Regressions cover the Kimi
alias, a foreign static segment, another client's shape, extra depth, and that
every shipped client has a declaration.

local checks: NOT RUN

* test(integrations): prove real builder paths canonicalize, not just that templates exist

The template table is a second copy of what the exporters do, and the earlier
case only asserted each client had a non-empty list. That would stay green while
a client's actual fragment path drifted out of its declaration, which is the one
failure the table exists to prevent.

Each shipped client's contribution is now built from a bounded fixture context
and every emitted fragment path is canonicalized through that client's own
templates. Any segment the templates do not name must not appear in the
published path, so Kimi's per-model alias is checked against real builder output
rather than a hand-written example.

local checks: NOT RUN

* feat(integrations): assemble the value-free plan an operator confirms

Turns the shared observation into the plan itself: the managed places the
operation would touch, the history it would write, the foreign-edit status, and
whether it can proceed at all.

Refusals are derived in the writer's own order, which is not cosmetic. An
uninstalled client is reported as not installed rather than as whatever its
leftover file classifies as, and an unreadable file is reported before either,
because that is the sequence the writer refuses in. A plan naming a different
reason than the mutation would name is worse than no plan. Overwrite stays the
one operation allowed through a conflict the operator has been shown.

Drift is passed in rather than recomputed, so the plan and the mutation read it
from the same comparison, and it is bound into the fingerprint with the rest of
the restore inputs.

A path that does not canonicalize is omitted rather than guessed at. For a
shipped client that cannot happen and the parity case proves it; what it covers
is a record written by another version, where declining to describe a path is
the honest answer while the fixed ownership entry still tells the operator that
ownership changes. A refused plan reports no places and still carries its
reason, because knowing undo is blocked by an expired backup is the answer an
operator needs.

Regressions cover the change list, replacement versus addition, refusal
ordering, overwrite through conflict, expired and drifted restore, and that
neither a configured value nor a filesystem path reaches the response.

local checks: NOT RUN

* feat(integrations): add the read-only preview entrypoint

previewIntegration runs the shared observation with both write-capable effects
off, so it prunes nothing, recovers nothing, takes no lock and enters no
mutation flight. Everything it reads is a read: the target file, the ownership
records, and for restore the journal row and its snapshot.

When observation itself refuses, the plan carries a fixed unbound token rather
than a fingerprint. Such a plan never read the state it would have bound, so
there is nothing to bind, and sharing one value is safe precisely because
canApply is false and only a plan that could apply may be bound to a mutation.

A restore whose operation id is unknown or belongs to another client is refused
without saying which, since naming it would report on journal contents the
caller did not select.

The filesystem regression proving preview leaves the config, store, snapshots
and journal byte-identical is the next commit; it needs a temp home whose path
resolution is verified rather than assumed.

local checks: NOT RUN

* test(integrations): prove a preview leaves the filesystem untouched

The feature's whole promise is that looking changes nothing, and that is a
claim about the filesystem rather than about the code's intentions. This drives
the real preview against a temp home and a temp store, then compares the client
file's bytes and every file under the store before and after.

The path resolution is asserted rather than assumed. Every client resolves its
config through the home argument today, and a client that stopped doing so must
fail this test loudly instead of quietly reading somebody's real configuration.

Also checks that the plan describes places and not contents: neither the home
path nor the proxy address appears anywhere in it.

local checks: NOT RUN

* fix(integrations): decide each operation the way that operation decides

Review found the plan applied one global refusal sequence to all four
operations, and the writer does no such thing.

Apply checks installation and admission before anything the classifier says,
reports a conflict ahead of unsafe, and treats an already-current file as a
success that writes nothing. Disable never asks about installation or
admission at all: removing what we wrote from a file that still exists is
meaningful whether or not the client is installed now, and it emits nothing
admission policy could object to; an absent block is a no-op rather than a
refusal. Restore stays on its own journal, snapshot and drift questions. A plan
is only useful if it reaches the same verdict, for the same reason, as the
mutation it describes.

Two consequences follow. An operation that would write nothing now says so and
names no places, because reporting a snapshot and a journal row for a no-op
describes consequences that never happen. And whether a managed place is
occupied is read from the document rather than from our own record, since
deciding from the record called an overwrite of somebody else's key an
addition, which is the one situation overwrite exists for.

The filesystem proof now snapshots the entire temp home rather than the target
file alone, so a writer lock or a marker sibling appearing next to the file
would fail it. It seeds pending maintenance and asserts it is still pending
afterwards, and it leaves an interrupted client transaction in place to show
that a preview repairs nothing.

local checks: NOT RUN

* feat(management): let a read-only caller bring its own model roster

A preview has to show what a writer would write without performing the gather,
because the gather reaches providers and, through the initial-selection
finalizer, can persist configuration. That is not something a read may do.

Only the gather is the problem. Everything after it is the projection: the
disabled computation, native and account-bound rows, custom rows and the public
list. Swapping the gather while duplicating the projection would be worse than
leaving it alone, because the two copies would drift and a preview would then
disagree with the commit that follows it for a reason that has nothing to do
with the roster changing. So the roster becomes a parameter and the projection
stays exactly where it is, shared by construction.

Supplying it is the only way to skip the gather, and skipping the gather is the
only thing supplying it does.

local checks: NOT RUN

* feat(management): serve integration mutation plans on read-only routes

Two POSTs that write nothing: one plans an apply, overwrite or disable for a
named client, the other plans an undo for a journalled operation. Both build the
same input a mutation builds and differ in one deliberate way, the roster comes
from the read-only path that skips the initial-selection finalizer, so a preview
and the commit that follows cannot disagree except when the state truly moved.

A restore preview answers an unknown operation as not found rather than reading
the row back. It runs before any confirmation, which makes it the cheapest place
in the system to probe journal contents, and it declines to be one.

They are POSTs because the operation descriptor is a bounded body, and they are
registered as non-mutating with an interactive-preview exemption: there is no
standalone thing for a CLI to do with a plan, since it is only meaningful to the
caller about to commit it and a scripted caller drives the mutation directly.

local checks: NOT RUN

* test(management): cover the preview routes against the real temp home

Plans an apply through the route and asserts the client file is byte-identical
afterwards, that the response names places rather than locations, and that a
malformed operation or an unknown client is refused before any planning runs.
An undo for an operation that is not there answers not found rather than
reading the journal row back to the caller.

local checks: NOT RUN

* fix(integrations): plan an undo the way the writer performs one

Restore was being previewed through the general observation, and the writer's
undo path reads a different specification. It compares the resolved config path
against the one the journal row was recorded for, reads the snapshot, and reads
the target's bytes. It never parses and never classifies.

Three consequences, all wrong in the direction that matters. A file that was
readable but unparseable classified unsafe, so the preview refused an undo the
writer would perform, denying the operator their backup at the moment the file
is in the state that most needs one. Only the row's client was checked, not the
path it was recorded against, so a row from a previous home previewed as
applicable when path equality is the single thing that undo exists to enforce.
And the coordinated restore's refusal for writer-lock clients with no client
home was never applied.

observeRestore now mirrors that order exactly and derives state from bytes
alone: a missing target is absent, one that no longer matches the recorded
result is a conflict, anything else is current. Admission is not consulted,
because restore emits nothing an admission policy could object to and the
writer does not consult it either. The places an undo touches come from the
provenance the row carries rather than from whatever a record says today.

local checks: NOT RUN

* fix(management): never gather a model roster to serve a preview

Skipping the initial-selection finalizer was not enough, and the reviewer was
right to push back. Discovery itself refreshes credentials and writes the
provider model cache, so a preview that gathered was still a write wearing a
read's name. That the models list already performs a gather describes what a
GET happens to do, not what a preview is permitted to do.

previewExportModels now reads already-captured per-provider cache entries and
never fetches. When no provider has one there is no honest snapshot to plan
against, so the route answers a bounded refusal instead of triggering discovery
to manufacture one; the operator opens the models view or performs the
mutation directly, both of which are allowed to gather.

The route regression asserts that refusal and that the client file is
untouched, which is the property that mattered in the first place.

local checks: NOT RUN

* feat(management): bind a confirmed plan to the mutation it authorizes

Toggle and restore now accept an operation and a plan fingerprint together, and
re-plan before the writer runs. A fingerprint that no longer matches returns 409
with a freshly computed plan, so the operator decides again against what is true
now instead of confirming something that has moved.

Both fields or neither. A half-bound request is refused rather than quietly
treated as unbound, because dropping one half would answer 200 to a caller who
believed their confirmation was being checked, and a confirmation naming a
different operation than the request performs is not a confirmation of that
request.

The fingerprint is an optimistic token and never authorization: management
authentication and every ownership rule still decide whether the mutation may
happen at all. Existing unbound callers are unaffected.

Validation currently runs immediately before the writer rather than inside its
lock, which closes the window an operator can observe but not the one between
this check and the lock; moving it under coordinatedWrite is the next step and
the writer's own compare-before-commit guard remains in place meanwhile.

local checks: NOT RUN

* fix(integrations): check a confirmation where the lock already holds

Validating the fingerprint just before calling the writer left a window between
the check and lock acquisition. Narrow, but the wrong kind of narrow: the whole
point of binding a confirmation is that it describes the state the mutation is
about to change, and a check outside the lock describes state from a moment
earlier.

coordinatedWrite now takes a revalidation hook and runs it after the input is
frozen and the lock is held, before any side effect. Clients without a writer
lock, and the case where an absent client home means no lock is taken, run the
same hook immediately before the operation, which is as close as those paths
allow.

The route keeps the fresh plan from that hook so a stale confirmation still
answers 409 with something the operator can decide against, rather than a bare
refusal that tells them only that they were too late.

local checks: NOT RUN

* fix(integrations): check an Aside confirmation before its preference write

Aside is the one place where checking under the writer lock is provably too
late, and the code already said so. mutateAsideProfiles persists the user's
preference before any writer runs, under a comment noting that the await
precedes model loading, writer preflight, snapshots and all client writes.
restoreAsideProfile persists and then imports the operation, which captures a
snapshot and appends a journal row, before the coordinated restore.

A confirmation validated under that lock would therefore fire after it had
already rewritten the preference and the history it was meant to protect.

Both now take a revalidation hook and run it once profile and path selection is
frozen, which is everything the check needs, and before anything is written.
Bulk mutation is unaffected because one fingerprint cannot honestly bind several
independently changing files.

local checks: NOT RUN

* test(management): a bound change cannot commit on a plan that fails to validate

The case worth pinning is not which refusal comes back but that none of them
lets the write through. A refactor that dropped the binding on the way to the
writer, or moved the check somewhere it no longer runs, would turn this into a
200 and a modified file.

Asserts the refusal and that the client file is byte-identical afterwards,
accepting either reason the plan can fail to validate, since both mean the same
thing to the operator: the change they confirmed is not the change that would
happen now.

local checks: NOT RUN

* fix(integrations): answer an expired backup and a vanished file the way the writer does

Two exact divergences from the writer's undo path.

Expiry is now decided before the target is read. Reading first meant an expired
backup over an unreadable file reported the file as the problem, when the answer
the operator needs is that the backup is gone.

And drift decides the state before absence does. A row that recorded a file and
now finds none has drifted; calling that absent described a missing file as an
ordinary undo while the writer refuses it pending confirmation. Absence is only
honest when the row recorded absence too, and both cases are pinned.

local checks: NOT RUN

* fix(management): preview reads a finished roster, not raw provider caches

The per-provider cache was the wrong source and the re-review was right to
block it. Static and forward providers return without ever populating one, so a
static-only install would have refused previews permanently; a mixed config
would have silently dropped the cacheless providers; and the cache sits before
the retention, metadata, augmentation, combo and filtering that decide what a
client is actually given.

So preview reads the completed projection instead. An ordinary export load
retains its final result, keyed by a digest over the provider graph's shape, the
blocklist and custom models, and a preview returns that only when the key still
matches. Changing any of them retires the snapshot rather than letting a plan
describe a roster the user no longer has. Credentials are not part of the key
and are not read here.

A cold process has no snapshot and the route answers a bounded refusal until the
ordinary models path populates one, which is a recoverable state rather than a
read that gathers. No second gather exists anywhere on this path.

local checks: NOT RUN

* fix(integrations): actually check a bound undo, and bind it to one roster

Two defects review found in the binding, both of which made it weaker than it
appeared.

restoreIntegrationCoordinated has its own coordinated path and never called the
revalidation hook, so a bound restore carried a fingerprint that nothing ever
compared. It now runs the hook in both branches, with the lock held where there
is one, before the snapshot, the write and the journal row.

And a bound toggle built its writer input through the refreshing loader before
the guard ran, while the guard re-planned against the passive snapshot. The
mutation and its own confirmation check would then disagree about the roster by
construction, which is precisely the disagreement the binding exists to detect.
A bound request now uses the passive snapshot for both; an unbound one keeps its
existing path unchanged.

local checks: NOT RUN

* fix(management): never silently drop a preview binding on the Aside routes

The pre-persistence hooks added for the Aside paths were unreachable over HTTP,
because these routes neither parsed nor forwarded the binding fields. A caller
sending them got a mutation that proceeded unchecked while believing their
confirmation was being verified, which is worse than either honouring or
refusing it.

Both routes now parse the fields strictly: together or not at all, the operation
must agree with the change being requested, and an exact profile is required
since one fingerprint cannot honestly describe several independently changing
files. A well-formed binding is then refused outright, because the
profile-scoped plan owner these routes would need does not exist yet.

That refusal is deliberate and temporary. It removes the silent-drop failure
now; honouring the binding needs the Aside preview owner, which is the next
unit. Unbound callers, which is every caller today, are unaffected.

local checks: NOT RUN

* test(management): prove a confirmation is compared, not merely required

The existing case accepted either refusal, so it could pass without a
fingerprint ever being compared. It proved that a bound request without a valid
plan does not write, which is worth having, but it could not distinguish a
working binding from one that refuses everything.

This drives the real sequence: populate the passive roster snapshot, preview an
apply, commit with that exact operation and fingerprint, then replay the same
confirmation. The commit succeeds once and the replay comes back stale with the
file byte-identical to what the first commit produced.

The replay is the case that matters. Without a genuine comparison it would
apply a second time, because nothing else in the request distinguishes it from
the first.

local checks: NOT RUN

* fix(management): carry the binding into every path that can mutate

Review found two ways a bound request still reached a writer without its
confirmation being examined.

The generic restore route parsed the binding and then called the Aside restore
handler with only the operation id and drift flag, so a bound Aside restore
slipped past the rejection that route had just gained and executed unbound. The
binding now travels with the request.

And a bound restore built its writer input through the refreshing loader before
the guard, while the guard re-planned from the passive snapshot, so the mutation
and its own check disagreed about the roster by construction. Bound restores now
use the passive input for both; unbound restores keep the old path.

Also drops a provider field from the roster snapshot key that does not exist on
the config type, which is what broke the typecheck gate.

local checks: NOT RUN

The Aside profile binding is still refused rather than honoured, which is an
interim state and not the finished requirement.

* fix(management): forward the binding through the nested Aside restore too

The nested profile restore adapter rebuilt the request body from the two fields
it cared about, which dropped any binding before the handler that would have
examined it. A bound restore on that path therefore reached the writer with its
confirmation unexamined, the same defect just fixed on the generic route and in
the same shape: a body reconstructed field by field silently loses anything the
reconstruction does not know about.

Both Aside entry points now forward the fields as sent.

local checks: NOT RUN

Bound Aside profile changes are still refused rather than honoured. That is a
fail-closed interim, not the delivered feature.

* fix(management): validate the roster the mutation will actually write

The guard rebuilt its own input from the current snapshot instead of planning
the one the coordinator had frozen. An ordinary export load can replace that
snapshot at any moment, and nothing serialises it against the writer lock, so
the check could validate a fingerprint computed from one roster while the
mutation went on to write from another. That is the exact failure binding
exists to prevent, reintroduced inside the mechanism meant to prevent it.

Revalidation now plans the coordinator's frozen input. Whether the snapshot it
came from is still current is a separate question, answered by comparing an
opaque generation identity captured with the input, so a replacement is detected
without ever swapping the roster the mutation is about to use. On mismatch the
response carries a plan built from the new snapshot, and the old one is never
committed.

The generation identity also gives the roster snapshot a real version rather
than a value inferred from its contents.

local checks: NOT RUN

* feat(integrations): plan one Aside profile's change without performing it

The Aside binding could not be honoured because nothing produced a plan an
Aside route could compare a fingerprint against. This is that owner.

A profile is the unit, because a fingerprint can only honestly describe one
independently changing file. The scope it builds is the same scope the mutation
uses - that profile's store, IO and resolved path pair - so the plan describes
what would actually happen rather than an approximation. The roster comes from
whatever the caller injected, so a preview inherits the caller's no-gather
guarantee instead of reaching for a second source of models.

Nothing calls it yet. Wiring it into the profile routes and the revalidation
hooks, and deleting the interim refusal, is the next commit; the refusal stays
until the guard that replaces it exists.

local checks: NOT RUN

* feat(management): honour a confirmed plan on Aside profile changes

Replaces the interim refusal with the real guard. A bound profile toggle or
restore now re-plans that exact profile scope and compares the fingerprint
before anything is written, and a mismatch returns 409 with the fresh plan.

Placement is the whole point here. The hooks this passes through sit ahead of
the preference write and the journal import, both of which happen before any
writer lock is taken, so a check under that lock would fire after the thing it
was meant to prevent.

The guard and the mutation share one roster by construction: a bound request
replaces the injected models with the passive snapshot for both, so they cannot
disagree about what would be written for any reason except the state genuinely
moving. Without a cached roster the request is refused rather than planned
against a gathered one.

A binding still requires an exact profile, since one fingerprint cannot honestly
describe several independently changing files, and bulk profile mutation stays
unbound.

local checks: NOT RUN

* fix(management): take the roster and its identity in one read

The roster was captured by an awaited call and its snapshot identity read
afterwards, so a concurrent export load could publish a new snapshot in between.
The guard would then hold the identity of one snapshot while the mutation held
the roster of another, and the check would pass by validating the wrong pair.

previewExportSnapshot returns both from a single synchronous read of one
reference, and every bound path now carries that pair: the input is built from
its roster and the guard compares its identity. Nothing reads the identity
independently afterwards.

local checks: NOT RUN

* fix(management): keep the roster snapshot independent of its producer

Freezing the array left the model objects shared with the caller that produced
them, so anything editing one in place would have silently rewritten the roster
a later preview plans against, and moved the fingerprint with it. The snapshot
is now a deep clone.

Also corrects the recovery claim in the comment. I had named /api/models, which
calls listManagementModelRows and therefore populates nothing. The path that
does populate it is the Integrations collection read, which is the page an
operator must open before they can confirm anything, so a cold process recovers
through the ordinary flow rather than a special step.

local checks: NOT RUN

* test(management): a refused confirmation writes nothing anywhere

Asserting the target file's bytes was too narrow. A snapshot, an ownership
record or a journal row written on the way to a refusal is still a write, and
those live in the store rather than in the client's config, so the old
assertion would have passed straight through them.

The refusal case now compares the whole store listing before and after.

local checks: NOT RUN

* fix(management): clone the roster on the way out too, and check writes by content

Two halves of the same mistake, both found by review.

The retained snapshot was cloned on the way in but handed out by reference, so a
reader holding those objects could edit the roster every later preview plans
against without going near this module. Reads now clone as well, with the same
atomic identity, and the regression mutates both a model and a nested array
through a read before asserting a fresh read is unaffected.

And the zero-write assertion compared file names. A journal append, an
overwritten ownership record and a replaced snapshot all leave the listing
identical, so it would have passed straight through every one of them. It now
compares content.

That test also stopped accepting either refusal. With a roster present the only
way to reach 409 is a fingerprint comparison, so it asserts exactly that and the
case can no longer pass without the binding being compared at all.

local checks: NOT RUN

* test(management): pin the interleaving the identity check exists for

Publishes a new roster from the lock-acquisition seam, which puts the
replacement exactly where it is hardest to notice: after the request captured
its input and before the guard runs under the lock.

A guard that re-read the roster at that moment would validate the new one and
write the old. That is the failure the captured-pair ordering exists to make
impossible, and until now nothing proved it stayed impossible. The commit comes
back stale and the client file is untouched.

local checks: NOT RUN

* test(management): carry a bound undo all the way through

Every binding case for restore so far was a refusal, which proves the guard can
say no but not that a correct confirmation still reaches the writer. A guard
that refused everything would have passed all of them.

Applies, previews the resulting journal row, commits the undo with that exact
operation and fingerprint, and asserts the file actually changed back.

local checks: NOT RUN

* feat(management): route the Aside profile preview

The profile plan owner existed but nothing served it, so the dashboard had no
way to obtain a plan for a profile it was about to change. A bound profile
request could only ever have been refused, because no caller could get the
fingerprint it needed.

POST on a profile's preview path plans that one profile, using the passive
roster like every other preview and refusing when none is cached. An unscoped
preview is rejected: a plan describes one profile, so there is nothing for an
unscoped one to describe.

Also extends the interleaving case to witness the whole store's content rather
than the target file alone, since a snapshot or journal row written before the
guard refused would be invisible to a bytes check on one file.

local checks: NOT RUN

* docs(structure): record who owns a mutation plan and why it is placed where it is

The integration contract gains a read-only plans section covering the single
shared observation, the strict dependency direction, the two effects a preview
declines by name, the declared path grammar, and the fingerprint's inputs and
placement. Aside is written down as the exception that proves the placement:
it persists preferences and imports journal rows before any writer lock, so its
check runs earlier rather than under one.

The management API contract gains the three preview endpoints, what they
refuse and why, and the paired binding rules on the mutation routes.

Both say plainly that the fingerprint is an optimistic token and never
authorization, because that is the sentence a future change is most likely to
forget.

local checks: NOT RUN

* fix(management): retire the roster snapshot when discovery moves underneath it

The config key could not see the case that matters most: the same configuration
resolving to different models because a discovery completed. A plan built
before that and confirmed after it would have described a roster the provider
no longer has.

The snapshot now carries the model cache's own generation for each configured
provider, and a preview is only served while that still matches.

Reading it needed a passive observer. captureModelCacheGeneration seeds an
entry for a provider it has not seen, which is right for a discovery about to
run and wrong for a caller that must change nothing, and
isModelCacheGenerationCurrent inherits that. observeModelCacheGeneration reads
the same stamp and treats absence as zero, so observing a provider cannot alter
what a later capture returns.

This is the gathered half of the authority. The configuration half is still a
content digest over a hand-maintained field list, because neither candidate
generation owner advances on the config writes that change a roster; that
remains open rather than papered over.

local checks: NOT RUN

* test(management): assert what a successful undo actually does

The bound-restore case read the config file back after the undo, which cannot
work: Hermes has no file before the apply, so the snapshot apply takes is
"none" and a successful undo deletes the file rather than rewriting it. The
assertion would have thrown on a passing implementation.

It now asserts the file is gone and that the journal carries both the restore
row and the apply it undid, which is where the evidence actually lives.

local checks: NOT RUN

* fix(models): retire a derived roster on publication, not on authority change

The stamp I bound was the cache generation, and that advances when an authority
clear revokes an in-flight discovery's right to publish. It does not move when a
discovery succeeds and publishes different rows, which is the case a derived
roster most needs to notice. My regression incremented the generation by hand
and so never exercised the real trigger.

A separate revision now counts accepted publications and removals. It is
deliberately not the generation: moving that on a successful publication would
cancel cache writes that are still legitimate, which is the opposite of what it
is for. Reading stays passive, with an unseen provider at zero rather than a
seeded entry.

The regression drives a real setCached with changed rows.

The configuration half of this authority is still a content digest over a
hand-maintained field list, as noted before, and is still open.

local checks: NOT RUN

* fix(integrations): plan the undo row the mutation will actually use

An Aside profile restore resolves a journal row through findAsideOperation,
which selects a specific row from a specific store, and Aside can legitimately
hold more than one valid copy. The preview re-resolved from a reconstructed
scope, so a plan and the mutation it authorized could each pick a different
valid row. The fingerprint then compared two plans that were never about the
same operation.

The route resolves once and passes the exact row and its source store into both
the preview and the guard, and neither resolves again. The general restore
observation accepts a pre-selected row for the same reason.

This is the same shape as the roster substitution fixed earlier: the check was
correct in form and attached to a different object than the mutation used.

local checks: NOT RUN

* fix: unblock the typecheck and finish carrying one selected row and one content revision

Four corrections.

observeRestore took a parameter named resolved into a function that already
declares a local of that name, which is the compile error that took the whole
gate red. The parameter is now selectedOperation.

The Aside restore mutation still resolved its own copy of the journal row after
the preview and guard had been given an exact one, so the three could disagree
on a duplicate store. It now accepts the selected row and uses it.

A wholesale cache clear empties the map, so no per-provider counter can record
it and every derived roster would have read as unchanged. The observed revision
now carries a global term that a clear advances, which also lets the
per-provider entries be dropped in the same step without an ABA when a provider
returns.

Dropping those entries on a clear is also what stops the map growing with
providers that no longer exist.

local checks: NOT RUN

Not claimed: this does not resolve gather concurrency in general, only the
publication and clear events a derived roster must notice.

* fix(models): prune revision entries, and advance the global term before dropping one

Reconciliation tracked every per-provider map except the new revisions, so a
provider the configuration no longer has kept its entry for the life of the
process unless something cleared the whole cache, which may never happen.

Dropping the entry alone would have been an ABA: the provider returns, its
entry comes back at zero, and a roster built before it left matches again. The
global content term is advanced before any deletion, so a returning provider
cannot present the counter a stale roster was built against.

Regressions cover both events that no per-provider counter can express: a
wholesale clear, and a provider removed and then brought back.

local checks: NOT RUN

* test(management): prove a bound profile change is planned, committed once, and refused when stale

Three cases the binding had none of.

Profile zero is planned successfully, because zero is a real profile id and the
kind of thing an absent-check turns into a bug.

A previewed profile change commits with its binding and then reports itself
stale on replay, with the profile's file unchanged and a sibling profile
untouched.

And a stale confirmation is refused with the preference never saved. That last
assertion is the one that matters for placement: Aside writes its preference
before any writer runs, so a check that fired under the writer lock would have
saved it already and the test would fail.

local checks: NOT RUN

* fix(models): drop a pruned provider's revision after the cache deletion that bumps it

The prune deleted the revision entry and then called the cache deletion, whose
own bump recreated the entry it had just removed. The map therefore still grew
with providers the configuration no longer has.

Deletion now happens last. The global epoch is already advanced above it, so
removing the entry is still not an ABA when the provider returns.

local checks: NOT RUN

* test(models): make the prune case actually remove a cached provider

The reconcile regression supplied its roster, which skips the gather, so
nothing tracked the provider and the prune had nothing to remove. It asserted
the snapshot was retired by a code path that never ran.

The provider is now cached before the removal and cached again on return, so
the case exercises a real prune and a real ABA opportunity rather than an
empty one.

local checks: NOT RUN

* test(management): witness the whole store when a profile confirmation is refused

The stale profile case checked the target file and the saved preference. Neither
sees an ownership record, a snapshot or a journal row, and an Aside restore
imports history before any writer runs, so the two writes most likely to slip
through were exactly the ones not being watched.

It now compares the whole Aside tree and the whole store by content before and
after the refusal.

local checks: NOT RUN

* fix(management): identify a roster by the configuration that was admitted, not a field list

The snapshot key was a digest over fields I chose, which is only as complete as
whoever last thought about it: a field it forgets is a roster change nothing
notices, and the reviewer was right that it already missed export-affecting
configuration.

It now uses the admission snapshot, which hashes the configuration file in the
same read it parses, so no window exists between hashing and reading and no
list needs maintaining.

Unreadable configuration yields no key, and that fails closed in both
directions: nothing is retained and nothing is served. A preview with no
provable idea of which configuration a roster belongs to is worse than no
preview.

One residual is named in the code rather than papered over: the digest
describes the file on disk while the roster was built from an in-memory
configuration a caller supplied, and proving those are the same needs the
admitted configuration to carry its own revision. That is separate work and is
not claimed here.

local checks: NOT RUN

* fix(management): a missing config file is defaults, not an unprovable configuration

Binding the roster to the admission digest introduced a regression I caught
reading my own change back: the snapshot reports no digest both when the file
cannot be parsed and when it simply is not there. Collapsing those together
would have refused every preview on a machine with no configuration file,
which is the ordinary state of a fresh install and of CI.

Absence is now its own stable identity. A file that exists and cannot be parsed
is genuinely unprovable and still fails closed, which is the case the guard was
for.

local checks: NOT RUN

* test(management): pin both halves of the configuration identity

An absent configuration file is defaults and must serve a roster, or the
feature looks dead on a fresh install and in CI. A file that exists and cannot
be parsed says nothing about which configuration a roster belongs to and must
fail closed. Those are different states and the code now treats them so.

The cases run against their own configuration directory rather than whatever
the machine happens to have, which is also what makes the second one
expressible at all.

local checks: NOT RUN

* docs(management-api): document previewing and confirming an integration change

Covers the three preview routes, the plan's shape, and what a caller must do
with each refusal: a stale confirmation carries a fresh plan and needs another
decision rather than a retry, and an unavailable roster is the state of a
freshly started proxy that reading the integrations collection resolves.

States plainly that a fingerprint is an optimistic check and never
authorization, and that a plan returns no configuration value, file location or
selected member identity.

The seven translated copies still need the same contract; they are unwritten
and this English page does not contradict them, it is ahead of them.

local checks: NOT RUN

* docs(ko): document previewing and confirming an integration change

Korean copy of the preview and binding contract, written to the page's own
register rather than transliterated from the English.

Six locales still need it. They are abridged rather than full mirrors of the
English reference, so each needs a section sized to the page it lands on.

local checks: NOT RUN

* docs(ja, fr): document previewing and confirming an integration change

Japanese and French copies, each written to its own page rather than
transliterated, and each sized to a reference that is abridged relative to the
English one.

Four locales remain: ru, tr, zh-cn and zh-tw.

local checks: NOT RUN

* docs(ru, tr, zh-cn, zh-tw): document previewing and confirming an integration change

Completes the localized reference coverage. All seven translations now carry
the three preview routes, the plan's shape, the two refusals and what a caller
should do with each, and the rule that a fingerprint is an optimistic check
rather than authorization.

Each is written to its own page rather than transliterated, and sized to a
reference that is abridged relative to the English one.

local checks: NOT RUN

* docs: correct what an unavailable roster actually means

I wrote that the refusal means a roster has not been established yet and that
reading the integrations collection establishes one. Both were too strong.

The refusal means no usable roster is currently retained, which covers a cold
process and equally a roster retired because the configuration or the provider
cache moved. And the collection read only establishes one when discovery
succeeds and the configuration can be identified, since publication is declined
without a configuration identity. It is the usual remedy, not a guarantee.

Corrected in the English and all seven localized references and in the
integration contract.

local checks: NOT RUN

* test(management): a duplicate copy of an operation cannot redirect a bound undo

Aside can legitimately hold the same operation in more than one profile store,
and that is the situation the row-resolution fix exists for: a preview and the
mutation could each resolve a valid row and resolve a different one, leaving
the confirmation bound to an operation other than the one that runs.

Copies a journal row into a sibling profile so the request has two valid rows
available, then previews and commits a bound undo for the profile that was
asked for. The undo acts on that profile and the sibling is untouched.

local checks: NOT RUN

* test(management): make the duplicate copy one resolution actually has to choose

The previous version copied the row into a sibling profile, which nothing ever
scans: operation rows come from the requested profile's store and the root
store only. The duplicate was unreachable, so the case passed whether or not
the selected row was carried through, which is the one thing it existed to
prove.

It now puts a stored copy in the root store and expires the profile's own, so
resolution prefers the alternate and the request genuinely depends on which
copy was chosen. The undo restores the original bytes from that copy, the
journal records both it and the apply it undid, and the sibling profile's store
is unchanged by content.

local checks: NOT RUN

* fix(models): carry each provider's revision out with the rows it vouches for

Sampling the cache revision after a gather returns is wrong under concurrent
flights. Flight A can publish rows and retain them while flight B publishes
before A's await resolves, so the roster recorded A's rows under B's revision
and every later check agreed it was current.

Every provider result is built through one helper, and that helper now stamps
the provider's content revision as it constructs the result. That is the only
point synchronous with choosing the rows; anywhere later is another chance for
the two to come from different moments. The flight carries the map out, the
gather exposes it through the same out-parameter pattern its other flight-local
authority already uses, and the export projection retains those revisions
instead of observing globals.

A provider the gather did not report falls back to observation so the stamp
stays total. That covers a provider configured after the rows were chosen, and
it retires the snapshot on the next read rather than implying the roster
covered it.

A supplied roster still observes, because no gather happened and there is
nothing tighter available.

local checks: NOT RUN

* test(integrations): make the captured-row handoff observable, not merely plausible

The HTTP duplicate case proved resolution finds the alternate copy, but it
would still pass if the selected row were dropped on the way to the writer,
because a fresh lookup would find the same row again. It tested discovery, not
the handoff.

A lower-level case now removes the row from the journal a fresh lookup reads
and restores with the row already captured. Only the captured row can carry
that through; a resolver that looked it up again would find nothing and refuse.

The route case keeps its job as route proof and its assertions are now exact:
the restored bytes, a restore row and the original operation found by parsing
the profile's own journal rather than a substring of two files concatenated,
the chosen copy unrewritten, and the sibling profile unchanged in both its
document and its store.

local checks: NOT RUN

* test(integrations): choose the captured copy when only lookup diverges

The previous version of this case deleted the operation the fresh lookup would
find, which is not reachable: deleting the newest row throws before restore, and
deleting an older one prunes the snapshot the unchanged-source guard checks. It
proved nothing it claimed to prove.

The divergence is now confined to enumeration. The root store's listOperations
hides the copied row after capture while findOperation and readSnapshot stay
real, so re-resolution lands on the profile store's expired copy and refuses
before any write, and only the captured row carries the restore through. The
refusal is taken through the public entry point and witnessed with no saves, an
unchanged profile store tree, unchanged applied bytes and an unchanged source.

The routes case now asserts the success envelope and pins the single restore row
to the opId that envelope returned, and witnesses the root snapshot bytes rather
than only the root journal.

local checks: NOT RUN

* test(models): interleave two publications inside one export load

The production fix carries each provider's content revision out with the rows it
vouches for, and nothing exercised the interleaving it exists for.

This runs a real one. The load gathers two providers, alpha answers immediately
and beta is held open, so the load is still inside its own await once alpha has
chosen, published and stamped its rows. A competing publication for alpha lands
in that window. The load still returns the rows it fetched, which is correct,
but the retained preview is refused because the revision that vouches for those
rows is no longer the current one.

Reverting the fix makes the retained stamp the competing publication's, so the
preview would match on the way out and serve those rows as current: the second
case fails. The first case is the control, so a preview refused for an unrelated
reason cannot pass for the race being closed.

local checks: NOT RUN

* fix(management): identify a roster by the configuration in hand, not only the file

The snapshot key named the configuration file and nothing else, so it could not
tell which in-memory configuration a roster was actually built from. Two callers
holding different configuration objects that correspond to the same bytes shared
one key, and a configuration edited in place while a load was awaiting was
invisible to it. That was recorded as a known residual rather than fixed.

The identity now carries both terms: the admission snapshot's file digest and a
canonical structural digest of the configuration object itself. Structural for
the same reason the file digest exists, because a list of the fields that seemed
to matter is only as complete as whoever last thought about it, and it already
missed export-affecting configuration once.

The load takes that identity before the gather and requires it to be unchanged
after. Reading it only at retention would attribute an edit that landed during
the await to rows chosen under the previous configuration, which is the same
substitution the per-provider revision prevents one layer down. A configuration
that moves during a load leaves no snapshot rather than one recorded under an
identity its rows never had.

Null is unprovable in either term and every caller fails closed on it. Nothing
derived from the configuration is logged or serialized; the digest travels and
the configuration does not.

The existing case asserting that a blocklist or custom-model edit retires the
snapshot was left behind by the move to a file-only key and could not have been
passing; it is covered again by construction, and a new case pins the in-memory
divergence directly, including a field no hand-written list ever named.

local checks: NOT RUN

* fix(management): gather and project one admitted configuration, then prove it

A roster was identified by the configuration file and, since the previous
commit, by the configuration object as well. Both terms were read around the
gather rather than carried through it, so one pass could still gather under the
state it found and project under whatever the resident object had become, and a
file that was readable but did not load cleanly was accepted on the strength of
its digest alone, before anything looked at what the parse produced.

An export load now detaches the configuration it is about to use and runs the
whole authoritative pass against that copy: the gather, the projection and the
visibility filter all see one state. The detachment is a real copy rather than a
serialization, because serializing drops functions silently and invokes getters
and toJSON, which would let the object decide what the check sees. An accessor,
a cycle, and any value JSON could not have produced are refused rather than read.
A provider's fetch executor is the one field that is not data; it is carried by
reference so the transport still works and swapping it invalidates the binding.

Before anything is retained the admission is revalidated against three things
that move independently: the file, the resident object, and the detached copy a
consumer was handed. Only then does the roster become preview authority.

The binding deliberately does not require the resident configuration to equal
the file. The proxy routes by what it is holding, so that is what a preview and
the mutation it authorizes must describe, and a file edited under a process that
has not adopted it is supported rather than broken: live reconciliation retains
live changes and the active listener binding on purpose and can persist a
binding the resident object does not have. Demanding equality would make preview
permanently unavailable on those configurations while proving nothing about the
rows.

Pending initial selection is resolved against the live configuration before the
admission is taken, so it still adopts and persists where it always did rather
than committing into a private copy.

The identity a caller carries between a preview and its confirmation is now
process-local and opaque. It used to be the configuration file's digest with a
counter appended, which handed a dashboard a fingerprint of the operator's
configuration dressed as a token.

local checks: NOT RUN

* fix(integrations): freeze the configuration a coordinated write was checked against

A coordinated write freezes every mutable resolution seam before its first
await, and the configuration was the one it still held by reference. The
sequence is plan, await the writer lock, revalidate, then serialize the
document from that input, so a management route editing the live configuration
in that window left the plan vouching for one configuration while the document
described another. The exposure is real rather than theoretical: the client
document carries the proxy base URL and its auth shape, both read from this
object after the check.

The freeze now takes a plain-data copy, so the plan, the revalidation and the
document all read one configuration. The copy is the same detacher the export
admission uses, which refuses an accessor rather than invoking it and carries a
provider transport executor by reference; a configuration it cannot copy is left
as the caller's object, which is no worse than the reference that was there
before.

The regression drives a real coordinated apply and edits the live configuration
inside the revalidation, after it has agreed the write may proceed. Reverting
the freeze writes the edited host into the client document.

local checks: NOT RUN

* fix(integrations): one input from the check to the document, or a refusal

Three places still read the caller's objects twice, with an await in between,
and the second read is not the one any check approved.

The coordinated write froze every resolution seam except the two that carry the
document's content. It now copies the configuration and the model roster as
plain data before the first await, so a management route editing the live
configuration, or a caller editing the model objects it passed, cannot land
between the plan and the bytes.

Aside is the wider window and the more certain one: it checks the confirmation,
awaits the preference write, and only then builds each profile's write input.
That preference write edits the live configuration itself, so the document was
always serialized from a configuration the check had not seen. The context now
captures the configuration when it is created, before the check, and every
profile write and policy read in the action uses that copy. The preference write
remains a real effect on the live configuration.

An input that cannot be copied is refused before the plan, the lock and the
document. Returning the caller's object was a copy in name only, and the caller
went on to describe it as the input it had checked.

The copier moved to src/lib/plain-data.ts and reads through property descriptors
everywhere, including array elements. The previous walk iterated arrays
normally, so an accessor defined on an index would have been invoked by the
check that claimed not to invoke accessors.

Three regressions drive real coordinated writes and edit the configuration, the
roster and the Aside preference in the window each hazard lives in, plus a
refusal case that asserts the accessor is never read.

local checks: NOT RUN

* test(integrations): pin that a committed Aside change leaves the roster available

The commit reloads the roster while holding the configuration its own preference
write just edited. If that load cannot admit what it is holding it clears the
retained roster, and the next confirmation is answered with no roster cached
rather than with a comparison. The route-level case reports exactly that, so
this pins the behaviour at the layer that owns it.

local checks: NOT RUN

* test(integrations): say what a committed Aside change does to the roster

Committing an Aside change writes the operator's preference into the
configuration, so the configuration a roster was admitted under is no longer the
one in hand and the roster is retired. A replayed confirmation is then refused
for the earlier of the two reasons: there is nothing to replan against until an
ordinary load runs.

The route case expected a stale-plan comparison instead. It could only reach one
because its fixture stubs persistence, so the configuration file never moved;
with a real save the file moves and the roster has always been retired the same
way. The expectation now matches what an operator gets, and the case keeps every
assertion that matters: the replay writes nothing and the sibling profile is
untouched.

The owner-level case pins the same sequence at the layer that causes it,
including the recovery: an ordinary load brings the roster back.

local checks: NOT RUN

* fix(integrations): check the Aside input that will be written, prepared before any effect

Two bindings were still open on the Aside path, and both let a check answer
about something other than what the write would use.

The guard rebuilt its own view from the live configuration. The context copies
the configuration when it is created, so a configuration edited to something
else and back again while the action was in flight produced a check that planned
the configuration the operator confirmed, agreed with the confirmation, and let
the write proceed from the copy the action was actually holding. Both entry
points now prepare the write input before the check and hand it to the check,
which plans that input directly instead of reconstructing one.

The roster was resolved lazily at each profile write, which happens after the
preference write. A caller still holding those model objects could edit them in
that window and the document carried the edit. It is now resolved once and
copied before the check, so every profile in one action writes the same roster
and the check reads exactly it.

The check still runs before the preference write and before any import effect,
which is the ordering that makes it useful at all. Preparing an input performs
no write of its own, and a profile that cannot be prepared refuses rather than
reaching an unchecked write.

Two regressions: a confirmed plan taken under one configuration, an action begun
under another, and the live configuration restored before the check, where the
guard must plan the prepared input and refuse; and a roster edited during the
preference write, where the document carries the roster that was checked.

local checks: NOT RUN

* fix(integrations): bring the Aside input forward only for a checked change

Preparing every Aside change's write input before the preference write was too
broad in two ways that CI caught at edbc4dce15.

It resolved the roster for changes nobody checks, and an unconfirmed change
whose preference write fails must not have done model work by then. That is a
contract with its own regression, and this broke it.

It also moved the model load ahead of the preference write for ordinary
toggles, so the roster that load retained was admitted under the configuration
as it stood before the toggle and was retired a moment later by the toggle
itself. A preview taken after an ordinary change then had nothing to plan
against, which showed up as an unrelated preview route answering 409.

Preparation now happens only when a confirmation has to be checked, which is the
case that needs it: the check must read the same input the write will use. An
unchecked change resolves its roster where it always did, after the preference
write, and the write still uses the prepared input when one exists.

The synthesized refusal for a profile that cannot be prepared now carries a
profile id, which the outcome type requires.

local checks: NOT RUN

* fix(config): treat a non-executor provider fetch field as data, not as a refusal

The executor exception was keyed on the field name alone, so a provider whose
configuration happens to carry a `fetch` value that is not a function refused
the whole admission and took previews away for a field nobody calls. The
exception now applies when the value is an executor; anything else is copied
and compar…
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
… Mode (#5228)

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

Completes review findings left open when #5208 merged: normalizeAnthropicImages now receives the request abort signal at the anthropic adapter and claude-messages passthrough call sites (abortSignal moves onto NormalizeOptions so both entry points accept it), and the decode gate re-checks aborted after admission so a request cancelled while queued never starts a native decode. Adds regression coverage for the post-admission abort and for rejecting an image whose dimensions header cannot be sniffed.

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

The web-search and image-bridge loops build each attempt from an iteration-local shallow copy (iterParsed) of the outer parsed request, but rotateSidecarProviderOn429 rebound only the outer parsed. On a Kiro OAuth rotation the retried request kept the failed account's _kiroAuthContext and continuation/replay scope, pairing the new account's bearer with the previous account's routing metadata.

The on429 hook now receives the exact iterParsed the retry is built from. The shared hook hands it to applyFailoverSnapshot, which already syncs _kiroAuthContext for a supplied retry request, and rebinds the route reasoning-replay/continuation scope on it — the same pattern the continuation loop uses for nextParsed.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
* feat(dashboard): preview-bound confirmations for file integrations

Every file-integration mutation dialog now fetches the server-owned
plan, renders bounded value-free change kinds and managed paths, and
submits the exact operation plus plan fingerprint. A stale plan
replaces the display, announces the change, and requires an explicit
re-confirmation; nothing auto-retries. Unavailable previews recover
through the ordinary page load. Bulk disable plans each client
independently and never reuses a fingerprint. All strings are
localized in every catalog; accessibility behavior is preserved.
Native integrations and the all-profiles switch stay on their existing
owners.

Part of #5118

* fix(dashboard): bind drift intent to the plan and fix review gates

Review fold: restore state now binds confirmDrift alongside the active
plan — a stale applicable plan retains the failed request's drift flag
and a drift refusal strengthens the binding, with a regression proving
exactly one explicit re-confirmation and no auto-retry. The consequence
dialog drops its synchronous prop-to-state effect for a
fingerprint-keyed override. Plan duplicate detection uses a
Map<kind, Set<path>> instead of a NUL-delimited string that tripped the
i18n lint.

Part of #5118

* fix(dashboard): cancellable previews, refusal guidance, accessible pending states

Review fold: preview reads are abortable and dismissable (Escape,
backdrop, Close) with generation fences so late results cannot reopen a
dismissed dialog, while pending mutations keep their dismiss policy.
Known refusal reasons map to localized reason/action guidance in all ten
catalogs with a generic fallback and no raw server text; mutations
announce a localized pending status with aria-busy; and the privacy
assertion now feeds a hostile malformed preview through the real page,
asserting generic failure with no DOM leakage.

Part of #5118

* fix(dashboard): load the restore preview outside the effect body

react-doctor's no-set-state-after-await-in-effect fired on the restore
dialog's preview effect. Preview loading now lives in a memoized async
callback that the effect only invokes and cleans up; all post-await
state updates happen inside the callback. Abort, generation fencing,
drift binding, and stale reconfirmation are unchanged.

Part of #5118

* fix(dashboard): defer the initial preview load per repo convention

Review fold: the previous fix only moved the lint-visible site; the
deferred load now follows the repository's own convention — the effect
schedules window.setTimeout(() => void loadPreview(), 0), and cleanup
clears the timer first, then invalidates the generation and aborts.
Abort-on-dismiss, late-result fencing, drift binding, and stale
reconfirmation are unchanged.

Part of #5118

* fix(dashboard): reconciliation-safe previews and deterministic tests

Review fold: loadPreview now depends only on the restore identity with
latest callbacks in refs, so a parent reconciliation no longer restarts
the preview or clears a mutation failure; preview-blocking and mutation
failures are distinct states, and the retry-button contract holds. The
cancel test waits for the observable preview signal before canceling,
and the Aside test waits for an enabled Restore and asserts one exact
bound POST. No auto retry anywhere.

Part of #5118

* fix(dashboard): update latest-callback refs in the commit phase

react-compiler's no-ref-current-in-render fired on the restore dialog's
latest-callback refs. They now update in a commit-phase effect, so
reconciliation never mutates refs during render and preview loading
stays identity-scoped. Abort, fencing, deferred loading, drift binding,
and stale reconfirmation are unchanged.

Part of #5118

* test(dashboard): synchronize restore clicks on observable readiness

Final gates fold: the remaining restore interaction cases now wait for
an enabled Restore before clicking and assert exactly one bound POST
with the expected opId, confirmDrift, operation, and fingerprint. All
timing, payload, and profile assertions preserved.

Part of #5118

* docs(pr): preview-confirmation screenshots for the integration plan dialogs

Captured from the exact-head hosted build (dashboard-preview artifact
bf1bf42, gui tree ce7f101 == PR head 580f087's gui/
tree) served statically with fixture API responses; real browser at
1280x720 and 480x800. Fixture-rendered GUI proof, not a live backend.

Part of #5118

* docs(pr): Korean narrow-viewport and keyboard captures + capture receipt

Supplement from the same provenance-checked artifact (gui tree
ce7f101, unchanged at this head): Korean locale at 390 CSS px
(restore-drift, stale-reconfirm) and a keyboard focus ring capture with
Escape dismissal verified. The receipt records fixture routes, request
sequences, viewports/DPR, provenance, and SHA-256 for every image.

Part of #5118

* docs(pr): add the reproduction command to the capture receipt

The receipt now records the fixture-server start command and the Aside
repl driver path so the captures are reproducible from the artifact.

Part of #5118

* docs(guides): explain the preview-confirm flow in the integrations guide

The original issue's step 5: a concise user-facing section on preview,
review of bounded change paths/kinds, confirm, stale-plan re-confirmation
(never auto-retry), reload recovery for unavailable previews, and the
single-profile Aside scope. English plus the three existing translations
(fr, tr, zh-tw); no new locale files.

Part of #5118

* fix(dashboard): describe no-op plans as document-scoped

Final acceptance fold: a willChange:false plan means the managed client
document needs no changes — not that nothing happens; a profile-scoped
no-op still saves the sync preference on confirm, and the dialog now
says so in all ten catalogs. The integrations guide section matches in
all four of its languages. Binding and mutation semantics unchanged.

Part of #5118

* fix(dashboard): promise rollback only when the plan includes one

Final render-accuracy fold: the consequence dialog rendered its
backup/rollback copy unconditionally, which is false for a no-op plan.
The slot now renders only when the active plan (including a stale
override) contains snapshot or journal changes; unbound legacy dialogs
keep their generic copy. Assertions cover both directions.

Part of #5118

* docs(pr): publish final integration preview evidence

* fix(dashboard): preserve aggregate Aside mutations
…nCode gateways (#5240)

* fix(registry): add modelResponsesTerminalRepair for muse-spark on opencode-go

* fix(registry): add modelResponsesTerminalRepair for muse-spark on opencode-zen

* test(registry): add regression tests for muse-spark terminal repair
* docs: close contract implementation campaign and record release handoff

* docs: retain active release follow-up in its own plan unit

* docs: distinguish historical checkpoints from final closure
Co-authored-by: ingwannu <ingwannu@teamwicked.me>
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 20, 2026 03:34
@lidge-jun
lidge-jun merged commit 7c625fc into main Sep 20, 2026
21 of 36 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 20, 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-20T03:35:41.580524Z 015c67c 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.

@lidge-jun
lidge-jun deleted the release/2.60.0 branch September 20, 2026 03:34
@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 598 files, which is 298 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: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d065bc33-979b-462a-a90c-131a8a21b4fd

📥 Commits

Reviewing files that changed from the base of the PR and between 134c92a and 015c67c.

⛔ Files ignored due to path filters (17)
  • .github/pr-assets/364-prompt-layer-unmapped.png is excluded by !**/*.png
  • .github/pr-assets/508-grok-coupon-unknown.png is excluded by !**/*.png
  • .github/pr-assets/5088-integrations-failed-cold.png is excluded by !**/*.png
  • .github/pr-assets/5089-claude-desktop-malformed-status.png is excluded by !**/*.png
  • .github/pr-assets/5197-apply-desktop.png is excluded by !**/*.png
  • .github/pr-assets/5197-apply-narrow.png is excluded by !**/*.png
  • .github/pr-assets/5197-keyboard-focus.png is excluded by !**/*.png
  • .github/pr-assets/5197-ko-profile-disable-noop-390.png is excluded by !**/*.png
  • .github/pr-assets/5197-ko-restore-drift-390.png is excluded by !**/*.png
  • .github/pr-assets/5197-ko-stale-reconfirm-390.png is excluded by !**/*.png
  • .github/pr-assets/5197-overwrite-foreign-desktop.png is excluded by !**/*.png
  • .github/pr-assets/5197-overwrite-foreign-narrow.png is excluded by !**/*.png
  • .github/pr-assets/5197-restore-drift-desktop.png is excluded by !**/*.png
  • .github/pr-assets/5197-restore-drift-narrow.png is excluded by !**/*.png
  • .github/pr-assets/5197-stale-reconfirm-desktop.png is excluded by !**/*.png
  • .github/pr-assets/5197-stale-reconfirm-narrow.png is excluded by !**/*.png
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (598)
  • .github/pr-assets/5197-capture-receipt.json
  • .github/scripts/issue-translation.cjs
  • .github/scripts/issue-translation.test.cjs
  • devlog/_fin/260919_contract_gap_analysis/000_plan.md
  • devlog/_fin/260919_contract_gap_analysis/001_source_research.md
  • devlog/_fin/260919_contract_gap_analysis/002_candidate_dispositions.md
  • devlog/_fin/260919_contract_gap_analysis/003_consensus.md
  • devlog/_fin/260919_contract_gap_analysis/004_source_fingerprints.md
  • devlog/_fin/260919_contract_gap_analysis/005_existing_issue_followups.md
  • devlog/_fin/260919_contract_gap_analysis/010_issue_implementation_paths.md
  • devlog/_fin/260919_contract_gap_analysis/011_delivery.md
  • devlog/_fin/260919_contract_gap_analysis/020_issue_t1.md
  • devlog/_fin/260919_contract_gap_analysis/021_issue_t2.md
  • devlog/_fin/260919_contract_gap_analysis/022_issue_t3.md
  • devlog/_fin/260919_contract_gap_analysis/023_issue_g1.md
  • devlog/_fin/260919_contract_gap_analysis/024_issue_s1.md
  • devlog/_fin/260919_contract_gap_analysis/025_issue_p1.md
  • devlog/_fin/260919_contract_gap_analysis/026_issue_p2.md
  • devlog/_fin/260919_contract_gap_analysis/027_issue_v1.md
  • devlog/_fin/260919_contract_gap_analysis/028_issue_o1.md
  • devlog/_fin/260919_contract_gap_analysis/029_issue_o2.md
  • devlog/_fin/260919_contract_gap_analysis/030_issue_d1.md
  • devlog/_fin/260919_contract_gap_analysis/031_issue_d2.md
  • devlog/_fin/260919_contract_gap_analysis/032_issue_d3.md
  • devlog/_fin/260919_contract_gap_analysis/033_issue_r1.md
  • devlog/_fin/260919_contract_gap_analysis/034_issue_r2.md
  • devlog/_fin/260919_contract_gap_analysis/035_issue_r3.md
  • devlog/_fin/260919_contract_resolution/000_plan.md
  • devlog/_fin/260919_contract_resolution/001_status.md
  • devlog/_fin/260919_contract_resolution/010_dispatch.md
  • devlog/_fin/260919_contract_resolution/020_integration.md
  • devlog/_fin/260919_contract_resolution/021_pr_5125.md
  • devlog/_fin/260919_contract_resolution/022_pr_5126.md
  • devlog/_fin/260919_contract_resolution/023_pr_5127.md
  • devlog/_fin/260919_contract_resolution/024_pr_5129.md
  • devlog/_fin/260919_contract_resolution/025_pr_5130.md
  • devlog/_fin/260919_contract_resolution/026_pr_5134.md
  • devlog/_fin/260919_contract_resolution/027_pr_5138.md
  • devlog/_fin/260919_contract_resolution/028_pr_5152.md
  • devlog/_fin/260919_contract_resolution/029_pr_5153.md
  • devlog/_fin/260919_contract_resolution/030_pr_5155.md
  • devlog/_fin/260919_contract_resolution/031_pr_5157.md
  • devlog/_fin/260919_contract_resolution/032_ci_sideband.md
  • devlog/_fin/260919_contract_resolution/033_schema_report_review.md
  • devlog/_fin/260919_contract_resolution/034_strict_schema_policy.md
  • devlog/_fin/260919_contract_resolution/035_static_policy_resolver.md
  • devlog/_fin/260919_contract_resolution/036_send_assertion_followup.md
  • devlog/_fin/260919_contract_resolution/037_acceptance_ledger.md
  • devlog/_fin/260919_contract_resolution/038_metrics_review.md
  • devlog/_fin/260919_contract_resolution/039_decode_hint_review.md
  • devlog/_fin/260919_contract_resolution/040_preview_review.md
  • devlog/_fin/260919_contract_resolution/041_transport_acceptance_followup.md
  • devlog/_fin/260919_contract_resolution/042_release_followup_authorization.md
  • devlog/_fin/260919_contract_resolution/043_implementation_handoff.md
  • devlog/_plan/260919_5008_antigravity_turn_ordering/000_upstream_contract_evidence.md
  • devlog/_plan/260920_regression_release/000_scope.md
  • docs-site/astro.config.mjs
  • docs-site/src/content/docs/fr/getting-started/quickstart.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/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/fr/reference/management-api.md
  • docs-site/src/content/docs/getting-started/quickstart.md
  • docs-site/src/content/docs/guides/codex-integration.md
  • docs-site/src/content/docs/guides/codex-native-context.md
  • docs-site/src/content/docs/guides/integrations.md
  • docs-site/src/content/docs/guides/model-routing.md
  • docs-site/src/content/docs/guides/providers.md
  • docs-site/src/content/docs/ja/getting-started/quickstart.md
  • docs-site/src/content/docs/ja/guides/providers.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/ja/reference/management-api.md
  • docs-site/src/content/docs/ko/getting-started/quickstart.md
  • docs-site/src/content/docs/ko/guides/codex-integration.md
  • docs-site/src/content/docs/ko/guides/codex-native-context.md
  • docs-site/src/content/docs/ko/guides/providers.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/ko/reference/management-api.md
  • docs-site/src/content/docs/reference/adapters.md
  • docs-site/src/content/docs/reference/cli/lifecycle.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/management-api.md
  • docs-site/src/content/docs/reference/proxy-formats.md
  • docs-site/src/content/docs/ru/getting-started/quickstart.md
  • docs-site/src/content/docs/ru/guides/providers.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/ru/reference/management-api.md
  • docs-site/src/content/docs/tr/getting-started/quickstart.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/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/tr/reference/management-api.md
  • docs-site/src/content/docs/zh-cn/getting-started/quickstart.md
  • docs-site/src/content/docs/zh-cn/guides/providers.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-cn/reference/management-api.md
  • docs-site/src/content/docs/zh-tw/getting-started/quickstart.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/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
  • docs-site/src/content/docs/zh-tw/reference/management-api.md
  • gui/src/components/CompactionRoutingPanel.tsx
  • gui/src/components/codex-set/PromptLayerDialog.tsx
  • gui/src/hooks/useGrokResetCoupons.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/ru.ts
  • gui/src/i18n/tr.ts
  • gui/src/i18n/vi.ts
  • gui/src/i18n/zh-TW.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/ClaudeDesktop.tsx
  • gui/src/pages/dashboard-overview-panels.tsx
  • gui/src/pages/integrations/AsideProfilesPage.tsx
  • gui/src/pages/integrations/ConsequenceDialog.tsx
  • gui/src/pages/integrations/FileIntegrationPage.tsx
  • gui/src/pages/integrations/IntegrationPlanDetails.tsx
  • gui/src/pages/integrations/IntegrationsOverview.tsx
  • gui/src/pages/integrations/RestoreDialog.tsx
  • gui/src/pages/integrations/integration-api.ts
  • gui/src/styles-integrations.css
  • gui/tests/aside-profiles-page.test.tsx
  • gui/tests/claude-desktop-vertical.test.tsx
  • gui/tests/codex-set-prompt-layers.test.tsx
  • gui/tests/compaction-routing-panel.test.tsx
  • gui/tests/fr-localization.test.ts
  • gui/tests/grok-reset-coupons.test.tsx
  • gui/tests/integration-preview-confirmations.test.tsx
  • gui/tests/integrations-api.test.ts
  • gui/tests/integrations-surfaces.test.tsx
  • package.json
  • scripts/structure-ssot.ts
  • scripts/test-layout/layout.json
  • src/adapters/anthropic-image-codec.ts
  • src/adapters/anthropic-image-normalize.ts
  • src/adapters/anthropic.ts
  • src/adapters/base.ts
  • src/adapters/coding-agent/turn.ts
  • src/adapters/command-code.ts
  • src/adapters/cursor.ts
  • src/adapters/cursor/checkpoint-store.ts
  • src/adapters/cursor/discovery.ts
  • src/adapters/cursor/live-transport.ts
  • src/adapters/cursor/request-builder.ts
  • src/adapters/cursor/transport.ts
  • src/adapters/devin.ts
  • src/adapters/devin/cloud-direct/chat.ts
  • src/adapters/devin/cloud-direct/stated-reset-retry.ts
  • src/adapters/google-antigravity-replay.ts
  • src/adapters/google-antigravity-wire.ts
  • src/adapters/google-http.ts
  • src/adapters/google-tool-schema.ts
  • src/adapters/google-wire-compiler.ts
  • src/adapters/google-wire-shape.ts
  • src/adapters/google.ts
  • src/adapters/openai-chat-images.ts
  • src/adapters/openai-chat.ts
  • src/adapters/openai-responses/image-gen.ts
  • src/adapters/openai-responses/passthrough.ts
  • src/adapters/openai-responses/reasoning.ts
  • src/adapters/opencode-go-additional-tools.ts
  • src/bridge/sse.ts
  • src/cli/account-extended.ts
  • src/cli/dispatch.ts
  • src/cli/doctor.ts
  • src/cli/hub.ts
  • src/cli/index.ts
  • src/cli/opencode.ts
  • src/cli/provider.ts
  • src/client/machine-api.ts
  • src/client/machine-listener.ts
  • src/client/runtime.ts
  • src/codex/account-store.ts
  • src/codex/auth-api/account-list.ts
  • src/codex/auth-api/pool-quota-probe.ts
  • src/codex/catalog/gather-capture.ts
  • src/codex/catalog/model-hints.ts
  • src/codex/catalog/parsing.ts
  • src/codex/catalog/provider-models.ts
  • src/codex/catalog/retained-sync.ts
  • src/codex/catalog/routed-gather.ts
  • src/codex/context-compat.ts
  • src/codex/desired-state.ts
  • src/codex/history-job.ts
  • src/codex/history-provider.ts
  • src/codex/history-rollout-read.ts
  • src/codex/internal/catalog-writer.ts
  • src/codex/model-cache.ts
  • src/codex/model-entitlements.ts
  • src/codex/observed-model-denials.ts
  • src/codex/prompt-text-probe.ts
  • src/codex/routing.ts
  • src/codex/shim.ts
  • src/codex/subagent-model-fallback.ts
  • src/combos/failover.ts
  • src/config.ts
  • src/config/admitted-identity.ts
  • src/config/diagnostics.ts
  • src/config/feature-flags.ts
  • src/config/load-degrade.ts
  • src/config/proxy-env.ts
  • src/config/schema/compaction-triggers.ts
  • src/config/schema/config-schema.ts
  • src/config/schema/leaf-validators.ts
  • src/grok/reset-coupons.ts
  • src/images/loop.ts
  • src/integrations/aside-profile-context.ts
  • src/integrations/aside-profile-journal.ts
  • src/integrations/aside-profiles.ts
  • src/integrations/mutation-plan.ts
  • src/integrations/writer.ts
  • src/lab/live/transport.ts
  • src/lab/live/types.ts
  • src/lab/subject/behavior-fingerprint.ts
  • src/lib/admin-secrets.ts
  • src/lib/debug-log-buffer.ts
  • src/lib/debug.ts
  • src/lib/errors.ts
  • src/lib/http-response-semantics.ts
  • src/lib/lab-live-pinned-sender.ts
  • src/lib/pinned-http.ts
  • src/lib/plain-data.ts
  • src/lib/process-control.ts
  • src/lib/provider-outbound.ts
  • src/lib/socks5-fetch.ts
  • src/lib/spend-ledger-owner.ts
  • src/lib/spend-reservation-ledger.ts
  • src/lib/windows-system-proxy.ts
  • src/oauth/callback-server.ts
  • src/oauth/generic-account-failover.ts
  • src/oauth/health.ts
  • src/oauth/index.ts
  • src/oauth/login-flow-state.ts
  • src/providers/derive.ts
  • src/providers/devin-cli-authmode-migration.ts
  • src/providers/key-failover.ts
  • src/providers/model-rename-migration.ts
  • src/providers/model-rename-startup.ts
  • src/providers/openai-virtual-models.ts
  • src/providers/quota/antigravity.ts
  • src/providers/quota/vendor-probes-key.ts
  • src/providers/registry/entries-core.ts
  • src/providers/registry/entries-extended.ts
  • src/providers/registry/model-ids.ts
  • src/providers/registry/model-seeds.ts
  • src/providers/registry/types.ts
  • src/providers/resolved-model-policy-merge.ts
  • src/providers/resolved-model-policy.ts
  • src/providers/stale-vision-classification-migration.ts
  • src/responses/apply-patch-envelope.ts
  • src/responses/freeform-wrapper-scan.ts
  • src/responses/legacy-dotted-tool-name-repair.ts
  • src/responses/progressive-freeform-input.ts
  • src/responses/reasoning-envelope.ts
  • src/responses/state.ts
  • src/responses/tool-name-aliases.ts
  • src/router.ts
  • src/routing/compatibility/behavior.ts
  • src/routing/compatibility/subject.ts
  • src/server/adapter-resolve.ts
  • src/server/auth-cors.ts
  • src/server/chat-completions.ts
  • src/server/claude-messages.ts
  • src/server/effort-row.ts
  • src/server/grok-responses-control-frame.ts
  • src/server/index.ts
  • src/server/index/serve-options.ts
  • src/server/index/spend-ledger-lifecycle.ts
  • src/server/index/websocket-handler.ts
  • src/server/management-api.ts
  • src/server/management-auth.ts
  • src/server/management/aside-profile-routes.ts
  • src/server/management/config-routes.ts
  • src/server/management/context.ts
  • src/server/management/integration-routes.ts
  • src/server/management/metrics-routes.ts
  • src/server/management/model-rows.ts
  • src/server/management/route-registry.ts
  • src/server/management/shared.ts
  • src/server/management/system-restart.ts
  • src/server/management/system-routes.ts
  • src/server/management/usage-aggregate-cache.ts
  • src/server/readiness.ts
  • src/server/relay-eager.ts
  • src/server/relay.ts
  • src/server/request-log.ts
  • src/server/request-metrics.ts
  • src/server/responses-custom-tool-repair.ts
  • src/server/responses-undeclared-tool-guard.ts
  • src/server/responses/adapter-continuation.ts
  • src/server/responses/adapter-dispatch.ts
  • src/server/responses/compact.ts
  • src/server/responses/compaction-routing.ts
  • src/server/responses/core-codex-account.ts
  • src/server/responses/core-combo.ts
  • src/server/responses/core-normalize.ts
  • src/server/responses/core-opaque-recovery.ts
  • src/server/responses/core-options.ts
  • src/server/responses/encrypted-payload.ts
  • src/server/responses/passthrough-delivery.ts
  • src/server/responses/passthrough-dispatch.ts
  • src/server/responses/policy-fallback.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-transport.ts
  • src/server/responses/run-turn-execution.ts
  • src/server/responses/sidecar-execution.ts
  • src/server/responses/ws-upstream.ts
  • src/server/sse-payload-rewrite.ts
  • src/tray/windows-tray.ps1
  • src/types.ts
  • src/types/config.ts
  • src/types/provider.ts
  • src/types/request.ts
  • src/types/tools.ts
  • src/vision/eligibility.ts
  • src/vision/plan.ts
  • src/web-search/executor.ts
  • src/web-search/loop.ts
  • structure/AGENTS.md
  • structure/INDEX.md
  • structure/adapters/compatibility-lab.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/decisions/ADR-5236-responses-http-sse.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/google.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/abort-race.test.ts
  • tests/adapters/adapter-inner-send-budget-wiring.test.ts
  • tests/adapters/adapter-inner-send-budget.test.ts
  • tests/adapters/anthropic/anthropic-image-normalize.test.ts
  • tests/adapters/anthropic/anthropic-quota-dispatch.test.ts
  • tests/adapters/anthropic/anthropic-sidecar-account-failover.test.ts
  • tests/adapters/bridge.test.ts
  • tests/adapters/empty-tool-output-annotation.test.ts
  • tests/adapters/google/google-tool-schema-contract.test.ts
  • tests/adapters/google/google-wire-shape.test.ts
  • tests/adapters/openai/openai-chat-image-normalization.test.ts
  • tests/adapters/openai/openai-chat-native-policy.test.ts
  • tests/adapters/openai/openai-provider-option-e2e.test.ts
  • tests/adapters/terminal-continuation-owner-rotation.test.ts
  • tests/ci-workflows/cold-spawn-warmup.test.ts
  • tests/ci-workflows/docs-provider-preset-counts.test.ts
  • tests/ci-workflows/structure-ssot.test.ts
  • tests/ci-workflows/test-runner.test.ts
  • tests/ci-workflows/warmup-registration.test.ts
  • tests/claude-integration/claude-code-thought-signature-scope.test.ts
  • tests/claude-integration/claude-inbound-cache-stabilize.test.ts
  • tests/claude-integration/claude-messages-endpoint.test.ts
  • tests/claude-integration/claude-native-affinity.test.ts
  • tests/cli/cli-account-pool-verbs.test.ts
  • tests/cli/cli-provider.test.ts
  • tests/cli/hub-invite.test.ts
  • tests/clients/aside-profiles.test.ts
  • tests/clients/client-machine-listener.test.ts
  • tests/clients/client-runtime.test.ts
  • tests/clients/integrations-writer-frozen-config.test.ts
  • tests/clients/mutation-plan.test.ts
  • tests/codex-integration/codex-account-store.test.ts
  • tests/codex-integration/codex-auth-api.test.ts
  • tests/codex-integration/codex-catalog-sync-hardening.test.ts
  • tests/codex-integration/codex-desired-state.test.ts
  • tests/codex-integration/codex-history-provider.test.ts
  • tests/codex-integration/codex-inject-integration.test.ts
  • tests/codex-integration/codex-model-denial-evidence.test.ts
  • tests/codex-integration/codex-prompt-route.test.ts
  • tests/codex-integration/codex-prompt-text-probe.test.ts
  • tests/codex-integration/codex-shim-destroyed-probe.test.ts
  • tests/codex-integration/codex-shim.test.ts
  • tests/codex-integration/codex-sqlite-home.test.ts
  • tests/codex-integration/context-compat.test.ts
  • tests/codex-integration/doctor.test.ts
  • tests/codex-integration/issue-702-expired-replay-state.test.ts
  • tests/codex-integration/main-account-hard-lock-auth.test.ts
  • tests/codex-integration/model-pinned-effort.test.ts
  • tests/codex-integration/multi-agent-compat.test.ts
  • tests/codex-integration/native-main-owner-lifetime.test.ts
  • tests/codex-integration/reserve-auth-context.test.ts
  • tests/codex-integration/reserve-catalog-lifecycle.test.ts
  • tests/codex-integration/reserve-dispatch.test.ts
  • tests/codex-integration/slug-codec.test.ts
  • tests/config/settings-stream-mode.test.ts
  • tests/e2e-style/phase100-native-parity.test.ts
  • tests/fixtures/google-wire-shape-cases.ts
  • tests/fixtures/test-layout-expected.json
  • tests/gui/volcengine-providers.test.ts
  • tests/helpers/codex-shim-install-fixture.ts
  • tests/helpers/combo-failover-upstream.ts
  • tests/helpers/combo-tool-routing-cases.ts
  • tests/helpers/compaction-routing-fixtures.ts
  • tests/helpers/custom-tool-repair-fixtures.ts
  • tests/helpers/deferred-reset-sse-upstream.ts
  • tests/helpers/native-injection-fixture.ts
  • tests/helpers/nested-test-run-lock-controller.ts
  • tests/helpers/owned-spend-home.ts
  • tests/helpers/passthrough-key-url.ts
  • tests/helpers/phase-timing.ts
  • tests/helpers/pool-reauth-cause.ts
  • tests/helpers/request-log-entry.ts
  • tests/helpers/responses-core-source.ts
  • tests/helpers/sideband-relay-probe.ts
  • tests/helpers/spend-ledger-owner-child.ts
  • tests/helpers/sse-stream.ts
  • tests/helpers/warmup-registration.ts
  • tests/helpers/warmup-tokens.ts
  • tests/helpers/ws-upstream-fixtures.ts
  • tests/images/loop.test.ts
  • tests/images/z-handler-activation.test.ts
  • tests/lab/core-lab-boundary.test.ts
  • tests/lab/lab-live-pinned-timeouts.test.ts
  • tests/lib/debug.test.ts
  • tests/lib/pinned-http-content-coding.test.ts
  • tests/lib/process-control-graceful.test.ts
  • tests/lib/socks5-upload-lifecycle.test.ts
  • tests/lib/spend-ceiling-enforcement.test.ts
  • tests/lib/spend-ledger-file-journal.test.ts
  • tests/lib/spend-ledger-owner.test.ts
  • tests/lib/transport-null-body.test.ts
  • tests/oauth/adapter-event-oauth-failover.test.ts
  • tests/oauth/generic-oauth-failover.test.ts
  • tests/oauth/oauth-account-attribution.test.ts
  • tests/oauth/oauth-callback-server.test.ts
  • tests/oauth/oauth-health.test.ts
  • tests/oauth/oauth-manual-code.test.ts
  • tests/providers/alibaba-token-plan-responses-optin.test.ts
  • tests/providers/codebuddy-adapter.test.ts
  • tests/providers/command-code-provider.test.ts
  • tests/providers/cursor/cursor-effort-rows.test.ts
  • tests/providers/cursor/cursor-stream-health.test.ts
  • tests/providers/cursor/cursor-tool-suspended-checkpoint.test.ts
  • tests/providers/cursor/cursor-ultra-mode.test.ts
  • tests/providers/cyber-policy-error-fidelity.test.ts
  • tests/providers/deepseek-inbound-wire.test.ts
  • tests/providers/deepseek-responses-item-id-repair.test.ts
  • tests/providers/devin-adapter.test.ts
  • tests/providers/devin-cli-authmode-migration.test.ts
  • tests/providers/devin-hardening.test.ts
  • tests/providers/devin-image-passthrough.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/github-copilot/github-copilot-account-origin.test.ts
  • tests/providers/github-copilot/github-copilot-stream-contract.test.ts
  • tests/providers/github-copilot/github-copilot-wire-defaults.test.ts
  • tests/providers/kiro/kiro-auth-context-continuation.test.ts
  • tests/providers/meta-muse-oauth.test.ts
  • tests/providers/model-rename-migration.test.ts
  • tests/providers/muse-key-quota.test.ts
  • tests/providers/opencode-cli.test.ts
  • tests/providers/opencode-go-grok46-responses.test.ts
  • tests/providers/opencode-go-luna-wire.test.ts
  • tests/providers/opencode-go-session-header.test.ts
  • tests/providers/opencode-management-transport.test.ts
  • tests/providers/opencode-muse-terminal-repair.test.ts
  • tests/providers/provider-account-quota.test.ts
  • tests/providers/provider-outbound.test.ts
  • tests/providers/provider-registry-parity.test.ts
  • tests/providers/rate-limit-retry.test.ts
  • tests/providers/resolved-model-policy.test.ts
  • tests/providers/upstream-transient-retry.test.ts
  • tests/providers/vision-classification-seed-repair.test.ts
  • tests/providers/xai/grok-effort-inject.test.ts
  • tests/providers/xai/grok-reset-coupons.test.ts
  • tests/providers/zai-reasoning-replay.test.ts
  • tests/responses/chat-completions-endpoint.test.ts
  • tests/responses/chat-conversation-affinity.test.ts
  • tests/responses/chat-json-sse-fallback.test.ts
  • tests/responses/chat-refusal.test.ts
  • tests/responses/empty-completion-core.test.ts
  • tests/responses/fresh-connection-optout.test.ts
  • tests/responses/openai-responses-passthrough.test.ts
  • tests/responses/passthrough-abort.test.ts
  • tests/responses/responses-account-label.test.ts
  • tests/responses/responses-compact-handoff-admission.test.ts
  • tests/responses/responses-compaction-override.test.ts
  • tests/responses/responses-compaction-routing.test.ts
  • tests/responses/responses-console-go-upload-retry.test.ts
  • tests/responses/responses-custom-tool-repair-dispatch.test.ts
  • tests/responses/responses-custom-tool-repair.test.ts
  • tests/responses/responses-custom-tool-stream-consistency.test.ts
  • tests/responses/responses-default-namespace-emit-normalize.test.ts
  • tests/responses/responses-forward-incomplete-quota.test.ts
  • tests/responses/responses-freeform-wrapper-keys.test.ts
  • tests/responses/responses-function-tool-repair.test.ts
  • tests/responses/responses-hosted-tool-min-spread.test.ts
  • tests/responses/responses-image-gen-repair.test.ts
  • tests/responses/responses-inbound-store-default.test.ts
  • tests/responses/responses-legacy-dotted-tool-name-repair.test.ts
  • tests/responses/responses-muse-tool-name-alias.test.ts
  • tests/responses/responses-native-main-refresh.test.ts
  • tests/responses/responses-opaque-blob-recovery.test.ts
  • tests/responses/responses-passthrough-transient-policy.test.ts
  • tests/responses/responses-pool-401-refresh.test.ts
  • tests/responses/responses-preview-main-read-fence.test.ts
  • tests/responses/responses-reasoning-effort-downgrade.test.ts
  • tests/responses/responses-reasoning-summary-passthrough.test.ts
  • tests/responses/responses-self-named-namespace-scrub.test.ts
  • tests/responses/responses-send-budget-counts.test.ts
  • tests/responses/responses-shadow-intercept.test.ts
  • tests/responses/responses-show-thinking-summary.test.ts
  • tests/responses/responses-snapshot-repair-server.test.ts
  • tests/responses/responses-state.test.ts
  • tests/responses/responses-stateless-dangling-call-repair.test.ts
  • tests/responses/responses-tool-search-repair.test.ts
  • tests/responses/responses-undeclared-tool-guard.test.ts
  • tests/responses/sse-failed-tail.test.ts
  • tests/responses/ws-endpoint.test.ts
  • tests/responses/ws-native-steering.test.ts
  • tests/responses/ws-upstream.test.ts
  • tests/routing/combo-management-api.test.ts
  • tests/routing/fastwire-characterization-wire.test.ts
  • tests/routing/fastwire-observability.test.ts
  • tests/routing/probe-lease-dispatch-wiring.test.ts
  • tests/routing/resolved-model-policy-consumers.test.ts
  • tests/routing/router-combo-failover-classification.test.ts
  • tests/routing/routing-policy-fallback.test.ts
  • tests/routing/routing-policy-surface-parity.test.ts
  • tests/routing/subagent-fallback-handle-responses.test.ts
  • tests/routing/subagent-model-fallback.test.ts
  • tests/server/agent-task-recovery-cache.test.ts
  • tests/server/agent-task-recovery-combo.test.ts
  • tests/server/agent-task-recovery-fallback.test.ts
  • tests/server/agent-task-recovery-security.test.ts
  • tests/server/agent-task-recovery.test.ts
  • tests/server/aside-profiles-routes.test.ts
  • tests/server/cancel-body-on-abort.test.ts
  • tests/server/context-history-ownership.test.ts
  • tests/server/management-google-tool-schema-policy.test.ts
  • tests/server/management-integration-routes.test.ts
  • tests/server/management-metrics-export.test.ts
  • tests/server/management-model-roster-gather-race.test.ts
  • tests/server/management-model-roster.test.ts
  • tests/server/plaintext-v2-agent-messages-server.test.ts
  • tests/server/proxy-env.test.ts
  • tests/server/proxy-liveness.test.ts
  • tests/server/response-model-identity.test.ts
  • tests/server/server-agent-task-recovery-replay.test.ts
  • tests/server/server-auth.test.ts
  • tests/server/server-combo-failover-e2e.test.ts
  • tests/server/server-combo-reasoning-replay-eligibility.test.ts
  • tests/server/server-combo-zero-output-failover.test.ts
  • tests/server/server-live.test.ts
  • tests/server/server-management-auth.test.ts
  • tests/server/spend-ledger-lifecycle.test.ts
  • tests/server/spend-ledger-owner-startup.test.ts
  • tests/server/terminal-guard-server.test.ts
  • tests/server/v2-agent-message-failfast.test.ts
  • tests/service/service-tier-capability.test.ts
  • tests/test-layout-tooling.test.ts
  • tests/usage/request-log.test.ts
  • tests/usage/usage-aggregate-cache.test.ts
  • tests/vision/vision-custom-row-precedence.test.ts
  • tests/web-search/web-search-passthrough-bridge.test.ts
  • tests/web-search/web-search-retry-heartbeat.test.ts
  • tests/web-search/web-search-sidecar-429.test.ts
  • tests/web-search/web-search.test.ts
  • tests/windows/windows-deploy-close-regressions.test.ts
  • tests/windows/windows-tray.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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot changed the title release: promote the verified 2.60.0 tree to main [WRONG BRANCH] release: promote the verified 2.60.0 tree to main Sep 20, 2026
@github-actions

github-actions Bot commented Sep 20, 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.