diff --git a/.github/pr-assets/3863-storage-skip-referenced.png b/.github/pr-assets/3863-storage-skip-referenced.png
new file mode 100644
index 0000000000..0fcc6370a4
Binary files /dev/null and b/.github/pr-assets/3863-storage-skip-referenced.png differ
diff --git a/.github/pr-assets/muse-spark-meta-search-content-types-400.jpg b/.github/pr-assets/muse-spark-meta-search-content-types-400.jpg
new file mode 100644
index 0000000000..d18dd98dab
Binary files /dev/null and b/.github/pr-assets/muse-spark-meta-search-content-types-400.jpg differ
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8c15cb696a..00abe5ec24 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,6 +26,10 @@ on:
push:
branches: [main, preview, dev]
paths:
+ - "Dockerfile"
+ - "compose.yaml"
+ - ".dockerignore"
+ - "docker/**"
- "src/**"
- "bin/**"
- "tests/**"
@@ -180,6 +184,10 @@ jobs:
# start the workflow so the aggregate check exists, while these
# paths decide whether the expensive test jobs need to run.
ci:
+ - 'Dockerfile'
+ - 'compose.yaml'
+ - '.dockerignore'
+ - 'docker/**'
- 'src/**'
- 'bin/**'
- 'tests/**'
@@ -423,6 +431,7 @@ jobs:
run: |
bun x tsc --noEmit
bun x tsc --noEmit -p tests/tsconfig.doctor-service-memory-contract.json
+ bun x tsc --ignoreConfig --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts
- name: GUI tests
run: cd gui && bun test --isolate tests
@@ -908,6 +917,26 @@ jobs:
bun run scripts/keyring-smoke.ts
'
+ # Exercise the source-build Compose contract, including real volume reuse.
+ # Host fixtures cannot prove image construction or container recreation.
+ docker-smoke:
+ name: docker smoke
+ needs: changes
+ if: github.event_name != 'pull_request' || needs.changes.outputs.ci == 'true'
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+ - name: Checkout
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
+ with:
+ persist-credentials: false
+
+ - name: Setup project Bun
+ uses: ./.github/actions/setup-project-bun
+
+ - name: Build, start, and recreate the container
+ run: bun scripts/ci/docker-smoke.ts
+
npm-global-smoke:
name: npm-global ${{ matrix.os }}
needs: changes
@@ -986,7 +1015,7 @@ jobs:
# direct dependencies only, so a failing `select-windows-runner` would
# otherwise reach this gate as nothing at all while its dependents report
# `skipped` — which the gate is required to read as a deliberate skip.
- needs: [changes, select-windows-runner, test, storage-policy, api-usage, gates, platform-macos, macos-control, platform-windows, keyring-smoke, npm-global-smoke]
+ needs: [changes, select-windows-runner, test, storage-policy, api-usage, gates, platform-macos, macos-control, platform-windows, keyring-smoke, docker-smoke, npm-global-smoke]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
diff --git a/.github/workflows/cleanup-orphaned-workflows.yml b/.github/workflows/cleanup-orphaned-workflows.yml
index 3c33c21dc8..6915a063ed 100644
--- a/.github/workflows/cleanup-orphaned-workflows.yml
+++ b/.github/workflows/cleanup-orphaned-workflows.yml
@@ -37,7 +37,7 @@ jobs:
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
- bun-version: 1.3.14
+ bun-version: 1.4.2
- name: Remove stale workflow histories
env:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 685a13876b..7b565b6800 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -334,40 +334,57 @@ jobs:
}
- name: Publish (or dry-run)
+ id: publication
env:
DRY_RUN: ${{ inputs.dry-run }}
NPM_DIST_TAG: ${{ inputs.tag }}
run: |
+ set -euo pipefail
if [ "$DRY_RUN" = "true" ]; then
echo "::notice::DRY RUN — building + packing, not publishing"
npm run prepublishOnly
npm pack --dry-run
else
npm publish --tag "$NPM_DIST_TAG" --access public
+ echo "published=true" >> "$GITHUB_OUTPUT"
fi
- # Confirm the registry actually has the new version (real publishes only).
+ # Publication is acknowledged before registry reads, which can lag or fail.
+ # Recover only observation failures in this run; never retry npm publish.
- name: Post-publish registry smoke
- if: ${{ inputs.dry-run != true }}
+ id: registry-smoke
+ if: ${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }}
env:
RELEASE_VERSION: ${{ inputs.version }}
+ PUBLISHED: ${{ steps.publication.outputs.published }}
run: |
- for attempt in $(seq 1 30); do
- if VERSION=$(npm view "@bitkyc08/opencodex@${RELEASE_VERSION}" version 2>/dev/null); then
+ set -euo pipefail
+ test "$PUBLISHED" = "true" || {
+ echo "::error::No successful publication receipt; refusing registry recovery"
+ exit 1
+ }
+ pkg_name="$(node -p "require('./package.json').name")"
+ for attempt in $(seq 1 6); do
+ if VERSION=$(timeout --kill-after=2s 10s npm view "${pkg_name}@${RELEASE_VERSION}" version --fetch-retries=0 --fetch-timeout=8000 2>/dev/null); then
+ if [ "$VERSION" != "$RELEASE_VERSION" ]; then
+ echo "::error::Registry returned an unexpected version; refusing to create a release"
+ exit 1
+ fi
echo "registry version=$VERSION"
- test "$VERSION" = "$RELEASE_VERSION"
- npm dist-tag ls @bitkyc08/opencodex
+ echo "verification=verified" >> "$GITHUB_OUTPUT"
+ echo "Registry verified ${pkg_name}@${RELEASE_VERSION}." >> "$GITHUB_STEP_SUMMARY"
+ timeout --kill-after=2s 10s npm dist-tag ls "$pkg_name" --fetch-retries=0 --fetch-timeout=8000 || echo "::warning::Could not read npm dist-tags; exact version was verified"
exit 0
fi
- echo "::notice::@bitkyc08/opencodex@${RELEASE_VERSION} not visible in npm registry yet (attempt $attempt/30)"
- sleep 10
+ echo "::notice::Registry lookup not confirmed (attempt $attempt/6)"
+ if [ "$attempt" -lt 6 ]; then sleep 5; fi
done
- echo "::error::npm registry smoke failed after 30 attempts"
- npm view @bitkyc08/opencodex versions dist-tags --json || true
- exit 1
+ echo "verification=pending" >> "$GITHUB_OUTPUT"
+ echo "::warning::npm publish succeeded, but registry verification remains pending; continuing GitHub release creation without republishing"
+ echo "Publication acknowledged for ${pkg_name}@${RELEASE_VERSION}; registry verification pending after bounded reads. Inspect the registry before announcing availability. Do not republish this version." >> "$GITHUB_STEP_SUMMARY"
- name: Create GitHub release
- if: ${{ inputs.dry-run != true }}
+ if: ${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_VERSION: ${{ inputs.version }}
diff --git a/Dockerfile b/Dockerfile
index 1ed000743d..8d3e72c619 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Keep the runtime aligned with package.json and pin the multi-platform image index.
-ARG BUN_IMAGE=oven/bun:1.4.0@sha256:5ff609364c049b54eb0ff560ec96319729a972078ef2c755d758f0c6ef89c2d6
+ARG BUN_IMAGE=oven/bun:1.4.2@sha256:9114c058aeae42162ee16dd5084b95fe9473970bb6bcb5b232ab1630f0546895
FROM ${BUN_IMAGE} AS build
WORKDIR /home/bun/app
@@ -25,7 +25,10 @@ RUN cd gui && bun run build
FROM ${BUN_IMAGE} AS runtime
WORKDIR /home/bun/app
+# Docker supervises this foreground process; retain routed state on stop/recreate.
+# This uses the existing service lifecycle mode and does not install a service manager.
ENV NODE_ENV=production \
+ OCX_SERVICE=1 \
OPENCODEX_HOME=/home/bun/.opencodex \
CODEX_HOME=/home/bun/.codex \
OCX_API_TOKEN_FILE=/home/bun/.opencodex/service-api-token
diff --git a/README.md b/README.md
index 61b93b8240..371b222e52 100644
--- a/README.md
+++ b/README.md
@@ -99,6 +99,29 @@ account exclusion, affinity expiry, or 401/403 and 429 recovery can rebind them.
selection order when one of them — usually your Codex Desktop login — should only be reached for
once the others are drained.
+### Sponsors
+
+Sponsors keep opencodex maintained across every upstream protocol change. Interested?
+See [SPONSORS.md](./SPONSORS.md).
+
+
+
+
+
+
+
+
+
Thanks to OrcaRouter for sponsoring this project! OrcaRouter is one OpenAI-compatible AI gateway for production AI: adaptive routing that grades every prompt and sends it to the model that clears your bar, automatic failover, routing rules as code, zero-markup provider pricing with prompt caching, and guardrails, an agent firewall, and request logs on every call across 200+ models. Pick OrcaRouter in the Add provider picker or run ocx provider add orcarouter; orcarouter/auto is the adaptive router.
+
+
+
+
Thanks to PackyCode for sponsoring this project! PackyCode is a stable, high-performance API relay provider, offering relay services for Claude Code, Codex, Gemini, and more. With automatic failover, smart routing, and unlimited concurrency, it turns AI into a real productivity tool. Register via this link and get started! Pick PackyCode in the Add provider picker or run ocx provider add packycode. PackyCode 是一家稳定、高效的 API 中转服务商,提供 Claude Code、Codex、Gemini 等多种中转服务。具备自动故障转移、智能路由和无限并发等多种功能,让 AI 编程成为真正的生产力工具。点此链接注册,立即开始使用!
+
+
+
+
+---
+
Docker Compose
@@ -211,6 +234,7 @@ see the [installation docs](https://opencodex.me/getting-started/installation/).
- **Sub-agents on any model** — feature routed models in Codex's sub-agent picker, with v1/v2
surface control and fallback chains. See the
[sub-agent guide](https://opencodex.me/guides/sub-agent-surface/).
+
- **Log in once, skip the API key** — OAuth for xAI, Anthropic, and Kimi; or forward
`codex login`, paste a key, or use `${ENV_VAR}` references.
- **Web search & vision sidecars** — non-OpenAI models get real web search and image understanding
@@ -263,10 +287,11 @@ full-slash form keeps working too. Details: [model routing docs](https://opencod
## Providers & adapters
+
OpenAI (ChatGPT login or API key), Anthropic, Google Gemini, xAI, Kimi, Azure OpenAI, Ollama
(local + Cloud), Cursor (experimental), and every OpenAI-compatible endpoint — plus DeepSeek,
Groq, OpenRouter, Together, Fireworks, Cerebras, Mistral, Hugging Face, NVIDIA NIM, MiniMax,
-Qwen Cloud, SiliconFlow, and more. Full list: `ocx init` or the
+Qwen Cloud, Qoder Global and CN (official PAT + CLI), SiliconFlow, and more. Full list: `ocx init` or the
[provider docs](https://opencodex.me/guides/providers/).
## CLI
diff --git a/SPONSORS.md b/SPONSORS.md
new file mode 100644
index 0000000000..76a54c377b
--- /dev/null
+++ b/SPONSORS.md
@@ -0,0 +1,105 @@
+# Sponsors
+
+opencodex is an independent, MIT-licensed project maintained without company backing. Provider
+sponsorships fund maintenance and keep the proxy current with every upstream protocol change.
+This page is the public rule set: what a sponsor gets, who qualifies for which tier, and how to
+ask. It is written so that a sponsor, a contributor, and a user reading the README all see the
+same terms.
+
+"Sponsor" here means a paying provider sponsor. It is unrelated to the `maintainer-sponsored`
+label in [`MAINTAINERS.md`](./MAINTAINERS.md), which is about a maintainer vouching for a
+contributor's change to a restricted surface.
+
+Sponsorship buys placement and maintenance attention. It never buys a change in routing behavior,
+a default model, a weaker security default, or an exception to the review policy in
+[`MAINTAINERS.md`](./MAINTAINERS.md). A sponsored preset goes through the same registry
+pattern, typecheck, tests, and review as any other provider.
+
+## Tiers
+
+Two tiers, split by what the sponsor is.
+
+### Main — model developers
+
+Reserved for organizations that train or host their own foundation models (the OpenAI,
+Anthropic, Google, Moonshot, MiniMax class). API relays and gateways are never sold Main
+regardless of budget.
+
+Every model developer is supported as a first-class provider whether or not it sponsors; that
+part does not change. A Main sponsor additionally receives:
+
+- The single banner slot above the sponsor table in the README (one at a time; see
+ [Placement](#placement)).
+- First mention in the README login and provider lines (the "Log in once" OAuth paragraph and
+ the Providers & adapters summary, both marked with a `sponsors:main-first-mention` comment)
+ and priority ordering in the built-in provider picker.
+- Everything in the Standard tier below.
+
+### Standard — relays, gateways, and API resellers
+
+For OpenAI-compatible relays, routers, gateways, and other resellers of model access. A Standard
+sponsor receives:
+
+- One row in the sponsor table: logo (about 150px wide, linking to the sponsor URL), a
+ "Thanks to X for sponsoring this project!" line, and a blurb of up to about 80 English words
+ supplied by the sponsor and published verbatim. The maintainer may decline or require edits to
+ text that is false, misleading, disparages third parties, or breaches applicable law or GitHub
+ policy. A second-language blurb (for example Chinese) may run alongside the English one.
+- A built-in provider preset (`ocx provider add `) shipped in a public npm release,
+ listed near the top of the provider picker in the dashboard and CLI and marked as a sponsor
+ there. (The registry field and picker ordering that back this land with the first sponsor
+ preset; today the picker follows registry order.)
+- A detailed entry on the [providers page](https://opencodex.me/guides/providers/) of the docs
+ site.
+- Maintenance: if a release breaks the preset or its adapter, the maintainer fixes it; issues
+ filed against that provider are triaged first. There is no response-time SLA.
+
+## Placement
+
+The README sponsor section sits directly under **Quick start**, before the Docker Compose
+details, so it is on screen before a first-time visitor scrolls. It carries one line of context
+and the placements themselves:
+
+1. One Main banner (empty until a Main sponsor signs).
+2. The Standard table, one row per sponsor, in order of signing date.
+
+The README says nothing else about sponsorship; tiers, pricing, and contact channels live only on
+this page.
+
+The translated READMEs under [`readme/`](./readme) carry one linking line right after their
+own quick-start block instead of duplicating the section, so a sponsor change is one edit in
+English.
+
+## Pricing
+
+Pricing is by inquiry; there is no public rate card. Sponsors who sign before the repository
+reaches 20,000 GitHub stars lock in their rate for the length of their agreement. Rates rise
+once that mark is passed.
+
+Agreements are integration-scoped: they name the deliverables above, anchor the term to the npm
+release that ships them, and carry no marketing obligations on either side. Both sides can walk
+away with a pro-rated refund of unused months if the integration cannot be delivered.
+
+## How to ask
+
+- X: DM [@claudeebum](https://x.com/claudeebum)
+- Discord: [discord.gg/JEaPEtkHwh](https://discord.gg/JEaPEtkHwh), channel `#sponsors`
+- Email: jun@lidgeai.com
+
+Send what you are (model developer or relay), the base URL and model list of your
+OpenAI-compatible endpoint, and the tier you want. The maintainer replies with terms and a
+draft agreement.
+
+## What sponsors do not get
+
+- No influence on routing defaults, failover order, quota policy, or which provider a user's
+ request reaches.
+- No relaxation of the [security review](./MAINTAINERS.md) that applies to authentication,
+ credentials, or workflow changes.
+- No access to user data, request logs, or telemetry; opencodex does not collect any.
+- No say over unrelated issues, pull requests, or the release schedule.
+
+## Current sponsors
+
+Listed in the README sponsor section. This page carries the rules; the README carries the
+names.
diff --git a/assets/pr-screenshots/client-compaction-dashboard.png b/assets/pr-screenshots/client-compaction-dashboard.png
new file mode 100644
index 0000000000..89c3cf1c40
Binary files /dev/null and b/assets/pr-screenshots/client-compaction-dashboard.png differ
diff --git a/assets/sponsors/orcarouter-overview-mobile.png b/assets/sponsors/orcarouter-overview-mobile.png
new file mode 100644
index 0000000000..a43db45789
Binary files /dev/null and b/assets/sponsors/orcarouter-overview-mobile.png differ
diff --git a/assets/sponsors/orcarouter-overview.png b/assets/sponsors/orcarouter-overview.png
new file mode 100644
index 0000000000..a067b5ea60
Binary files /dev/null and b/assets/sponsors/orcarouter-overview.png differ
diff --git a/assets/sponsors/orcarouter-picker.png b/assets/sponsors/orcarouter-picker.png
new file mode 100644
index 0000000000..2c4e5b1628
Binary files /dev/null and b/assets/sponsors/orcarouter-picker.png differ
diff --git a/assets/sponsors/orcarouter-readme.png b/assets/sponsors/orcarouter-readme.png
new file mode 100644
index 0000000000..dfad19db9e
Binary files /dev/null and b/assets/sponsors/orcarouter-readme.png differ
diff --git a/assets/sponsors/orcarouter.png b/assets/sponsors/orcarouter.png
new file mode 100644
index 0000000000..2d65f01c08
Binary files /dev/null and b/assets/sponsors/orcarouter.png differ
diff --git a/assets/sponsors/packycode-overview-mobile.png b/assets/sponsors/packycode-overview-mobile.png
new file mode 100644
index 0000000000..934fa6341f
Binary files /dev/null and b/assets/sponsors/packycode-overview-mobile.png differ
diff --git a/assets/sponsors/packycode-overview.png b/assets/sponsors/packycode-overview.png
new file mode 100644
index 0000000000..ca86f481f3
Binary files /dev/null and b/assets/sponsors/packycode-overview.png differ
diff --git a/assets/sponsors/packycode-picker.png b/assets/sponsors/packycode-picker.png
new file mode 100644
index 0000000000..0f61d1fa86
Binary files /dev/null and b/assets/sponsors/packycode-picker.png differ
diff --git a/assets/sponsors/packycode-readme.png b/assets/sponsors/packycode-readme.png
new file mode 100644
index 0000000000..36e9f8a667
Binary files /dev/null and b/assets/sponsors/packycode-readme.png differ
diff --git a/assets/sponsors/packycode.png b/assets/sponsors/packycode.png
new file mode 100644
index 0000000000..8b2afee75f
Binary files /dev/null and b/assets/sponsors/packycode.png differ
diff --git a/bun.lock b/bun.lock
index c4619c2866..6161766917 100644
--- a/bun.lock
+++ b/bun.lock
@@ -8,11 +8,11 @@
"@bufbuild/protobuf": "^2.14.0",
"@modelcontextprotocol/sdk": "^1.30.0",
"@napi-rs/keyring": "1.3.0",
- "bun": "1.4.0",
+ "bun": "1.4.2",
"zod": "4.4.3",
},
"devDependencies": {
- "@types/bun": "1.4.0",
+ "@types/bun": "1.4.2",
"typescript": "7.0.2",
},
},
@@ -60,31 +60,31 @@
"@napi-rs/keyring-win32-x64-msvc": ["@napi-rs/keyring-win32-x64-msvc@1.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-4DnCWXwDc0HRKwyRlG5y0VhKZW2tNRQfKKfyj6IX/KWfDNyq9hn4n+GL1auyDcOO/v8PwnhmYo2+rOOqCkvvOg=="],
- "@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.4.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GCpf8QuFLsyioVawP5HrMxA1ZRBlu6Hq9RNnSc3UTUWAzIxBso9trjoZczw1HdgpqSssFkszfIV2zmOzFTjhkw=="],
+ "@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.4.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXdZkP1featqxZ+/VTXWG1BVjM4OGBehVY2Q88EeUj/7L0UMeCGItmyPYTN+wxvlGJ6F66JEtzsw+GvQWewnag=="],
- "@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.4.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cIrhwOr0SPEraewznhC+c/k6TG8bwFn5uZ4EJuXwjiKJLcAF36q7/bGjWkeXSe48JwMcPRUR054JXF7+cRwSSA=="],
+ "@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.4.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-gZTxZuLjkUhAWjTETu3tw0WhsEdNkJ64daj60ybhPf835a2yollV3yTkK9JozvzKPx4TRFzLSl8C+U525pxVbw=="],
- "@oven/bun-freebsd-aarch64": ["@oven/bun-freebsd-aarch64@1.4.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-09x7wnjMR6M5KGBDBhVl2CpfoCIQOkVDbPX2KfIhpXv4N6grbWE7dfLPw/Ydi9gaUMGhU7UKhoz444Nu6RCycA=="],
+ "@oven/bun-freebsd-aarch64": ["@oven/bun-freebsd-aarch64@1.4.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-SMNItMw1Z8QeeQVKnw8jA7xQNkeXdP+OPgin4Wi/QTx/B8RHHLnuZfqmFy7NtVeT2NF0kKYppW4WWd2CCYZjhQ=="],
- "@oven/bun-freebsd-x64": ["@oven/bun-freebsd-x64@1.4.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dRwzti/qJqV1HWplU27iUWUqp+f2DtFSf2yqQKSb+HH2dDOC//Uqd9u/A5h1DMsLszfP5OGP9UwQIKxVwFODaA=="],
+ "@oven/bun-freebsd-x64": ["@oven/bun-freebsd-x64@1.4.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-THbPKXhO54N0DpFRKZNDZpQ7dpbX0bWASuARckAUS9wRtFIHsiY+uULXJvxJGo2YD1YewvXQ4G8Fj7XT5oBCiw=="],
- "@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y5yAtCbHK6JjprXEtkdklDQFPADgs+CkfcliyY5g4JJ8baGHyQSrfpSkX3XVJ2C+aBLsdwNDdW+oczMsAwx6uA=="],
+ "@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.4.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-3BBP9ovJ2RGHFH6Ae1CAtxNtG1+YY6GD6rmYbsUosoAk9+OEl6zeDQ/k4fBkc6dYOJCtWnx8hUxzNzQATSmvYQ=="],
- "@oven/bun-linux-aarch64-android": ["@oven/bun-linux-aarch64-android@1.4.0", "", { "os": "android", "cpu": "arm64" }, "sha512-HpPIxJfDNPBPhiBNMyZoo/dOLijARfsx5j72vNuLtaTvl0Hh7HUculxjsOQ2WSyGoCgqXMEr1Qqjab1im9u1RA=="],
+ "@oven/bun-linux-aarch64-android": ["@oven/bun-linux-aarch64-android@1.4.2", "", { "os": "android", "cpu": "arm64" }, "sha512-3mZKO2rhsNgbAUtAHC1UKUlF2zTxFraDZT/Elv8wzyH0fJL9h+Iv3TgB9lO63w89PRn3eFe+NRA1bhVgikKNPQ=="],
- "@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RUjAAkJ/CdNV++zVxyANWshPc73CECYsfhk0fWAkoJjtywxJ2BwXzI6nopBBDMfs0HS+fhRGn6zGwU8ccxLeJg=="],
+ "@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.4.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+Sm6y+lSiSFBOtXmnekp5Q6n1tUKlyv71FCPWBc61Cgb14T5eBs8SN/nh4MUCOKzONkI3O+as3MGUgikS4aCBQ=="],
- "@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Du44zebtPXJujvMLmtIxEQ6ykOhYt7L/Q+YIGVm+Yy+Pj/fpOnq60ggwIpKp/pGAFbYHNiTrA3JTjuZ9MTbZIg=="],
+ "@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.4.2", "", { "os": "linux", "cpu": "x64" }, "sha512-9/E/UXOTpSo3YsV5g+FhtTd/qTpiWoKuxS12cqtuYA1ssu9fRAoPQnipFgGyck3tWO63iUdxBiygq+kELFawng=="],
- "@oven/bun-linux-x64-android": ["@oven/bun-linux-x64-android@1.4.0", "", { "os": "android", "cpu": "x64" }, "sha512-u++KyLlfMn36yWz+AgJs+fZtS46UFDNpSSZhrcitkytONtNwq0X6Q9BDVEFXxYl/+Eec0xme1rb6MgW+U35WeA=="],
+ "@oven/bun-linux-x64-android": ["@oven/bun-linux-x64-android@1.4.2", "", { "os": "android", "cpu": "x64" }, "sha512-6HC5tzcC79113n2IHCTJMWv+HsQImv4ZFEK2XpYLxY6HbT8tM4cUM2Zv1bHZBQsS3jv/zYBamDJ1UX7If0d5tw=="],
- "@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-C1Dv+ISL8YKEKM9jAHzNifOcRUoziy6UMxh+yVXjUCP6QnbRhENDHLaIWWkQZJyBLTn0I3xozflorAlHiGzGqA=="],
+ "@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.4.2", "", { "os": "linux", "cpu": "x64" }, "sha512-vVTKUg1bnPhRP/Hp73jIVoFh2vPFNYEqYX0ERKfZBOQEEHitNAeukZzzuUDZS0SoDCIpuWUGSpd/CDMbjdR+Uw=="],
- "@oven/bun-windows-aarch64": ["@oven/bun-windows-aarch64@1.4.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-FBAYaQpJBP0asgqzL6NFUfjdQqsV+kvTpJ/eWxPKj+RcDgIfPSuE8kvQuPYu5pa8u8JTujYMjmuyvHxVuQsInA=="],
+ "@oven/bun-windows-aarch64": ["@oven/bun-windows-aarch64@1.4.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-8EJ1ST7339WJE3poPW5nBgVW/lWf9HBz4W27ZUNhburKmcBLOByPyE6DP9fHD8FQGm5c+ilUN2hX1mrW0jxq9Q=="],
- "@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.4.0", "", { "os": "win32", "cpu": "x64" }, "sha512-jRKv1NPLznMSZY5BEWciMF7zv0Tiyo2pQSxAJ3w+YWJ6y3VWNJQQQdLlV5Jx8lbOFDrJdrc9dD3GV17k3BP41A=="],
+ "@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.4.2", "", { "os": "win32", "cpu": "x64" }, "sha512-+bN6OuVld/9diT/RLSXSW7JE6CvNE3gL9XsAEjULi1nUsXd6DNO6GuA9jNdNb3r8PdJFnYHr5aypNV1Oj3Rd9g=="],
- "@types/bun": ["@types/bun@1.4.0", "", { "dependencies": { "bun-types": "1.4.0" } }, "sha512-K+lZULY23vRgK/CfTjFIV+tyifaNdSMlPh9j+6mQ/cLfpOznLyAuzgV/JQysyECpkBQLVMSyvjlr2fBUSA9wFQ=="],
+ "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="],
"@types/node": ["@types/node@26.0.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw=="],
@@ -136,9 +136,9 @@
"body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="],
- "bun": ["bun@1.4.0", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.4.0", "@oven/bun-darwin-x64": "1.4.0", "@oven/bun-freebsd-aarch64": "1.4.0", "@oven/bun-freebsd-x64": "1.4.0", "@oven/bun-linux-aarch64": "1.4.0", "@oven/bun-linux-aarch64-android": "1.4.0", "@oven/bun-linux-aarch64-musl": "1.4.0", "@oven/bun-linux-x64": "1.4.0", "@oven/bun-linux-x64-android": "1.4.0", "@oven/bun-linux-x64-musl": "1.4.0", "@oven/bun-windows-aarch64": "1.4.0", "@oven/bun-windows-x64": "1.4.0" }, "os": [ "!aix", "!sunos", "!openbsd", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-iRiFkc2W7UVpCyZXO9tod45TP9QCyN19fWqbpeN/jaM/K7uzeHYx/OSPsahMJazGKBgPsnxRt+4Jc43d8BcHZw=="],
+ "bun": ["bun@1.4.2", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.4.2", "@oven/bun-darwin-x64": "1.4.2", "@oven/bun-freebsd-aarch64": "1.4.2", "@oven/bun-freebsd-x64": "1.4.2", "@oven/bun-linux-aarch64": "1.4.2", "@oven/bun-linux-aarch64-android": "1.4.2", "@oven/bun-linux-aarch64-musl": "1.4.2", "@oven/bun-linux-x64": "1.4.2", "@oven/bun-linux-x64-android": "1.4.2", "@oven/bun-linux-x64-musl": "1.4.2", "@oven/bun-windows-aarch64": "1.4.2", "@oven/bun-windows-x64": "1.4.2" }, "os": [ "!aix", "!sunos", "!openbsd", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-TrSXo6HJfIEaczpb3kjX82I2pL47vK1QUNmHRCUdz9IzaOwa9lzOXSWwu2l18YHE3sNfGRapVLd4nNm+22vVVA=="],
- "bun-types": ["bun-types@1.4.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-iIKw23BspnQQYd3prITOBxeUsxBHnwzX6YJfGMuNOZzeNcMmVqzIIVGRm1l69ogaPQmb4wB6BN8mA5bE9YuC5Q=="],
+ "bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
diff --git a/devlog/_fin/260905_always_on_429_failover/090_outcome.md b/devlog/_fin/260905_always_on_429_failover/090_outcome.md
index 3de38c8936..07e4399881 100644
--- a/devlog/_fin/260905_always_on_429_failover/090_outcome.md
+++ b/devlog/_fin/260905_always_on_429_failover/090_outcome.md
@@ -18,7 +18,7 @@ the tree rather than against the plan — the plan's own criteria were satisfied
Two were defects the fix itself created (#3499, #3503), three were surfaces still describing the
old contract (#3517, #3520, #3523), one closed the structural gap that let this unit ship two
subset-rotator loops (#3512), and one cleaned up after a collision with concurrent maintainer
-work (#3526). All are recorded in `091`.
+work (#3526). The runtime post-merge findings and CI lessons are recorded in `091`.
## What changed
diff --git a/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md b/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md
index 490040325d..297213b2a3 100644
--- a/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md
+++ b/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md
@@ -67,14 +67,37 @@ The post-merge run on `dev` then showed `ci failure`, which was a genuinely alar
out. It turned out to be cancellation by the maintainer's next merge two minutes later, not a
real failure — every job read `cancelled`, not `failure`.
-**Rule:** verify with the check-runs API and require zero `null` conclusions, not a pass count:
+**Rule:** use the exact head SHA, require every expected aggregate or policy gate by name, and
+also require zero non-terminal check runs. A missing check is not success. Paginate before treating
+the returned set as complete:
```bash
-gh api repos///commits//check-runs \
- --jq '[.check_runs[] | .conclusion] | group_by(.) | map({(.[0]//"null"): length}) | add'
+set -o pipefail
+gh api --paginate repos///commits//check-runs \
+ | jq -se '
+ [.[].check_runs[]] as $runs
+ | ["ci", "enforce-target", "hygiene", "react-doctor"] as $expected
+ | ($expected - [
+ $runs[]
+ | select(.status == "completed" and .conclusion == "success")
+ | .name
+ ]) as $missing
+ | [
+ $runs[]
+ | select(.status != "completed" or .conclusion == null)
+ | .name
+ ] as $pending
+ | if ($missing | length) == 0 and ($pending | length) == 0
+ then {ready: true, expected: $expected}
+ else error("missing=\($missing) pending=\($pending)")
+ end'
```
-A clean result looks like `{"skipped":3,"success":24}` — no `null` key at all.
+A clean result is `{"ready":true,...}` with exit status 0. This does not replace review-policy
+checks such as confirming the approval belongs to the same head. Every `$expected` value is an
+exact Checks API `.check_runs[].name`, not a workflow title or workflow-run name. If those required
+check-run names change, update this list with the policy; silently accepting an absent name
+recreates the original bug.
The near-miss paid for itself: sweeping `dev` afterwards found a real defect. #3511 and #3513
landed concurrently, one moving `anthropic-quorum-cache.test.ts` into `tests/routing/` and the
diff --git a/devlog/_fin/260907_axis1_bugfixes/000_plan.md b/devlog/_fin/260907_axis1_bugfixes/000_plan.md
new file mode 100644
index 0000000000..ad0da69270
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/000_plan.md
@@ -0,0 +1,24 @@
+# Axis 1: measured bug fixes and failure diagnostics
+
+Completed: see [031_delivery_record.md](031_delivery_record.md) for merged commits, final CI, attribution and deferrals.
+
+Archetype: satisfy existing contracts. Trigger: owner assigned axis 1 (#3809, #3464, #3661). Goal: deliver reviewable fixes through a manual PR chain and merge the verified scope. Non-goals: new account/retry policy, auth defaults, multipart recovery, releases, native stacks, sibling edits. Stop: merged feasible scope plus explicit unresolved dispositions. Escalation: defer a policy-dependent or unreproducible slice; reclaim a worker slice after two failed packets. Evidence: this unit plus ignored `.tmp/axis1/` and `.codexclaw` receipts. Resources: task-owned worktree/branches and GitHub repository access; Astra high leaves within host capacity; no caller-specified token or wall-clock budget.
+
+Baseline: origin/dev 137d6a727; source PR #3809 at 4a1012359a522ddd6d7ff77203c9e5f3632d605c. Assigned 5cc8 checkout has pre-existing changes and remains untouched. Code lives in /tmp/ocx-axis1-20260907.
+
+## Cycle map
+1. wp0: docs-only scope, source audit and dependency roadmap; no runtime changes.
+2. wp1: bounded quota, version-guidance and recovery-diagnostic changes; independent source/security review and structural checks. Runtime verification deferred explicitly to wp2.
+3. wp2: publish ordinary PR chain, run final cumulative hosted CI, resolve findings, admin merge bottom-up and verify dev ancestry. Lower CI only if final CI fails.
+
+## Delivery contract
+The owner explicitly requests a manual delivery chain even where units are independent: quota -> CLI guidance -> recovery reasons, with each layer carrying its own tests and credit. This order is an integration order, not a fabricated runtime dependency. No native registration. Lower commits carry [skip ci] to defer duplicate workflow runs; final head does not. Skipped lower runs are never called passing. No local tests/typecheck/build suites and no hook-triggered suites; task pushes use --no-verify. Hosted ci.yml on the final head must cover all changed runtime/tests; lower-level runs are diagnostic only after final failure. Merge with --admin under the explicit owner exception; preserve original commits/trailers with merge commits, retarget each child to dev, and check integration trees against final evidence. Concurrent dev changes require fresh combined verification.
+
+## Work boundaries
+- Quota: src/providers/quota.ts, src/oauth/anthropic-routing.ts, src/oauth/health.ts, src/server/responses/core.ts, src/images/loop.ts, src/web-search/loop.ts, focused quota tests/layout, provider documentation.
+- CLI: src/cli/version-skew.ts and relevant status/doctor consumers, tests/cli/cli-version-skew.test.ts, troubleshooting documentation. No service restart or repair behavior changes.
+- Recovery: src/server/responses/agent-task-recovery.ts, agent-task-recovery-cache.ts, src/lib/bounded-body.ts and existing focused tests, Responses error projection if needed, recovery documentation. No expanded admission/retry.
+- Main owns shared core.ts integration and test-layout files. Workers must not touch each other's paths or git index.
+
+## Verification and acceptance
+No local suite commands are executed. Source mapping, git diff --check and documentation structural checks are local evidence only. Hosted Cross-platform CI at final head provides runtime/typecheck/privacy and affected platform proof; inspect jobs for skipped coverage. Build completion is provisional until that run and independent audit succeed. Original PR author(s) must be named in commit Co-authored-by trailers, sourced from original commits/API; report authors may also be acknowledged accurately. Source-of-truth sync uses relevant existing structure and docs-site pages.
diff --git a/devlog/_fin/260907_axis1_bugfixes/010_roadmap.md b/devlog/_fin/260907_axis1_bugfixes/010_roadmap.md
new file mode 100644
index 0000000000..75e07478c0
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/010_roadmap.md
@@ -0,0 +1,3 @@
+# wp0: scope roadmap
+
+Read current source, prior issue disposition and PR #3809 before choosing changes. Independent Astra high reviewers map each bounded issue. Confirm existing launcher behavior and bounded recovery reasons are already in dev; plan only residual fixes. Record exact file boundaries and acceptance scenarios in 020. Success: all three slices have verifiable requirements, main-owned shared files, original author anchors and explicit policy exclusions. Local evidence is documentation and source inspection; no runtime claim.
diff --git a/devlog/_fin/260907_axis1_bugfixes/011_audit.md b/devlog/_fin/260907_axis1_bugfixes/011_audit.md
new file mode 100644
index 0000000000..cc1cb1d51e
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/011_audit.md
@@ -0,0 +1,5 @@
+# wp0 audit disposition
+
+Independent Astra high reviewer Hooke: VERDICT: GO-WITH-FIXES (blockers=1). Shared-flight failure propagation was the blocker. Accepted: 000/020 now assign cache and bounded-body ownership and define shared typed outcomes, success-only cache, caller-local cancellation and capacity semantics. Source scouts independently identified and confirmed these requirements. Fixed stale CLI test path. Windows runtime proof requires final workflow_dispatch, now explicit in 030.
+
+No runtime code changed. Documentation source/ownership inspection and git diff --check are the wp0 evidence. Runtime verification remains wp2.
diff --git a/devlog/_fin/260907_axis1_bugfixes/012_roadmap_lock.md b/devlog/_fin/260907_axis1_bugfixes/012_roadmap_lock.md
new file mode 100644
index 0000000000..cf2bf0afce
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/012_roadmap_lock.md
@@ -0,0 +1,5 @@
+# Roadmap lock
+
+The second independent audit returned VERDICT: PASS with no remaining blockers. The three accepted slices are ready for scoped implementation. Original quota author: Éverton Toffanetto (everton-dgn), commit identity from 4f3779c04753 and 3ef0ade296c3. Issue reporters: garysassano (10464497) and Hu9956 (282876394). Reporter acknowledgement is separate from code authorship.
+
+Preserve raw unequal version diagnostics. Detailed recovery outcomes must travel in the shared flight, not caller-local closures. Quota observations use immutable dispatch identity. Final verification is hosted workflow_dispatch for full Windows coverage; local suites remain prohibited.
diff --git a/devlog/_fin/260907_axis1_bugfixes/020_bounded_fixes.md b/devlog/_fin/260907_axis1_bugfixes/020_bounded_fixes.md
new file mode 100644
index 0000000000..836f743a73
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/020_bounded_fixes.md
@@ -0,0 +1,20 @@
+# wp1: implement bounded bug fixes
+
+## Quota
+Carry only the source PR diff onto current dev, with original-author trailer. Header utilization fraction -> percentage; reset epoch -> timestamp. Creation: parser; serialization: account quota cache; deserialization: existing hydration; consumers: account ranking/health and management reading. Account-bound writer generation is captured with serving credentials, including retry/sidecar/continuation rebinds. Header observations merge model-specific windows and cannot indefinitely postpone probes. Existing 429 eligibility and retry count stay unchanged. Explicit reset evidence must not be truncated by an invented six-hour policy; any unresolved policy piece is deferred.
+Scenarios: 200 and 429 on main/sidecar/continuation attribute only the serving account; generation invalidation discards writes; partial/malformed headers preserve known fields; no prior probe means model-window probe is still due; weekly rejected reset outlasts five-hour reset; absent evidence retains existing fallback. Verify with focused tests included in final hosted CI.
+
+## Version guidance
+Compare CLI and running proxy using existing semantic-version utilities if present. CLI newer points to service restart; proxy newer points to upgrading/PATH resolution of CLI; equal/unknown retain suppression; incomparable differing builds use neutral wording. status and doctor share advice. Preserve whether requests are allowed and do not perform repair. Test both directions, prereleases, placeholders, malformed versions and consumer projection.
+
+## Recovery reasons
+Keep existing public wrapper returning boolean and typed detailed result. Classify actual upstream HTTP refusal, transport error, timeout/caller cancellation, response-body/decode failures with a bounded vocabulary. Creation: request/collector; propagation: detailed recovery result; consumers: existing response reason projection/tests/docs. No raw upstream body/errors/tokens/ciphertext in output. Strict admission, one attempt, same credential and unchanged request mutation guarantees. Exercise each failure branch, cancellation races, malformed terminal output and successful recovery in final hosted CI.
+
+Main owns src/server/responses/core.ts and layout metadata. Source/security review must check public boundaries and negative cases, not only implementation-mirroring tests. Source-only C evidence does not claim runtime correctness; wp2 is mandatory.
+
+## Source-map clarification from independent #3464 research
+Use src/lib/strict-semver.ts unchanged. Raw unequal versions remain skewed; equal precedence with different build metadata and invalid/whitespace/v-prefixed values get neutral wording, not normalization or a guessed direction. Placeholder suppression is unchanged. src/cli/doctor.ts must not call suppressed placeholders a confirmed match. Focused files: tests/cli/cli-version-skew.test.ts, tests/cli/cli-status-json.test.ts, tests/codex-integration/doctor.test.ts. Documentation: reference/cli/lifecycle.md and directly affected Korean/Russian pages. Existing launcher landed via #3616 (4e2246c32); no service runtime changes.
+
+## Audit refinements
+Quota: observe physical responses at the existing oauthDispatch boundary before any main/continuation replacement or return. Use immutable request binding to pair response with selected account; skip when final authorization headers do not prove that bearer or credentialGeneration has changed. An active-account switch alone does not invalidate another account's in-flight observation. Native Claude passthrough and single-account expansion remain outside #3809 carry. Preserve Retry-After precedence; only reject nonfinite/unrepresentable deadlines rather than invent an anomaly ceiling. Header-only rows are probe-due; hydrated Anthropic observations must be probe-due unless probe time is proven. Failed probes settle with the most recent committed observation for all joiners.
+Recovery: worker owns agent-task-recovery-cache.ts and bounded-body.ts narrow decode discriminator alongside focused tests. Shared flight carries typed outcome, cache retains only success plaintext, cancelled waiters remain local. Recognized caller cancellation precedes owned timeout, which precedes decode/transport classification. Fatal UTF-8 discriminator must identify actual decoder exceptions without reclassifying fetch/body-reader TypeErrors. Rejected-response cancellation is nonblocking best effort. Keep current public wrappers and combo error projection. Update documented reason lists in structure/04_transports-and-sidecars.md and docs-site/reference/architecture.md.
diff --git a/devlog/_fin/260907_axis1_bugfixes/021_source_review.md b/devlog/_fin/260907_axis1_bugfixes/021_source_review.md
new file mode 100644
index 0000000000..516a760813
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/021_source_review.md
@@ -0,0 +1,7 @@
+# wp1 source review
+
+Three bounded patches implemented with regression coverage. Hooke independently passed the physical-response quota observer wiring; Tesla independently passed quota/recovery security and source review with zero blockers. Version comparator and status/doctor projections inspected by main. All source workers report no local suite/typecheck/build execution.
+
+Quota source: #3809, Éverton Toffanetto; Co-authored-by included in f215f79b4. Version report: garysassano; Reported-by included in f91e3953a. Recovery report: Hu9956; Reported-by included in recovery commit.
+
+Source-only checks: git diff --check and documentation fence/whitespace inspection. These do not prove runtime correctness. wp2 final cumulative hosted CI is still mandatory. Final CI dispatch includes Windows because ordinary PR workflow omits it. No release/deploy workflow will be dispatched.
diff --git a/devlog/_fin/260907_axis1_bugfixes/030_delivery.md b/devlog/_fin/260907_axis1_bugfixes/030_delivery.md
new file mode 100644
index 0000000000..be851f530d
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/030_delivery.md
@@ -0,0 +1,7 @@
+# wp2: hosted proof and manual-stack landing
+
+Publish task-owned branches with --no-verify. Standard PR template, source links, truthful skipped-local/lower-CI disclosure and contributor trailers. Lower layers use [skip ci], final cumulative head runs existing Cross-platform CI; never modify shared workflow filters or fabricate checks. On final failure inspect failing jobs, fix owned defects, and only then use lower CI to localize ambiguity. Leave unrelated/unresolvable slices unmerged with evidence.
+
+Before admin merge: source/security review findings resolved, final CI SHA/run pinned, current PR head and manual membership inspected. Record owner-authorized admin review/lower-CI exception. Merge bottom-up with original commits preserved; do not delete parent branches while children depend on them. Retarget child to dev after parent landing. Reconcile concurrent dev before claiming final integrated proof. Verify every merge SHA is ancestor of refreshed origin/dev. Close #3809 only after its accepted replacement scope lands; keep #3661 open for multipart/retry and #3464 open if broader original acceptance remains unresolved. No release/deploy.
+
+Final full platform evidence uses workflow_dispatch ci.yml on the final cumulative branch, because ordinary PR CI excludes the Windows runtime job. Cancel only duplicate task-owned PR CI runs; skipped/cancelled runs are not passing evidence.
diff --git a/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md b/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md
new file mode 100644
index 0000000000..439c395f8b
--- /dev/null
+++ b/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md
@@ -0,0 +1,53 @@
+# Axis 1 delivery record
+
+Terminal outcome: DONE for the authorized bounded bug/diagnostic scope, with the explicitly listed broader work deferred. Completed 2026-09-07.
+
+## Delivered
+
+- #3825 carries #3809 with serving-credential quota attribution, upstream deadline handling, probe-clock preservation and known-reset expiration. Invalid reset metadata does not erase otherwise valid usage; no new unknown-window TTL or synthetic zero was introduced.
+- #3826 corrects CLI-versus-proxy version guidance in both directions and prevents false doctor match claims.
+- #3827 exposes bounded recovery refusal/timeout/transport/invalid-output reasons through shared flights while preserving admission, success-only caching and caller-local cancellation.
+- #3842 is supporting validation work: exact private BigInt file identities preserve existing Aside profile boundaries, including high-ID distinction and directory replacement detection. Public IO/serialization and link refusals remain unchanged.
+
+## Landing proof
+
+All four ordinary PRs were merged bottom-up with owner-authorized admin authority. No native stack was registered. Children were retargeted to dev before their parent branches could be automatically deleted.
+
+| PR | Reviewed layer head | Merge commit |
+| --- | --- | --- |
+| [#3825](https://github.com/lidge-jun/opencodex/pull/3825) | `d3c70f9d8c8cc6fced7a93577b93e8b141473ea3` | `85fbdb59621046da3db1839a5cce4c7260f99385` |
+| [#3826](https://github.com/lidge-jun/opencodex/pull/3826) | `872f0e5aa714f6a2e757510195d1c038ac70e26d` | `860baaf9032fa7ea3030c78ab555608e3325a338` |
+| [#3827](https://github.com/lidge-jun/opencodex/pull/3827) | `2e8ef03428f8e619dc92b250fbbc5d5dd7ad53cb` | `5a97db9b20f03a65e714ddc88d2523bea9aeacae` |
+| [#3842](https://github.com/lidge-jun/opencodex/pull/3842) | `b29bbb440aaf70b283445a9c37e194a4a4e6859a` | `5fdf9bbdd9ff7657f0b6d7101697317d708af0e7` |
+
+The runtime integration commit is `5fdf9bbdd9ff7657f0b6d7101697317d708af0e7`. Its full tree `90a75118402d2f310393bef9ac3e4668cfcbdcfa` exactly matches the final combined validation candidate `9470fdb1bc9a02715a3760c36301d3d030a4e4fa`. A fresh fetch and ancestor check confirmed every merge on dev. The candidate included dev `bf85e675484a2391b94b2135bbebe739813a9621` plus all four layers.
+
+## Verification
+
+- [Cross-platform CI 34074350604](https://github.com/lidge-jun/opencodex/actions/runs/34074350604): all 26 jobs succeeded at the combined candidate, including Linux, macOS, Windows, Docker smoke, typecheck, privacy, build and operational checks.
+- [Service lifecycle 34074351720](https://github.com/lidge-jun/opencodex/actions/runs/34074351720): Linux, macOS and Windows succeeded at the same candidate.
+- Independent Astra high source/security audits covered the scoped implementations, merge interactions and exact-identity support.
+- All current review threads on the four delivered PRs were resolved after runtime evidence was available.
+- No local application test suite or local typecheck ran. Pushes used --no-verify; per-layer CI was deferred by explicit owner instruction. Cancelled and skipped checks were never represented as passing tests.
+- Privacy scanning passed. Documentation static build produced 425 pages in 8.23 seconds at 2522264d5; its documentation subtree remained unchanged by the supporting identity fix. Dependencies were installed from the frozen lockfile with install scripts disabled. The build changed no tracked files.
+- The assigned pre-existing working-tree changes were preserved; delivery used an isolated worktree.
+
+## Corrections and remaining limits
+
+Initial verification exposed incomplete test homes/default configuration and old calendar reset dates in current-measurement fixtures. Those fixtures were corrected without removing behavioral assertions. Known-expiry tests use explicit simulated time. Later review added expired-window handling, field normalization and a global test network guard.
+
+Imported axis-five closeout contact addresses blocked privacy scanning. [#3836](https://github.com/lidge-jun/opencodex/pull/3836) removed the addresses while retaining author names and all commit attribution; no scanner rule or allowlist was weakened.
+
+Earlier Windows Aside incidents reported an apparent shared catalog target. Their actual file IDs were not captured. The independently demonstrable Number-precision defect was corrected by #3842, and semantic/native regressions plus the previously failing route case passed in final CI. This does not retroactively prove every earlier incident's raw IDs or cause.
+
+An earlier Windows outbound-proxy test timed out at its existing 15-second bound. Its scoped test/transport files were unchanged and the stalled phase was not measured. No timeout increase or unrelated proxy repair was made; later passing execution is not a claim that the timing root cause was fixed.
+
+## Attribution and issue disposition
+
+Éverton Toffanetto's Co-authored-by trailer is retained in reachable commit `f215f79b4562735029ad5672a68bc6104e534b98`. The issue reporters garysassano and Hu9956 are acknowledged in the corresponding diagnostic commits. Merge commits preserve those commits and trailers.
+
+The original #3809 was confirmed closed with a landed-via-#3825 marker at final recheck. The initial carry source was 4a1012359; the original author subsequently updated the source PR, so this record does not claim a verbatim merge of its later head.
+
+#3464 remains open for its broader automatic-repair/request-policy requests. #3661 remains open for multipart reconstruction and recovery retry policy. Those choices were outside this delivery. No release, deployment, new account-selection strategy or authentication-default change was performed.
+
+The preceding numbered documents are historical plans and audits; their original _plan paths refer to the planning stage.
diff --git a/devlog/_fin/260907_axis3_protocol/000_plan.md b/devlog/_fin/260907_axis3_protocol/000_plan.md
new file mode 100644
index 0000000000..d0511f46ec
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/000_plan.md
@@ -0,0 +1,17 @@
+# Axis 3 protocol fidelity roadmap
+
+Mode: satisfy-spec HOTL, requested by the maintainer on 2026-09-07. Deliver source-grounded dispositions for #3815, #3816, #3807, #3719 and land accepted fixes with original authors credited in commits. No local suites or typecheck; verification is remote exact final-head CI, with lower-layer CI only on final failure. Ordinary manual PR chain only; admin merge authorized. No explicit token or wall-time limit was requested; agents use bounded tasks and waits. Do not invoke private provider accounts or spend inference credits. Tools: local Git/files, GitHub gh, Astra high leaf agents. Writes confined to task worktrees and this axis's GitHub branches/PRs. Preserve unrelated dirty work.
+
+Scope: ordered Claude thinking/redacted/tool-result envelope fidelity; Grok strict-client control frame projection; valid task-seed diagnosis. Exclude new auth/routing/default policies, fabricated provider signatures or tool pairing IDs (new Responses reasoning item IDs are permitted transport identities), cache savings claims, unrelated axes, deployment/release. Unknown field/runtime reports receive explicit deferred dispositions per user direction.
+
+Work phases: wp0 roadmap audit and lock; wp1 prepare two independently reviewable source layers and any justified contract regressions, then remote final combined verification; wp2 publish/merge ordinary PRs bottom-up and record final ancestry/dispositions. The two source fixes are independent; the manual chain is the user's requested integration/CI grouping, not a runtime dependency.
+
+Success: roadmap verified, accepted changes reviewed and remotely validated, commits credit SB Yoon (yansigit) and Yumi for #3815 and Danh Thanh (dt418) for #3816, landed SHA proven ancestor of refreshed dev; uncertain #3807/#3719 runtime or cache claims remain open. Stop only after accepted delivery and explicit dispositions. Escalate only an unavoidable owner-policy choice; defer that portion and continue the rest.
+
+Acceptance: (1) thinking then text/tool then result retains order and genuine signatures; opaque blocks remain bounded and malformed/nested signatures fail closed. (2) Grok user agent receives ordinary Responses data without codex.rate_limits/codex.response.metadata, while proxy inspection and normal clients retain metadata. (3) valid external task seeds preserve text/order; absent metadata invalid tool outputs still reject. (4) no credential, admission, cache-retention default, provider/routing policy mutation. (5) final CI must really run relevant tests/typecheck, not skip/cancel or fabricate success. No local suite was run. Final failure permits lower-layer CI for localization; unrelated failures may defer delivery, never count as success.
+
+Sources: PRs https://github.com/lidge-jun/opencodex/pull/3815 and /pull/3816; issues /issues/3807 and /issues/3719. Current dev 137d6a727. Evidence snapshots under .tmp/axis3. Public notes contain no unreleased vulnerability detail; any new security investigation stays in scratch.
+
+## Terminal outcome
+
+Runtime scope delivered in3830–3832 with the evidence and explicit diagnostic remainders in021_delivery_record.md. Documentation-only completion retains the late source-author rows and archives this unit. Initial planning statements are historical; the delivery record is the outcome authority.
diff --git a/devlog/_fin/260907_axis3_protocol/001_roadmap_lock.md b/devlog/_fin/260907_axis3_protocol/001_roadmap_lock.md
new file mode 100644
index 0000000000..115f8c3dfa
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/001_roadmap_lock.md
@@ -0,0 +1,3 @@
+# Roadmap lock
+
+Independent Astra high reviewer Pauli passed the amended wp0 roadmap. Transport reasoning IDs are permitted; fabricated tool pairing IDs remain prohibited. Claude fallback retention must be bounded or removed and checked remotely. Grok parser must follow SSE last-field/reset semantics. No runtime was changed in wp0. Next: wp1 carries source layers, adds justified regression coverage and verifies the final combined head remotely.
diff --git a/devlog/_fin/260907_axis3_protocol/010_prepare_and_verify.md b/devlog/_fin/260907_axis3_protocol/010_prepare_and_verify.md
new file mode 100644
index 0000000000..c278f094bf
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/010_prepare_and_verify.md
@@ -0,0 +1,42 @@
+# Prepare and verify combined protocol candidate
+
+Reverify base/source heads before build. Carry exact source deltas from the scratch diff snapshots, fold independently confirmed review fixes only. Each commit contains verified contributor trailers. Do not include upstream planning notes or unrelated changes.
+
+Layer 1 MODIFY:
+scripts/test-layout/layout.json
+src/claude/inbound.ts
+src/claude/outbound.ts
+src/responses/reasoning-envelope.ts
+tests/claude-integration/claude-code-thought-signature-scope.test.ts
+tests/claude-integration/claude-inbound.test.ts
+tests/claude-integration/claude-outbound.test.ts
+tests/claude-integration/claude-source-envelope.test.ts
+tests/fixtures/test-layout-expected.json
+tests/responses/reasoning-envelope.test.ts
+
+Preserve genuine signatures; encode bounded unsigned/redacted fallback; keep structured tool results. Layer 2 NEW src/server/grok-responses-control-frame.ts and MODIFY:
+src/server/grok-responses-control-frame.ts
+src/server/responses/core.ts
+tests/responses/responses-snapshot-repair-server.test.ts
+
+Separate strict-client filtering from internal inspection. On a Grok metadata frame, forward no incompatible client frame; on ordinary delta, preserve unchanged; ordinary clients remain unchanged. No shared account/routing changes.
+
+Potential follow-up tests belong only in existing responses/Claude test files after diagnosis, with independent expected values. If no valid unhandled #3807 input is established, leave production guards unchanged. #3719 cache-hit and true Anthropic signed replay cannot be certified by codec fixtures.
+
+SoT: update docs-site/src/content/docs/guides/claude-code.md and existing translated counterparts only if #3815 makes their drop-policy statements stale. Read docs-site/AGENTS.md first. No global retention change.
+
+Verification: user prohibits local suites/typecheck (NOT RUN). Inspect source and diff-check locally. Push task branches with --no-verify. Dispatch existing Cross-platform CI workflow on final combined head, lane all. Confirm workflow head SHA, jobs, conclusion, test/typecheck execution from logs. Final CI failure permits lower-layer CI. Keep workflow/protection configuration unchanged; suppress only task-owned redundant automatic runs when needed for requested top-first scheduling, reporting cancelled runs honestly. No real accounts are used.
+
+## Audit amendments
+
+New rs_ reasoning IDs are normal transport identity, not fabricated tool call pairing. Do not synthesize tool-call IDs to bypass #3807 validation.
+
+Before acceptance, remove unbounded thinkingBuf retention introduced by #3815 or charge it to the existing TranslatorBudget retained bytes with normal fail-closed overflow. Use the established budget and error event; no silent truncation or new policy default. Cover multi-part text exactness, empty continuity fallback, and overflow with a small injected existing budget in remote regression tests. Decoder/consumer traces must prove any compact continuity marker still replays the original summary.
+
+#3816 must use SSE last-event-field-wins semantics, including colonless/empty resets and removal of only one optional leading space. Test event-only, data-only, repeated event fields in both orders, and preservation of ordinary completion data. Keep downstream Grok WebSocket support deferred because the existing surface marker is absent there; do not claim this HTTP/SSE patch solves it.
+
+## WP1 source refresh and scoped hardening
+
+Previous D: roadmap locked; execute reviewed source preparation. PR #3815 advanced to 76e07d181c48dca8c80167878381e1edb5642395 during investigation, including budget fixes and translated guide changes; carry fresh source, not old snapshots. Add a third dependent hardening layer only for source-proven preservation faults. MODIFY src/responses/parser.ts: retain recognized redacted-only and empty signed envelopes even when text is empty, preserving real boundary grouping. MODIFY src/bridge.ts: preserve signed block boundaries and redacted block positions identically in streaming/buffered output; signature fragments must be assembled at owning adapter boundary. MODIFY src/claude/outbound.ts only for exact block order/text restoration where current contract permits; do not invent a new signed continuity carrier or change hide-thinking policy. If hidden signed replay needs a new policy/carrier, explicitly defer that part rather than widening scope. Existing budget/guard contracts remain.
+
+Tests: existing tests/responses/anthropic-thinking-signature.test.ts or matching current domain file and Claude envelope tests get exact block-array roundtrip oracles; no fixture claims a live genuine signature. tests/responses/responses-compaction-routing.test.ts gets an established-history complete send_message_to_thread envelope across normal response, stored-ID continuation, v2 compaction_trigger and v1 compact endpoint, preserving real pairing and task content. If current fixture support makes a case impractical, record exact gap; no runtime seed repair.
diff --git a/devlog/_fin/260907_axis3_protocol/011_candidate.md b/devlog/_fin/260907_axis3_protocol/011_candidate.md
new file mode 100644
index 0000000000..7edc9aa1ce
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/011_candidate.md
@@ -0,0 +1,9 @@
+# Combined candidate
+
+Source baseline: dev 137d6a727. Foundation carries #3815 through 76e07d181 with SB Yoon/Yumi commit trailers. Grok carries #3816 d5e0a9a2 and corrects SSE event overwrite/reset semantics, with Danh Thanh trailers. Added established-history external-task HTTP/continuation/compact fixtures without changing the missing-ID guard. Replay hardening preserves signed/opaque-only inputs and block ordering; signature updates replace previous values according to the SDK accumulator contract, and block closure waits for the next semantic event.
+
+Independent source reviews: Pauli scoped foundation PASS (18/18 files); Faraday Grok/seed PASS. Final Claude combined source audit and remote CI pending. Local suites/typecheck/build not run under user instruction. No live accounts invoked.
+
+Deferred: #3807 lacks raw failing current-version input; #3719 still needs live intended-Anthropic acceptance and controlled cache comparisons. Locally hidden text through Claude and legacy combined-envelope streaming order recovery are not claimed supported. Existing compatibility enforcement, hidden presentation, credential/admission and retention policies remain.
+
+Ordinary PR chain is an integration grouping requested by owner, with final combined CI first. Lower-layer runs only if it fails. Admin merge is authorized after accepted evidence. No GitHub native stack or fabricated check status.
diff --git a/devlog/_fin/260907_axis3_protocol/020_delivery.md b/devlog/_fin/260907_axis3_protocol/020_delivery.md
new file mode 100644
index 0000000000..714a9c0b8e
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/020_delivery.md
@@ -0,0 +1,15 @@
+# Publish and deliver verified manual chain
+
+Prerequisite: wp1 accepted-source review and successful final-head remote validation, or source-grounded defer outcome. Publish ordinary PRs targeting dev then the parent branch, using every repository template section. Bodies name source PRs, own layer-only diff, exact final combined CI evidence and explicit lower-layer CI deferral per owner instruction. Do not attest local CI. Preserve original contributor trailers in commits; admin merge with merge commits preserves their identity.
+
+Read live native-stack membership and head/base identity before merge. Never register a native stack. Parent merges to dev first; retain its branch, retarget child to dev, verify current head and ancestry. If integration tree changes materially, refresh final combined CI before landing. Use --admin and --match-head-commit exact guard. Do not merge into the parent branch by mistake. Refresh origin/dev and prove each merge SHA ancestor. Close superseded source PRs only after equivalent fix is actually landed, with credit and replacement link. Keep #3807 and #3719 open if real reproduction/cache acceptance remains unmet. No release or deployment.
+
+Record final PR URLs, source-to-delivery mapping, commit authors/trailers, CI run and exact SHA, review verdicts, remaining limitations and preserved dirty-work evidence. No fabricated status checks. Completion: every candidate has an honest disposition, accepted work is landed, unresolved diagnostics explicitly deferred under user direction.
+
+## Delivery revalidation
+
+Previous D: all 24 real GitHub runtime producer jobs succeeded at final9b5b670db; same-head remote Bun1.4 full suite20897pass18skip0fail, focused405pass, docs build pass. Aggregate ci is still queued; do not claim the workflow complete or manufacture a status. Its only operation is combining those passed producer results. Maintainer explicitly authorized admin merge, and live dev rules expose no required_status_checks rule. Delivery may use the actual completed producer evidence with aggregation status explicitly disclosed; never waive an unrun or failed runtime producer.
+
+Carry late source docs #3815 through221353662: eight outbound redacted-reasoning table rows in the same eight locales. Prepared docs-only68d90aa37 has runtime/test trees identical to9b and remote docs build passed. After three runtime PRs land bottom-up, bring this docs-only tail and a final delivery record into a fourth ordinary PR. MOVE the completed owning unit from devlog/_plan/260907_axis3_protocol to devlog/_fin/260907_axis3_protocol and NEW021_delivery.md with actual merge/CI/source-credit evidence and deferred issues. No new runtime tests: exact code-tree equality plus docs build/hygiene are the applicable checks.
+
+Refresh dev and membership before each guarded admin merge; compare merged runtime tree with tested9b. Any unrelated concurrent dev change requires integration review and appropriate renewed evidence. Original #3815 and #3816 close only after their full carried changes (including docs tail) are landed. #3807 and #3719 remain open for the already recorded limits.
diff --git a/devlog/_fin/260907_axis3_protocol/021_delivery_record.md b/devlog/_fin/260907_axis3_protocol/021_delivery_record.md
new file mode 100644
index 0000000000..e27fd8b41b
--- /dev/null
+++ b/devlog/_fin/260907_axis3_protocol/021_delivery_record.md
@@ -0,0 +1,31 @@
+# Axis 3 delivery record
+
+## Delivered runtime
+
+Ordinary PR chain, merged bottom-up with explicit owner admin authorization:
+
+| PR | Scope | Merge commit |
+| --- | --- | --- |
+| [3830](https://github.com/lidge-jun/opencodex/pull/3830) | Claude envelope foundation from #3815 | 2269e076d4222ada6ea3694fb8eed04f91a201d2 |
+| [3831](https://github.com/lidge-jun/opencodex/pull/3831) | Grok strict-client projection from #3816 and SSE field correction | 07f8d70a75f088b19f4c9dd849e34034a88ab5f3 |
+| [3832](https://github.com/lidge-jun/opencodex/pull/3832) | Replay boundaries, terminal overflow, established-history fixtures | 4349cf3cefdb5ed04575f49023ae34ffe6462e1c |
+
+Original contributors are retained in commits: SB Yoon and Yumi for #3815, Danh Thanh for #3816. Merge commits preserve the carried commits. The documentation-only tail of #3815 through221353662 is carried with both original contributor trailers in68d90aa37.
+
+## Verification
+
+- [Final candidate CI](https://github.com/lidge-jun/opencodex/actions/runs/34065721438) completed SUCCESS: all25 jobs at9b5b670db3e24ae5522c5d61e74c071c71257a26, including Linux, macOS shards/control and all six Windows shards.
+- Same-head remote Linux Bun1.4.0 full suite:20897pass18skip0fail with `bun run test -- --parallel=1`; typecheck, privacy scan and documentation build passed. Focused protocol coverage:405pass1skip0fail.
+- While CI ran, dev advanced to b65b9d8f2 with BigModel/Raycast changes. Conflict-free integration cc6afe2c97fb423363e99682b906bcb529478688 passed remote typecheck and633tests1skip0fail across15 relevant files, including shared passthrough/registry/layout guards.
+- Actual runtime landing tree at4349cf3ce equals the integration tree ccaf0a0383cb3e8808e24576271c861625b506fb exactly. This is integration proof, not a claim that the earlier full CI ran on4349cf3ce.
+- Independent Astra high source/security/integration reviews passed. The terminal-closure overflow finding was fixed before acceptance. New-test oracle mistakes found remotely were corrected without weakening exact assistant-array or pairing assertions.
+- The earlier parallel remote run had21 catalog timeouts; isolated and final sequential runs passed, and final hosted CI passed. No separate root-cause fix is claimed.
+- No local test suite or typecheck ran. All pushes used `--no-verify`. Native stacks and fabricated check statuses were not used. Automatic lower/intermediate CI was deferred or cancelled under the owner's combined-first direction.
+
+## Explicit remainders
+
+#3807 remains open: the demonstrated complete external-task envelope is already supported, and current-version raw reporter reproduction is unavailable. New ordinary, stored-ID continuation, v2-trigger and v1-compact fixtures preserve established history without relaxing missing-call-ID validation.
+
+#3719 remains open: live intended-Anthropic acceptance and controlled cache measurements are unverified. Locally hidden text through the Claude boundary and legacy combined-envelope streaming ordering remain outside the preservation claim. Existing compatibility enforcement, hidden display, authentication, routing and cache-retention defaults remain intact.
+
+The supplied dirty worktree and existing remote main checkout were preserved; execution used separate task worktrees. No release, deployment or account configuration change was made.
diff --git a/devlog/_fin/260907_axis5_display_cli/000_plan.md b/devlog/_fin/260907_axis5_display_cli/000_plan.md
new file mode 100644
index 0000000000..eb6ed46d27
--- /dev/null
+++ b/devlog/_fin/260907_axis5_display_cli/000_plan.md
@@ -0,0 +1,37 @@
+# Axis 5: display names and provider automation
+
+Date: 2026-09-07. Class C3, scoped satisfy-spec HOTL loop requested by owner.
+Goal: deliver feasible unique changes from #3627, #2716, #3780 on dev with original author trailers.
+Scope: display-only catalog metadata, discovered-model editor, optional JSONL CLI output, regression coverage and their docs. No auth/default/routing changes, native stacks, releases, or edits to existing dirty work.
+Resources: existing repository/GitHub credentials and Astra high leaf agents; no user-set time/token cap. Isolated checkout /tmp/ocx-axis5-01a078d6. Owner authorizes no-verify push and admin merge. All local suites are prohibited; typecheck/build/test evidence will come from final combined GitHub CI. No invented lower-layer CI successes.
+Terminal: merged, proven already delivered, or evidence-backed deferred when infeasible; finish after verifying all dispositions. New product decisions are isolated and deferred rather than guessed.
+Records: this unit, .tmp/axis5-evidence, and session-bound .codexclaw goalplan.
+
+## Roadmap
+
+WP0: documentation-only source-delta and delivery plan, independent plan audit and document validation.
+WP1: implement three scoped source carries with individual credited commits, publish ordinary manual PR chain, audit final tree, validate final combined head, merge verified layers bottom-up, and record dev ancestry.
+The three layers are a user-requested review/integration sequence, not a claimed runtime dependency: native catalog -> JSONL CLI -> discovered editor. Source PR branches are never rewritten.
+Read 010_delivery.md for diff-level scope and activation scenarios.
+
+## Sources
+
+- https://github.com/lidge-jun/opencodex/pull/3627
+- https://github.com/lidge-jun/opencodex/pull/2716
+- https://github.com/lidge-jun/opencodex/pull/3780
+- Base dev: 137d6a7270e7ecfb1c791993800a17c0e30022d9
+- Existing API display-name contract from #3212 is already on dev; only missing UI is carried.
+
+## CI and merge
+
+.github/workflows/ci.yml has pull_request triggers on all bases and workflow_dispatch lane=all for complete coverage. Pushes to feature branches do not independently trigger it. Defer/cancel only this task's lower-layer expensive runs as authorized, recording cancellation as cancellation. Dispatch all on final head; only if final CI fails use lower-layer runs to isolate. Do not edit shared workflow policy or fabricate check statuses.
+Use merge commits and retain parent branches so commit identity and author trailers survive bottom-up merges. Retarget a child only after its parent lands. If dev moves concurrently, integrate the new dev into the top and refresh exact combined CI before shipping the resulting changed tree.
+Review-ready requirements remain visible; local suite prohibition is explicitly documented instead of ticking a false local attestation. Admin waiver applies to the requested merge, not to truthful evidence.
+
+CI scope refinement: the discovered editor is the final layer so the final commit and PR diff include gui/**, activating GUI lint/build/artifact jobs. ci.yml gates always run GUI tests; docs deployment is NOT dispatched because it publishes. Public docs receive static source consistency inspection here, with docs build explicitly unverified unless an existing build-only remote path is available.
+
+CI scheduling refinement: lower-layer head commits may use GitHub documented [skip ci] to avoid push/pull_request suite launches; this yields missing/pending evidence, NOT green. Final head has no skip marker and receives lane=all workflow_dispatch. Source: https://docs.github.com/en/actions/how-tos/manage-workflow-runs/skip-workflow-runs (opened 2026-09-07). Admin merge records this explicit owner-requested lower-layer waiver. Do not propagate skip markers into integration merge messages.
+
+## Terminal status
+
+DONE: all three feature layers landed; see 020_delivery.md for exact commits, verification boundaries and deferred Mac test-runner investigation.
diff --git a/devlog/_fin/260907_axis5_display_cli/001_roadmap_audit.md b/devlog/_fin/260907_axis5_display_cli/001_roadmap_audit.md
new file mode 100644
index 0000000000..2e4b740b4d
--- /dev/null
+++ b/devlog/_fin/260907_axis5_display_cli/001_roadmap_audit.md
@@ -0,0 +1,11 @@
+# Roadmap audit closure
+
+WP0 documentation implementation, 2026-09-07.
+Independent Astra high reviewers: Carver (#3627), Godel (#2716), Anscombe (#3780 and integrated roadmap).
+
+The integrated verdict was GO-WITH-FIXES (four blockers). The plan now distinguishes lower-layer waived CI from final combined passing evidence; removes the unreachable empty-provider CLI acceptance; requires confirmed-persistence reconciliation after GUI refresh failure; and requires timeout reachability analysis against the installed bounded-fetch wrapper before adding any timeout logic.
+
+Source heads: native f699ec7f998d56bf205db96762b821cd8c228a35; editor 93ed44053b68a9707f8271981d5f7e4bc25e9b70; JSONL 9b873e6f7519a022dd4658db4d1cb92689bb4663.
+The physical manual chain is native -> JSONL -> GUI, enabling final GUI CI jobs. It is owner-requested integration ordering, not a claimed runtime dependency.
+Native external-name preservation is qualified by existing pinned Astra normalization; existing policy remains intact.
+No product tests, typecheck or build ran. WP0 checks only roadmap structure, source paths, explicit acceptance and credit records. Product verification remains WP1 remote CI.
diff --git a/devlog/_fin/260907_axis5_display_cli/010_delivery.md b/devlog/_fin/260907_axis5_display_cli/010_delivery.md
new file mode 100644
index 0000000000..b9cc7e2c4d
--- /dev/null
+++ b/devlog/_fin/260907_axis5_display_cli/010_delivery.md
@@ -0,0 +1,37 @@
+# WP1: reconcile, deliver, verify and merge axis 5
+
+Depends on WP0 roadmap audit. Source baseline dev 137d6a727. Previous D must confirm roadmap-only completion before production patches.
+
+## Layer 1 — #3627 native display names
+
+MODIFY src/codex/catalog/sync.ts: introduce reversible native label overlay at observed-state merge, restore original label before metadata normalization, strip marker from template clones, apply configured label to supported bare native rows only. MODIFY src/codex/convergence.ts: supply the same modelDisplayNames map as retained sync. MODIFY tests/codex-integration/codex-catalog.test.ts and provider configuration docs (English, Japanese, Korean, Simplified Chinese).
+Field chain: existing providers.openai.modelDisplayNames config -> both merge call sites -> nativeDisplayNames argument -> display_name plus catalog-only opencodex_native_display_name {slug,original,applied} -> JSON catalog serialization -> restoration before next normalization. Clone consumers must remove overlay markers; source inputs remain immutable.
+Activation: configured label replaces native name; removing/blanking restores owned original; external Sol rename is preserved; Astra remains subject to existing pinned-metadata normalization and docs/tests state that exception; newer native metadata upgrades after reset; repeated serialized cycles stable; account-qualified/combo/pro/custom rows unchanged. Exact model IDs and capabilities unchanged.
+Credit: Co-authored-by: Éverton Toffanetto .
+
+## Layer 2 — #2716 discovered name editor
+
+NEW gui/src/components/ModelDisplayNameDialog.tsx and gui/tests/models-display-name-editor.test.tsx from source PR after current API contract comparison. MODIFY gui/src/pages/Models.tsx, models-shared.ts, gui/src/styles.css, all nine locale modules, English provider configuration docs.
+Field chain: existing /api/models displayNameOverride/displayNameSource -> ModelRow optional fields -> Name action/dialog -> existing display-name save/reset endpoint -> persisted provider modelDisplayNames -> reload /api/models. No new persisted field or endpoint is needed.
+Activation: save/reset/unchanged cancel; blank/too long/slash/control input; one submit under double click; save failure retains dialog; reload failure remains recoverable; focus returns after close; original selector always visible and alias action remains separate.
+Credit: Co-authored-by: Zig Zag .
+Browser smoke: render real isolated app, open Name dialog and observe screenshot; use mocked management responses or isolated disposable home, never mutate personal config. GUI tests/build/i18n/lint and docs build are remote CI obligations; not run locally.
+
+## Layer 3 — #3780 provider JSONL
+
+MODIFY src/cli/provider.ts and src/cli/capabilities.ts to accept --jsonl, emit existing configured-array objects one per line, reject combined --json/--jsonl before reading config. MODIFY tests/cli/cli-provider.test.ts, public CLI docs and skills/ocx/references/01_management_surface.md, 02_json_shapes.md, 03_recipes.md. Regenerate or reconcile derived surface with generator source; no unrelated output.
+Field chain: argv -> consumeFlag -> output choice; no config serialization changes. JSONL entries use exactly existing JSON configured fields; no credentials added. The real config loader seeds providers; a zero-provider CLI scenario is not a reachable acceptance claim. Preserve existing loader behavior. Extend source tests to compare every emitted object with --json.configured for multiple registry/custom providers, ensure empty stdout on both conflicting flag orders, and verify escaping. Update all seven translated CLI provider tables and describe consumer-side line processing without claiming producer streaming.
+Activation: multiple providers including custom names -> one parseable record each; default human and --json unchanged; both flags rejected; unknown args still rejected; conflicting flags -> empty stdout before config loading.
+Credit: Co-authored-by: 투린 .
+
+## Verification and disposition
+
+Static git diff --check and independent source audits throughout. Existing focused test paths are reviewed for target coverage, but ALL LOCAL SUITES NOT RUN by owner instruction. Final ci.yml workflow_dispatch lane=all on published final SHA supplies typecheck, full tests and platform results; inspect actual job conclusions and head SHA. Add missing coverage within source scope if audit identifies a contract gap. Inspect GUI workflow coverage and obtain remote GUI/build evidence if not present in final dispatch.
+Source-of-truth: provider configuration and CLI docs above; update structure/03_catalog-and-subagents.md only for native overlay contract. No new enforcement layer; tests/CI are evidence, admin bypass is owner-authorized and recorded.
+Before merging: fresh heads and native membership, independent review dispositions, final CI proof, original author trailers, screenshot for GUI PR. If infeasible, record concrete cause and leave only that layer unmerged. After each merge: verify mergeCommit SHA and inclusion on fetched dev. Close superseded original PR only once its delivery is on dev and preserve attribution.
+
+Audit amendment: native label restoration preserves an external edit only subject to existing metadata normalization, notably pinned Astra replacement. Do not change native normalization policy. Add the Astra external-edit regression and qualify the promise consistently in all four affected docs. The native feature must preserve metadata including capabilities; English/Japanese wording is explicit. Final physical branch order is native -> JSONL -> GUI to activate final GUI gates; numeric sections above identify features, not alternate dependency claims.
+
+GUI audit amendment: confirmed persisted save/reset must reconcile editor snapshot and draft even when reload fails. A saved:true error is distinct from an unpersisted error. Stalled requests must not lock every dialog exit indefinitely: use existing UI request cancellation/deadline conventions, and represent uncertain write outcome without claiming rollback. Add focused source tests for first-save/reset plus reload failure, saved:true errors, duplicate protection and stalled cancellation.
+
+Plan audit synthesis (Astra high Anscombe): GO-WITH-FIXES, four blockers folded. (1) Lower layer CI is explicitly waived/deferred, never labeled passing; fresh head/base checks plus resulting tree equivalence tie admin merges to final combined evidence. (2) Removed unreachable empty-provider CLI scenario; loader behavior preserved. (3) Confirmed-persistence vs refresh state and tests required. (4) First rederive stalled-request reachability through installed global createBoundedFetch; reuse existing bound if it already applies, add no duplicate budget. Any remaining timeout scenario must be production-reachable.
diff --git a/devlog/_fin/260907_axis5_display_cli/020_delivery.md b/devlog/_fin/260907_axis5_display_cli/020_delivery.md
new file mode 100644
index 0000000000..7a2b76d0f8
--- /dev/null
+++ b/devlog/_fin/260907_axis5_display_cli/020_delivery.md
@@ -0,0 +1,42 @@
+# Axis five delivery record
+
+Outcome: DONE on 2026-09-07. The three feature layers landed in dev through owner-authorized admin integration. Original contribution credit is present in both carried commits and merge commits.
+
+| Source | Delivery | Merge commit |
+| --- | --- | --- |
+| #3627 native OpenAI display names | #3820 | 1e16fe4c077ecf353d79c46873d8039d9176704d |
+| #3780 provider list JSONL | #3821 | be24986e5ff8474ca6699895855f0ad9352e9d86 |
+| #2716 discovered-model name editor | #3824 | 44c69fdd619b272066113388edd80f6c59b0682a |
+
+The source pull requests were closed after landing. The late #3627 head 81f150e4 added metadata wording already covered by the delivery; its runtime files were checked byte-for-byte against dev before closure.
+
+## Delivered behavior
+
+Native labels are reversible overlays on supported bare native rows. IDs, capabilities and routing remain intact; restoring a label still respects existing pinned Astra normalization. Both retained synchronization and convergence pass the same configuration map.
+
+JSONL emits one configured-provider object per line using the existing JSON fields. Both conflicting flag orders fail without stdout. Multi-provider parity and escaping are covered, and all translated CLI tables and generated capability documentation were updated.
+
+The editor preserves exact selectors, validates labels, supports reset, and recovers confirmed saves separately from failed refreshes and unknown transport outcomes. Stalled operations use the existing bounded-fetch mechanism. Draft reconciliation preserves the mounted dialog and focus behavior. Desktop/mobile Korean rendering and save/reset/validation/focus were driven against the compiled CI artifact with disposable fixtures.
+
+## Verification boundaries
+
+- Feature head f51ec2421c49df0fd4eac8a9a56a6283b426387d: [Cross-platform CI attempt 2](https://github.com/lidge-jun/opencodex/actions/runs/34068041704/attempts/2), 25 successful jobs. Dashboard tests: 1,737 passed, zero failed. Typecheck, lint, scans and build passed.
+- Late platform base changes had zero overlap with the 39-file feature delta and passed [their 26-job CI](https://github.com/lidge-jun/opencodex/actions/runs/34068218011). Independent compatibility review checked the decompression diagnostics and container lifecycle interaction.
+- Prospective merge tree 85c9b25818a93859a6d6fc824e2ed0678da46c8f passed 370 focused tests on isolated Linux with project Bun 1.4.0: 344 catalog/CLI tests and 26 editor tests, zero failures. The transmitted source archive SHA-256 was ae191e1f0a809e75c9c198bc92233964880541f6747e4603a47b2c180f773d49.
+- The actual final runtime merge 44c69fdd619b272066113388edd80f6c59b0682a has exactly that tested tree. This is focused merged-tree evidence plus full feature-head CI, not a claim of full CI on the final merge commit.
+- No local test suite, typecheck or build ran. Pushes used --no-verify. Lower-layer CI was deferred until a final-head failure, and no cancelled or missing check was presented as passing.
+- Public documentation was source-reviewed. This axis did not run a documentation build.
+
+## Diagnostic disposition
+
+One Mac shard reached its 20-minute limit after an unchanged history-lock test. The full Mac control had two Cursor decoded-frame-silence assertion failures; the separately annotated server-auth stream reset was intentional and its test passed. Only the unsuccessful Mac jobs were replayed, with unchanged source and limits, and they passed. The [baseline control comparison](https://github.com/lidge-jun/opencodex/actions/runs/34069848260) also passed. These observations do not establish the stall or timing root cause. No threshold increase, assertion suppression, or unrelated harness fix was included; deeper investigation remains deferred.
+
+## Attribution
+
+- Éverton Toffanetto
+- 투린
+- Zig Zag
+
+Original author identities remain in the landed commits; this note lists names without contact addresses.
+
+The preceding numbered files are the historical roadmap and audits; their original _plan locations refer to the planning phase before this closeout.
diff --git a/devlog/_fin/260907_init_publication_guidance/010_implementation.md b/devlog/_fin/260907_init_publication_guidance/010_implementation.md
new file mode 100644
index 0000000000..80b5954924
--- /dev/null
+++ b/devlog/_fin/260907_init_publication_guidance/010_implementation.md
@@ -0,0 +1,28 @@
+# Issue #3893: implementation plan
+
+Satisfy-spec work, triggered by issue #3893 and the request to implement separate draft PRs. Goal: actionable first-run publication diagnostics. Non-goals: changing file writes, permissions, replacement/cleanup guarantees, or adding a filesystem fallback. Stop after a verified draft PR; unresolved platform checks are reported, never marked passed. Escalate if resolving the issue requires weakening publication guarantees. This file records the plan and eventual evidence.
+
+Class C2: diagnostic propagation and user documentation. One independent branch from 522ce5f8c; no branch dependencies or orchestration state changes.
+
+File map:
+- MODIFY src/config/initialize.ts: add an optional hardeningFailed flag to constructor options; select a fixed privacy-safe permission diagnostic when hardening throws. Track the flag around the existing harden call only, and pass it in the existing error options. Append supported-location guidance to denied-link diagnostics. All I/O order and cleanup remain identical.
+- MODIFY tests/config/config-mutation-lock.test.ts: inject a harden failure and prove write/link never happen, target remains absent, no residue remains, and raw error details do not appear. Assert all five denied-link codes provide recovery guidance while retaining uncertain-publication state. Partial-write errors must not be mislabeled as permission failures.
+- MODIFY tests/service/init-eof.test.ts: use its existing child bootstrap seam to inject publication errors during the real CLI wizard; verify exit=1, diagnostics and residue warnings, no configuration/backup damage or integration prompts.
+- MODIFY docs-site/src/content/docs/getting-started/quickstart.md and structure/02_config-and-codex-home.md: explain supported locations, inspection before retry, separate permission and link failures, and fresh-install OPENCODEX_HOME examples. Existing translations reviewed for contradictions.
+
+Optional constructor input chain: created by the publication function; consumed by Error.message; no config serialization, migration, or persistent state. Existing constructor calls keep their meaning.
+
+Verification: focused config/init tests read the real publication and CLI code; typecheck includes src; privacy scan; required docs-site build. Baseline focused run: 35 pass, 3 skip, 2 fail (Windows file-symlink privilege: symlinkSync EPERM and dependent missing-residue assertion). No baseline failure will be hidden by changing tests. New regression checks must pass. Windows-native filesystem support remains bounded by the host.
+
+Audit: direct O_EXCL and replacement fallbacks rejected because they change complete-file/no-replace guarantees. Reuse the existing error and test seams; no new diagnostic module. Guidance never prints raw cause text or candidate bytes.
+
+## Verification before draft publication
+
+- `bun install --frozen-lockfile`: passed; lockfile unchanged.
+- New diagnostics were observed failing before implementation: 9 failures across the focused hardening/link/CLI fault cases. After implementation: 9 passed.
+- `bun test tests/config/config-mutation-lock.test.ts tests/service/init-eof.test.ts`: 38 passed, 3 skipped, 2 failed. The same two tests failed on unchanged 522ce5f8c: file-symlink creation is denied on this Windows host, and the swapped-symlink test then lacks its expected residue. New recovery tests pass; no skips or weakened assertions were added.
+- `bun run typecheck`: passed.
+- `bun run privacy:scan`: passed.
+- `cd docs-site; bun install --frozen-lockfile; bun run build`: passed, 425 pages. Translated quickstarts contain no conflicting recovery/fallback instructions.
+- CLI fault scenarios verify exit=1, distinct permission/link messages, uncertain-publication/residue warnings, backup preservation and no integration prompts. Partial-write errors keep the generic diagnostic.
+- No physical non-NTFS filesystem support is claimed. Maintainer review remains required; this is a draft handoff.
diff --git a/devlog/_fin/260908_b_track_quota_recovery_stack/000_plan.md b/devlog/_fin/260908_b_track_quota_recovery_stack/000_plan.md
new file mode 100644
index 0000000000..d73b85568a
--- /dev/null
+++ b/devlog/_fin/260908_b_track_quota_recovery_stack/000_plan.md
@@ -0,0 +1,69 @@
+# 000_plan.md — B트랙 대화 복구·quota 스택 배송
+
+## 목표
+#3889(만료된 forward continuation의 WebSocket 복구)과 #3934(자격증명 세대 기반 늦은 WS quota 차단)를
+원저자 기여를 보존한 수동 종속 브랜치 체인으로 재구성하고, 최종 tip 한 곳에서만 CI를 태워
+green이면 tip을 dev에 통합한다.
+
+## 제약 (사용자 지시)
+- 로컬 스위트 절대 실행 금지: bun run test / test:changed / typecheck / build / install 모두 NOT RUN.
+- 푸시는 `--no-verify`.
+- CI는 최종 tip에만 트리거한다. 하위 레이어에는 PR을 열지 않는다.
+- 원작 PR이 있으면 원저자를 Co-authored-by로 보존한다.
+- tip이 dev에 머지되는 순간 연결 이슈도 닫는다.
+
+## CI 트리거 계약 (근거)
+`.github/workflows/ci.yml`의 `on.pull_request`에는 base 브랜치 필터가 없다(주석에 stacked child PR을
+일부러 포함시켰다고 명시). 따라서 **PR을 여는 것 자체가 CI run을 만든다.**
+`push:`는 `branches: [main, preview, dev]`로 제한되므로 포크/작업 브랜치 푸시는 CI를 만들지 않는다.
+결론: 하위 레이어 L1은 **브랜치 푸시만** 하고 PR을 열지 않는다. tip L2에만 PR을 연다.
+
+## 의존성 정렬 (PHASE-SPLIT-01)
+효율이 아니라 의존 구조로 나눈다. 두 변경 모두 `src/server/responses/core.ts`를 만지므로
+같은 파일 위에서 순서를 가진 체인으로 쌓는다.
+
+- L1 = #3889 continuation 복구 (core.ts:3598 부근 오류 코드 계약)
+- L2 = #3934 WS quota 세대 펜싱 (core.ts:1004 부근 observer) — L1 위에 쌓는다
+
+텍스트 충돌은 없다(두 훅 사이 거리 약 2600줄). 체인 순서는 리뷰 단위 분리를 위한 것이다.
+
+## 파일 변경 맵
+### L1 (#3889, 원저자 ykvv / y2ambition-ai)
+- MODIFY `src/server/responses/core.ts` — 400 응답 코드를 `invalid_request_error` → `previous_response_not_found`,
+ 메시지를 "전체 대화를 다시 보내라"로 변경. HTTP 상태와 인증 전 거부 위치는 유지.
+- MODIFY `tests/codex-integration/issue-702-expired-replay-state.test.ts` — 기존 HTTP 기대값의 code 갱신 +
+ expired/missing 두 모드의 WebSocket 재연결·전체 도구 이력 재전송 회귀 추가.
+- MODIFY `docs-site/src/content/docs/guides/codex-integration.md`, `.../ko/guides/codex-integration.md`
+
+### L2 (#3934, 원저자 luvs01)
+- MODIFY `src/server/responses/core.ts` — `codexWsQuotaObserver`에서 pool 자격증명 generation을 포착하고
+ `isCodexAccountGenerationLive`가 false면 늦게 도착한 quota 프레임을 무시.
+- MODIFY `tests/responses/responses-account-label.test.ts` — 교체된 자격증명의 늦은 quota가 지워진 상태를
+ 되살리지 못하는 회귀 추가.
+
+## 범위 밖 (OUT)
+- `REPLAY_TTL_MS` 등 캐시 보존 기간 변경
+- 인증/자격증명 회전 정책 변경
+- main-pool writer 소유권 규칙 변경
+- B트랙 외 항목(#3906/#3886/#3922/#3917/#3900/#3896/#3924/#3930/#3890)
+
+## 검증자 (PLAN-VERIFIER-REAL-01)
+로컬 스위트가 금지되었으므로 **로컬 검증자는 NOT RUN으로 기록한다**. 유일한 실행 검증자는
+tip PR head SHA에 대한 hosted Cross-platform CI다. 관측 대상: 4 Linux shard, Windows,
+macOS lane, gates(typecheck/lint/privacy scan), packaging.
+- `gh api repos/lidge-jun/opencodex/actions/runs?head_sha=` → conclusion=success
+- 이 CI는 `src/**`와 `tests/**`를 changes 필터에 포함하므로 실제로 이번 변경 대상을 관측한다.
+
+## 수용 기준
+1. L1/L2 커밋 각각에 원저자 Co-authored-by 트레일러가 살아 있다.
+2. L1에는 PR이 없고 CI run도 없다. CI run은 tip 하나뿐이다.
+3. tip head SHA의 CI conclusion이 success다.
+4. 로컬 스위트 미실행, 푸시는 --no-verify.
+5. tip이 dev 조상이 되고, #3889/#3934가 정리되며 연결 이슈가 닫힌다.
+
+## 우회 경로 (PLAN-BYPASS-NAMED-01)
+- tier: E2 (hosted CI 게이트)
+- 실행 주체: GitHub Actions + maintainer 통합
+- 알려진 우회: admin 권한 보유자는 CI 미완료 상태에서도 머지 가능. 이 계획은 그러지 않는다.
+- 잔여 위험: 하위 레이어 L1은 자체 CI 없이 tip 누적 CI로만 증명된다. 사용자 지시에 따른 의도된 선택.
+- 문구 하향: 없음.
diff --git a/devlog/_fin/260908_b_track_quota_recovery_stack/010_phase1_l1_continuation_recovery.md b/devlog/_fin/260908_b_track_quota_recovery_stack/010_phase1_l1_continuation_recovery.md
new file mode 100644
index 0000000000..4c054dd8c3
--- /dev/null
+++ b/devlog/_fin/260908_b_track_quota_recovery_stack/010_phase1_l1_continuation_recovery.md
@@ -0,0 +1,56 @@
+# 010_phase1_l1_continuation_recovery.md — L1 (#3889) 브랜치 구성
+
+## 목적
+만료·부재한 forward continuation 상태를 Codex WebSocket 클라이언트가 스스로 복구할 수 있게,
+프록시가 돌려주는 400 오류의 코드를 클라이언트가 인식하는 `previous_response_not_found`로 바꾼다.
+
+## 브랜치
+`codex/b-stack-l1-continuation-recovery`, base = `origin/dev`.
+
+## 커밋 계약
+원저자 보존이 필수다. 체리픽으로 원 커밋의 author를 그대로 유지한다.
+
+```
+git cherry-pick -x e8d82a181ea0daa06c5111c09e0148475e45458f
+```
+
+체리픽은 원 커밋의 author(ykvv <229483879+y2ambition-ai@users.noreply.github.com>)를 보존한다.
+squash 병합 시 author가 소실될 수 있으므로 커밋 메시지에 트레일러도 추가한다:
+
+```
+Co-authored-by: ykvv <229483879+y2ambition-ai@users.noreply.github.com>
+```
+
+## 정확한 변경 (before → after)
+`src/server/responses/core.ts` 약 3598행:
+
+```diff
+ if (
+ hasUnexpandedPreviousResponse
+ && isCanonicalOpenAiForwardProvider(route.provider)
+ ) {
+ return formatErrorResponse(
+ 400,
+- "invalid_request_error",
+- "OpenAI forward continuation state is unavailable or expired; start a new session instead of reusing this previous_response_id.",
++ "previous_response_not_found",
++ "OpenAI forward continuation state is unavailable or expired; resend the full conversation without previous_response_id.",
+ );
+ }
+```
+
+가드 위치(인증·어댑터·upstream I/O 이전)는 바뀌지 않는다. HTTP 상태 400도 유지한다.
+
+테스트: `tests/codex-integration/issue-702-expired-replay-state.test.ts`
+- 기존 HTTP 케이스: `code`를 `previous_response_not_found`로 갱신, `type`은 `invalid_request_error` 유지.
+- 신규: expired/missing 두 모드로 WebSocket 연결 → 거부 확인 → upstream 요청 0건 확인 →
+ 재연결 후 전체 이력 재전송 → upstream 1건 + `previous_response_id` 없음 + 도구 호출/결과 쌍 보존.
+
+문서: `docs-site/src/content/docs/guides/codex-integration.md` 및 한국어 페이지에 복구 경계 문단 추가.
+
+## 검증
+로컬 스위트 NOT RUN(사용자 금지). 이 레이어는 PR을 열지 않으므로 자체 CI도 없다.
+증명은 L2 tip의 누적 CI가 담당한다.
+
+## 감사 반영
+서브에이전트 audit-3889의 결과에 따라 문서의 TTL 수치와 error type/code 매핑을 확정한다.
diff --git a/devlog/_fin/260908_b_track_quota_recovery_stack/020_phase2_l2_ws_quota_generation_fence.md b/devlog/_fin/260908_b_track_quota_recovery_stack/020_phase2_l2_ws_quota_generation_fence.md
new file mode 100644
index 0000000000..8ac37b83f9
--- /dev/null
+++ b/devlog/_fin/260908_b_track_quota_recovery_stack/020_phase2_l2_ws_quota_generation_fence.md
@@ -0,0 +1,54 @@
+# 020_phase2_l2_ws_quota_generation_fence.md — L2 (#3934) tip 레이어
+
+## 목적
+pool 자격증명이 교체된 뒤 이전 WebSocket 연결에서 늦게 도착한 quota 프레임이,
+새 자격증명을 위해 비워둔 quota 상태를 되살리지 못하게 막는다.
+
+## 브랜치
+`codex/b-stack-l2-ws-quota-generation`, base = `codex/b-stack-l1-continuation-recovery` (L1 위에 쌓음).
+이 브랜치가 스택의 tip이며, **PR은 여기에만 연다.**
+
+## 커밋 계약
+```
+git cherry-pick -x e5c01f44e9736baba5b3a993c7f489f6b60d5ddd
+```
+원저자 luvs01 보존 + `Co-authored-by: luvs01 ` 트레일러.
+
+## 정확한 변경 (before → after)
+`src/server/responses/core.ts` 약 1004행:
+
+```diff
++import { isCodexAccountGenerationLive } from "../../codex/account-store";
+
+ function codexWsQuotaObserver(authCtx, provider): CodexWsQuotaObserver | undefined {
+ if (!isCanonicalOpenAiForwardProvider(provider) || !usesCodexForwardPoolAuth(authCtx, provider)) return undefined;
+ const { accountId, writerGeneration } = authCtx;
++ const credentialGeneration = authCtx.kind === "pool" ? authCtx.generation : undefined;
+ const mainWriter = authCtx.kind === "main-pool" ? authCtx.mainQuotaWriter : undefined;
+- return headers => applyCapturedCodexQuota(accountId, headers, writerGeneration, mainWriter);
++ return headers => {
++ if (credentialGeneration !== undefined && !isCodexAccountGenerationLive(accountId, credentialGeneration)) return;
++ applyCapturedCodexQuota(accountId, headers, writerGeneration, mainWriter);
++ };
+ }
+```
+
+`credentialGeneration === undefined`면 기존 동작을 그대로 유지한다(main-pool·비pool 경로 무변경).
+
+테스트: `tests/responses/responses-account-label.test.ts`
+- quota 10 전달 → 자격증명 교체 → quota clear → 옛 연결에서 quota 100 전달 → 최종 상태가 null인지 확인.
+
+## L1과의 관계
+같은 파일이지만 서로 다른 함수(약 2600줄 간격)라 텍스트 충돌이 없다.
+체인 순서는 리뷰 단위를 나누기 위한 것이며, L2 diff는 이 변경만 보여준다.
+
+## CI 계약
+`.github/workflows/ci.yml`의 `on.pull_request`는 base 필터가 없어 PR 생성 즉시 CI가 붙는다.
+따라서 L1에는 PR을 열지 않고, tip인 L2에만 PR을 연다 → CI run 정확히 1개.
+`changes` 필터가 `src/**`, `tests/**`, `docs-site` 외 경로를 보므로 이 변경 세트는 `ci=true`가 되어
+4개 Linux shard, Windows, macOS lane, gates가 모두 돈다.
+
+## 머지 후 처리
+- tip PR 머지 → `git merge-base --is-ancestor`로 dev 조상 확인
+- #3889, #3934: 내용이 dev에 들어갔으므로 원저자 크레딧을 명시하며 닫는다
+- 연결 이슈: dev 머지 시점에 닫는다 (PR base가 dev라 GitHub 자동 종료가 안 됨 — AGENTS.md 명시)
diff --git a/devlog/_fin/260908_b_track_quota_recovery_stack/030_outcome.md b/devlog/_fin/260908_b_track_quota_recovery_stack/030_outcome.md
new file mode 100644
index 0000000000..7f5ef7e74e
--- /dev/null
+++ b/devlog/_fin/260908_b_track_quota_recovery_stack/030_outcome.md
@@ -0,0 +1,58 @@
+# 030_outcome.md — 배송 결과
+
+## 결과
+PR [#3937](https://github.com/lidge-jun/opencodex/pull/3937)이 `dev`에 머지되었다.
+머지 커밋 `ca381ea764cfbc63bec978f53eb58e96c00c0c64`, 2026-09-07T18:31:27Z.
+
+## 스택 구조 (실제)
+```
+dev 942c02873
+ └─ 7273a0d1f docs(devlog): plan the B-track ... [계획]
+ └─ 531753340 fix(responses): recover expired ... [L1, author ykvv]
+ └─ a06bfa2f2 fix(codex): fence late WS quota [L2 = tip, author luvs01]
+```
+L1에는 PR을 열지 않았다. tip에만 PR을 열어 CI를 1회 트리거했다.
+
+## CI 증거
+- tip `a06bfa2f2`: Cross-platform CI run 1건, conclusion=success, run_attempt=1
+ ([run 34149252860](https://github.com/lidge-jun/opencodex/actions/runs/34149252860)).
+ 잡 21/21 완료, failure 0. Linux shard 4, macOS lane 2, gates, packaging, keyring, Docker smoke 포함.
+- 하위 레이어 `531753340`: workflow run **0건**. 브랜치 푸시가 CI를 만들지 않는다는 계약이 실측으로 확인됐다.
+- `enforce-target`은 동시성 그룹 충돌로 1차 시도가 취소되어, 대기 중이던 중복 run을 취소하고 재실행해 success를 받았다.
+
+## 검증 한계 (사실대로 기록)
+- **로컬 제품 스위트는 한 번도 실행하지 않았다** (`bun run test`/`test:changed`/`typecheck`/`build`/`install`: NOT RUN).
+ 사용자 지시에 따른 것이며, hosted CI가 유일한 실행 검증자였다. 푸시는 전부 `--no-verify`.
+- tip SHA에 취소된 체크 2건이 남아 있다: `enforce-target`(101832157192, 옛 시도)과 `label`(101827844691).
+ 같은 워크플로의 후속 시도가 success로 끝났고 failure는 0건이다. 체크 목록이 전부 깨끗하다고 말하면 사실이 아니다.
+- CI가 검증한 트리(tip)와 최종 dev 트리는 동일하지 않다. 머지 직전 별도 PR #3936(문서)이 먼저 착륙해
+ lifecycle 문서 5개가 차이로 남는다. `git diff --exit-code a06bfa2f2 ca381ea76 -- src tests`는 exit 0으로,
+ **소스와 테스트는 CI가 본 그대로** 착륙했다.
+
+## 감사 (astra-high 서브에이전트 4기)
+1. `audit-3889`: PASS. `formatErrorResponse`의 2번째 인자는 `classifyError` 입력이며
+ `previous_response_not_found` 분기가 `type=invalid_request_error`/`code=previous_response_not_found`를 만든다
+ (`src/bridge.ts:2130`, `src/lib/errors.ts:179`). 문서의 1시간은 `RESPONSE_TTL_MS=3_600_000`과 일치.
+2. `audit-3934`: PASS. `main-pool`에 `generation`이 없는 것은 의도된 분리이며 `mainQuotaWriter`가 별도 펜싱한다.
+ `writerGeneration`(설정 재조정)과 `generation`(영속 자격증명)은 다른 개념이라 새 검사가 중복이 아니다.
+ generation `0`은 엄격 동등으로 정상 처리된다.
+3. `verify-stack`: PASS. 체리픽 hunk 무결성, 두 변경의 공존, import/export, 테스트 심볼, layout, privacy 6항목.
+4. `verify-landing`: 7개 주장 중 6개 CONFIRMED, 1개 REFUTED(위 취소 체크 건). 이 문서가 그 반증을 반영한다.
+
+## 원저자 크레딧
+머지 커밋에 두 트레일러가 모두 살아 있다.
+```
+Co-authored-by: ykvv <229483879+y2ambition-ai@users.noreply.github.com>
+Co-authored-by: luvs01
+```
+원본 PR #3889·#3934는 배송 완료 안내와 함께 closed(미머지)로 처리했다.
+
+## 연결 이슈
+GraphQL `closingIssuesReferences`로 확인한 결과 #3889·#3934·#3937 모두 종료 대상 이슈가 **0건**이다.
+따라서 이번 머지로 닫을 이슈는 없었다. (#3885는 A트랙 #3886 소관이라 대상이 아니다.)
+
+## 이번에 나아지지 않은 것
+- 하위 레이어 L1은 자체 CI 증거 없이 tip 누적 CI로만 증명됐다. 사용자 지시에 따른 의도된 선택이며,
+ 레이어별 독립 회귀 증거가 필요한 변경에는 이 방식을 그대로 쓰면 안 된다.
+- `enforce-target` 동시성 충돌은 재실행으로 우회했을 뿐 원인을 고치지 않았다.
+ 같은 SHA에 워크플로가 두 번 트리거되는 조건이 남아 있다.
diff --git a/devlog/_fin/260908_bug6_manual_stack/000_plan.md b/devlog/_fin/260908_bug6_manual_stack/000_plan.md
new file mode 100644
index 0000000000..cda1225ad6
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/000_plan.md
@@ -0,0 +1,18 @@
+# Six-item bug stack — completed delivery
+
+All five new product PRs merged into `dev` on 2026-09-08. The sixth source item, #3965, had independently landed and required no duplicate PR. [071](071_delivery.md) records verification and retained failure history; [072](072_final_proof.md) records actual landing proof.
+
+| Source | Delivery | Disposition |
+| --- | --- | --- |
+| #3838 Go placement/stateless residual | #3986 | Landed; source closed; lossy mixed-ciphertext filtering declined |
+| #3907 xAI string child result | #3991 | Landed; issue completed |
+| #3944 V2 proxy guidance | #3992 | Landed; source closed |
+| #3951 server-owned delegation preset | #3993 | Landed; source closed |
+| #3965 canonical operation alias | Existing merge402be7c1f | Verified landed NOOP for another PR |
+| #3973 cooldown recovery, consolidated #3995 | #4002 | Landed; issue completed and source PR closed |
+
+This was one ordinary manual chain. Children were retargeted to dev before their parents merged because repository settings automatically delete merged branches. Original authorship and Co-authored-by trailers were preserved. #3997/#3996 remain outside this delivery.
+
+The earlier decade documents are historical plans and audit amendments. Their future-tense steps describe what was required at that point; this outcome and the final ledger are authoritative for completion. The work used repeated PABCD cycles and independent Astra high source/security reviews.
+
+Local product tests, installs, typechecks and builds: **NOT RUN**, by owner instruction. Commits disabled hooks per invocation and pushes used --no-verify. Hosted CI, synthetic dashboard observation and isolated remote documentation builds supplied verification. No release, deployment, main/preview promotion, live account operation or reset credit was used. All 30 pre-existing user files were preserved.
diff --git a/devlog/_fin/260908_bug6_manual_stack/010_go_compatibility.md b/devlog/_fin/260908_bug6_manual_stack/010_go_compatibility.md
new file mode 100644
index 0000000000..fa7a4e7845
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/010_go_compatibility.md
@@ -0,0 +1,42 @@
+# wp1: Go compatibility residuals
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp0. C3 with independent boundary review. Source PR #3838 head `d84e5a80a5e40a65462a0466d82cdcec463a847e`; baseline dev `9e1468d4b7a41b498ed2aca98507ada2c741afea`. #3942 already landed the generic array agent-message normalizer. Reimplement the remaining Go behavior on current owners; do not restore the removed `opencode-go.ts` or duplicate namespace logic.
+
+## Main decisions
+
+Carry Go additional-tools placement and the canonical preset's stateless intent. Retain current all-parts readable/fail-closed agent-message behavior; the old lossy mixed-content hunk is deliberately declined because successful transport alone does not prove complete task content. Original PR disposition must name that decision rather than claim every historical hunk landed. Custom renamed providers retain explicit configuration semantics; no destination-based configuration migration is added.
+
+## File changes
+
+- NEW `src/adapters/opencode-go-additional-tools.ts`: export a small immutable placement helper taking body and base URL. Match HTTPS `opencode.ai`, standard port, exact `/zen/go/v1` (optional terminal slash); reject credentials/query/fragment and other paths. For valid `additional_tools` array wrappers append their already-normalized tools to top-level tools and remove the wrapper. Preserve unrelated input and supported nameless hosted tools. Non-array malformed wrappers remain unchanged; no valid wrappers returns the original body. Existing namespace/custom owners perform identity lowering and dedupe before this pass.
+- MODIFY `src/adapters/openai-responses.ts`: import helper; invoke only inside non-forward dispatch after existing namespace/custom/search lowering around baseline line 2455, before code-mode/compaction and later hosted-tool pruning. Response alias maps stay owned by prior normalization.
+- MODIFY `src/providers/registry.ts`: canonical `opencode-go` entry gains `statelessResponses: true`. Existing derive logic seeds/backfills only absent values; explicit false remains authoritative.
+- MODIFY `tests/providers/opencode-go-grok46-responses.test.ts`: replace the old expected private wrapper with promoted tools; cover duplicate containers, distinct namespace same-name children, custom/function handling, hosted Luna search versus Go Grok denial, tool_choice none/allowed list, tool_search_output activation, forward/Zen/lookalike/wrong-port exclusion and immutable replay.
+- MODIFY `tests/providers/opencode-go-luna-wire.test.ts`: cover seed/backfill/false, full-history continuation with synthetic reasoning and paired tool results; assert previous_response_id removed, store false, call pairing/history retained. Cover stateless orphan and reasoning-summary interactions through existing focused suites. No new test file is required if these current owners remain reviewable.
+- MODIFY `docs-site/src/content/docs/reference/configuration/providers.md` and `structure/04_transports-and-sidecars.md`: record Go wrapper placement and canonical stateless default with explicit override and full-history limits. Update only contradicting translated statements.
+
+## Before / after flow
+
+Before: namespace normalization leaves valid declarations inside `input.additional_tools`; strict Go receives a private wrapper. After: the same normalized declarations appear in `tools`, and valid wrappers are removed. Before: canonical Go may forward previous_response_id with replay history. After: existing stateless normalization strips the stored-continuation parameters and sends complete history.
+
+## Activation and observable coverage
+
+Use production adapter fixtures, not a duplicate normalizer oracle. Namespace alpha.lookup and beta.lookup must both remain callable; duplicate wire identities follow the existing canonical owner. Nameless hosted tools must survive placement until provider/model pruning. Malformed wrapper, unapproved destination and forward controls stay byte-identical. Seed false must differ from default true. A two-turn synthetic continuation must preserve meaningful reasoning/tool history while removing stored-state references. Inspect existing stateless orphan repair and summary tests; extend any missing Go model coverage without weakening assertions.
+
+Hosted verification: PR CI covers changed runtime and provider suites, with final full dispatch before integration. Local product tests/install/typecheck/build are NOT RUN. Preserve original PR account-linked Co-authored-by credit; resolve identity from GitHub before commit. The full source investigation is in ignored `.tmp/bug6-01a07e9d/go-xai-plan.md`; it is not public implementation proof.
+
+## wp1 P refresh
+
+Previous wp0 D directs Go residual implementation. During live refresh dev advanced to c15662855 (#3975), changing only tests/codex-integration/codex-prompt-text-probe.test.ts. Hook-disabled merge incorporated that unrelated probe fixture correction before B; Go owners and this design are unchanged. The initial A narrative said unchanged dev based on the pre-fetch snapshot; this entry corrects it.
+
+## C audit foldback and repair plan
+
+Independent review at 9b42c1a80 found two blockers. F1 accepted: the stateless flag enables content-to-summary output normalization, but the continuation cache records original output; full-history overlap then fails. The adapter-only full-history fixture bypassed the affected server boundary. F2 accepted: baseUrl-only matching misses split/endpoint-inclusive configurations and can affect an overridden non-Go resource. Neither finding conflicts with preserving opaque items or existing fail-closed policy.
+
+Repair F1: MODIFY `src/server/responses/core.ts` at `rememberPassthroughResponseChecked` only. After current namespace/custom/function restoration, apply existing `rewriteReasoningSummaryInJson` under the same `hideThinkingSummary !== true && routeUsesContentChannelReasoning(provider, model)` condition as client output, then record that representation. Preserve item content and IDs under the existing opaque-item rule; do not weaken overlap comparison or use ID-only matching. This aligns stored output with the actual client serialization for SSE and JSON. Extend the current Go server fixture to send actual full-history plus previous_response_id and assert each prior call/message occurs exactly once; retain delta replay and hiding/opaque controls. The shared callback is an explicit narrow scope expansion required by this newly activated path, not unrelated state refactoring.
+
+Repair F2: the helper now accepts the final resolved Responses request URL already built by the adapter. Match exact origin and `/zen/go/v1/responses`, rejecting userinfo/query/fragment. Positive fixtures cover normal base, endpoint-inclusive base and split custom path; negative fixtures cover an override resolving to Zen/non-Go and assert both actual request URL and body. Update destination wording in docs and preserve all prior host/port/immutability controls.
+
+Re-review the repaired diff with the same implementation auditor; retain CI failures and repair evidence. No local product commands are authorized.
diff --git a/devlog/_fin/260908_bug6_manual_stack/020_xai_continuation.md b/devlog/_fin/260908_bug6_manual_stack/020_xai_continuation.md
new file mode 100644
index 0000000000..8308cc290e
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/020_xai_continuation.md
@@ -0,0 +1,25 @@
+# wp2: xAI string child-result continuation
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp1 current outbound placement and full-history regression controls. C3. Issue #3907 posts string `agent_message.content`; #3942 already implements arrays for all non-forward destinations. Scope is the string residual only.
+
+## File changes
+
+- MODIFY `src/adapters/routed-agent-messages.ts`: extend `normalizeRoutedAgentMessages` with optional `{ allowStringContent?: boolean }`, default false. If enabled and content is a nonblank string, create one input_text part containing the exact original string. Existing attribution and array handling continue. Whitespace-only, unknown, malformed and ciphertext shapes remain unchanged; never trim the forwarded text or mutate the input.
+- MODIFY `src/adapters/openai-responses.ts`: reuse `isXaiResponsesDestination` from `src/providers/xai-transport.ts`, pass its result as allowStringContent inside the existing `!forward` call. Existing array behavior stays available for other non-forward destinations. No custom-forward exception.
+- MODIFY `tests/adapters/routed-agent-messages.test.ts`: exercise both exact xAI hosts, API-key and OAuth, exact text/newlines, attribution, missing transport item ID and input immutability. String controls: native/custom forward, other providers, lookalike hosts and blank content stay unchanged; existing all-parts array/ciphertext tests remain.
+- MODIFY `tests/server/server-xai-responses-streaming.test.ts`: extend the synthetic server fixture with parent request, child request, then parent continuation containing string child result plus genuine paired tool history. Upstream stub rejects surviving private agent_message with 422; assert user-message child text, ordinary response completion, paired calls preserved and no repeated incompatible dispatch. This exercises the wire boundary, not the actual Codex scheduler.
+- MODIFY `docs-site/src/content/docs/reference/adapters.md`, `docs-site/src/content/docs/reference/configuration/providers.md`, and the contradicting Russian adapters paragraph: describe existing non-forward array conversion and xAI string extension, preserving forward/encrypted exclusions. Sync `structure/04_transports-and-sidecars.md` without broadening the passive manifest claims.
+
+## Before / after
+
+Before the raw-body outbound normalizer requires array content and leaves the issue's string item on the strict xAI wire. After it produces `{type: message, role: user, content: [{type: input_text, text: originalText}]}` through the existing attribution rules, only for an approved non-forward xAI destination. No tool result is synthesized and no encrypted message is partially discarded.
+
+## Verification
+
+Pin parent/child fixtures to synthetic input. The strict upstream stub must reject the pre-fix request shape and accept the normalized one; destination-negative controls prove the guard is active. Hosted PR CI and final full dispatch execute adapter/server regressions. Local tests/install/typecheck/build remain NOT RUN. Source audit checks raw-body call placement and all consumers of the added option. There is no serialized configuration field or migration: option creation and consumption are both in-memory adapter calls.
+
+## wp2 P refresh
+
+Previous wp1 D: PR3986 at d1f61e933 passed run34178540141 and independent source/security audit, with18Go replay scenarios and remote docs425pages. Proceed to xAI string residual. Candidate339e42c1e was prepared in an isolated worktree under the owner-authorized parallel-preparation amendment; it is not yet adopted. Its base exactly equals the certified preceding layer, and the eight-file diff matches this plan. Existing xAI predicate remains the destination owner; no account changes. Issue3907 is still open. Main revalidates candidate before B and retains fresh hosted CI before wp2 closure.
diff --git a/devlog/_fin/260908_bug6_manual_stack/030_v2_guidance.md b/devlog/_fin/260908_bug6_manual_stack/030_v2_guidance.md
new file mode 100644
index 0000000000..aac9ffab00
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/030_v2_guidance.md
@@ -0,0 +1,55 @@
+# wp3: V2 guidance carry
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp2 in the owner-requested manual chain. Carry PR #3944 at 6fb0fc6f1d34c77b98a74fe817e5bd90063a7d1a with both original commits and contributor trailer. Local product verification is NOT RUN.
+
+ separate proxy routing metadata from native policy
+
+Source: [pinned collaboration implementation](https://github.com/lidge-jun/opencodex/blob/6fb0fc6f1d34c77b98a74fe817e5bd90063a7d1a/src/server/responses/collaboration.ts#L244), [pinned regression changes](https://github.com/lidge-jun/opencodex/blob/6fb0fc6f1d34c77b98a74fe817e5bd90063a7d1a/tests/codex-integration/multi-agent-compat.test.ts#L1188). C3 source change, with C4 care for developer-instruction and public-contract semantics; this lane does not run orchestration.
+
+### Concrete before -> after hunks
+
+| Exact path / baseline anchor | Before | After to carry |
+| --- | --- | --- |
+| `src/server/responses/collaboration.ts:242` | Only the native proactive constant exists. | Add private `OPENCODEX_SUBAGENT_GUIDANCE_OPEN_TAG` / `CLOSE_TAG` constants after it. Leave `PROACTIVE_MULTI_AGENT_MODE_TEXT` unchanged. |
+| `src/server/responses/collaboration.ts:466-490` | Custom and built-in v2 bodies use native tags; built-in prescribes overrides, `fork_turns`, and preferred-model use. | Wrap both v2 paths in the proxy tag; replace only built-in preamble with routing-metadata wording; preferred clause ends with a period. Preserve placeholder substitution, effective preferred model, account namespace filtering, roster/fallback text, stale/unknown suppression and roster-drop budget. |
+| `src/server/responses/collaboration.ts:543-545` | Exact generated-item predicate only. | Add `generatedGuidanceFamily(text)` recognizing exactly the two outer tag families. This is a dedup classification, not an authorship assertion. |
+| `src/server/responses/collaboration.ts:583-594` | Latest-match handling only for native tag; other text dedups against any earlier exact match. | For either known family, compare incoming text to the latest exact generated developer text within that family in the replay prefix. For untagged text retain existing exact-item behavior. |
+| `src/types/config.ts:472-475,515-516` | Effort JSDoc prescribes spawn overrides; custom-body wrapper is native tag. | Describe effort as advisory v2 metadata; update wrapper name. Preserve type declarations, injectionModel dependency and reasoning-level validation documentation. |
+| `tests/codex-integration/multi-agent-compat.test.ts:270,387,615,741,781,847,1185` | Old v2 wrapper and imperative expectations; native-family A-B-A only. | Carry all changed expectations and new proxy/native replay matrices from the head; preserve existing v1, catalog, placement, sanitization and shape-negative tests. |
+| `docs-site/src/content/docs/reference/configuration/agents.md:77-93` | Excludes v1 leaf workers and describes model/fork overrides. | Correct already-shipped leaf eligibility; describe proxy wrapper, advisory metadata, preserved custom body and per-family latest-text dedup. State mixed-version limitations. |
+| `docs-site/src/content/docs/ja/reference/configuration/agents.md:31-37` | Old roster/guidance contract. | Carry corresponding roster correction and proxy/native/replay qualification. |
+| `docs-site/src/content/docs/ko/reference/configuration/agents.md:31-37` | Same old contract. | Same localized contract. |
+| `docs-site/src/content/docs/ru/reference/configuration/agents.md:38-57` | Same old contract, longer prose. | Carry full localized explanation including historical-message limitation. |
+| `docs-site/src/content/docs/zh-cn/reference/configuration/agents.md:31-37` | Same old contract. | Same localized contract. |
+
+Do not mass-replace ``: `collaboration.ts:493-497` remains the v1 max/ultra parity path, and native/legacy history must remain byte-identical. Do not add a settings migration or infer the author of an old tagged message. No revocation of already injected instructions is claimed.
+
+### Data creation and consumers
+
+Existing config fields, not new fields: `/api/injection-model` maps `model`, `effort`, `prompt`, `multiAgentGuidanceEnabled` to `OcxConfig.injectionModel`, `injectionEffort`, `injectionPrompt`, `multiAgentGuidanceEnabled` (`agent-settings-routes.ts:501-508,529-589`). `saveConfigPreservingClaudeCode` persists the existing JSON config. No changes to that input/storage contract are needed.
+
+`src/server/responses/core.ts:2421-2429` passes those fields, route account namespace, featured models and fallback to `multiAgentGuidanceText`. `collaboration.ts:366-405` retains feature/tool/catalog admission; `:409-464` retains request-scoped roster and preferred/fallback derivation. Only the final rendered text changes. `applyInjectionPlaceholders` at `:504-509` still substitutes the four placeholders and preserves unknown placeholders.
+
+`core.ts:2430-2433` calls `injectDeveloperMessage`. `collaboration.ts:583` creates raw `{type:"message",role:"developer",content:[{type:"input_text",text}]}`; `:597-613` creates the parsed `{role:"developer",content:text,timestamp}` and places it; `:616-621` splices raw input at the matching conversation position. Both representations must retain the same ordered text across stateful replay. `src/server/responses.ts:6` reexports the same public helpers unchanged. `src/codex/subagent-model-fallback.ts:688-692` continues owning fallback prose. Native default sync is an independent consumer per `structure/03_catalog-and-subagents.md:459-465`; do not merge it with guidance.
+
+### Regression activation
+
+Carry the existing hermetic `CODEX_HOME` / catalog fixture builders (`multi-agent-compat.test.ts:23-103`), including the fresh catalog override and its cleanup. Test the actual helpers through `parseRequest`, raw input, `_replayPrefixLen`, and `_continuationConversationMessageIndex`.
+
+1. V2 built-in has proxy tags and model/effort/roster/fallback metadata, and lacks native tag, `fork_turns`, and preferred-model imperative. V1 max/ultra retains native tag and below-top silence. Disabled guidance and stale/unknown catalog produce null.
+2. Built-in A -> custom B -> built-in A appends last A; unknown placeholders/newlines in custom B remain unchanged.
+3. Native A -> proxy P -> native B -> same proxy P adds nothing; native text dedup ignores later proxy P.
+4. Old built-in/native-tagged custom text + native policy + new proxy text preserves the original prefix and appends new proxy metadata. Never assert historical authorship or automatic cleanup.
+5. Keep exact-shape negatives, 700-character fixture, external-task input, leading tool-result, compaction marker and raw/parsed alignment cases.
+6. Small additional hunk recommended in `tests/server/server-combo-failover-e2e.test.ts:2285` beside the existing generated-guidance replay case: configure a synthetic v2 tool/catalog route, change built-in -> custom -> built-in across actual response continuations, capture adapter input, assert latest proxy guidance and native policy survive once and precede the current task. Use the existing server harness. Preserve current-dev compaction/recall fixtures in this file. This activates the caller/replay integration rather than only manually assigning parsed indices.
+
+Remote-only focused activation: `bun test tests/codex-integration/multi-agent-compat.test.ts`; additionally `bun test tests/server/server-combo-failover-e2e.test.ts` if adding the caller fixture. **NOT RUN here.** Negative controls for the remote verification owner: reverting the custom wrapper, collapsing the two families, or changing latest-family comparison to any-ever comparison must fail the corresponding transition tests. No local mutation/control execution.
+
+
+Main decision: preserve the complete original diff. The optional extra server caller fixture is deferred unless source audit reveals an untested change; do not duplicate the existing replay matrix merely for volume. Sync structure/03_catalog-and-subagents.md to the new tag and policy boundary.
+
+## wp3 P refresh
+
+Previous wp2 D: PR3991 head00eb47886 passed run34180674115, source audit and remote docs425pages; proceed guidance carry. Prepared layer3 consists of24977adf2,21757b71a,8000e2482, based on d1f61e933. Intervening wp2 changes affect xAI adapter/tests, provider/adapters docs and structure04; none overlap the9layer3 files. Original #3944 remains open at6fb0fc6f. Independent prepared-source/security audit PASS in isolated v2GuidanceReviewer.md; actual adoption requires unchanged-delta/interdiff verification and own hostedCI.
diff --git a/devlog/_fin/260908_bug6_manual_stack/040_v2_preset.md b/devlog/_fin/260908_bug6_manual_stack/040_v2_preset.md
new file mode 100644
index 0000000000..4ab32b4768
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/040_v2_preset.md
@@ -0,0 +1,96 @@
+# wp4: server-owned proactive preset carry
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp3. Carry PR #3951 at db502d486c8d8de80c0143fcfd6f86238d1ce917 with its contributor trailer. All local product commands are NOT RUN.
+
+ make the server own proactive preset recommendations
+
+Source: [pinned policy module](https://github.com/lidge-jun/opencodex/blob/db502d486c8d8de80c0143fcfd6f86238d1ce917/src/codex/multi-agent-mode-policy.ts#L1), [pinned API additions](https://github.com/lidge-jun/opencodex/blob/db502d486c8d8de80c0143fcfd6f86238d1ce917/src/server/management/agent-settings-routes.ts#L252), [pinned GUI source binding](https://github.com/lidge-jun/opencodex/blob/db502d486c8d8de80c0143fcfd6f86238d1ce917/gui/src/pages/Subagents.tsx#L48). C3 API/GUI change, C4 care for persisted developer-policy text and management boundary.
+
+### Concrete before -> after hunks
+
+| Exact path / baseline anchor | Before | After to carry |
+| --- | --- | --- |
+| `src/codex/multi-agent-mode-policy.ts` (new, head lines 1-24) | Browser owns the preset; no recommendation owner. | Create dependency-free constant `{revision:"proactive-trigger-v1",text:[six clauses].join(" ")}`, two exact released legacy strings, and exact-equality canonicalizer. The recommendation changes the delegation trigger while preserving user/authority/scope/tool rules. |
+| `src/codex/features.ts:39,1077-1094` | Non-null writer probes support then forwards original text. | Import canonicalizer; after existing capability probe set `canonicalValue = value === null ? null : canonicalizeOpenCodexModeHint(value)`; pass only that value to existing `setV2StringField`. No read-time/startup migration. |
+| `src/server/management/agent-settings-routes.ts:43,250,423` | GET/PUT return stored hint only. | Import recommendation constant and append `multiAgentModeHintRecommendation: MULTI_AGENT_MODE_HINT_RECOMMENDATION` to both successful serializers. Do not add it to accepted PUT fields or config storage. |
+| `gui/src/pages/use-subagent-delegation.ts:22-31` | State has stored hint but no recommendation. | Export `UltraModeHintRecommendation {text:string;revision:string}`; require `recommendation: UltraModeHintRecommendation \| null` in `UltraModeState`. Keep patch type as hint text/null and mode. |
+| `gui/src/pages/Subagents.tsx:11,43,60-79` | Mode state outlives apiBase; no recommendation validation. | Add `UNLOADED_ULTRA_MODE` including null recommendation; hold `{apiBase,mode}`; derive current/unloaded state by exact apiBase. Validate nonblank string text AND revision, retaining their exact bytes; malformed/missing recommendation becomes null. Preserve abort/generation/current-server guards. |
+| `gui/src/pages/Subagents.tsx:97-118,343` | Save checks busy only; forwarded busy does not describe hydration. | Refuse save without current-server mode or matching current apiBase; forward `ultraSaving || !ultraModeCurrent`. Keep PUT then GET refresh and stale-server outcome suppression. |
+| `gui/src/components/subagents-workspace/SubagentDelegationSection.tsx:299-328` | Enable/Restore use local constant. | Enable sends current server recommendation.text; disable still sends null. Disable install if forced-v2 eligibility or recommendation is absent; existing nonblank hint remains clearable. Pass nullable server preset to editor. Keep editor key based on stored hint, not recommendation revision. |
+| `gui/src/components/subagents-workspace/SubagentDelegationSection.tsx:341-391` | Editor requires string preset; exported browser preset remains. | Nullable preset; Restore changes draft only and is disabled without preset; Save preserves nonblank draft bytes. Remove local `ULTRA_MODE_PRESET` export. |
+| `gui/tests/multi-agent-guidance.test.tsx:68,153` | Fixtures lack new field. | Add null recommendation and recommendation-refresh/unsaved-draft regression. |
+| `gui/tests/subagents-ultra-mode.test.tsx:1-178` | Imports local preset and asserts duplicated text. | Remove preset import; lazy-import createRoot after DOM setup; use distinctive server recommendation fixture; carry API/malformed/edit/restore/save/server-switch cases. |
+| `tests/codex-integration/codex-v2-gate.test.ts:47,426,1342` | Existing TOML and API contracts only. | Import recommendation; independently pin both released strings; add writer normalization, custom preservation, GET-no-write/unrelated-PUT preservation, readback and idempotence cases. |
+
+All nine locale modules retain keys and change exactly these five values: `sub.ultraMode`, `sub.ultraModeText`, `sub.ultraModeLoadFail`, `sub.ultraModeSaveFail`, `sub.ultraModeSaved`. Exact baseline anchors: `gui/src/i18n/en.ts:712`, `de.ts:683`, `fr.ts:695`, `ja.ts:643`, `ko.ts:700`, `ru.ts:698`, `tr.ts:705`, `zh-TW.ts:550`, `zh.ts:693`. English label becomes “Always proactive delegation”; no hardcoded JSX copy or locale-key rename.
+
+Docs: merge the wp4 proactive-preset section into `docs-site/src/content/docs/reference/configuration/agents.md:48-60`, and add the equivalent section to `ja/`, `ko/`, `ru/`, `zh-cn/` versions of that same path. Preserve every wp3 roster/proxy-wrapper/replay paragraph. These five files are the only shared files between the original PRs; carry their hunks, not whole-file replacement from #3951. The combined original carry touches 26 distinct files.
+
+Recommended small SOT followups, main to include in its phase write allowlist: at `structure/03_catalog-and-subagents.md:459` record the separate native-hint versus proxy-guidance owners; at `structure/05_gui-and-management-api.md:129` add the response-only recommendation and explicit-save-only canonicalization contract. No broader restructuring.
+
+### Complete field lifecycle / consumer audit
+
+1. **Creation:** policy module owns constant `text` and `revision`. Revision labels server guidance; the GUI validates a nonblank string, does not whitelist revisions, does not infer installed native capability from it.
+2. **Serialization:** GET at route `:234-254` and successful PUT at `:413-427` add the same nested object. `src/server/auth-cors.ts:259-263` JSON.stringify serializes it with the existing JSON content type. No new envelope, endpoint, auth path or DTO needed.
+3. **GUI hydration:** `Subagents.loadUltraMode` GET reads the object, retains both fields only if valid, and stores it with exact apiBase. `SubagentsWorkspace.tsx:47-60` forwards typed state; it needs no runtime logic change. The recommendation is not written to session-list cache.
+4. **GUI interaction:** `ultraOn` remains derived from nonblank stored hint (`SubagentDelegationSection.tsx:57-60`). Enable uses recommendation.text, Clear sends null, Restore only updates local draft, Save sends draft. Recommendation-only refresh must not remount the editor; stored-hint changes still do. While a new API source is pending, the previous source's editor/hint disappears and all mode writes are disabled.
+5. **Write input:** `/api/v2` accepts only the existing `multiAgentModeHintText?: string|null` for this behavior. Blank/non-string validation at route `:308-310` and unsupported-runtime preflight at `:335-339` remain before mutations. The recommendation object and revision are never sent back as configuration. The GUI PUT body at `Subagents.tsx:103-107` is JSON.stringify(patch).
+6. **Persistence:** route `:390` calls `setMultiAgentModeHintText`. Its capability check remains first. Exact legacy strings become recommendation.text; arbitrary custom text, including one-space variants, stays byte-identical; null stays null. `features.ts:951-1061` owns dedicated/inline/boolean TOML forms, sibling/comment/EOL preservation and atomic writes; `:485` owns string escaping. Persist only `features.multi_agent_v2.multi_agent_mode_hint_text`. Never persist text/revision as extra TOML keys: native config rejects unknown members.
+7. **Readback:** `getMultiAgentModeHintText` at `features.ts:935-937` uses `getV2StringField` at `:857`; no canonicalization on read. The successful PUT re-reads stored hint and independently returns recommendation. CLI `src/cli/v2.ts:138,151,167` reads or invokes the same writer, so CLI explicit writes also gain exact-legacy normalization without a CLI implementation edit.
+8. **Other consumers:** `gui/src/pages/Models.tsx:476-486,1116-1127,1244-1255` deliberately projects flag/mode/thread/hybrid fields and ignores recommendation; `dashboard-core-poll.ts:233-244` projects mode only; `use-dashboard-data.ts:609-615` sends mode only. These clients need no new required field. Existing synthetic missing-recommendation responses remain useful old-server fixtures. `ULTRA_MODE_PRESET` has only the local component and `subagents-ultra-mode.test.tsx` consumers found in the repository.
+9. **Native consumer boundary:** the stored hint is for native Codex sessions; OpenCodex's v2 request guidance does not read this field. Keep the v1 proactive constant and new recommendation as distinct owners rather than replacing one with the other. No capability claim or live native delegation behavior was tested here.
+
+### Regression activation
+
+Carry backend fixtures at pinned #3951 `codex-v2-gate.test.ts:52-57,434-446,1382-1412`. Independently pinned release strings must remain in tests; do not import the production legacy array, which would make deleting a compatibility entry delete its oracle too.
+
+Backend cases: each legacy input canonicalizes only on an explicit write; GET preserves exact TOML bytes; unrelated PUT preserves stored legacy; successful PUT returns canonical stored hint plus unchanged recommendation; re-save is changed:false; adjacent comments and concurrency limit survive; null clears; whitespace variants/custom text survive; unsupported binary leaves a combined request unchanged; existing inline, dedicated, boolean, CRLF, quoting and multiline-refusal tests remain active.
+
+Small additional hunks recommended in the same registered file:
+
+- Beside baseline API tests at `:1360`: PUT a custom string with leading/trailing spaces, newline, quotes and backslash; assert exact response hint and decoded TOML equality, same recommendation, and no persisted recommendation/revision keys. Assert a recommendation-only body is rejected without changing files, and recommendation extras beside a valid hint never replace the server constant.
+- Beside CLI test at `:1626`: `cmdV2(["mode-hint", legacy])` for both released values; read/status returns canonical text; re-save no change; custom one-space variant preserved; `--clear` removes only hint. Use `fixtureConfig`, temporary CODEX_HOME and `installModeHintRuntime(true)` with existing cleanup.
+
+GUI cases, pinned [subagents-ultra-mode.test.tsx:126-318](https://github.com/lidge-jun/opencodex/blob/db502d486c8d8de80c0143fcfd6f86238d1ce917/gui/tests/subagents-ultra-mode.test.tsx#L126): distinctive server text in exact PUT; missing/bad fields block install; existing custom text remains editable/clearable; Restore sends no PUT; Save sends one; A -> pending B hides A and blocks writes; B missing/malformed/valid selects correct behavior; late A response cannot overwrite B. Preserve recommendation-only refresh draft test in `multi-agent-guidance.test.tsx:154-182`. Extend malformed matrix with null, empty revision, omitted text/revision, and non-object values; no local preset fallback.
+
+Remote-only focused activation: `bun test tests/codex-integration/codex-v2-gate.test.ts`; from gui, `bun test tests/subagents-ultra-mode.test.tsx tests/multi-agent-guidance.test.tsx`. **NOT RUN here.** The existing test-layout entries are already present at `scripts/test-layout/layout.json:488,825` and `tests/fixtures/test-layout-expected.json:323,660`; additions to these existing files need no new registration. GUI test discovery already covers `gui/tests`. Main's full hosted gates remain authoritative.
+
+## UI proof: hosted bundle, synthetic API, existing browser (main-owned)
+
+The author's missing screenshot is **not a blocker**. Use the current workflow's existing artifact: [ci.yml at baseline](https://github.com/lidge-jun/opencodex/blob/9e1468d4b7a41b498ed2aca98507ada2c741afea/.github/workflows/ci.yml#L451). The `gates` job builds GUI when GUI changes, writes `build-commit.txt` / `build-gui-tree.txt`, and uploads `dashboard-preview-${github.sha}` (`:451-470`). No workflow edits are required for this source lane.
+
+Main's execution recipe:
+
+1. Select the hosted artifact covering the cumulative carry candidate. Verify run/event/head, archive artifact ID, build-commit, and build-gui-tree against the actual CI checkout. A pull_request merge SHA may differ from branch head; record that and prove the GUI tree matches the carried candidate. Do not relabel an old artifact as current.
+2. Unpack into isolated scratch; serve prebuilt JS/CSS/assets unchanged using a small static/synthetic HTTP server. No Bun/Vite/TypeScript build or product server locally. Fixture state lives in memory and receives only synthetic local requests.
+3. Serve the actual SPA at `/#subagents` (`gui/src/App.tsx:431`) and open Advanced (`SubagentDelegationSection.tsx:235-236`). Supply synthetic bootstrap metadata in served HTML: token `ocx_session_fixture`, CSRF `fixture-csrf`, browser/server origins equal the scratch origin. `gui/src/api.ts:90-105,139-149` requires these fields. This modifies only served bootstrap HTML, not bundled implementation. Implement the fixture bootstrap path if requested; never connect it to the user's daemon or credentials.
+4. Minimal page fixtures: GET `/api/subagent-models` -> `{available:[],chosen:[]}`; GET `/api/subagent-model-fallback` -> `{available:[],models:[],pollMs:60000}`; GET `/api/injection-model` -> `{multiAgentGuidanceEnabled:true,syncCodexSubagentDefaults:false,model:null,effort:null,efforts:[],available:[]}`. Give other app-shell reads safe synthetic responses with appropriate content types; record requested routes rather than silently forwarding unknown routes. Nonfixture writes must fail closed.
+5. GET `/api/v2` baseline -> `{enabled:true,multiAgentMode:"v2",keepNativeChatGptOnV1:false,multiAgentModeHintText:null,multiAgentModeHintRecommendation:{text:,revision:"proactive-trigger-v1"}}`. PUT validates/captures the JSON patch, changes only fixture hint/mode, and returns fresh full state plus `ok:true`. Subsequent GET echoes that state. Use the exact candidate text for screenshots, and a second distinctive text/revision for source-of-preset behavioral proof.
+6. Exercise: enable -> expected text PUT and editor; edit custom -> no PUT until Save; Restore -> draft changes without PUT; Save -> exact text PUT; Clear -> null; missing and malformed recommendation with/without existing hint; disabled v2; initial GET 503 then retry; PUT 502 -> error without false saved state. Keep request log assertions next to screenshots.
+7. Server switching: the actual App keys Subagents by sharedBase (`App.tsx:431`), while unit tests also cover in-place prop updates. Use two synthetic fixture sources through the existing connection UI if supported by the host; otherwise retain hosted component-test proof for the delayed A/B update and explicitly label that branch browser-NOT-RUN. Do not rebuild a special component harness locally or fake a source switch by altering product code.
+8. Capture the changed component at 1440, 1024, 768, 390 and dense 320 px widths; EN and KO long labels, light/dark and visible keyboard focus. Check textarea readability, label/button clipping and horizontal overflow. Save representative off/on/custom/old-server/error screenshots and viewport/state/request-log manifest. No need for decorative assets.
+
+Suggested main-owned scratch outputs: `ui-v2/source-manifest.json`, `ui-v2/requests.jsonl`, `ui-v2/en-desktop-on.png`, `ui-v2/ko-mobile-custom.png`, `ui-v2/old-server.png`, `ui-v2/error-retry.png`. This lane has created none of them. Screenshots prove the carried GUI rendering and fixture interaction; they do not prove real native delegation or TOML persistence. Backend hosted tests supply persistence evidence. Main can attach its observed images to the carrying PR; it need not wait for the author's images.
+
+
+Main decision: preserve original 23-file diff and all regressions. Suggested extra CLI/API test cases remain a targeted audit decision rather than mandatory scope expansion. Sync structure/03_catalog-and-subagents.md and structure/05_gui-and-management-api.md with the response-only recommendation and explicit-write behavior. Render QA uses the existing built artifact.
+
+## wp4 P refresh and artifact publication
+
+Previous wp3 D: PR3992 at3ceef0121 passed CI34181398746, target-check rerun34181398713, independent source/security audit and425page remote docs build. Proceed server-owned preset. Candidate5b60a4fa7+e5a6f35b8 was independently audited25files; all25preimage files on actual predecessor3ceef0121 equal candidatebase8000e2482. Preserve original contribution and both layers of agent guides.
+
+UI proof uses the immutable matching hosted dashboard artifact and reviewed auxiliary stdlib fixture at /tmp/ocx-bug6-prep-v2-01a07e9d/.tmp/ui-v2/server.py. No product server/build or actual account operations. Capture and inspect representative desktop/mobileEN/KO, valid/custom/restore/save/clear/missing/malformed/error cases; hosted tests retain in-place delayed-server-switch coverage. Publish only sanitized screenshot assets on an owned evidence branch via noverify push and link immutable commit URLs in this PR, so adding review evidence does not rewrite the tested product head. This evidence-only branch is not another product PR or native stack. Actual product delivery remains the one six-layer chain. Preserve asset provenance/buildGUI-tree checks and teardown proof.
+
+## C render foldback: narrow editor layout
+
+Real prebuilt GUI capture at320px shows an unbroken configuration-key hint clipped and the textarea compressed beside both actions;390px has no page overflow but editing space is unnecessarily narrow. Evidence ui-qa/ko-320-custom.png and ko-mobile-custom.png under ignored scratch. This is a bounded improvement of the changed preset surface, not a claim that the original PR introduced the old layout.
+
+MODIFY gui/src/styles-subagents-workspace.css only: add overflow-wrap:anywhere to existing delegation setting hints; give the preset editor a minmax(0,1fr)/auto/auto grid with min-width0 textarea; reuse existing640px media breakpoint to span textarea across a full first row and place two actions on the second row. NoJS, labels, fields or authority semantics change. Rebuild only remotely; compare head-stamped320/390/1440captures and DOMwidth/textareawidth, plus existing frontendgates. Retain prior functional UI request evidence becauseJS unchanged; verify a representative Save on finalrender. Main re-audits this CSS scope before B and captures finalartifact before publishing screenshotproof.
+
+## C verification foldback: bounded guard probes
+
+Run34183701289 timed out on macos1/2 after test-home-guard passed its unregistered-home case, then Bun reported a dangling process. Runtime root cause remains unproven (H1retainedchildhandles/H2syncwait/H3isolate state); source establishes an unbounded synchronous probe owner. This is a verification-harness correction, not a claim to fix Bun internals. No production guard behavior changes.
+
+MODIFY tests/ci-workflows/test-home-guard.test.ts only: convert runProbe and all its callers to awaited async Bun.spawn; reuse exported captureTestOutput from scripts/test.ts (its executable entry is import.meta.main gated, already imported by test-runner tests); preserve exact argv/cwd/environment filtering/fake homes and all existing assertions. Use existing watchdogMs(5000) below CI60s test ceiling, bounded execution/TERM/KILL/reap/output-drain stages with cleared timers and cleanup of probe scratch. Require natural exit0, no signal, complete output; timeout/nonzero/incomplete/unreaped is a thrown diagnostic, never a success marker. Record safe probe-boundary ID/PID/exit diagnostics without inherited environment. Add synthetic nonzero-exit and nonterminating-probe controls proving failures are reported and owned child gone; do not skip guards or extend CI deadlines. All product verification stays remote. If new diagnostics still stall/fail, investigate that boundary; passing the converted harness is not an upstream-root-cause claim.
diff --git a/devlog/_fin/260908_bug6_manual_stack/050_credit_alias.md b/devlog/_fin/260908_bug6_manual_stack/050_credit_alias.md
new file mode 100644
index 0000000000..30c38ee20b
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/050_credit_alias.md
@@ -0,0 +1,29 @@
+# wp5: canonical reset-credit operation identity
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp4 for the owner-requested delivery chain. C4; no live credit consumption. Source PR #3965 at `6c1477d19c7d1a77a1866cabfd2b4411f1a210d7` carries #3919 by luvs01. Revalidate both source heads and current dev before implementation; do not rewrite their branches.
+
+## Published patch to carry
+
+- MODIFY `src/codex/auth-api.ts` at the reset consume handler: `const identity` becomes `let identity`; after execute admission assign `identity = { ...identity, operationId: opened.operationId };`. Upstream dispatch and both durable settlement paths then share the canonical operation ID. Authentication, admission failures, account binding and terminal replay stay before this assignment.
+- MODIFY `tests/codex-integration/codex-auth-api.test.ts`: import the existing ledger opener, assert a settled alias replay consumes no additional credit, and construct truly pending canonical operations for thrown fetch, non-2xx and unknown-code alias failures. Assert the durable row becomes ambiguous while account key and canonical ID remain unchanged and terminal code remains null.
+- MODIFY `docs-site/src/content/docs/reference/management-api.md`: carry the source paragraph distinguishing unfinished alias joins, known terminal replay and new explicit intent after settlement.
+
+Retain `Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>` and original source commit references. Do not carry auto-redeem worker changes: #3970 is already on baseline.
+
+## Verification
+
+The final immutable three-file source range is `abb46a1599ec0d0bbfbe03905114178df92e67f5..62412d38606851f7cace76360f3c5737db9cae20`; the landed equivalent is `abb46a1599ec0d0bbfbe03905114178df92e67f5..402be7c1f88283eb8465c3aec8437ccecd2542ec`. These final pins supersede the initial intake head above. A live source-head mismatch requires renewed comparison before carry; the mutable PR files page is navigation, not patch authority. Each negative fixture begins pending, so it observes the changed failure-settlement path instead of rechecking an already ambiguous row. Existing no-operationId and ordinary terminal paths remain regression controls. Hosted CI runs the auth and ledger suites; local tests/typecheck/build/install are NOT RUN by owner instruction. A source/security reviewer verifies the exact carried head before merge. Existing source-PR CI failure is historical and must not be described as passing.
+
+All additional unpublished security analysis lives in ignored `.tmp/bug6-01a07e9d/credit-plan.md` and later audit artifacts. It must not be copied into this public unit.
+
+## wp5 P refresh
+
+Previous wp4 D certified PR3993 head727683f44 with CI34185870948, source/security/GUI audits, QA and remote docs. Proceed canonical alias carry. Live refresh supersedes the prepared pin: #3965 merged at03:17:07Z with head62412d386 and merge402be7c1f; prepared bdb9f4bfe+9eb44cfb4 passed two source/security audits. All three target files on actual predecessor727683f44 equal preparedbase d1f61e933; intervening V2/GUI/test-harness deltas do not modify this owner. Keep exact3filecarry and original attribution. No real credentials/resetcredits and no localproductcommands. Actual adoption equality and hostedCI remain required.
+
+## Verified landed disposition
+
+Current origin/dev402be7c1f contains the #3965 merge402be7c1f. Its three target files exactly equal prepared candidate9eb44cfb4 (git diff exit0); PR CI34181771859 passed at exacthead62412d386, including Linux4/macOS2/gates. Thus the source item is already landed, not a new product fix. The initial A narrative retained the old OPEN assumption; this fresh source/API evidence corrects it before B.
+
+NOOP for a new PR. Adopt the identical two contribution commits locally only as the prerequisite for wp6; preserve provenance and contributor credit. The final new recovery PR targets existing layer4 and explains the already-landed alias dependency in its base-relative diff. No duplicate fifth PR is created and no original branch is rewritten. c5 closes on live merged-state/CI/ancestry/file equality evidence; wp6 and final cumulative integration still run their full gates. The single product stack has five new PRs plus this independently landed sixth source item.
diff --git a/devlog/_fin/260908_bug6_manual_stack/060_credit_recovery.md b/devlog/_fin/260908_bug6_manual_stack/060_credit_recovery.md
new file mode 100644
index 0000000000..1fe1b8137e
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/060_credit_recovery.md
@@ -0,0 +1,43 @@
+# wp6: manual reset recovery
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp5 canonical operation identity. C4. Implements the user-visible contract in public issue https://github.com/lidge-jun/opencodex/issues/3973 . No real account actions or credit consumption are authorized by this development task.
+
+## File map and private implementation appendix
+
+- MODIFY `src/codex/auth-api.ts`: connect the authenticated manual operation with the existing quota-observation and routing-recovery ownership contracts.
+- MODIFY `src/codex/routing.ts`: reuse narrowly targeted recovery ownership rather than broad account-health clearing.
+- MODIFY `tests/codex-integration/codex-auth-api.test.ts` and `tests/codex-integration/codex-cooldown-recovery.test.ts`: mocked endpoint and ownership-race regressions using existing fixture conventions.
+- MODIFY `docs-site/src/content/docs/reference/management-api.md` and `structure/08_openai-provider-tiers.md`: document the resulting supported contract when the patch is public, without account examples or internal proof material.
+- NO CHANGE to persisted ledger schemas, auto-redemption policy, selected-account policy, GUI, or real credentials.
+
+The complete before/after design, exact current source anchors, threat model, reachable activation cases and observable negative assertions are recorded in ignored `.tmp/bug6-01a07e9d/credit-plan.md`, section "Layer 2", against baseline `9e1468d4b7a41b498ed2aca98507ada2c741afea`. This is a mandatory implementation appendix, not deferred planning. Repository AGENTS.md requires unpublished security working notes to stay in scratch, overriding public devlog placement. Both the A reviewer and B worker must read the appendix; loss of the appendix requires reconstructing and auditing it before B.
+
+## Acceptance and verification
+
+Only the matching account's eligible pre-existing cooldown may be recovered after confirmed reset and fresh supporting evidence. Ordinary successful requests, uncertain results and replay do not gain broader recovery authority. Existing unrelated scopes and caller selections remain intact. The private appendix enumerates the full mocked positive/negative matrix and claim cleanup requirements.
+
+Run no local product commands. Hosted CI must execute the affected auth, cooldown, quota and provenance suites; independent security review remains required. PR #3848 overlaps the flight interface: refresh before B and integrate any landed change without absorbing its unrelated registration behavior. New code belongs to this owned stack; do not modify other open PRs. Record privacy-safe outcome evidence here only after publication.
+
+## wp6 P refresh
+
+Previous wp5 D verified #3965 already landed in dev402be7c1f, exacthead62412d386CIpassed, and locally adopted identical prerequisite (926b3719f); no duplicatePR5. This recovery PR targets existing layer4 #3993 and identifies the already-landed alias prerequisite in its relative diff. Source3973 remains open. Fresh inventory found overlapping contributorPR3995 (e172453052bf7bbc4a0ae5aa24592982c0c64b15) and independent fallbackPR3997; the latter resolves3996 and is outside this goal. The earlier no-overlap narrative was incorrect and is superseded before B.
+
+Prepared recovery e6e081c09 plus repair a87a3f624 passed independent security and behavior audits. The private repair synthesis and updated handoff under ignored scratch resolve main-publication ordering and positive refresh provenance; never copy security working analysis into this public unit. All six target preimages on actual predecessor926b3719f equal auditedbase9eb44cfb4. Revalidate the unchanged candidate across intervening V2/GUI/testharness context, then adopt. All mocked regressions, current-head hostedCI, privacy, finalfullcohort proof and source-item closeout remain required. No localproductcommands or realcreditactions.
+
+## Concurrent source reconciliation in P/A
+
+Review new3995 against the prepared candidate before adoption. Preserve originalcontributor credit and include its useful language/CLI docs or regression cases when source comparison warrants. Existing prepared recovery provides bounded claims/publication/provenance invariants; no competing implementation is accepted solely from prior green claims. Comparative security/behavior source reviews are in progress, all notes remain scratch. No productdelta forwp6 has been adopted yet.
+
+## Consolidated source decision
+
+Retain audited recovery e6e081c09+a87a3f624 and consolidate contributorPR3995 rather than creating competing deliveries. Comparative security review retains its PASS; detailed algorithm findings remain private in credit3995Comparison.md. Keep pause/reauth eligibility and existing background lease ownership conservative and document that recovery can remain pending under those conditions. #3997/#3996 stays outside scope.
+
+Additional MODIFY paths: docs-site/src/content/docs/ko/reference/management-api.md and docs-site/src/content/docs/reference/cli/providers-accounts.md, carrying the matching contributor guidance with parity to the final conditional recovery contract. This expands six unique files to eight. Do not duplicate the fuller English API paragraph. Adapt PR3995 tests into the existing auth-api test: two cold-main reset/already_redeemed cases without prior listing/reconciliation, bogus consume99 versus freshWHAM1; strengthen the existing saturation test with pre-existing shared cooldown, one consume, zero usage and retainedcooldown; adapt the two-old-flight/current-generation convergence scenario to assert fresh fourthdispatch completes before oldresponses, then oldresponses cannotoverwritefreshquota or recoveredcooldown. Preserve and await every deferred fixture cleanup. No new testfile, account-store schema or CLI runtime change.
+
+Carry sourcee172453052 with Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> in the adaptation commit and final PR body; describe exactly which tests/docs are adopted. B includes local candidate adoption and these bounded test/doc additions; independent interdiff review and exacthead hostedCI remain mandatory. No local tests/install/typecheck/build or realcredits.
+
+## C fixture foldback
+
+CI34188041321 caught a shared401-recovery budget leaking between fake-home cases: prior manual-a selfrefresh spends generation2, and the next case creates a different generation2 in a newhome but doesnotreset the module budget. The early spent-budget refusal prevents the intended external-replacement replay. MODIFY only the existing auth-api test: import/call resetQuotaRecoveryForTests in beforeEach/afterEach, assert empty budget at the negative-case start, observe real force-refresh provenance, and KEEP expectedfreshremaining2, replay URLs and cooldown-preservation assertions. No production relaxation. Also use existing watchdogMs(10000) and60souter ceiling for the new convergence fixture; its current run passed, so this is convention/contended-runner safety, not increasing a failing behavioral timeout. Source/interdiff review and newexactheadCI are required.
diff --git a/devlog/_fin/260908_bug6_manual_stack/070_integration.md b/devlog/_fin/260908_bug6_manual_stack/070_integration.md
new file mode 100644
index 0000000000..8a2dac4482
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/070_integration.md
@@ -0,0 +1,61 @@
+# wp7: hosted verification and integration
+
+Historical phase record. Delivery is complete; see [071](071_delivery.md) and [072](072_final_proof.md) for terminal evidence.
+
+Depends on wp1–wp6. The owner explicitly requested a single manual branch chain. This cycle changes only its delivery records and evidence; a discovered product defect is assigned an audited repair cycle before integration continues.
+
+## File changes
+
+- MODIFY this unit's `000_plan.md`: replace in-progress outcomes with exact source commit, PR, run IDs, tested heads and terminal dispositions; record failed/skipped checks separately.
+- NEW `071_delivery.md`: six-row original-to-carried PR mapping, attribution, pinned GitHub evidence, active branch/base topology and merge result per layer. Store no account identifiers or private payloads.
+- NEW `072_final_proof.md`: fetched dev SHA; per-layer ancestry command results; final candidate tree and landed tree comparison; unchanged pre-existing-file fingerprint verification. If a merge commit contains concurrent changes, isolate and explain each difference rather than claiming whole-tree equality.
+- MOVE this completed unit to `devlog/_fin/260908_bug6_manual_stack/` only when all outcomes are terminal. Evidence generated before moving records both paths. Do not move other units.
+- GUI screenshot files, if needed, use the existing `.github/pr-assets/` convention after verifying the generated image contains synthetic settings only.
+
+## Exact delivery actions
+
+1. For each nonempty candidate use a new owned `codex/bug6-01a07e9d-*` branch. Bottom base is dev; each upper base is the prior owned branch. Preserve author trailers and satisfy every section of `.github/PULL_REQUEST_TEMPLATE.md`.
+2. Commit with `git -c core.hooksPath=/dev/null commit`; push with `git -c core.hooksPath=/dev/null push --no-verify`. No install, test, typecheck or build hook runs locally.
+3. Read each PR's current head/base and native `stack` field. A native membership conflict is inspected without mutating membership. Our newly created ordinary PRs must remain manual.
+4. Inspect `gh pr checks` and matching workflow runs. Before landing obtain final candidate `ci.yml` `workflow_dispatch` with `lane=all` as well as required PR checks. Bind conclusions to `head_sha`, event and run attempt. Retry failed jobs only after investigating the actual failure and ensuring it does not hide a product regression.
+5. For the preset UI, download the hosted `dashboard-preview-*` artifact from the verified head. Verify `build-commit.txt` and `build-gui-tree.txt`; serve the prebuilt bundle with synthetic API fixtures on a disposable loopback port; observe preset activation/restoration and server-switch behavior in a browser; capture/read the screenshot. No local product compilation. Existing browser driver only, no installation.
+6. Refresh MAINTAINERS.md, live actor permission, reviewer objections and security evidence. Record maintainer integration in the owned PR body. The repository deletes merged head branches: inspect direct children and retarget our next child to dev immediately before merging its parent, so automatic deletion cannot close it. Land only the bottom PR with `--match-head-commit`; verify the resulting integration head and CI evidence before advancing. Never merge an upper PR into its parent branch as if that landed it in dev. Do not change repository settings or unrelated children.
+7. Fetch dev after each merge and prove the merged commit is an ancestor. At final integration compare actual trees against the final certified candidate, including any explicitly reviewed concurrent dev changes.
+8. Refresh each original item and mark closed only if its entire user-visible bug is resolved by the landed tree. Preserve unresolved residuals as open; report the exact residual rather than treating overlap as duplication.
+
+## Activation and observation
+
+- Failed/queued/cancelled hosted job: inspect actual run/head; no merge until required evidence is successful.
+- Base advances: recompute integration tree and obtain fresh evidence; old SHA checks are historical.
+- A maintainer objection remains: resolve its concrete finding or obtain withdrawal before merge.
+- A source PR lands concurrently: verify its actual delta and remaining contract; use an evidence-backed NOOP rather than reapplying it.
+- UI stale-server or malformed-recommendation fixture: preset install disabled; custom edit/clear retained; no cross-server write.
+- Final condition: all six source contracts mapped to landed results; no destructive changes to user files, service state or credentials.
+
+## Validation limits
+
+Local product tests, installs, typechecks and builds: NOT RUN by owner instruction. Hosted tests and independent source audits provide product evidence; docs-only filesystem/link/whitespace checks provide document evidence. Neither substitutes for the other.
+
+## wp7 P refresh
+
+Previous wp6 D:6904ecd9c passed CI34188893148 and source/security/interdiff audits; coldmain, busy, same-tick replacement and converged-flight regressions passed; docs425pages plus renderedlink/KOparity passed. Latestdev402be7c1f is pinned for integration. Read-only merge-tree predicts conflicts only in reference/management-api.md and codex-auth-api.test.ts because dev already contains the canonicalalias prefix. Both dev versions exactly equal our adopted alias predecessor9eb44cfb4; resolve those two to our current versions, which include that prefix plus the audited recovery. No pre-existing userfile overlaps the incomingdevdelta.
+
+Merge402be7c1f into the topbranch with hooksdisabled, preserving all other incomingfiles. Record exactresolvedtree, recheckcurrentdev, publishnoverify, and dispatchci.yml lane=all on that exacthead. NewPRchain is3986→3991→3992→3993→4002;3965alreadymerged. All original candidateheads retain passingPRCI; any rewrittenhead gets freshproof. Refresh each target/head/membership/review/CI before its separately authorized ordinary merge. Use merge commits to preserve ancestry/attribution, retarget each nextchild todev, and prove resolved integration content is covered by the certifiedtop. Current-headrequiredchecks and source/security duties remain separate.
+
+After productlanding, close only satisfied sourceitems, including superseded3995 aftercore3973lands; preserve3997. Archive this unit with an evidence-only closing PR if needed, so completedrecords do not change the tested product tree. Verify that closingdelta is documentation-only and receives its properCI; retain exact product-tree equivalence to the full-matrix candidate rather than attributing skipped productjobs to passingexecution. No release/main/preview/deployment changes.
+
+## Final CI repair amendment
+
+Full run34190287787 at f1b436324 failed Windows3/6: the first restart-help correctness test returned an unobserved exit status after its fixed10s synchronous subprocess bound. Other observed shards passed; wait for the complete run before deciding whether any additional repair is needed. The source investigation does not establish a Bun defect or a startup latency cause.
+
+Modify only `tests/cli/cli-restart-health.test.ts` for this repair. Replace synchronous spawning with awaited Bun.spawn, existing captureTestOutput and watchdogMs(10000). Preserve all eight command tests, arguments, private homes, output assertions and legitimate health exit1. Independently bound execution, TERM grace5s, KILL reap2s and output drain1s; clear timers and keep timeout, signal, rejected observation, incomplete output and unreaped child as failures even after eventual exit0/1. Use an outer cleanup envelope below the existing60s CI ceiling. Keep child ownership and avoid deleting an unreaped child's private home. Emit safe stage/PID/exit diagnostics without inherited environment or credentials. Add small controlled wrapper regressions for sticky timeout, incomplete output at0/1, unreaped child and spawn/observation errors; reuse capture-owner coverage for its internals. No production CLI or workflow timeout changes, assertion removal, skip, retry loop or local product execution.
+
+An independent plan audit precedes implementation; an independent patch audit precedes publication. Publish the repaired top head with hooks disabled and --no-verify, obtain fresh PR checks and a new full lane=all dispatch on that exact SHA, and verify the original Windows lane. Passing results establish that head's observed outcomes, not the historical root cause. The final docs build runs remotely on the integrated docs tree. Preserve failed-run evidence and all prior user files.
+
+## Last-layer ancestry repair
+
+Four lower PRs landed with exact predicted trees; current dev is `74f62f9c2914ead2fba474aa97734e322251bd46`. Candidate `f80f39d20e8395901d3b62758d118ea3a559a9f4` passed PR CI34193213502 attempt2 and full CI34193218874 attempt2 (26 named jobs and execution steps). Each investigated macOS retry was limited to its failed/cancelled job; prior failures remain recorded.
+
+GitHub refuses the last PR as conflicting even after its base metadata was refreshed to actual dev; ordinary GraphQL and REST merges both refused. Local merge-tree remains clean and equals candidate tree `1b3bd117702b86da5810b1ad21988a2c60df6d17`. The histories have two merge bases, `727683f44e9f1daa9b6b1e2dbf93167e4ce30cc1` and `402be7c1f88283eb8465c3aec8437ccecd2542ec`; this explains the need to simplify ancestry without claiming a proven server implementation cause.
+
+Merge that exact current dev into the owned top branch with hooks disabled. Before adding this record, require exact candidate-tree equality; no product files may change. Include only this integration record in the merge commit. Independently audit both parents and the exact record-only tree delta, preserve all 30 user files, push no-verify, and obtain fresh PR and full lane=all CI on the new head before merging #4002. Preserve the earlier successful candidate evidence as historical; do not label it new-head execution. All source closures and final archive duties remain pending until landing.
diff --git a/devlog/_fin/260908_bug6_manual_stack/071_delivery.md b/devlog/_fin/260908_bug6_manual_stack/071_delivery.md
new file mode 100644
index 0000000000..0598a4b401
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/071_delivery.md
@@ -0,0 +1,35 @@
+# Delivery and verification ledger
+
+Certified final head `5d5d35756b9b672aecf10a64be0db1f7afc144ae` has tree `5fba579b0d10183e921657dbcf4edbd166c20ec7`. All five owned PRs merged bottom-up, and actual product dev `9ad218a9bdd34ee33004c35706d78396bf02eef2` has exactly the same tree.
+
+| Owned PR | Certified head | Actual dev merge | PR CI run / attempt |
+| --- | --- | --- | --- |
+| #3986 | `d1f61e933b0cde3df3862baed65546a5cf81066f` | `7b2223776450804a6b8a4509a115dd42ee1b9c40` | 34178540141 / 1 |
+| #3991 | `00eb47886690e7b24b0eed69b6d870c33ceade62` | `7730f666ee1acabe2cd7729ec56f4c53149d926c` | 34180674115 / 1 |
+| #3992 | `3ceef0121712b290c3d4443e9fc3f0a04cecead6` | `74292a21e6d504960ef753b403341498fd5bfe30` | 34181398746 / 1 |
+| #3993 | `727683f44e9f1daa9b6b1e2dbf93167e4ce30cc1` | `74f62f9c2914ead2fba474aa97734e322251bd46` | 34185870948 / 1 |
+| #4002 | `5d5d35756b9b672aecf10a64be0db1f7afc144ae` | `9ad218a9bdd34ee33004c35706d78396bf02eef2` | 34198172044 / 1 |
+
+Final full `ci.yml` workflow_dispatch lane=all: [34198186409](https://github.com/lidge-jun/opencodex/actions/runs/34198186409), attempt2. All 26 named jobs and mandatory execution steps were verified successful. PR #4002 CI [34198172044](https://github.com/lidge-jun/opencodex/actions/runs/34198172044) passed at the exact final head. A successful attempt2 summary includes successful jobs retained from attempt1; it does not mean those jobs executed again.
+
+## Failures and bounded repairs
+
+- Go's initial synthetic userinfo fixture failed privacy scanning; fixture construction was corrected before candidate CI34178540141 passed.
+- The preset's home-guard subprocess stalled on macOS. Its bounded execution/reap/capture repair retained all10 original fixtures and38 assertions; CI34185870948 passed. The native cause remains unproven.
+- Recovery CI34188041321 exposed shared test-budget state between synthetic homes. Isolation was corrected without dropping assertions; CI34188893148 passed.
+- Full34190287787 at f1b436324 failed Windows restart-help with an unobserved synchronous child exit at10s. The bounded asynchronous CLI harness retained8 original tests/18 assertions and added10 lifecycle controls. Independent source review and later Windows execution passed.
+- At f80f39d20, PR34193213502 attempt1 hit a macOS job cancellation at an unchanged injection-lock test boundary. Same-head full macOS1 passed the same tests; one investigated job-only rerun passed. Full34193218874 attempt1 separately timed out in an unchanged Copilot cancellation test; the same-head macOS shard passed that case. One control-only rerun passed, with21,805 main-suite passes and0 failures. Scheduler, ordering and native causes were not established.
+- After four parents landed, GitHub refused the last merge while local merge calculation was clean. Two common ancestors were observed. The final ancestry merge incorporated actual dev74f62f9c; independent review proved that only the070 record changed from the already certified f80 product. Fresh exact-head CI was obtained; no old run was relabeled as execution on the new head.
+- Full34198186409 attempt1 failed Windows3 cleanup: EPERM removing a fixed test directory in afterEach caused subsequent setup/cleanup failures. Identical product files had passed the preceding Windows3 run. Independent inspection supported one failed-job-only diagnostic rerun. Job101977029312 passed3,304 tests with0 failures; the affected TTL case passed172.72ms. The handle/permission owner remains unknown. No test threshold or product code changed for this retry.
+
+Passing jobs were retained during these job retries, not rerun. Failed/cancelled attempts remain historical evidence. No root-cause or flake-eradication claim follows from a successful retry.
+
+## Attribution, UI and documentation
+
+The carried Go intent retains `Co-authored-by: jpierrevd <265811239+jpierrevd@users.noreply.github.com>`. V2, alias and adapted #3995 coverage/docs retain `Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>`. Merge commits preserve their history. The lossy mixed-ciphertext filtering proposal from #3838 was declined; fail-closed behavior remains.
+
+Dashboard tree `b0bc09ba867906375e52cf0180caa4ea4ea95bea` equals the inspected artifact tree. Hosted artifact10039810403 from34183701289 was observed against a synthetic API: enable, exact custom Save, draft-only Restore, Clear, malformed/missing recommendation, error/retry, server switching,320/390px and desktop layouts, and keyboard focus. Two independent reviewers accepted it. Immutable screenshots are in [#3993](https://github.com/lidge-jun/opencodex/pull/3993), evidence commit924327cdd71a14a0aea1936e4c5e1f6b6b660438. Owned fixture/browser ports were closed.
+
+Docs tree `7041e912691a5150893fbf4f782734c94e49d056` equals the remotely built integrated tree. Bun1.4.0 / Node24.20.0 frozen install and build on isolated macmini-cf scratch produced425 pages; rendered CLI/API anchor and English/Korean recovery text were checked. Archive SHA-256 a51cdbd83f409472defcb7758873734edba167f116a17869ec345366e0e9063d. An early incomplete-transfer attempt was excluded from passing evidence. No docs deployment occurred.
+
+Local product tests/install/typecheck/build: **NOT RUN**. This archive changes only this unit's Markdown records; its own metadata/CI/privacy verification is separate from product execution.
diff --git a/devlog/_fin/260908_bug6_manual_stack/072_final_proof.md b/devlog/_fin/260908_bug6_manual_stack/072_final_proof.md
new file mode 100644
index 0000000000..7763124487
--- /dev/null
+++ b/devlog/_fin/260908_bug6_manual_stack/072_final_proof.md
@@ -0,0 +1,23 @@
+# Actual product landing proof
+
+Verified 2026-09-08. Final candidate `5d5d35756b9b672aecf10a64be0db1f7afc144ae` and fetched product dev `9ad218a9bdd34ee33004c35706d78396bf02eef2` have identical tree `5fba579b0d10183e921657dbcf4edbd166c20ec7`. `git diff --exit-code` returned0. Each owned head and actual merge commit is ancestral to fetched dev; #3965's existing402be7c1f merge is also ancestral.
+
+| PR | Actual merge commit |
+| --- | --- |
+| #3986 | `7b2223776450804a6b8a4509a115dd42ee1b9c40` |
+| #3991 | `7730f666ee1acabe2cd7729ec56f4c53149d926c` |
+| #3992 | `74292a21e6d504960ef753b403341498fd5bfe30` |
+| #3993 | `74f62f9c2914ead2fba474aa97734e322251bd46` |
+| #4002 | `9ad218a9bdd34ee33004c35706d78396bf02eef2` |
+
+Before each merge, current head/base, actor admin permission, maintainer roster/reviews, CI, native membership and direct-child inventory were refreshed. The dev-only maintainer-integration decision and exact verification were recorded in each owned PR body. No maintainer change request remained. Independent technical/security review duties were retained; this was not self-approval. Native stack membership was empty.
+
+The first four actual merge trees matched their serial predictions. GitHub's final merge refusal was repaired with an independently audited ancestry merge; the final actual dev tree then matched the newly certified head exactly. Full CI34198186409 attempt2 verified all26 named jobs and mandatory execution steps; PR CI34198172044 attempt1 passed. Earlier failed attempts are recorded in071.
+
+Sources3838/3944/3951 are closed, issue3907 is completed, and3965 was already merged. After actual4002 landing, issue3973 was completed and3995 was closed as consolidated. The scope excludes3997/3996. Thirty original user files matched their pinned SHA-256 values with0 missing and0 mismatched; they were excluded from all commits. Scratch/evidence directories remain untracked.
+
+## Archive-only completion record
+
+This closing change moves exactly this unit from `devlog/_plan/260908_bug6_manual_stack/` to `devlog/_fin/260908_bug6_manual_stack/`, updates its terminal records and adds this proof. Product content is unchanged. The closing PR and session receipt verify the exact old/new paths, regular-file modes and blob IDs against the reviewed delta, plus closing CI/metadata and a remote privacy scan. Documentation-only skipped product jobs are NOT RUN, not passing product executions.
+
+The closing PR's own merge SHA cannot be embedded in the commit that creates it. Its observed post-merge ancestry and exact record-only delta are verified after landing in the final session receipt and delivery report, rather than predicted here.
diff --git a/devlog/_fin/260908_c248_individual_fixes/000_plan.md b/devlog/_fin/260908_c248_individual_fixes/000_plan.md
new file mode 100644
index 0000000000..3dca83c8cb
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/000_plan.md
@@ -0,0 +1,33 @@
+# Lane C: independently reviewable 2.48 preparation fixes
+
+Scope: satisfy-spec HOTL requested by the owner on 2026-09-08. Goal: independently land #3953, #3899 and the timezone-only part of #3950 into dev, retaining original authors. This returned/stored roadmap is the memory artifact. Baseline dev: `514350e6f79ed4539378388bc39d3fc79ff2c70c`. No resource budget was specified; native host limits apply. Tool scope: local Git/source/artifact checks, GitHub repository/Actions, and explicitly authorized A/B coordination; astra high read-only auditors. No local product tests, typechecks, builds or dependency installation, including incidental Git-hook execution. Use per-command `git -c core.hooksPath=/dev/null` for mutating Git operations, and `push --no-verify`; do not modify shared Git configuration.
+
+## Work phases and ownership
+
+`roadmap` (this docs-only full PABCD) precedes three independent delivery cycles: `privacy`, `release_notes`, `timezone`. `reconcile` depends on those deliveries and lane B's JWT evidence. The processing order is scheduling, not a code dependency: each delivery remains a separate dev-targeted PR. Reuse original #3953 if unchanged and reviewable; carry #3899 onto current dev if needed; timezone gets a new PR sourced from only commit 1d8f6ff7e8d48f33c3ce7a1b7118068754bbbe83. Never create a combined code-delivery PR or squash different bugs together. Local roadmap/outcome commits stay on this coordination branch until a separate documentation-only closeout is appropriate. A separately audited evidence-only workflow branch may add supplemental hosted platform proof without entering any delivery PR or changing its required CI.
+
+## Boundaries
+
+No JWT changes, provider/routing work, main/preview promotions, version changes, deployments, release execution, live-account/service probes, history rewriting or public reproduction of removed material. Confidential investigation stays in ignored `.tmp/c248/`. The public docs describe only approved correction scope, not sensitive values. No new runtime type/enum/field is added, so creation/serialization/deserialization/consumer field-chain work is N/A.
+
+## Verification contract
+
+The roadmap uses actual file and source-object inspection plus `git diff --check` (run in this checkout before the roadmap close). Delivery uses the repository's existing hosted CI on each PR's current head; source-sensitive suites and the actual workflow scope must be checked. Local product commands are explicitly NOT RUN. No blind retries, cancelled/skipped/pending-as-pass, broad test weakening or artificial screenshots. A docs-only scope check is not a product-suite pass. Head rewrites require fresh current-head evidence. If dev moves, classify the actual delta and do not claim an unexecuted integration tree was tested. Before merge, validate required gates and exact head; preserve unrelated destination changes and prove the landed source diff.
+
+## Integration coordination
+
+The active A and B workstreams agreed on `/ocx-248-dev-merge.lock`: atomic mkdir, owner.json with sessionId/pid/hostname/PR/SHA/acquiredAt, owned only from final refresh through landed verification. Never hold it while waiting for CI or delete another owner's lock. This is a cooperative serialization convention, not a security boundary; an uncooperative actor can bypass it. The main thread resolves collisions, missing permissions or contradictory evidence without expanding worker scope; a new worker slice requires a plan amendment, and two distinct failed workers return the slice to main.
+
+Use the repository PR template and MAINTAINERS.md. Explicit maintainer integration is allowed only after checking live identity/role, outstanding objections, required CI, and required security review. Existing PR head authors remain attributed; carried commits use cherry-pick provenance and a Co-authored-by trailer surviving squash. After landing, verify merge SHA ancestry, actual file delta, destination preservation, and authors. Close original carry PRs only then. #3950 stays open until both timezone and B JWT fixes are proven on dev; C owns final closure. A/B status contributes to a readiness report, not release authority.
+
+## Stop and outcomes
+
+DONE requires all three delivered/proven already present and #3950 reconciled; final report lists source PR, delivery PR, landed SHA, actual CI results, authors and residuals. A blocked item does not stop independent work. Missing authority or unsafe evidence is unresolved, not a successful criterion. Read goalplan/ledger after each D and continue remaining cycles. Scope does not include a fixed cost/time budget or new paid service purchases.
+
+## Roadmap audit and completion
+
+Independent astra high roadmap audit: PASS, no blocking findings. The timeout prose was aligned with the dedicated child marker used in the exact patch. The roadmap-only check is Git diff whitespace plus independent source/semantic audit; no product suite was run. Next cycle: adopt and validate the unchanged #3953 correction.
+
+## Final reconciliation
+
+Privacy and release-note cycles completed before the timezone cycle. All delivery evidence and residuals are in050_outcome.md. Original3950 closed after both BJWT and Ctimezone landing proof. This unit archives to_fin through a separate docs-only PR; no product commit is combined with this record.
diff --git a/devlog/_fin/260908_c248_individual_fixes/010_privacy.md b/devlog/_fin/260908_c248_individual_fixes/010_privacy.md
new file mode 100644
index 0000000000..6e22b7a5f2
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/010_privacy.md
@@ -0,0 +1,19 @@
+# Phase privacy: adopt the exact #3953 correction
+
+Source SHA: 05fd82807b4a0014f84b9d74d05b70a3591cb574. Source URL: https://github.com/lidge-jun/opencodex/pull/3953
+
+MODIFY the two existing records under devlog/_plan/260904_provider_quota_refresh/: 030_wp3_live_verification_and_pr.md and 031_live_verification_record.md. DELETE assets/030_accounts_refresh_button.png and assets/040_accounts_refresh_result.png. The exact after-content is the existing source SHA's Git blobs, retrieved by `git show :`; do not copy removed values into this plan. The two deletions and two post-image blobs define the complete executable patch; no other path changes. Reuse the unchanged existing PR if its head still matches; otherwise refresh and re-audit instead of force-pushing the contributor branch.
+
+Acceptance: both asset paths are absent in the candidate tree; no retained Markdown literal reference points to them; the isolated-instance and real forced-read evidence remains; the cleanup statement still says moved to Trash, never permanent destruction. Do not open/display either removed PNG. Independent privacy/semantic review checks this exact source. Current-head hosted PR scope check and aggregate must complete, with all skipped jobs described as skipped. Inspect full candidate delta and workflow equality before approving a fork run. No public operating values are recorded in new artifacts. Public documentation is the SoT target; history cleanup is out of scope.
+
+Rollback: retain source/landed SHAs, but do not automatically reintroduce removed captures; any rollback needs explicit privacy assessment. Completion uses actual merged PR state/merge SHA, touched-path equality, unchanged destination paths and author attribution.
+
+Execution decision: use a maintainer-owned carry PR with the identical source commit. The contributor checklist asks for local-CI attestation that this run cannot truthfully supply under the no-local-product-check instruction; no source rewrite or new behavior is needed. Original #3953 remains open until the carry lands, and its author is preserved in the squash trailer.
+
+C review repair: CodeRabbit requested American-English afterward at the existing isolation sentence. Accepted one-word correction in 0ed232d5c, with surrounding historical facts unchanged. Previous CI 34166442230 passed 3 scope/aggregate jobs and skipped 10 product jobs; it does not certify the new head. The new head must be checked before landing.
+
+Source refresh correction: original #3953 advanced to ca21efd29730086ede902c4701124893ce58b404 before closure. It remains OPEN; any earlier closure claim in the operational task log was premature and has been corrected. The initial carry is already landed and must not be rewritten. Audit and carry the incremental 05fd828..ca21efd2 delta as a separate privacy follow-up: MODIFY 000_plan.md, 030_wp3_live_verification_and_pr.md, 031_live_verification_record.md under the source unit; DELETE assets/010_meta_usage_quota.png and assets/020_usage_refresh_result.png. Exact post-images are sourceca21efd2 blobs, retaining the landed afterward spelling. The complete delta is retrieved with git diff05fd828..ca21efd2 scoped to those five paths. Acceptance: one retention rule covers both Accounts/Usage, textual behavior and Trash historical outcomes remain, no PNG inspected, all four capture assets and all scoped old references absent, current-head hosted scope checks and fresh source/author/landing proof.
+
+Review synthesis: #3959 exposed two issues. Accepted the source plan/actual isolation mismatch and corrected both old restart sites so completed scratch evidence supersedes the working-service restart plan (fc6b07eaf). Declined history purge as explicitly outside owner scope; the historical reachability residual is preserved, not claimed fixed. Both review threads have documented dispositions. No runtime operation was performed. Latest head needs fresh hosted scope CI.
+
+DONE: initial carry#3955 landed9c54000c9 and follow-up#3959 landed01c23aedc. Current-head hosted scope CI34167651789 success3/skipped10, independent final privacy audit PASS, all known review findings dispositioned; automatic rereview was pending at merge and not counted as successful. Both landed trees, parents, dev ancestry and actual author trailers verified. Original#3953 closed at refreshedca21efd2. History purge remains explicitly outside scope.
diff --git a/devlog/_fin/260908_c248_individual_fixes/020_release_notes.md b/devlog/_fin/260908_c248_individual_fixes/020_release_notes.md
new file mode 100644
index 0000000000..de8b38e701
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/020_release_notes.md
@@ -0,0 +1,144 @@
+# Phase release_notes: exact leading enforcement marker normalization
+
+Source PR #3899, source SHA 4d6896cd0bd62434b4703a1956fe57a99cd4959a. MODIFY the three files below. Preserve/reuse the source PR's related numbered implementation record if carrying its whole commit; it is documentation for this same bug, not another feature. Security review covers title text handling only: no workflow, command dispatch, credentials, publishing or release execution change. SoT: structure/06_docs-and-release.md.
+
+Activation/acceptance: prefixed generated and carried notes lose only the exact leading marker in summaries and full changelog; conventional scope grouping and attribution remain; unrelated bracketed/nonleading/near-match markers remain. Hosted CI must execute tests/ci-workflows/release-notes.test.ts (via the existing shard manifest) plus required gates. Explicit security review is recorded before maintainer sponsorship/integration. No local tests or typecheck are run. Rebase/carry applies only to our branch, uses original author and -x/Co-authored-by, and exact current-head checks. Issue #3895 closes only after verified dev landing. One independent revert restores only this bug's diff.
+
+Exact source patch follows; refresh against latest dev at its P phase:
+
+```diff
+diff --git a/scripts/release-notes.ts b/scripts/release-notes.ts
+index 16627f5f9..d0a58a043 100644
+--- a/scripts/release-notes.ts
++++ b/scripts/release-notes.ts
+@@ -546,8 +546,14 @@ export function parseGeneratedNotes(body: string): ReleaseNoteCategory[] {
+ const CONVENTIONAL_COMMIT_PREFIX =
+ /^(?:feat|fix|docs|chore|refactor|perf|test|build|ci|style|revert|merge|release)(?:\(([^)]+)\))?:\s*(.+)$/i;
+
++function stripPrEnforcementPrefix(title: string): string {
++ const text = title.trim();
++ const prefix = "[WRONG BRANCH] ";
++ return text.startsWith(prefix) ? text.slice(prefix.length).trim() : text;
++}
++
+ export function cleanPrTitle(title: string, prNumber: number | null = null): { scope: string | null; text: string } {
+- let text = title.trim();
++ let text = stripPrEnforcementPrefix(title);
+ let scope: string | null = null;
+ const prefix = CONVENTIONAL_COMMIT_PREFIX.exec(text);
+ if (prefix) {
+@@ -689,7 +695,7 @@ export function renderReleaseNotes(input: {
+ changelog.push(`Full Changelog: https://github.com/${repo}/compare/${from}...${to}`, "");
+ }
+ for (const pr of allPrs) {
+- changelog.push(`- #${pr.number} ${pr.title.trim()} @${pr.author}`);
++ changelog.push(`- #${pr.number} ${stripPrEnforcementPrefix(pr.title)} @${pr.author}`);
+ }
+ parts.push(changelog.join("\n"));
+ }
+diff --git a/structure/06_docs-and-release.md b/structure/06_docs-and-release.md
+index 8c6149802..886c8fc04 100644
+--- a/structure/06_docs-and-release.md
++++ b/structure/06_docs-and-release.md
+@@ -227,6 +227,11 @@ so stable notes are the aggregate of their preview train. The raw commit dump is
+ intentionally gone — non-PR commits stay reachable via the Full Changelog compare link when
+ that link is available.
+
++Both summary bullets and full-changelog titles strip the exact leading `[WRONG BRANCH] `
++enforcement marker. Other bracketed text is preserved. Summary bullets still remove conventional
++commit prefixes and group by scope; full-changelog entries keep those conventional prefixes,
++PR numbers, and author attribution. This normalization does not change PR-target enforcement.
++
+ The deterministic renderer produces the structure but not curated prose. Maintainers who want
+ the OpenAI-style grouped summaries can run the optional local polish step against the rendered
+ body (needs an OpenAI-compatible API key):
+diff --git a/tests/ci-workflows/release-notes.test.ts b/tests/ci-workflows/release-notes.test.ts
+index 11196108d..d27036008 100644
+--- a/tests/ci-workflows/release-notes.test.ts
++++ b/tests/ci-workflows/release-notes.test.ts
+@@ -455,6 +455,20 @@ describe("rewriteTakeoverCredits", () => {
+ });
+
+ describe("cleanPrTitle", () => {
++ test("removes the enforcement marker before extracting scope and sentence casing", () => {
++ expect(cleanPrTitle(" [WRONG BRANCH] chore(release): promote validated 2.45.0 to main (#3813) ", 3813)).toEqual({
++ scope: "release",
++ text: "Promote validated 2.45.0 to main",
++ });
++ });
++
++ test.each([
++ ["[Preview] chore(release): keep this marker", "[Preview] chore(release): keep this marker"],
++ ["fix: document [WRONG BRANCH] markers", "Document [WRONG BRANCH] markers"],
++ ["[WRONG BRANCH]ish: keep this title", "[WRONG BRANCH]ish: keep this title"],
++ ])("preserves meaningful title text: %s", (title, text) => {
++ expect(cleanPrTitle(title).text).toBe(text);
++ });
+ test("strips conventional prefix, keeps scope, and sentence-cases the title", () => {
+ expect(cleanPrTitle("feat(providers): add Baseten Model APIs preset", 653)).toEqual({
+ scope: "providers",
+@@ -488,6 +502,55 @@ describe("cleanPrTitle", () => {
+ });
+
+ describe("renderReleaseNotes", () => {
++ test.each(["delta", "carried"])("removes the bot marker from summaries and full changelogs (%s)", source => {
++ const body = [
++ "## What's Changed",
++ "### Chores",
++ "* [WRONG BRANCH] chore(release): promote validated 2.45.0 to main by @lidge-jun in https://github.com/lidge-jun/opencodex/pull/3813",
++ ].join("\n");
++ const notes = renderReleaseNotes({
++ npmMetadata: "",
++ ...(source === "delta" ? { deltaPrNotes: body } : { carriedPreviewNotes: [
++ "## Chores", "",
++ "- [WRONG BRANCH] chore(release): promote validated 2.45.0 to main (#3813)", "",
++ "## Changelog", "",
++ "- #3813 [WRONG BRANCH] chore(release): promote validated 2.45.0 to main @lidge-jun",
++ ].join("\n") }),
++ });
++ expect(notes).toBe([
++ "## Chores", "",
++ "- Promote validated 2.45.0 to main (#3813)", "",
++ "## Changelog", "",
++ "- #3813 chore(release): promote validated 2.45.0 to main @lidge-jun", "",
++ ].join("\n"));
++ });
++
++ test("groups a bot-prefixed title with ordinary titles of the same scope", () => {
++ const notes = renderReleaseNotes({
++ npmMetadata: "",
++ deltaPrNotes: [
++ "## What's Changed", "### Chores",
++ "* [WRONG BRANCH] chore(release): promote verified version by @maintainer in https://github.com/lidge-jun/opencodex/pull/10",
++ "* chore(release): update notes by @contributor in https://github.com/lidge-jun/opencodex/pull/11",
++ ].join("\n"),
++ });
++ expect(notes).toContain("- Release: Promote verified version; Update notes (#10, #11)");
++ expect(notes).toContain("- #10 chore(release): promote verified version @maintainer");
++ expect(notes).toContain("- #11 chore(release): update notes @contributor");
++ expect(notes).not.toContain("[WRONG BRANCH]");
++ });
++
++ test.each([
++ "[Preview] chore(release): retain the preview marker",
++ "fix: document [WRONG BRANCH] markers (#99)",
++ "[WRONG BRANCH]ish: retain this title",
++ ])("preserves meaningful full-changelog title text: %s", title => {
++ const notes = renderReleaseNotes({
++ npmMetadata: "",
++ deltaPrNotes: `## What's Changed\n### Chores\n* ${title} by @contributor in https://github.com/lidge-jun/opencodex/pull/12`,
++ });
++ expect(notes).toContain(`- #12 ${title} @contributor`);
++ });
+ const carried = [
+ "",
+ "",
+```
+
+## C-stage correction: active release builder
+
+Accepted Codex review: actual release.yml invokes scripts/build-release-changelog.ts, whose changelog still used pr.title.trim(). The original tests certified a renderer but not this active entry. Extend the same bug fix: export stripPrEnforcementPrefix from scripts/release-notes.ts, import/use it for PR changelog titles in scripts/build-release-changelog.ts; add public buildReleaseNotes regressions in existing tests/ci-workflows/build-release-changelog.test.ts for generated-note enrichment and associated-PR fallback, asserting cleaned summary, preserved conventional changelog title/author/ID, and unrelated/embedded/near-match preservation. Keep category policy, direct-commit policy, network/dispatch and release coverage rules unchanged. The two new paths are part of this one bug, not a new delivery. Hosted current-head CI must execute both renderer test files. No local product test. Re-audit active caller and pure-string security boundary before accepting the repair.
+
+Repair source audit PASS at ef15842fc: actual builder emission and generated/associated regression paths verified. Source-of-truth paragraph corrected in be1f60f28 to distinguish active builder from standalone renderer; category selection/direct-commit policy unchanged. Final proof compares landed blobs to final reviewed candidate, not the original incomplete source. Prior run34167832861 passed16/skipped3 and showed original renderer cases onLinux/macOS; final newhead must be certified separately.
+
+DONE: PR3960 landed9c8f66b9d, finalheadbe1f60f28; CI34168481093 success16/skipped3. Both renderer files and new5 active-builder cases were observed in Linux logs; macOS lanespassed. Independent final source/security auditPASS. Exact destination60bcb9050 plus reviewed patch tree verified; coauthor present; source3899 and issue3895 closed. The combined destination tree was verified structurally, not claimed executed as the PR test tree. Local productcommandsNOTRUN.
diff --git a/devlog/_fin/260908_c248_individual_fixes/030_timezone.md b/devlog/_fin/260908_c248_individual_fixes/030_timezone.md
new file mode 100644
index 0000000000..479027db3f
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/030_timezone.md
@@ -0,0 +1,157 @@
+# Phase timezone: extract only the Santiago fixture
+
+Source PR #3950. Carry ONLY commit 1d8f6ff7e8d48f33c3ce7a1b7118068754bbbe83 onto current dev, retaining luvs01's author and adding a surviving Co-authored-by. MODIFY only gui/tests/usage-custom-range.test.tsx. No JWT, product UI, dependency or workflow change. No UI screenshot is fabricated: describe the test-only scope truthfully in the PR. No new SoT contract beyond fixture isolation; production date interpretation is unchanged.
+
+Activation/acceptance: parent TZ absent and set cases retain exact presence/value and local Date epoch; a child Bun process is created with TZ=America/Santiago and an exact anchored test-name filter, preventing recursion by that timezone value. Child asserts skipped midnight, final-day activity and tooltip as before. Process deadline 12s, child test timeout 10s, parent test timeout 15s; timeout, signal and nonzero exit surface captured diagnostics. Reviewer must check config/preload behavior under direct child invocation and Windows Bun 1.4.0 compatibility. Hosted dashboard test gate explicitly executes this test file; inspect result and logs, not only a generic check badge. Additional fault-path testing is required only if audit reveals a reachable unprotected failure; amend this doc before any code change. Local product tests/build/typecheck/install NOT RUN.
+
+#3950 original stays open until B's separate JWT fix is independently confirmed on dev. No assumption that the original mixed PR's CI certifies this split head. One independent revert covers the timezone test only.
+
+Exact source patch follows:
+
+```diff
+diff --git a/gui/tests/usage-custom-range.test.tsx b/gui/tests/usage-custom-range.test.tsx
+index 887c31134..02df29f3d 100644
+--- a/gui/tests/usage-custom-range.test.tsx
++++ b/gui/tests/usage-custom-range.test.tsx
+@@ -154,31 +154,45 @@ for (const connected of [false, true]) {
+ }
+
+ test("America/Santiago midnight DST retains final-day activity and tooltip", async () => {
+- const previous = process.env.TZ;
+- process.env.TZ = "America/Santiago";
+- try {
+- expect(new Date(2026, 8, 6, 0).getHours()).toBe(1);
+- await mount();
+- await respond(0, "preset-marker");
+- await enter("2026-09-05T00:00", "2026-09-07T23:59");
+- await apply();
+- const gate = requests.at(-1)!;
+- const data = report(gate, "santiago-marker", "2026-09-07");
+- data.days = ["2026-09-05", "2026-09-06", "2026-09-07"].map(date => ({
+- date, requests: date === "2026-09-07" ? 7 : 0, measuredRequests: 0, reportedRequests: 0,
+- totalTokens: date === "2026-09-07" ? 700 : 0, models: [],
+- }));
+- await act(async () => gate.resolve(Response.json(data)));
+- const active = container.querySelector('.heatmap-grid .heatmap-cell:not(.heatmap-cell-0)');
+- expect(active).not.toBeNull();
+- await act(async () => active!.dispatchEvent(new testWindow.MouseEvent("mouseover", { bubbles: true })));
+- expect(container.querySelector(".heatmap-tip-date")?.textContent).toBe("2026-09-07");
+- expect(container.querySelector(".heatmap-tip")?.textContent).toContain("700");
+- } finally {
+- if (previous === undefined) delete process.env.TZ;
+- else process.env.TZ = previous;
++ if (process.env.TZ !== "America/Santiago") {
++ // Restoring an absent TZ can change Bun's effective timezone on Windows.
++ // Start the DST case in its timezone without mutating this suite's clock.
++ const timezone = { present: Object.hasOwn(process.env, "TZ"), value: process.env.TZ };
++ const localTime = new Date(2020, 8, 15, 10, 20).getTime();
++ const child = Bun.spawnSync([
++ process.execPath, "test", import.meta.path,
++ "-t", "^America/Santiago midnight DST retains final-day activity and tooltip$",
++ "--timeout", "10000",
++ ], {
++ env: { ...process.env, TZ: "America/Santiago" },
++ stdout: "pipe", stderr: "pipe", timeout: 12000, killSignal: "SIGKILL",
++ });
++ const diagnostics = `${child.stdout.toString()}\n${child.stderr.toString()}`;
++ expect(child.exitedDueToTimeout, diagnostics).not.toBe(true);
++ expect(child.signalCode, diagnostics).toBeUndefined();
++ expect(child.exitCode, diagnostics).toBe(0);
++ expect({ present: Object.hasOwn(process.env, "TZ"), value: process.env.TZ }).toEqual(timezone);
++ expect(new Date(2020, 8, 15, 10, 20).getTime()).toBe(localTime);
++ return;
+ }
+-});
++ expect(new Date(2026, 8, 6, 0).getHours()).toBe(1);
++ await mount();
++ await respond(0, "preset-marker");
++ await enter("2026-09-05T00:00", "2026-09-07T23:59");
++ await apply();
++ const gate = requests.at(-1)!;
++ const data = report(gate, "santiago-marker", "2026-09-07");
++ data.days = ["2026-09-05", "2026-09-06", "2026-09-07"].map(date => ({
++ date, requests: date === "2026-09-07" ? 7 : 0, measuredRequests: 0, reportedRequests: 0,
++ totalTokens: date === "2026-09-07" ? 700 : 0, models: [],
++ }));
++ await act(async () => gate.resolve(Response.json(data)));
++ const active = container.querySelector('.heatmap-grid .heatmap-cell:not(.heatmap-cell-0)');
++ expect(active).not.toBeNull();
++ await act(async () => active!.dispatchEvent(new testWindow.MouseEvent("mouseover", { bubbles: true })));
++ expect(container.querySelector(".heatmap-tip-date")?.textContent).toBe("2026-09-07");
++ expect(container.querySelector(".heatmap-tip")?.textContent).toContain("700");
++}, 15000);
+
+ test("Apply submits inclusive bounds once; Clear restores the held preset without custom cache entries", async () => {
+ await mount();
+```
+
+## Audit-driven amendment before implementation
+
+The source patch's explicit 15-second per-test timeout overrides its child CLI 10-second timeout. Change the final test timeout to `process.env.OCX_USAGE_SANTIAGO_CHILD === "1" ? 10000 : 15000`. Add a unique completion marker printed only after the child's last UI assertion; require the marker in the parent as well as exit/signal/timeout checks. Set the child's cwd explicitly to the dashboard root resolved from import.meta.dir. These are same-bug test integrity changes; no production code changes. Preserve the original assertions and parameterized test cases.
+
+Existing hosted Windows/macOS jobs do not run gui/tests. A supplemental verification-only branch will use the already-registered ci.yml workflow_dispatch path, with a separately reviewed minimal workflow that checks out an immutable candidate SHA and executes only focused timezone proof on GitHub-hosted ubuntu/windows/macos. This branch/workflow is excluded from delivery and never merged. Candidate PR CI remains unchanged and required; the supplemental run is independently labeled, not passed off as normal candidate workflow CI. Actions use existing pinned SHAs, contents:read only, no secrets, checkout persist-credentials:false, Bun1.4.0, frozen root and dashboard installs on the hosted machines, and bounded jobs/processes. Never run any of these commands locally. Negative controls must restore candidate bytes before the final positive run and record source identity.
+
+The proposed hosted verification starts in gui/: `bun test --isolate ./tests/usage-custom-range.test.tsx`, with TZ absent, Etc/UTC, Asia/Seoul and America/Santiago in distinct subprocess environments. Verify parent environment and next tests, child success marker, nonzero-exit/absent-marker propagation and process deadline; no fixture/process may survive teardown. Exact workflow YAML, pinned commit and control script are reviewed before dispatch. The repository's Windows product runtime suite is distinct from this Windows dashboard proof.
+
+### Exact test-integrity follow-up diff atop the original source commit
+
+```diff
+--- a/gui/tests/usage-custom-range.test.tsx
++++ b/gui/tests/usage-custom-range.test.tsx
+@@ -1,5 +1,6 @@
+ import { afterEach, beforeEach, expect, test } from "bun:test";
+ import { Window } from "happy-dom";
++import { resolve } from "node:path";
+ import { act } from "react";
+ import type { Root } from "react-dom/client";
+ import { LanguageProvider } from "../src/i18n/provider";
+@@ -154,7 +155,7 @@
+ }
+
+ test("America/Santiago midnight DST retains final-day activity and tooltip", async () => {
+- if (process.env.TZ !== "America/Santiago") {
++ if (process.env.OCX_USAGE_SANTIAGO_CHILD !== "1" && process.env.TZ !== "America/Santiago") {
+ // Restoring an absent TZ can change Bun's effective timezone on Windows.
+ // Start the DST case in its timezone without mutating this suite's clock.
+ const timezone = { present: Object.hasOwn(process.env, "TZ"), value: process.env.TZ };
+@@ -164,17 +165,20 @@
+ "-t", "^America/Santiago midnight DST retains final-day activity and tooltip$",
+ "--timeout", "10000",
+ ], {
+- env: { ...process.env, TZ: "America/Santiago" },
++ cwd: resolve(import.meta.dir, ".."),
++ env: { ...process.env, TZ: "America/Santiago", OCX_USAGE_SANTIAGO_CHILD: "1" },
+ stdout: "pipe", stderr: "pipe", timeout: 12000, killSignal: "SIGKILL",
+ });
+ const diagnostics = `${child.stdout.toString()}\n${child.stderr.toString()}`;
+ expect(child.exitedDueToTimeout, diagnostics).not.toBe(true);
+ expect(child.signalCode, diagnostics).toBeUndefined();
+ expect(child.exitCode, diagnostics).toBe(0);
++ expect(child.stdout.toString().split(/\r?\n/), diagnostics).toContain("OCX_SANTIAGO_CASE_COMPLETED");
+ expect({ present: Object.hasOwn(process.env, "TZ"), value: process.env.TZ }).toEqual(timezone);
+ expect(new Date(2020, 8, 15, 10, 20).getTime()).toBe(localTime);
+ return;
+ }
++ expect(process.env.TZ).toBe("America/Santiago");
+ expect(new Date(2026, 8, 6, 0).getHours()).toBe(1);
+ await mount();
+ await respond(0, "preset-marker");
+@@ -192,7 +196,8 @@
+ await act(async () => active!.dispatchEvent(new testWindow.MouseEvent("mouseover", { bubbles: true })));
+ expect(container.querySelector(".heatmap-tip-date")?.textContent).toBe("2026-09-07");
+ expect(container.querySelector(".heatmap-tip")?.textContent).toContain("700");
+-}, 15000);
++ if (process.env.OCX_USAGE_SANTIAGO_CHILD === "1") console.log("OCX_SANTIAGO_CASE_COMPLETED");
++}, process.env.OCX_USAGE_SANTIAGO_CHILD === "1" ? 10000 : 15000);
+
+ test("Apply submits inclusive bounds once; Clear restores the held preset without custom cache entries", async () => {
+ await mount();
+```
+
+C review amendment: use the dedicated child marker as the sole recursion guard, even when the parent already starts in Santiago. This preserves all original DST assertions and makes completion/state checks run for every parent TZ. Accepted CodeRabbit finding; final source/evidence checkout SHA will be repinned and hosted proof rerun. Prior Linux/Windows proof8223788bd remains historical, not finalhead evidence.
+
+Final candidate ce71d9171 passed independent marker-guard source re-audit. Evidence workflow7d5f1097e/run34170111719 checks out exactcandidatece71d9171; Linux/Windows/macOS each completed10scenarios, fivepositive/fiveexpectednegative, with exactfailure attribution, timeoutPIDabsence and candidatebytesrestored. Actual evidence JSON logs checked. Normal PR3967CI34170093095 pending; no completion/landing claim yet. Existing maintainer gui-screenshot-waived exception applied for test-only change after workflow/label policy inspection. No UI screenshot fabricated, no product gate waived.
+
+NormalCI attempt1 of34170093095 was cancelled at macos1 job20-minute deadline. Last emitted test was the unchanged client-connect CLI rejection case, followed by dangling-process cleanup and no completion. This root macOS lane does not include gui/tests; exact cause remains under investigation. Preserve cancellation as an unsuccessful/incomplete attempt. One same-head failed-job recheck was requested for diagnosis; a green recheck alone does not establish the unrelated runner stall is fixed. Supplemental3OS timezoneproof remains separately valid.
+
+DONE: PR3967 landedc46c22f3e with luvs01 trailer and exactcandidate file. Final candidatece71d9171 supplemental3OS run34170111719 passed all30expected scenarios. StandardCI34170093095 attempt2 passed19jobs/skipped2; attempt1 macos1 stalled/cancelled20min at unchangedclientconnect boundary remains unresolved reliability residual, not a fixedflake claim. Exact destinationbbea77a48+candidatepatch tree and devancestry verified. BJWT3962/eb4188a9 confirmed ondev; source3950 closure follows reconciliation.
diff --git a/devlog/_fin/260908_c248_individual_fixes/040_reconcile.md b/devlog/_fin/260908_c248_individual_fixes/040_reconcile.md
new file mode 100644
index 0000000000..753a2fa2ee
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/040_reconcile.md
@@ -0,0 +1,3 @@
+# Phase reconcile: independent delivery and release readiness
+
+No product delta. MODIFY this unit's outcome record (050_outcome.md) with each original PR, actual delivery PR, reviewed head, CI run/check counts, landed SHA, author trailer and issue state. Query B for the JWT-only landing and independently verify it in dev together with C's timezone commit before closing #3950. Inspect A/B status and record readiness without doing their work or publishing a release. Move this unit from devlog/_plan to devlog/_fin only after all scoped tasks are complete; publish a separate docs-only closeout PR if needed, keeping it out of all three bug commits. Verify that closeout's scope check and diff preserve product files. No version change or promotion. Outcomes must distinguish true merged source PRs from closed carry sources.
diff --git a/devlog/_fin/260908_c248_individual_fixes/050_outcome.md b/devlog/_fin/260908_c248_individual_fixes/050_outcome.md
new file mode 100644
index 0000000000..aa085d5840
--- /dev/null
+++ b/devlog/_fin/260908_c248_individual_fixes/050_outcome.md
@@ -0,0 +1,35 @@
+# Lane C outcome
+
+All three scoped corrections landed into dev through independent bug PRs. The capture correction needed a separate follow-up after its author advanced the source PR during CI. No already-landed commit was rewritten. This record is documentation only and is not another product fix.
+
+| Source | Delivery PR | Landed SHA | Current-head CI | Scope |
+|---|---|---|---|---|
+| #3953 initial | [3955](https://github.com/lidge-jun/opencodex/pull/3955) | `9c54000c937276ba8d93ce63a922b3fe6797cbde` | [34166758020](https://github.com/lidge-jun/opencodex/actions/runs/34166758020) (3 success / 10 skipped) | Current-tree Accounts capture cleanup |
+| #3953 follow-up | [3959](https://github.com/lidge-jun/opencodex/pull/3959) | `01c23aedcdfcb913151a2ac8f7acebda58d91eee` | [34167651789](https://github.com/lidge-jun/opencodex/actions/runs/34167651789) (3 success / 10 skipped) | Consistent capture retention and isolation guidance |
+| #3899 / #3895 | [3960](https://github.com/lidge-jun/opencodex/pull/3960) | `9c8f66b9df4cdf133a16c95a95ee07ff5171a46d` | [34168481093](https://github.com/lidge-jun/opencodex/actions/runs/34168481093) (16 success / 3 skipped) | Release-note marker in both actual and standalone builders |
+| #3950 timezone only | [3967](https://github.com/lidge-jun/opencodex/pull/3967) | `c46c22f3e4d00ff31a0e6bb10f74505577806776` | [34170093095](https://github.com/lidge-jun/opencodex/actions/runs/34170093095) (19 success / 2 skipped) | Santiago subprocess isolation and oracle integrity |
+
+## Proof and attribution
+
+Each landing was serialized through the shared merge lock and checked against the then-current destination: actual merge parent, computed combined tree, dev ancestry and surviving Co-authored-by trailer. luvs01 is credited in both capture carries and the timezone carry; Joonsuh Park is credited in the release-note correction. The original source PRs were closed as carried, not described as directly merged.
+
+#3953 was closed only after its refreshed ca21efd2 follow-up was included. #3899 and issue #3895 closed after the active release builder was corrected and verified. #3950 was closed only after B's independent JWT delivery #3962 (eb4188a9f2e127f5ee2980b62d6e5bb213c43c70) and C's timezone delivery #3967 were both confirmed on dev. Product commits remain independently revertible.
+
+The release-note original patch missed scripts/build-release-changelog.ts, the actual release workflow entry. Review led to a shared normalizer and five public-builder cases covering generated and associated PR sources and negative marker preservation. Those cases and the original renderer cases were observed passing in the final Linux CI logs; the final macOS lanes also passed. The structure guide now accurately distinguishes the active and standalone renderers.
+
+Timezone final candidate ce71d917143ddcbd5675b6ba92d8b1053971cd25 was separately exercised by evidence workflow7d5f1097ec587a0ced441f475eb02d750e06b9ac in [run34170111719](https://github.com/lidge-jun/opencodex/actions/runs/34170111719). The workflow checked out that immutable candidate separately. Linux, Windows and macOS each completed ten scenarios: five positive/restored runs and five deliberately failing controls. Controls require the intended test failure and specific diagnostics, not any nonzero exit. All platforms verified the final candidate file hash recorded below. Child timeout termination and restored candidate bytes/HEAD were verified. The evidence branch is not in any delivery PR and is never merged.
+
+## Limits and remaining work
+
+- All local product tests, test:changed, typechecks, builds and dependency installs were NOT RUN. Mutating Git operations disabled hooks per command, and pushes used --no-verify. Git/diff/source and operational evidence checks are distinct from product tests.
+- Skipped jobs are not counted as passing tests. Normal PR workflows skip the full Windows runtime suite and macOS whole-pool control; the supplementary timezone run explicitly supplies Windows/macOS focused dashboard evidence, not a full runtime-suite result.
+- Timezone normal CI34170093095 attempt1 timed out after20minutes in the unchanged root macOS client-connect test. The next helper contains an unbounded synchronous child wait, but the actual stopping mechanism is unproven. Attempt2 succeeded on the same candidate without a source change. The cancelled attempt remains unsuccessful evidence and the unrelated CI reliability defect is not claimed fixed.
+- Privacy cleanup affects the current tree only. Historical blobs/links were not purged, and no claim of historical erasure is made. The working proxy was not restarted or reconfigured by this task.
+- Concurrent dev changes were preserved through actual-tree comparison. That structural proof does not imply every merged integration tree was separately executed by the candidate CI.
+- A and B were still active at reconciliation. B's JWT slice is verified; no assertion is made that their remaining changes or the overall2.48 release are complete. main/preview promotion, version changes and npm publication were outside C's authority and were not performed.
+
+## Final supplemental evidence
+
+- win32: Bun1.4.0, candidate file SHA-256 `6cbb58c96643f500cf2541ef3b7707aed072c1f981b16b49f97949536fe30f50`, ten scenarios, restored=True.
+- linux: Bun1.4.0, candidate file SHA-256 `6cbb58c96643f500cf2541ef3b7707aed072c1f981b16b49f97949536fe30f50`, ten scenarios, restored=True.
+- darwin: Bun1.4.0, candidate file SHA-256 `6cbb58c96643f500cf2541ef3b7707aed072c1f981b16b49f97949536fe30f50`, ten scenarios, restored=True.
diff --git a/devlog/_fin/260908_c_track_config_init_stack/000_plan.md b/devlog/_fin/260908_c_track_config_init_stack/000_plan.md
new file mode 100644
index 0000000000..046e2c627d
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/000_plan.md
@@ -0,0 +1,79 @@
+# 000_plan.md — C track: config file + init as a manual PR stack
+
+## Objective
+
+Land the C triage track (config-file and init surfaces) on `dev` as one manual,
+dependency-ordered branch chain whose tip carries every layer. The track has two
+existing contributor pull requests plus one gap discovered while planning:
+
+| Layer | Source | Surface |
+|---|---|---|
+| wp1 | PR #3900 by @x3M3x | `src/config/atomic-write.ts` Bun/Windows ENOENT |
+| wp2 | new (this unit) | `src/config/initialize.ts` sibling numeric flag |
+| wp3 | PR #3896 by @parkjs101 | `ocx init` publication recovery guidance (closes #3893) |
+
+wp2 exists on its own merit, not as glue. `publishInitialConfigNoReplace` still
+opens its temp file with the numeric spelling that Bun miscompiles on Windows,
+so shipping wp1 alone leaves first-run config publication exposed to the same
+`ENOENT`. #3900 never touches `initialize.ts`; the file overlap is between wp2
+and wp3 only.
+
+## Constraints (owner-stated, this session)
+
+- **No local product suite.** No `bun run test`, `bun run typecheck`,
+ `bun run build`, or install. Every such check is recorded **NOT RUN**.
+- **Push with `--no-verify`** on every layer.
+- **CI on the tip only.** Verified mechanism in `040`: the lower layers are
+ pushed as branches but **no pull request is opened for them** until the tip
+ has landed. `.github/workflows/ci.yml` triggers on `pull_request: {}` with no
+ draft filter, so opening a lower PR would start CI; draft status suppresses
+ nothing.
+- **Green tip merges; the rest resolve.** When the tip's exact head SHA is green
+ against a current `dev` base, merge the tip, then resolve the source PRs and
+ close issue #3893.
+- **Original authors are preserved** with full `Co-authored-by: Name `
+ trailers that survive the squash (AGENTS.md "Landing another author's work").
+
+## Build order
+
+```
+codex/c-track-init-guidance → the ONLY pull request (base dev) ← wp3 tip
+codex/c-track-initialize-flag → branch only, no PR ← wp2
+codex/c-track-atomic-write → branch only, no PR ← wp1
+──────────────────────────────── dev
+```
+
+Each branch is based on the one below, so the tip's tree is the cumulative
+result. wp2 sits between the carried PRs because wp3 inserts a line directly
+after the `openSync` call that wp2 rewrites; constructing wp2 first means that
+adjacent-hunk overlap is resolved once while carrying wp3. This is a chosen
+construction order for a single conflict resolution, not a semantic
+prerequisite — either change could be written first.
+
+## Scope boundary
+
+IN: the three layers above, their regression tests, the docs/structure text that
+#3896 already carries, and this devlog unit.
+
+OUT: `#3838`/`#3917` adapter work, any other triage track, release promotion,
+`main`/`preview`, and any behavioral change to hard-link publication, ACL
+hardening, or credential storage beyond the flag spelling.
+
+## Verifiers
+
+Local product gates are forbidden this session, so acceptance rests on
+repository CI against the tip plus read-only inspection.
+
+| Claim | Evidence | Status |
+|---|---|---|
+| Layers carry original authorship | `git log --format='%(trailers:key=Co-authored-by)'` on the tip, then on the landed commit | to run (read-only) |
+| wp2 removes the numeric spelling | `rg 'constants\.O_' src/config/initialize.ts` on the pushed tip tree | to run (read-only) |
+| Carried content really landed | tip tree vs. each source PR's pinned patch, then landed-merge tree comparison (see `040`) | to run (read-only) |
+| Layers build and pass | repository CI on the tip head SHA, base `dev` | tip only |
+| Local suite / typecheck / build | — | **NOT RUN** (owner instruction) |
+
+## Terminal outcome
+
+DONE requires: tip CI success on its exact head SHA against a current `dev`
+base, tip merged into `dev` proven by fetched ancestry and tree comparison,
+source PRs resolved with credit intact, and #3893 closed.
diff --git a/devlog/_fin/260908_c_track_config_init_stack/010_layer1_atomic_write.md b/devlog/_fin/260908_c_track_config_init_stack/010_layer1_atomic_write.md
new file mode 100644
index 0000000000..d9e76ba2bb
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/010_layer1_atomic_write.md
@@ -0,0 +1,72 @@
+# 010_layer1_atomic_write.md — wp1: carry PR #3900
+
+Source: [PR #3900](https://github.com/lidge-jun/opencodex/pull/3900) by @x3M3x,
+head `744eb644028492784446fe9f0f73813d5d1fe59f`, two commits
+(`52c749561`, `744eb6440`).
+
+Branch: `codex/c-track-atomic-write`, base `dev`.
+
+## Problem
+
+`src/config/atomic-write.ts` builds its exclusive-create flags numerically.
+Bun on Windows misreads that combination and drops the creation bit, so every
+private temp write fails with `ENOENT`: `ocx start`, management-API config
+saves, and OAuth credential refreshes all route through these two writers.
+
+## Change (MODIFY, carried unmodified from #3900)
+
+`src/config/atomic-write.ts`
+
+```diff
+- const descriptor = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
++ const descriptor = openSync(path, "wx", 0o600);
+```
+
+Applied in both `writePrivateTempFile` and `writePrivateTempFileAsync`; the now
+unused `constants` import is dropped.
+
+`tests/windows/windows-secret-acl.test.ts` gains the source-oracle guard
+"atomic secret temp writer portability", asserting exactly two portable calls.
+
+## Semantics note (audit correction)
+
+The PR description calls `"wx"` exactly `O_WRONLY | O_CREAT | O_EXCL`. Node and
+Bun actually map it to `O_WRONLY | O_CREAT | O_EXCL | O_TRUNC`. It is
+**behaviorally** equivalent here rather than bit-identical: exclusive creation
+rejects an existing path, so `O_TRUNC` can never truncate one. `0o600` remains
+a separate mode argument and still applies. Recorded so a later reader does not
+inherit the imprecise claim.
+
+## Security review (independent, read-only)
+
+No blocking finding. Exclusivity is preserved for every caller of the default
+wrappers, which include OAuth `auth.json`, Codex account credentials, service
+API tokens, `config.json`, and `ocx.pid`. Ownership is marked only after a
+successful create, so no new pre-existing-temp or symlink-following path opens.
+Windows ACL ordering (create → own → harden → identity check → write → close)
+is untouched.
+
+## Authorship
+
+Both commits are cherry-picked with `-x`, so each retains
+`x3M3x ` as its git author and records the source SHA:
+
+| Carried commit | Source commit |
+|---|---|
+| `6a0abcf90` fix: use portable exclusive config temp creation | `52c7495618f18f2847b7f9468421442c1c573da1` |
+| `24a078d80` test: guard atomic temp writes against Bun/Windows ENOENT | `744eb644028492784446fe9f0f73813d5d1fe59f` |
+
+A squash landing keeps only the squash message and drops per-commit authors, so
+`b1a7f111c` adds the `Co-authored-by: x3M3x ` trailer to
+the branch. That trailer must be carried into the tip PR squash message and
+re-read on the landed commit.
+
+## Verification
+
+An independent read-only audit of the built branch confirmed the carried
+source-and-test diff is byte-identical to #3900 pinned patch (2,176 bytes),
+that both `-x` annotations and the original author survive, that the trailer
+parses through `git interpret-trailers`, and that no other `src/` file changed.
+
+Repository CI on the stack tip only. Local suite, typecheck, and build:
+**NOT RUN** (owner instruction).
diff --git a/devlog/_fin/260908_c_track_config_init_stack/020_layer2_initialize_flag.md b/devlog/_fin/260908_c_track_config_init_stack/020_layer2_initialize_flag.md
new file mode 100644
index 0000000000..b25a419481
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/020_layer2_initialize_flag.md
@@ -0,0 +1,69 @@
+# 020_layer2_initialize_flag.md — wp2: sibling flag in initialize.ts
+
+New work in this unit. Branch `codex/c-track-initialize-flag`, base
+`codex/c-track-atomic-write`.
+
+## Why this layer exists
+
+wp1 fixes the two writers in `atomic-write.ts`, but
+`publishInitialConfigNoReplace` in `src/config/initialize.ts` still opens its
+temp file with the same numeric spelling. Independent inspection confirms the
+identical Bun/Windows exposure: first-run `ocx init` fails before writing or
+publishing `config.json`, leaving `publication = "not-published"` and
+`hardLinkUnavailable = false`, so the CLI prints "Initial config publication
+did not finish." and exits 1.
+
+It also sits between the two carried PRs deliberately. #3896 inserts a line
+immediately after this `openSync` call, so building wp2 first means the
+adjacent-hunk overlap is resolved once, while carrying #3896 in wp3. This is a
+chosen construction order rather than a semantic prerequisite: #3900 does not
+touch this file at all, and either change could be written first.
+
+## Change (MODIFY)
+
+`src/config/initialize.ts`
+
+```diff
+ import {
+- closeSync, constants, fchmodSync, fstatSync, linkSync, lstatSync,
++ closeSync, fchmodSync, fstatSync, linkSync, lstatSync,
+ openSync, unlinkSync, writeFileSync,
+ } from "node:fs";
+@@
+- fd = openSync(temp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
++ fd = openSync(temp, "wx", 0o600);
+```
+
+`constants` is referenced only by the import and that one expression, so the
+import entry is removed with it.
+
+## Change (MODIFY, regression)
+
+`tests/windows/windows-secret-acl.test.ts` gains a sibling source-oracle test
+next to the wp1 guard, asserting exactly one portable call in
+`src/config/initialize.ts`.
+
+## Contract preserved
+
+The no-replace publication contract does not depend on the numeric spelling:
+hardening, `verifyPrivateTemp`, the single `linkSync` publication with its
+`EEXIST`/`collided` and `hardLinkUnavailable` handling, and the
+descriptor-owned `removeOwnedTemp` cleanup are all unchanged.
+
+## Out of scope: the same pattern under `src/lab/`
+
+An independent scan found three more exclusive opens sharing this combination:
+`src/lab/ledger/store.ts:153` and `:185` (recovery mutex, ledger lock) and
+`src/lab/public/private-file.ts:209` (private publication temp). They deserve the
+same portability follow-up, but Lab is an opt-in subsystem off the core request
+path, so they stay out of this track rather than widening a config-surface fix.
+
+Two further matches are not exclusive opens and must not be swept in:
+`src/codex/native-main-lock-file.ts:89` and `src/lab/fabric/scratch.ts:416`. The
+read/write sites in `src/lab/artifacts/secure-fs.ts` need individual treatment because
+`"wx"` would drop read access.
+
+## Verification
+
+Repository CI on the stack tip only. Local suite, typecheck, and build:
+**NOT RUN** (owner instruction).
diff --git a/devlog/_fin/260908_c_track_config_init_stack/030_layer3_init_guidance.md b/devlog/_fin/260908_c_track_config_init_stack/030_layer3_init_guidance.md
new file mode 100644
index 0000000000..5f755c686d
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/030_layer3_init_guidance.md
@@ -0,0 +1,65 @@
+# 030_layer3_init_guidance.md — wp3: carry PR #3896 (stack tip)
+
+Source: [PR #3896](https://github.com/lidge-jun/opencodex/pull/3896) by
+@parkjs101 (Joonsuh Park), head `fc78bc37d419576061b995281baf39c46655eaa9`,
+closes [#3893](https://github.com/lidge-jun/opencodex/issues/3893).
+
+Branch: `codex/c-track-init-guidance`, based on `codex/c-track-initialize-flag`.
+This is the stack tip and the only pull request opened for this unit.
+
+## Problem
+
+`ocx init` already separates denied hard-link publication from a generic
+failure, but a required permission-hardening failure falls into the generic
+message, and neither message tells the user what to do next. The user cannot
+tell why publication stopped or where to move `OPENCODEX_HOME`.
+
+## Change (carried from #3896, rebased onto wp2)
+
+- `src/config/initialize.ts`: a `hardeningFailed` flag set immediately before
+ the hardening call and cleared immediately after it returns — the assignments
+ surround `hardenInitialConfig`, which runs after `openSync`. The flag selects
+ a distinct message; `InitialConfigPublicationError` takes the matching option,
+ and both messages gain `OPENCODEX_HOME` recovery direction.
+- `docs-site/src/content/docs/getting-started/quickstart.md`: inspection before
+ retry, preserving existing configuration, choosing a supported location.
+- `structure/02_config-and-codex-home.md`: records the diagnostic distinction.
+- `tests/config/config-mutation-lock.test.ts`, `tests/service/init-eof.test.ts`:
+ permission, link, and cleanup faults, privacy-safe messages, backup
+ preservation. Both files already exist in the test-layout registries, so no
+ registry entry is added.
+- `devlog/_plan/260907_init_publication_guidance/010_implementation.md`: carried
+ as-is; on terminal closure that unit moves to `_fin/`.
+
+The rebase keeps wp2's `openSync(temp, "wx", 0o600)` and both `hardeningFailed`
+assignments around the hardening call.
+
+## Review (independent subagent audit, read-only, this session)
+
+Reviewed at `fc78bc37d`, all six files. No blocking finding:
+
+- The flag cannot be left incorrectly true. Write, verify, link, and close
+ failures all occur after it is cleared (`src/config/initialize.ts:95-115`,
+ `:129-134`). A throwing injected `io.harden` test seam would select the same
+ message, which is a seam edge rather than a production defect.
+- File I/O ordering, the no-replace guarantee, and private permissions are
+ unchanged (`:38-43`, `:98-130`).
+- The new messages are fixed text naming the `OPENCODEX_HOME` variable; they
+ interpolate no real paths, bytes, or filesystem error text, and raw errors
+ stay in the `cause` the CLI does not print (`src/cli/init.ts:262-267`).
+
+This is a static agent review, not the maintainer security review or the
+approval required by `MAINTAINERS.md`; those are recorded separately in `040`.
+
+## Authorship
+
+Carried with `Co-authored-by: Joonsuh Park `, the identity
+on the source commit. The trailer must appear in the **squash message** of the
+landed commit, and is verified on the landed commit rather than only on the
+branch.
+
+## Verification
+
+This tip is the only layer that triggers repository CI, and its exact head SHA
+must be green against a current `dev` base. Local suite, typecheck, and build:
+**NOT RUN** (owner instruction).
diff --git a/devlog/_fin/260908_c_track_config_init_stack/040_layer4_landing.md b/devlog/_fin/260908_c_track_config_init_stack/040_layer4_landing.md
new file mode 100644
index 0000000000..4413166db9
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/040_layer4_landing.md
@@ -0,0 +1,62 @@
+# 040_layer4_landing.md — wp4: tip CI, merge, and closure
+
+## CI suppression: mechanism, not draft status
+
+`.github/workflows/ci.yml` triggers on `pull_request: {}` with **no draft
+filter** (line 7), and the `changes` job gates expensive work on the PR's own
+file list, which includes `src/**` and `tests/**`. Opening a lower-layer pull
+request — draft or not — therefore starts repository CI.
+
+The mechanism that actually satisfies "CI on the tip only" is to **open no pull
+request for wp1 and wp2**. Their branches are pushed so the tip has a real
+parent chain, but only `codex/c-track-init-guidance` gets a PR, based directly
+on `dev` so its diff is the cumulative stack. One workflow run, one subject.
+
+## Landing sequence
+
+1. Push all three branches with `--no-verify`.
+2. Open the tip PR only, base `dev`, with the full repository template
+ (Summary, Verification, Checklist) and `Closes #3893`. Record the local
+ suite as NOT RUN with the owner instruction as the reason; the Verification
+ section must not imply a local green run.
+3. Confirm the tip is based on the current `dev` head before CI. If `dev` has
+ advanced, rebase and cascade first — CI against a stale base does not certify
+ the integration tree that will actually merge.
+4. Wait for CI on the tip's exact head SHA. Skipped or cancelled checks are not
+ passing evidence.
+5. Record the merge decision. Both current maintainers hold `admin`, and
+ `MAINTAINERS.md` permits explicit maintainer integration into `dev` without a
+ second approval, provided the decision and exact-head CI evidence are
+ recorded and security review is kept separate. The credential-adjacent
+ `atomic-write.ts` carry is the security-review subject; its independent audit
+ is summarized in `010` and must be named in the merge record.
+6. Merge the tip, pinning the reviewed head SHA.
+
+## Proving the carried work landed
+
+Ancestry alone is insufficient: `dev` can contain the merge while a conflict
+resolution silently dropped a contributor hunk. Before closing anything:
+
+- Compare each source PR's pinned patch against the tip tree, documenting the
+ one intentional adaptation (wp2 rewrites the `openSync` line that #3896's
+ hunk sits next to).
+- After the merge, compare the landed tree on fetched `dev` against the
+ reviewed tip tree.
+- Re-read the landed commit's trailers to confirm both `Co-authored-by` entries
+ survived the squash.
+
+A squash landing does not make the original contributor SHAs ancestors, so
+trailer and content comparison are the credit and delivery evidence.
+
+## Closure
+
+1. Close #3900 and #3896 as landed through the tip, naming the merge commit and
+ crediting @x3M3x and @parkjs101 with the evidence above.
+2. Close issue #3893: PRs here target `dev`, and GitHub only auto-closes linked
+ issues on the default branch.
+
+## Failure handling
+
+If the tip's CI fails, fix the responsible layer and cascade the rebase upward
+(`DEV-STACK-02`) before re-running CI on the new tip head. Do not open or merge
+a lower layer independently to bypass a red tip.
diff --git a/devlog/_fin/260908_c_track_config_init_stack/050_outcome.md b/devlog/_fin/260908_c_track_config_init_stack/050_outcome.md
new file mode 100644
index 0000000000..05e19c97a1
--- /dev/null
+++ b/devlog/_fin/260908_c_track_config_init_stack/050_outcome.md
@@ -0,0 +1,82 @@
+# 050_outcome.md — terminal record
+
+## Result
+
+Landed on `dev` as `6188458ae3f4fd84ef57344b60cf3ceeed80aa6f` through
+[#3941](https://github.com/lidge-jun/opencodex/pull/3941) on 2026-09-07.
+
+| Layer | Source | Disposition |
+|---|---|---|
+| wp1 | [#3900](https://github.com/lidge-jun/opencodex/pull/3900) by @x3M3x | carried, PR closed as superseded |
+| wp2 | new here | landed |
+| wp3 | [#3896](https://github.com/lidge-jun/opencodex/pull/3896) by @parkjs101 | carried, PR closed as superseded |
+| — | [#3893](https://github.com/lidge-jun/opencodex/issues/3893) | closed |
+
+Both `Co-authored-by` trailers are on the landed squash commit. The 13 files in
+the reviewed tip hash identical to their landed counterparts, `atomic-write.ts`
+on `dev` hashes identical to #3900's pinned version, and `initialize.ts` equals
+#3896's pinned file apart from wp2's two intended substitutions.
+
+## What the plan got right
+
+The tip-only CI mechanism worked exactly as designed. `ci.yml` triggers on
+`pull_request` with no draft filter, so the first plan's assumption that draft
+status suppresses CI was wrong; opening no pull request for the lower layers is
+what actually produced one workflow subject. No Cross-platform CI run exists for
+either lower branch.
+
+Ordering wp2 between the two carried PRs also paid off as predicted. The cherry-pick
+of #3896 produced exactly one conflict — the adjacent hunk where `hardeningFailed = true`
+sits directly after the rewritten `openSync` line — and it was resolved once.
+
+## What the plan got wrong, and what caught it
+
+The first roadmap draft failed its independent audit with seven findings. Three
+mattered: the false draft-CI claim above, merging on stale-base CI evidence, and
+proving delivery by ancestry alone when a squash can silently drop a contributor
+hunk. It also misstated the file overlap as wp1/wp3 when #3900 never touches
+`initialize.ts`. The revised plan passed re-audit, and the stale-base rule
+earned itself back: `dev` moved twice during this delivery, so the tip was
+rebased and re-certified rather than merged on its first green run.
+
+## The CI failure that was not ours
+
+The pre-rebase head failed one job, `test 4/4`, in
+`prompt probe process lifecycle > the last cancellation drains the exact child`.
+Investigation attributed it to that test's final parent-side PID poll expiring at
+its 15-second internal deadline: every preceding assertion passed, the replacement
+command had already observed the old child gone, and the same test passed on macOS
+in the same run. `src/codex/prompt-text-probe.ts` imports `node:fs` only for
+`existsSync`/`statSync` and never calls the changed writers. A same-head rerun
+passed; the rebased head passed 25/25 on the first attempt.
+
+Worth recording honestly: the investigation could not name the exact mechanism.
+The replacement considered the PID absent while the parent still considered it
+alive, which PID reuse, runtime liveness behavior, or a real observation defect
+could all explain. It is a flake by evidence of non-reproducibility, not by proof.
+
+## Follow-up left open
+
+Three exclusive opens under `src/lab/` share the numeric spelling this track
+replaced: `ledger/store.ts` (two) and `public/private-file.ts`. Lab is opt-in and
+off the core request path, so they stayed out rather than widening a config-surface
+fix. The read/write sites in `artifacts/secure-fs.ts` need individual treatment
+because `"wx"` would drop read access; they are not a mechanical substitution.
+
+## Verification boundary
+
+The local product suite, typecheck, and build were **NOT RUN** by owner
+instruction. Acceptance rested on repository CI against the tip
+([run 34153124187](https://github.com/lidge-jun/opencodex/actions/runs/34153124187):
+19 jobs succeeded, 2 skipped, zero failures on the first attempt) plus independent
+read-only audits at each layer. The two skips are the dispatch-only `macos control`
+and Windows shard lanes, so Windows packaging and keyring smoke passed but the
+Windows suite itself did not run.
+
+One limit worth stating plainly: the green PR run tested the tip against the base it
+was rebased onto, and #3940 landed on `dev` between that run and the merge. The
+C-track content is byte-identical either way, and the four files #3940 touched do not
+overlap this change, but the combined tree is certified by the post-merge `dev` run
+rather than by the PR run. That run has since completed:
+[run 34153892496](https://github.com/lidge-jun/opencodex/actions/runs/34153892496) on
+`6188458ae` succeeded, 19 jobs and 2 skips, so the landed combined tree is certified.
diff --git a/devlog/_fin/260908_provider_runtime_stack/000_plan.md b/devlog/_fin/260908_provider_runtime_stack/000_plan.md
new file mode 100644
index 0000000000..c8da992329
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/000_plan.md
@@ -0,0 +1,65 @@
+# 000 — Plan and live manifest
+
+Unit: `devlog/_plan/260908_provider_runtime_stack`. Session `01a080e2-1dfc-7082-bff8-5043215bdd35`.
+Snapshot: 2026-09-08T12:00Z (fetch), `origin/dev` = `29bb221c3`
+(`Merge pull request #4021 from lidge-jun/codex/release-248-record`).
+Carry worktree: `/private/tmp/ocx-prs-stack-01a080e2` (linked worktree of the main checkout;
+`core.worktree` unset, toplevel verified).
+
+## Objective
+
+Land the open provider-runtime contributor PRs on `dev` as one ordinary manual dependent PR
+stack, integrated with the repository's provider discipline (test layout, provider marks,
+docs-site sections, contributor attribution), and merge the stack bottom-up into `dev`
+after a single green final-head CI run. Constraints given by the maintainer:
+
+- Never run the local product suite, typecheck, build, or install. Every one of those is
+ labelled NOT RUN in the delivery record. Hosted CI on the final head is the only proof.
+- Every mutating Git command runs as `git -c core.hooksPath=/dev/null` (the repository
+ `postmerge` hook can otherwise install dependencies and typecheck). Push with
+ `--no-verify`.
+- CI runs once, on the top of the stack. Merge only if that head is green.
+- Ordinary dependent PR bases, no GitHub native stack registration (DEV-STACK-OPT-IN-01).
+- Cherry-pick, reimplement, squash, or rebase are all permitted. Original authors stay
+ as commit authors (`cherry-pick -x`) or in a `Co-authored-by` trailer.
+- Subagents: `anthropic/claude-opus-5` unlimited; Aside browser delegation unlimited.
+- Out of scope: release/publish, `main`/`preview` promotion, unrelated subsystems.
+
+## Work-phase map (one PABCD cycle each)
+
+| WP | Scope | Doc |
+|----|-------|-----|
+| wp1 | Docs-only roadmap: this manifest, layer plan (010), conflict map (011), mark sourcing (012), secondary dispositions (013) | 000-013 |
+| wp2 | Carry L1-L3 (CodeBuddy #3340, Qoder Global #3349, Qoder CN #3350) onto `dev` with layout registration | 020 |
+| wp3 | L4 marks + display names + docs-site sections + attribution; accepted secondary layers | 030 |
+| wp4 | Publish, final-head CI, bottom-up admin merge, ancestry proof, closeouts, delivery record | 040, 060 |
+
+## Manifest (exact head at snapshot)
+
+| PR | Author | Head | Base | Mergeable vs dev | +/- | Files | Commits | Draft |
+|----|--------|------|------|------------------|-----|-------|---------|-------|
+| #3340 | Flowershangfromthebranches | `4b705e92d` | dev | clean (merge-tree) | 2108/6 | 17 | 4 | yes |
+| #3349 | Flowershangfromthebranches | `4ac98bd4d` | dev | CONFLICTING (`tests/providers/provider-connection-test.test.ts`, import-path only) | 2683/14 | 30 | 4 (3 shared with #3340) | yes |
+| #3350 | Flowershangfromthebranches | `a4e805084` | dev | conflicts inherited from #3349 | 2834/16 | 30 | 5 (4 shared) | yes |
+| #3010 | Liang-Psych | `2e3582328` | dev | CONFLICTING; OAuth/private-protocol design the maintainer review rejected | 1474/2 | 11 | 18 | yes |
+
+The three Flowershangfromthebranches PRs are already a contributor-declared chain
+(#3340 → #3349 → #3350); #3349 and #3350 GitHub diffs include the lower layers because
+each targets `dev`. The carry keeps that chain shape but rebases each layer onto its
+parent so every PR diff is layer-only (DEV-STACK-03).
+
+## Maintainer review state carried into this unit
+
+The prior maintainer reviews (grok-bot, 2026-09-03) on all three PRs left these open items,
+now dispositioned here:
+
+| Item | Disposition |
+|------|-------------|
+| AUP / terms acceptance for headless CLI proxy routing (CodeBuddy, Qoder) | Maintainer decided in this session by authorizing the landing. Recorded in 040. |
+| Provider marks missing in `gui/src/provider-icons.ts` | wp3, per the Meta precedent `81a1fc1cc` (#3338): first-party SVG with source notes, or documented initials tile when terms forbid. See 012. |
+| docs-site guide lacks a Qoder Global/CN section | wp3. CodeBuddy section already exists at `guides/providers.md:620`. |
+| Shared `coding-agent/protocol.ts` error classification broadened in the Qoder commit | Kept in L2 where the contributor put it; audit (wp2 A-phase) checks CodeBuddy fixture coverage. |
+| `qoder` promoted from free-directory reference id to runtime seed with `preserveCustomDestination` | Kept; parity test in the carried commits asserts the flag. |
+| #3010 relationship | Superseded by #3350 once landed; close with credit to Liang-Psych. |
+| Tests at `tests/` root | Blocker on current `dev`: layout guard. Fixed per layer in wp2. |
+| Draft readiness checklist (contributor-side) | Not applicable; maintainer carries the PRs under admin authority. Originals close as superseded. |
diff --git a/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md b/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md
new file mode 100644
index 0000000000..7735d51f34
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md
@@ -0,0 +1,34 @@
+# 010 — Layer plan
+
+Stack shape (merge bottom-up, ordinary dependent bases):
+
+| # | Branch | Base | Thesis | Source commits |
+|---|--------|------|--------|----------------|
+| 1 | `codex/prs-l1-codebuddy` | `dev` | CodeBuddy Global/CN headless CLI providers + shared `coding-agent` runtime | #3340: `7e56b6399`, `f651611f1`, `18530f8e8`, `4b705e92d` (cherry-pick -x) + layout fix commit |
+| 2 | `codex/prs-l2-qoder-global` | L1 | Qoder Global PAT provider, account-scoped live model discovery | #3349: `4ac98bd4d` (cherry-pick -x, import-path conflict resolved) + layout fix commit |
+| 3 | `codex/prs-l3-qoder-cn` | L2 | Qoder CN PAT profile | #3350: `a4e805084` (cherry-pick -x) |
+| 4 | `codex/prs-l4-marks-docs` | L3 | Provider marks, display names, docs-site Qoder section, CREDITS | new maintainer commits |
+| 5+ | `codex/prs-l5-*` | L4 | Secondary PRs accepted by 013 triage, one layer each | cherry-pick -x |
+
+Layer rules:
+
+- Each layer builds at its own tip. The layout-guard fix for a layer's tests lives in
+ that layer, not deferred upward.
+- Original author preserved by `cherry-pick -x` (author field + `(cherry picked from
+ commit …)` line). Maintainer-authored repair commits carry no trailer because they
+ are not the contributor's work; the PR body names the source PR.
+- PR bodies use the repository template and carry the stack map (DEV-STACK-03).
+- Only the top layer's head gets CI. Lower PRs are opened for review navigation and
+ merge order; their own PR CI may run (`pull_request` trigger) but is not the gate.
+
+Verification plan (hosted only):
+
+1. Push all layers with `--no-verify`.
+2. If the top PR's `pull_request` CI skips platform lanes, dispatch
+ `gh workflow run ci.yml -R lidge-jun/opencodex --ref -f lane=all`.
+3. Record run id, every job conclusion; skipped/cancelled are not passing.
+4. Merge bottom-up with `--admin`, retarget the next child to `dev` after each parent
+ lands, keep parent branches until no open child targets them.
+5. After the top merge: `git fetch origin dev`; every merge SHA must satisfy
+ `git merge-base --is-ancestor origin/dev`; `git rev-parse origin/dev^{tree}`
+ must equal the certified head's tree (or a diff limited to merge-commit metadata).
diff --git a/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md b/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md
new file mode 100644
index 0000000000..9c69195360
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md
@@ -0,0 +1,24 @@
+# 011 — Conflict map (measured)
+
+Method: `git merge-tree --write-tree origin/dev refs/pr/` and the actual cherry-picks in
+the carry worktree.
+
+| Layer | Conflicting file | Nature | Resolution |
+|-------|------------------|--------|------------|
+| L1 | none | `tests/providers/provider-registry-parity.test.ts` auto-merged | — |
+| L1 | `tests/codebuddy-adapter.test.ts`, `tests/codebuddy-protocol.test.ts` | Not a git conflict; layout guard (`tests/test-layout.test.ts`) rejects root test files since `260905_test_modularization_and_windows` | Move to `tests/providers/`, rewrite `../src` → `../../src`, `./helpers` → `../helpers`; register in `scripts/test-layout/layout.json` `explicit` and `tests/fixtures/test-layout-expected.json`. Commit `769e4208f`. |
+| L2 | `tests/providers/provider-connection-test.test.ts` | Import block: dev moved the file into `tests/providers/`; the PR adds one `setFetchQoderModelsForTests` import against the old path | Keep dev's `../../src` paths, add the Qoder import at the same depth. |
+| L2 | `tests/qoder-adapter.test.ts`, `tests/qoder-live-models.test.ts` | Layout guard, as L1 | Same move + registration. Commit `094cb93d0`. |
+| L3 | `tests/providers/qoder-adapter.test.ts`, `tests/providers/qoder-live-models.test.ts` | The CN commit edits the same import lines the L2 layout commit moved | Take the CN import set (adds `QODER_CN_PROFILE`, `resolveQoderProfile`) at the new depth. |
+
+Auto-merged without conflict (git content merge, needs the wp2 audit to confirm semantics):
+`README.md`, `docs-site/.../guides/providers.md`, `docs-site/.../reference/configuration/providers.md`,
+`src/codex/catalog/provider-fetch.ts`, `src/providers/registry.ts`,
+`src/server/management/provider-routes.ts`, `tests/adapters/adapter-*-conformance.test.ts`,
+`tests/adapters/adapter-registry-authority.test.ts`, `tests/providers/provider-registry-parity.test.ts`.
+
+Known dev-side drift since the PR base (`81a1fc1cc`, 2026-09-03) that touches carried files:
+provider namespace ownership (`bbea77a48`), Nous catalog limits (`5cd71ec91`), OrcaRouter
+PKCE (`c41232aa5`), keychain restore ownership (`924b65799`), BigModel repairs. The wp2 audit
+reads each of these against the carried edits in `provider-fetch.ts`, `model-cache.ts`, and
+`registry.ts`.
diff --git a/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md b/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md
new file mode 100644
index 0000000000..519fca9072
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md
@@ -0,0 +1,23 @@
+# 012 — Mark sourcing decision
+
+Research agent (claude-opus-5) verified on the public web, 2026-09-08. Assets held outside the
+repo at `/tmp/ocx-marks/` until wp3 commits them.
+
+| id | Decision | File | Source | Terms basis |
+|----|----------|------|--------|-------------|
+| `qoder` | ship | `qoder.svg` | `https://qoder.com/favIcon.svg` (declared site icon; 73,379 B; viewBox `0 0 206 206`; byte-identical on `qoder.cn`, `qoder.com.cn`, and the schema.org Organization logo URL) | Qoder ToS (BRIGHT ZENITH, 2026-04-29) reserves rights generally, no mark-use prohibition; same posture as `meta.svg` |
+| `qoder-cn` | ship, shared asset | `qoder.svg` | same file | CN agreement (通义云启(杭州)信息技术有限公司 + Alibaba Cloud, 2026-05-20) §五(a) reserves 商标 rights without restricting third-party use |
+| `codebuddy` | initials tile, documented | none | mark exists (`…/web/ide/logo.svg`) | CodeBuddy service agreement §9.3 "Tencent Logo": no use of Tencent brand features "under any circumstances" without written consent |
+| `codebuddy-cn` | initials tile, documented | none | same | same clause on `codebuddy.cn/document/term` |
+
+Wiring consequences:
+
+- `gui/tests/provider-icons.test.ts` derives the asset stem from `providerId.split("-")[0]`,
+ so committing `qoder.svg` fails the unwired-asset check for both `qoder` and `qoder-cn`
+ until each has its own alias row (the Meta commit pinned both ids for the same reason).
+- Do not mask `qoder.svg`: light plate + dark glyph, both neutral inks, 94.5% opaque; a
+ mask collapses it into a filled box (README "plate problem").
+- Display names: `qoder` → "Qoder", `qoder-cn` → "Qoder CN", `codebuddy` → "CodeBuddy",
+ `codebuddy-cn` → "CodeBuddy CN".
+- The CodeBuddy refusal goes into `gui/public/provider-icons/README.md` because no test
+ can detect an absent mark; without the note a later pass would re-fetch the logo.
diff --git a/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md b/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md
new file mode 100644
index 0000000000..07f7937551
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md
@@ -0,0 +1,23 @@
+# 013 — Secondary PR dispositions (bounded triage, read-only)
+
+Method: `gh pr view`, `git merge-tree --write-tree` against `origin/dev` and against the L3
+head `85ad0a29a`, blob reads. No bun command run. Triage agent: claude-opus-5.
+
+| PR | Author | Size | Conflicts vs dev / vs stack | C4 surface | Maintainer state | Layout | Verdict |
+|---|---|---|---|---|---|---|---|
+| #3990 Hermes source-preserving YAML | rrmlima | 5 files +106/−44 | none / none | no | approved ("머지하세요") | already mapped | INCLUDE → L5 |
+| #3988 Gemini model-tail continue nudge | rrmlima | 2 files +51/−14 | none / none | no | approved after CI | already mapped | INCLUDE → L6 |
+| #3833 Command Code native integration | rrmlima | 9 files +256/−4 | none / none | no | stale review mostly fixed | layout trap: `command-code-client.test.ts` seeds to `providers` (`layout.json:14`), explicit `clients` entry would trip the seed-mismatch check (`test-layout-tooling.test.ts:282`); needs rename or `pinnedOverrides` — design call | DEFER |
+| #3952 openai-chat freeform + Moonshot Responses | yxr1995-maker | 9 files +467/−11 | none / none | no | "지금 형태로는 merge하지 마세요"; bundles three changes; `apply-patch-envelope.ts:51-59` fence stripping can truncate legit bodies; flips `moonshot` adapter default | DEFER (split required) |
+| #3639 EntraID for Azure Foundry | chrisoro | 39 files +590/−62 | none / none | yes (new `@azure/identity` dep, new credential path) | hygiene-blocked, security review required | — | REJECT for this stack |
+| #3283 Antigravity pool + Gemini 3.8 | vanch007 | 14 files +960/−53 | 2 / 2 (`responses/parser.ts`, `server/responses/core.ts`) | yes | "merge 비추천"; competes with #2562 | — | REJECT |
+| #3282 Copilot context tier | Simon-Opopeee | 39 files +521/−14 | 8 / 8 | yes | provider guard missing, screenshot missing, hygiene-blocked | root test file | REJECT |
+| #2230 Gemini OAuth accounts | ppvia | 33 files +1637/−61 | 16 / 16 | yes (embedded OAuth client secret) | maintainer-sponsored security review mandatory | unregistered tests | REJECT |
+
+#3990 and #3988 are pairwise clean with each other and with every other candidate
+(`merge-tree` exit 0 for all combinations). Both are runtime-scope, no auth/credential/workflow
+surface, and the maintainer already approved their content. They become L5 and L6 above the
+marks layer, each cherry-picked with `-x` to keep rrmlima as author.
+
+DEFER/REJECT items are not closed by this unit; their disposition is recorded here for the
+next triage pass.
diff --git a/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md b/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md
new file mode 100644
index 0000000000..32677407ec
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md
@@ -0,0 +1,23 @@
+# 020 — wp2: carry L1–L3 with layout registration
+
+Status at write time: carried in the worktree, unpublished. Heads: L1 `769e4208f`,
+L2 `094cb93d0`, L3 `85ad0a29a` (pre-audit-fix).
+
+## Audit round 1 (claude-opus-5, adversarial, read-only) — NEAR-PASS
+
+| # | Finding | Disposition |
+|---|---------|-------------|
+| 1 | Qoder catalog branch in `src/codex/catalog/provider-fetch.ts` (4 hint calls, ~1598–1628) omits `captured.effectiveAlias`, which `45045623b` (#3601) threaded through every sibling branch. Git auto-merged because lines do not overlap. | FOLD — maintainer fix commit on L2 appends the argument to all four calls. |
+| 2 | `tests/adapters/adapter-tool-conformance.test.ts` exempts `codebuddy`/`qoder` with a bare `continue`; a future tool bridge would keep passing silently. | RESIDUAL — v1 contract is `--tools ""`, documented in registry notes and docs-site. A guard test cannot be validated locally under the no-local-suite rule; deferred to a follow-up that can run it. |
+| 3 | `src/adapters/coding-agent/protocol.ts:198` matches bare `authentication`, so vendor text like "authentication service degraded" becomes a 401 `invalid_api_key`, which drives reauth messaging and key-pool rotation. | FOLD — anchor to credential verdicts (`authentication (?:failed|error|required)`, `unauthorized`). Existing fixture "Not logged in; invalid token" still classifies 401. |
+| 4 | `qoder`/`qoder-cn` seed `noVisionModels` with the full roster, advertising image input the adapter rejects. | REBUT — this is the repository convention (`registry.ts:912`, parity test :388, CodeBuddy CN roster §二十九): membership routes images through the vision sidecar and the fail-closed strip applies to every such provider. The adapter's 400 is the defense when an image reaches it without the sidecar path. |
+
+Non-blocking notes carried: CodeBuddy Global roster has no `noVisionModels` (static, vendor
+manifest); `docs/qoder-cli-provider.md` lives outside docs-site (kept, wp3 adds the published
+section); `--effort` vs `--reasoning-effort` rests on vendor manifests.
+
+Clean under audit: registry contract shape, seed parity fields, `qoder` free-directory
+promotion + `preserveCustomDestination`, `authorityIdentity` backward compatibility,
+connection-test path ordering, layout-guard JSON (delta is exactly the four new keys),
+privacy (PAT redaction, allowlisted child env, SHA-256 fingerprint), CI path (no docs-site
+build or provider enumeration on `pull_request`).
diff --git a/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md b/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md
new file mode 100644
index 0000000000..0093ab15f1
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md
@@ -0,0 +1,15 @@
+# 030 — wp3: L4 marks/docs/credits, L5–L6 secondary layers
+
+L4 `codex/prs-l4-marks-docs` (maintainer-authored):
+
+- `gui/public/provider-icons/qoder.svg` from `/tmp/ocx-marks/qoder.svg` (verbatim).
+- `gui/src/provider-icons.ts`: aliases `qoder`/`qoder-cn` → `qoder.svg`; display names
+ Qoder, Qoder CN, CodeBuddy, CodeBuddy CN. No CodeBuddy asset (012).
+- `gui/public/provider-icons/README.md`: Qoder provenance + CodeBuddy refusal note (012 text).
+- `docs-site/src/content/docs/guides/providers.md`: "Official Qoder CLI (Global & CN)"
+ section after the CodeBuddy section; reference/configuration adapter list adds `qoder`.
+- `CREDITS.md`: not needed — original commits keep the contributor as author.
+
+L5 `codex/prs-l5-hermes-yaml`: cherry-pick -x `a1fe9caeb` (#3990, rrmlima).
+L6 `codex/prs-l6-gemini-tail`: cherry-pick -x `1837b8f99` (#3988; commit author is
+`root`, so add `Co-authored-by: rrmlima` via the PR body/merge commit).
diff --git a/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md b/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md
new file mode 100644
index 0000000000..cf056aafcf
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md
@@ -0,0 +1,16 @@
+# 040 — wp4: publish, CI, merge, prove, close
+
+1. Push six branches `--no-verify` with `-c core.hooksPath=/dev/null`.
+2. Open PRs bottom-up with explicit `--base` (L1→dev, L2→L1, …), template body + stack map.
+3. Dispatch `ci.yml` `lane=all` on the L6 head; record run id and every job.
+4. On green: merge L1 with `--admin --match-head-commit`, retarget L2 to `dev`, repeat.
+ Keep parent branches until no child targets them.
+5. Fetch `dev`; assert each merge SHA is an ancestor; compare `dev^{tree}` to the certified
+ L6 tree.
+6. Close #3340/#3349/#3350 superseded (credit Flowershangfromthebranches), #3990/#3988
+ superseded (credit rrmlima), #3010 superseded by the landed Qoder CN PAT provider
+ (credit Liang-Psych).
+7. Write 060 ledger; move unit to `_fin`.
+
+AUP decision: the maintainer authorized landing these headless-CLI PAT providers in this
+session (2026-09-08); recorded here as the maintainer decision the prior reviews asked for.
diff --git a/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md b/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md
new file mode 100644
index 0000000000..8ada5b0bc6
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md
@@ -0,0 +1,58 @@
+# 050 — Delivery record
+
+Snapshot: 2026-09-08T14:10Z. `origin/dev` = `e2bf1672c` (was `29bb221c3` at unit start).
+
+## What landed
+
+| Layer | PR | Merge SHA | Head SHA | Source | Author credit |
+|-------|----|-----------|----------|--------|---------------|
+| L1 CodeBuddy Global/CN | #4026 | `b77b05aa5` | `769e4208f` | #3340 (4 commits, cherry-pick -x) + layout move | Flowershangfromthebranches (author field + trailer) |
+| L2 Qoder Global | #4027 | `753ecb813` | `5adf130da` | #3349 (cherry-pick -x) + layout move + audit fix | Flowershangfromthebranches |
+| L3 Qoder CN | #4028 | `07ac34b2d` | `615c5c62c` | #3350 (cherry-pick -x) | Flowershangfromthebranches; Liang-Psych trailer for #3010 direction |
+| L4 marks/docs | #4029 | `9f0721299` | `6ba1e6750` | maintainer | — |
+| L5 Hermes YAML | #4030 | `5bb8faf7b` | `295bcf82b` | #3990 (cherry-pick -x) + fr/zh-TW sync | rrmlima |
+| L6 Gemini tail | #4031 | `e2bf1672c` | `16d49ceab` | #3988 (cherry-pick -x) + single-owner fix | rrmlima (trailer; carried commit author is `root`) |
+
+## Proof
+
+- CI: `ci.yml` `lane=all` run **34231255231** on `16d49ceab`: 26/26 jobs success. `windows 4/6`
+ failed once on `tests/codex-integration/token-guardian.test.ts` afterEach `EPERM rm` of its
+ temp dir (a file the stack does not touch); same-SHA rerun of that job passed. Earlier run
+ 34228268757 on `ba3912ce8` was cancelled when the head moved and is diagnostic only.
+- Ancestry: all six merge SHAs and all six head SHAs are ancestors of fetched `origin/dev`.
+- Tree: `origin/dev^{tree}` = `2201b9e54…` = `16d49ceab^{tree}`. Landed tree equals certified head.
+- Hygiene/enforce-target: green on every PR before merge after two repairs (trailers moved to
+ the body end where `pr-carry-attribution.cjs` reads them; L4 got pinned icon tests for
+ `missing_regression_test` and a before/after screenshot for the GUI gate).
+
+## NOT RUN (by maintainer instruction)
+
+`bun install`, `bun run typecheck`, `bun run test`, `bun run test:changed`, `bun run build:gui`,
+`bun run privacy:scan`, `bun run lint:gui` — none executed locally. Every Git mutation ran with
+`-c core.hooksPath=/dev/null`; pushes used `--no-verify`. Hosted CI is the only execution proof.
+
+## Audit dispositions
+
+Round 1 (L1–L3): blocker 1 `captured.effectiveAlias` folded (`5adf130da`); blocker 3 auth regex
+folded (same commit); blocker 2 tool-less conformance exemption → residual, follow-up; blocker 4
+`noVisionModels` → rebutted (repository convention). Round 2 (L4–L6): double `(continue)` nudge
+folded (`16d49ceab`); fr/zh-TW Hermes contradiction folded (`295bcf82b`); seven locale copies of
+the adapter list still stop at `azure-openai` (predates this unit; residual).
+
+## Closeouts
+
+#3340 (auto-closed by merge; credit comment added), #3349, #3350, #3990, #3988 closed as
+superseded with credit; #3010 closed as superseded by the PAT design with credit to Liang-Psych.
+
+## Secondary PR dispositions (not closed)
+
+DEFER #3833 (layout seed trap, design call), #3952 (split required). REJECT for this stack
+#3639, #3283, #3282, #2230 (C4 surfaces, conflicts, or maintainer-required security review).
+See 013.
+
+## Residuals for a follow-up
+
+1. Guard test proving `codebuddy`/`qoder` still expose no tool catalog (audit round 1, blocker 2).
+2. Locale adapter tables (ko/ja/zh-cn/zh-tw/fr/ru/tr reference/configuration/providers.md).
+3. `docs/qoder-cli-provider.md` lives outside docs-site; consider folding into the guide.
+4. Windows shard flake: `token-guardian.test.ts` temp-dir `EPERM` on cleanup.
diff --git a/devlog/_fin/260908_provider_runtime_stack/060_ledger.md b/devlog/_fin/260908_provider_runtime_stack/060_ledger.md
new file mode 100644
index 0000000000..cc5dbd4977
--- /dev/null
+++ b/devlog/_fin/260908_provider_runtime_stack/060_ledger.md
@@ -0,0 +1,17 @@
+# 060 — Ledger
+
+| When (UTC) | Event | Evidence |
+|-----------|-------|----------|
+| 2026-09-08T12:04 | Goal created; goalplan wp1–wp4 registered | `.codexclaw/goalplans/land-the-open-opencodex-provider-runtime-contrib` |
+| 2026-09-08T12:06 | Worktree `/private/tmp/ocx-prs-stack-01a080e2` on `origin/dev` `29bb221c3`; L1–L3 carried by `cherry-pick -x` | heads L1 `769e4208f`, L2 `094cb93d0`, L3 `85ad0a29a` |
+| 2026-09-08T12:30 | wp1 roadmap docs 000–040 written; audit NEAR-PASS (020) | this unit |
+| 2026-09-08T12:35 | wp2 audit fixes on L2 (`5adf130da`): effectiveAlias ×4, auth regex anchor; L3 cascaded | 020 |
+| 2026-09-08T12:40 | wp3: L4 `76c8a0b0b` (qoder.svg, aliases, names, README, docs-site), L5 `a49d1ad92`+`48666541b` (#3990 + fr/zh-TW sync), L6 `7bd84795b`+`ba3912ce8` (#3988 + single-owner nudge) | 030, audit round 2 |
+| 2026-09-08T12:48 | Pushed six branches `--no-verify`; PRs #4026 (L1→dev), #4027, #4028, #4029, #4030, #4031 (L6) with explicit dependent bases | GitHub |
+| 2026-09-08T12:49 | `ci.yml` `lane=all` dispatched on `ba3912ce8`: run 34228268757 (+ PR run 34228261835) | Actions |
+| 2026-09-08T13:02 | Hygiene gate: `missing_coauthor_credit` on every PR (trailers were inside the Summary, gate reads end of body) → trailers appended at body end; `missing_regression_test` on L4 → pinned Qoder/CodeBuddy icon tests added, L4 amended `6ba1e6750`, L5/L6 cascaded, force-with-lease pushed | GitHub |
+| 2026-09-08T13:24 | New top head `16d49ceab`; `lane=all` dispatched: run 34231255231 (first run 34228268757 on `ba3912ce8` kept only as diagnostic) | Actions |
+| 2026-09-08T13:55 | Run 34231255231 (`16d49ceab`, lane=all): 25/26 jobs success; `windows 4/6` failed on `tests/codex-integration/token-guardian.test.ts` afterEach `EPERM rm` of its temp dir (remove-tree retry exhausted). The stack touches no oauth/guardian/remove-tree file. Rerunning that job at the same SHA. | Actions |
+| 2026-09-08T14:00 | Run 34231255231 green 26/26 after same-SHA rerun of windows 4/6 | Actions |
+| 2026-09-08T14:07 | Bottom-up admin merges: #4026 `b77b05aa5`, #4027 `753ecb813`, #4028 `07ac34b2d`, #4029 `9f0721299`, #4030 `5bb8faf7b`, #4031 `e2bf1672c`; `origin/dev`=`e2bf1672c`; tree == `16d49ceab^{tree}` | 050 |
+| 2026-09-08T14:09 | Originals closed with credit: #3349 #3350 #3010 #3990 #3988 (#3340 auto-closed, credit comment) | GitHub |
diff --git a/devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png b/devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png
new file mode 100644
index 0000000000..18f4797503
Binary files /dev/null and b/devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png differ
diff --git a/devlog/_fin/260908_release_248/000_plan.md b/devlog/_fin/260908_release_248/000_plan.md
new file mode 100644
index 0000000000..221302a72d
--- /dev/null
+++ b/devlog/_fin/260908_release_248/000_plan.md
@@ -0,0 +1,31 @@
+# Release 2.48.0 plan
+
+Owner-authorized HOTL release train for OpenCodex 2.48.0. The owner asked for a regression check of `dev` against `main`, two promotion pull requests, merges into `main` and `preview`, and npm publication. The owner also forbade running the local test suite and required `--no-verify` for any push, so every verification claim in this unit rests on hosted CI at an exact SHA. Local typecheck, local `bun run test`, and local privacy scan are NOT RUN by instruction and are labeled that way wherever they would otherwise appear as evidence.
+
+## Candidate
+
+Release candidate: `7797586a8899c673eab48886a490e85b480c6d72` (`origin/dev` tip, 2.48.0 in package.json).
+
+Published baseline: `@bitkyc08/opencodex` `latest=2.47.0`, `preview=2.47.0-preview.20260908`. `origin/main` is `f7f890ff7` at 2.47.0; `origin/preview` is `3bef20677` at 2.47.0-preview.20260908. `dev` is 70 commits ahead of each.
+
+The candidate tip itself has no Cross-platform CI run because its only delta against `9ad218a9bdd34ee33004c35706d78396bf02eef2` is under `devlog/`, which the workflow's push path filter excludes. `git diff --name-only 9ad218a9b 7797586a8 -- . ':(exclude)devlog'` returns zero files, so `9ad218a9b` is the runtime-identical CI witness for the candidate: 19 successful check-runs, two deliberately skipped (`macos control`, the Windows shard placeholder). That equivalence is stated explicitly rather than assumed, because the promotion merge SHAs will carry their own push-event CI regardless.
+
+## Scope
+
+In scope: version metadata on the two promotion branches, promotion PRs into `preview` and `main`, merges, `release.yml` dispatch for preview and stable, and registry/tag verification. Also in scope: a PABCD repair cycle merged into `dev` if regression evidence shows a defect, followed by a repeat of the release verification.
+
+Out of scope: unrelated open PRs and issues, dev-version bumping beyond what the release requires, installed-service upgrades, account settings, and any change to branch protection or CI gates.
+
+## Work phases
+
+- wp1 — this roadmap. Pin the candidate, record the CI-equivalence argument and the promotion procedure. No product change.
+- wp2 — regression verification of the candidate against `main` using hosted evidence only.
+- wp3 — promotion branches and PRs, merged with exact-head CI.
+- wp4 — npm preview and stable publication with registry verification.
+
+## Verification and outcomes
+
+Each promotion SHA needs its own successful push-event Cross-platform CI and Service lifecycle before any publish dispatch. Publication proof is npm dist-tags, the published `gitHead`, tarball integrity, provenance, and the GitHub tag and release. `enforce-target` is expected to reject both promotion PRs because its allowed bases contain only `dev`; that is the established authorized promotion exception and is reported as failing, never as passing.
+
+DONE requires both channels published and verified with `dev` still ahead. BLOCKED is a concrete external prerequisite or a failed gate with no safe remedy. A failing gate is repaired or remains a blocker; it is never weakened, and no check is disabled to hide it.
+
diff --git a/devlog/_fin/260908_release_248/010_release.md b/devlog/_fin/260908_release_248/010_release.md
new file mode 100644
index 0000000000..9e1875d65f
--- /dev/null
+++ b/devlog/_fin/260908_release_248/010_release.md
@@ -0,0 +1,16 @@
+# Release operation
+
+1. Pin candidate `7797586a8899c673eab48886a490e85b480c6d72` and record its CI witness `9ad218a9bdd34ee33004c35706d78396bf02eef2` (runtime-identical; devlog-only delta). Confirm published baseline tags and that `v2.48.0` and `v2.48.0-preview.*` are unused.
+
+2. Regression review of `origin/main..origin/dev`: 70 commits, 162 changed files, 25 under `src/`. Read the delta for release-blocking risk in routing, auth, credentials, release automation, and workflows. Hosted CI on the witness SHA is the mechanical evidence; the local suite is NOT RUN by owner instruction.
+
+3. Create two independent promotion branches from `origin/preview` and `origin/main`, merge the frozen candidate into each, resolve only the channel version conflict, and set `package.json` to `2.48.0-preview.20260908` on the preview branch and `2.48.0` on the main branch. The runtime tree on each branch must equal the candidate exactly apart from that one version line; prove it with `git diff` restricted to non-version paths.
+
+4. Push both branches with `--no-verify` (owner instruction), open template-complete PRs, and wait for each merge SHA's own push-event Cross-platform CI and Service lifecycle. `enforce-target` will fail on both by design; record it as the authorized promotion exception.
+
+5. Dispatch `release.yml` with `expected-sha` equal to the branch tip: dry-run first, then preview, then stable, serialized. Verify `npm view @bitkyc08/opencodex dist-tags`, published `gitHead`, tarball SHA-512, provenance, and the GitHub tag and release. Run a published-package smoke in an isolated home.
+
+6. Record the outcome in `090_delivery.md`, confirm `dev` remains ahead of both channels, and leave unrelated dirty files in the primary checkout untouched.
+
+Activation scenarios: a moved branch means refuse the dispatch and repin; a failed CI job means inspect and repair rather than rerun blindly; a post-publish smoke failure means inspect registry metadata before any retry, and never republish blindly. Rollback artifact `v2.47.0` stays published; no destructive rollback is planned.
+
diff --git a/devlog/_fin/260908_release_248/020_progress.md b/devlog/_fin/260908_release_248/020_progress.md
new file mode 100644
index 0000000000..64ac908fa9
--- /dev/null
+++ b/devlog/_fin/260908_release_248/020_progress.md
@@ -0,0 +1,14 @@
+# Progress
+
+## wp1 — roadmap (this cycle)
+
+Candidate pinned at `7797586a8899c673eab48886a490e85b480c6d72`. CI witness `9ad218a9bdd34ee33004c35706d78396bf02eef2`: 19 successful check-runs, 2 deliberate skips. The delta between them is devlog-only, so the witness covers the candidate's runtime tree exactly.
+
+Roadmap committed as `38edcbf7c` on `codex/release-248-plan` in the dedicated worktree `/private/tmp/ocx-release-248`. The primary checkout keeps its pre-existing unrelated dirty files untouched.
+
+Local suite, typecheck, and privacy scan: NOT RUN by owner instruction.
+
+## wp2 — regression verification (next)
+
+Delta to review: 70 commits, 162 files, 25 under `src/`, ~2096 changed source lines against `origin/main`.
+
diff --git a/devlog/_fin/260908_release_248/030_wp2_regression_review.md b/devlog/_fin/260908_release_248/030_wp2_regression_review.md
new file mode 100644
index 0000000000..3e2e50712f
--- /dev/null
+++ b/devlog/_fin/260908_release_248/030_wp2_regression_review.md
@@ -0,0 +1,39 @@
+# wp2 — regression review of the candidate against main
+
+Reviewed `origin/main..origin/dev`: 70 commits, 162 files, 25 under `src/`, about 2096 changed source lines. The question this phase answers is narrow — does anything in that delta regress behavior that `main` currently ships? The local suite is NOT RUN by owner instruction, so the mechanical evidence is hosted CI and the argument below is a source read.
+
+## What changed, by risk
+
+Credential and quota handling carries the most weight. `src/codex/routing.ts` factors the background recovery settle path into `settleCooldownRecoveryLease` and adds a manual-reset claim/settle pair. The refactor moves `cooldownSource === "reset-derived"` and the scope restriction into the shared settle helper, which reads at first glance like a new restriction on the pre-existing background path. It is not: `claimDueCodexQuotaRecoveryProbes` already filters candidates to `(scope === undefined || scope === "shared")` with `cooldownSource === "reset-derived"`, so no claim that could previously settle successfully can reach the helper and fail those conditions. `tests/codex-integration/codex-cooldown-recovery.test.ts` and `codex-reset-credit-auto-redeem.test.ts` cover both paths.
+
+`src/codex/auth-api.ts` adds a `dispatchSequence` fence around WHAM usage publication so a slow in-flight response cannot overwrite a newer published quota. The added early returns hand back the cached account info rather than publishing, which is a strict narrowing of when stale data wins.
+
+`src/server/responses/core.ts` adds combo session recall for compaction triggers and a completion callback gate. The recall path is guarded on a bare model name, an actual `compaction_trigger` input item, no configured selector, and no resolvable combo id, so a request that previously routed by explicit selector still does. The previous-response error code changed from `invalid_request_error` to `previous_response_not_found`; that is a deliberate behavior change so Codex reconnects with full input instead of terminating the task, and it is the fix's whole point.
+
+`src/router.ts` and `src/providers/default-aliases.ts` extend alias-ownership so a provider's own configured name also claims an alias, not just an explicit `alias` field. This makes an ambiguous alias resolve to nothing rather than to the wrong provider — a correctness fix with a narrow blast radius.
+
+`src/config/atomic-write.ts` replaces `constants.O_WRONLY | O_CREAT | O_EXCL` with the `"wx"` flag string, which is the same semantics expressed portably; that was the point of the change on Windows.
+
+## Coverage
+
+Forty test files changed alongside the 25 source files, and every source area above has a focused test in the same domain directory. No source change in the delta arrived without paired coverage.
+
+## Hosted evidence
+
+Push-event run on `9ad218a9bdd34ee33004c35706d78396bf02eef2` (runtime-identical to the candidate): 19 successful check-runs, 2 skipped by design.
+
+Dispatched full-lane run [34206043085](https://github.com/lidge-jun/opencodex/actions/runs/34206043085) on the exact candidate `7797586a8899c673eab48886a490e85b480c6d72` with `lane=all`, which adds the six Windows shards and the unsharded macOS control that the push event does not run.
+
+## Verdict
+
+No regression identified against `main`. The delta is corrective, each risky path narrows rather than widens behavior, and the one intentional behavior change (the previous-response error code) is the documented fix.
+
+
+## Full-lane CI outcome
+
+Run [34206043085](https://github.com/lidge-jun/opencodex/actions/runs/34206043085) on the exact candidate `7797586a8899c673eab48886a490e85b480c6d72` completed **success** after one rerun of a single job.
+
+The first attempt failed on `windows 3/6`: `provider outbound GET transport > proxy mode reaches one real proxy across outbound, connection-test, and model-discovery paths` timed out at its own 15s bound, and the spawned fixture child was killed (exit 143). That test file is not in the release delta — `git log origin/main..origin/dev -- tests/providers/provider-outbound.test.ts` is empty — and the same content passed `windows 3/6` in dispatch run 34198186409 ninety minutes earlier. Rerunning the failed job passed. The evidence points at cold-runner timing on a 15s child-spawn budget, not at anything the candidate changed.
+
+That timeout is a real fragility worth tightening later, but it is not a 2.48.0 regression and does not block this promotion.
+
diff --git a/devlog/_fin/260908_release_248/040_wp3_promotion.md b/devlog/_fin/260908_release_248/040_wp3_promotion.md
new file mode 100644
index 0000000000..5ba9997eaf
--- /dev/null
+++ b/devlog/_fin/260908_release_248/040_wp3_promotion.md
@@ -0,0 +1,35 @@
+# wp3 — promotion pull requests and merges
+
+Both promotions are on their channels.
+
+| Channel | PR | Merge SHA | Version |
+|---|---|---|---|
+| `preview` | [#4010](https://github.com/lidge-jun/opencodex/pull/4010) | `c71474e83c92be1f39e9d8c1fe0743307ce93387` | 2.48.0-preview.20260908 |
+| `main` | [#4011](https://github.com/lidge-jun/opencodex/pull/4011) | `9a27e86992d7a014e0aa92c046199b9fac148201` | 2.48.0 |
+
+Candidate `7797586a8899c673eab48886a490e85b480c6d72` is an ancestor of both branches, verified with `git merge-base --is-ancestor` against freshly fetched refs. `git diff 7797586a8 origin/main` is empty: the main tree is byte-identical to the candidate, since the candidate already carried 2.48.0. The preview tree differs only in the channel version line.
+
+## Gate outcomes
+
+`enforce-target` failed on both, as expected and as documented in the PR bodies. Its allowed bases contain only `dev` and its one coded exception is a stacked child, so a release promotion cannot pass it. Both PRs were opened as drafts by that gate and were marked ready before the authorized admin merge. The failure is recorded as a failure; no check, protection, or target was altered.
+
+Every other check passed on both heads.
+
+## Flakes encountered, and why they are flakes
+
+`macos 1/2` on #4011 hung twice inside `tests/clients/client-connect.test.ts` after "connect transaction and offline disconnect > an unavailable config coordinator refuses before issuing any hub key", producing "killed 1 dangling process" and then a 20-minute job timeout. The same tree passed `macos 1/2` in candidate run 34206043085 and on #4010, and passed on the third attempt. Combined with the earlier `windows 3/6` timeout, both failures were child-process lifecycle timing on cold runners, in files outside the release delta.
+
+## Post-merge gates
+
+Preview `c71474e83`: Cross-platform CI success, Service lifecycle success.
+
+Main `9a27e8699`: Service lifecycle success, React Doctor success, Docs deploy success; Cross-platform CI observed in progress at the time of writing and must be green before the stable publish.
+
+
+## Merge verification commands
+
+```
+git merge-base --is-ancestor 7797586a8 origin/preview # YES
+git merge-base --is-ancestor 7797586a8 origin/main # YES
+git diff --stat 7797586a8 origin/main # empty
+```
diff --git a/devlog/_fin/260908_release_248/050_wp4_publication.md b/devlog/_fin/260908_release_248/050_wp4_publication.md
new file mode 100644
index 0000000000..672c8e0b45
--- /dev/null
+++ b/devlog/_fin/260908_release_248/050_wp4_publication.md
@@ -0,0 +1,35 @@
+# wp4 — publication
+
+Both channels are published and verified.
+
+| Channel | Version | Source SHA | npm gitHead |
+|---|---|---|---|
+| `preview` | 2.48.0-preview.20260908 | `c71474e83c92be1f39e9d8c1fe0743307ce93387` | matches |
+| `latest` | 2.48.0 | `9a27e86992d7a014e0aa92c046199b9fac148201` | matches |
+
+`npm view @bitkyc08/opencodex dist-tags` reports `{"latest":"2.48.0","preview":"2.48.0-preview.20260908"}`. GitHub releases `v2.48.0` and `v2.48.0-preview.20260908` exist at exactly those commits. Both publishes carry a signed provenance statement from GitHub Actions.
+
+Tarball integrity was checked independently: downloading `bitkyc08-opencodex-2.48.0.tgz` from the registry and hashing it locally yields `sha512-f2GmrBpUJYZ+bOT62VL1MWhNwIBkFz5JUVGrNPG+SAaWJheshmMsnHDoMyRIpyd5v50sK9uI0Ll4XZwI4PVjhA==`, identical to the `dist.integrity` npm reports and to the `integrity:` line in the publish log. The unpacked package declares version 2.48.0 and its `bin/ocx.mjs` launcher runs and correctly reports the Bun runtime requirement in an isolated `OPENCODEX_HOME`.
+
+## The dev-version gate
+
+The first stable dispatch failed at "Require dev to be ready for this release": `origin/dev` still carried 2.48.0, which does not outrank the version being released. That gate exists so `tests/ci-workflows/release-version-line.test.ts` does not go red on `dev` and on every pull request against it the moment a release ships.
+
+The repair was [#4019](https://github.com/lidge-jun/opencodex/pull/4019), a one-line `package.json` change moving `dev` to 2.49.0, with the version decided by `scripts/bump-dev-version.ts` rather than chosen by hand. It merged as `0372c43e663b25387a0a00b03b6a9ca9d4bf9048` with full CI green, after which the stable dispatch succeeded on the unchanged `main` SHA.
+
+## Registry propagation
+
+Both publishes reported "Your package is being processed" and the workflow's bounded six-attempt registry smoke ended `verification=pending` in each case. Neither was republished. Preview appeared in the registry roughly twelve minutes after acceptance, stable roughly seven; both were then verified by direct registry reads and by the independent tarball hash above.
+
+## Final branch state
+
+`dev` 2.49.0, `main` 2.48.0, `preview` 2.48.0-preview.20260908. `dev` remains ahead of both release channels.
+
+
+## Verification commands
+
+```
+npm view @bitkyc08/opencodex dist-tags --json
+npm view @bitkyc08/opencodex@2.48.0 dist.integrity dist.tarball --json
+gh release view v2.48.0 --json tagName,targetCommitish
+```
diff --git a/devlog/_plan/260904_dashboard_minimal/000_inventory.md b/devlog/_plan/260904_dashboard_minimal/000_inventory.md
index 2487c1afae..a1a1d0b094 100644
--- a/devlog/_plan/260904_dashboard_minimal/000_inventory.md
+++ b/devlog/_plan/260904_dashboard_minimal/000_inventory.md
@@ -1,31 +1,34 @@
# 000 — Dashboard inventory (as shipped, v2.42.0, dev @ 664d80c76)
-Evidence: `assets/_1440.png` (full page, ko, 1440 px headless Chrome against the live
-proxy), `assets/_text.txt` (visible text), `assets/_interactive.txt` (interactive
-controls with refs, `agbrowse snapshot --interactive`). Storage was captured mid-scan (its skeleton
-is the honest first paint on a 1.6 GB CODEX_HOME) and is inventoried from source.
+This inventory used full-page Korean captures at 1440 px against the live proxy,
+plus visible-text and interactive-control snapshots. Storage was captured mid-scan:
+its skeleton records the first paint, and its full inventory came from source.
+
+The capture pack was removed from the current tree after review. The route,
+control-count, and source inventory below retain the historical conclusions.
+Git history is unchanged.
Counts are from the captures: interactive = controls in the snapshot, words = visible text words.
-| Route | Source | Interactive | Words | Screenshot |
-|---|---|---|---|---|
-| Sidebar + top bar | gui/src/App.tsx, components/sidebar-github-row.tsx, styles.css | 22 | — | every capture, left rail |
-| #dashboard (overview) | pages/Dashboard.tsx, dashboard-overview-sections.tsx (669 L), dashboard-dialogs.tsx | 34 | 199 | dashboard_1440.png |
-| #dashboard/providers | same | 18 | — | dashboard_providers_1440.png |
-| #dashboard/models | same | 28 | — | dashboard_models_1440.png |
-| #startup | pages/Startup.tsx (403 L), startup-sections.tsx | 22 | 167 | startup_1440.png |
-| #providers | pages/Providers.tsx, components/provider-workspace/* | 27 | 310 | providers_1440.png |
-| #models | pages/Models.tsx (2329 L) | 135 | 460 | models_1440.png |
-| #models/combos | pages/Combos.tsx, components/combo-workspace-* | 59 | — | models_combos_1440.png |
-| #models/routing | pages/RoutingProfiles.tsx (1139 L) | 28 | — | models_routing_1440.png |
-| #models/compatibility | pages/CompatibilityMatrix.tsx | 27 | — | models_compatibility_1440.png |
-| #subagents | pages/Subagents.tsx, components/subagents-workspace/* | 60 | 232 | subagents_1440.png |
-| #logs | pages/Logs.tsx (1147 L) | 50 | 346 | logs_1440.png |
-| #logs/debug | pages/Debug.tsx, debug-log-viewer.tsx | 24 | — | logs_debug_1440.png |
-| #usage | pages/Usage.tsx (889 L) | 27 | 654 | usage_1440.png |
-| #storage | pages/Storage.tsx (1469 L), components/storage-workspace/* | 16 (skeleton) | — | storage_1440.png |
-| #codex-set | pages/codex-set-multiauth.tsx, codex-set-prompt.tsx, components/codex-set/*, CodexAccountPool.tsx | 51 | 361 | codex-set_1440.png |
-| #integrations | pages/Integrations.tsx, ApiKeys.tsx, Claude*.tsx, Grok.tsx | 86 | 233 | integrations_1440.png |
+| Route | Source | Interactive | Words |
+|---|---|---|---|
+| Sidebar + top bar | gui/src/App.tsx, components/sidebar-github-row.tsx, styles.css | 22 | — |
+| #dashboard (overview) | pages/Dashboard.tsx, dashboard-overview-sections.tsx (669 L), dashboard-dialogs.tsx | 34 | 199 |
+| #dashboard/providers | same | 18 | — |
+| #dashboard/models | same | 28 | — |
+| #startup | pages/Startup.tsx (403 L), startup-sections.tsx | 22 | 167 |
+| #providers | pages/Providers.tsx, components/provider-workspace/* | 27 | 310 |
+| #models | pages/Models.tsx (2329 L) | 135 | 460 |
+| #models/combos | pages/Combos.tsx, components/combo-workspace-* | 59 | — |
+| #models/routing | pages/RoutingProfiles.tsx (1139 L) | 28 | — |
+| #models/compatibility | pages/CompatibilityMatrix.tsx | 27 | — |
+| #subagents | pages/Subagents.tsx, components/subagents-workspace/* | 60 | 232 |
+| #logs | pages/Logs.tsx (1147 L) | 50 | 346 |
+| #logs/debug | pages/Debug.tsx, debug-log-viewer.tsx | 24 | — |
+| #usage | pages/Usage.tsx (889 L) | 27 | 654 |
+| #storage | pages/Storage.tsx (1469 L), components/storage-workspace/* | 16 (skeleton) | — |
+| #codex-set | pages/codex-set-multiauth.tsx, codex-set-prompt.tsx, components/codex-set/*, CodexAccountPool.tsx | 51 | 361 |
+| #integrations | pages/Integrations.tsx, ApiKeys.tsx, Claude*.tsx, Grok.tsx | 86 | 233 |
## Element-level notes from the captures (main agent's own pass)
diff --git a/devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md b/devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md
index d4ccdedcd9..a4d9723fa8 100644
--- a/devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md
+++ b/devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md
@@ -1,8 +1,10 @@
# 001 — Subagent opinions (independent, read-only, dev @ 664d80c76)
-Three reviewers were dispatched in parallel with the same packet (evidence pack in `assets/`,
-full source access, no edits, no suites, no proxy mutation). Model requested → model that
-answered (as self-reported in the REVIEWER line):
+Three reviewers were dispatched in parallel with the same temporary evidence packet and full
+source access (no edits, no suites, no proxy mutation). The packet was subsequently removed from
+the current tree. Filenames remain below only to preserve the reviewers' original reasoning.
+Model requested → model
+that answered (as self-reported in the REVIEWER line):
| # | Requested | Answered as | Agent | Status |
|---|---|---|---|---|
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/011_sidebar_footer_after.png b/devlog/_plan/260904_dashboard_minimal/assets/011_sidebar_footer_after.png
deleted file mode 100644
index 2d6250ab69..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/011_sidebar_footer_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/011_star_in_update_dialog.png b/devlog/_plan/260904_dashboard_minimal/assets/011_star_in_update_dialog.png
deleted file mode 100644
index a736e944ef..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/011_star_in_update_dialog.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/021_dashboard_after.png b/devlog/_plan/260904_dashboard_minimal/assets/021_dashboard_after.png
deleted file mode 100644
index 1a4d8f5b3b..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/021_dashboard_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/021_startup_autostart_row.png b/devlog/_plan/260904_dashboard_minimal/assets/021_startup_autostart_row.png
deleted file mode 100644
index 001fc819b8..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/021_startup_autostart_row.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/031_models_after.png b/devlog/_plan/260904_dashboard_minimal/assets/031_models_after.png
deleted file mode 100644
index d721fb7ef2..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/031_models_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/031_models_disclosures_open.png b/devlog/_plan/260904_dashboard_minimal/assets/031_models_disclosures_open.png
deleted file mode 100644
index 82bf0e2d7f..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/031_models_disclosures_open.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/041_integrations_after.png b/devlog/_plan/260904_dashboard_minimal/assets/041_integrations_after.png
deleted file mode 100644
index 26ac0ee107..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/041_integrations_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_after.png b/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_after.png
deleted file mode 100644
index b165b72285..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_more_open.png b/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_more_open.png
deleted file mode 100644
index 51f76c8367..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/051_codex_set_more_open.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/061_usage_after.png b/devlog/_plan/260904_dashboard_minimal/assets/061_usage_after.png
deleted file mode 100644
index dc2baee259..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/061_usage_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/071_startup_after.png b/devlog/_plan/260904_dashboard_minimal/assets/071_startup_after.png
deleted file mode 100644
index e041ce91f0..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/071_startup_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/081_subagents_after.png b/devlog/_plan/260904_dashboard_minimal/assets/081_subagents_after.png
deleted file mode 100644
index 1b4be7e3c4..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/081_subagents_after.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/codex-set_1440.png
deleted file mode 100644
index ebdd52d21e..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/codex-set_interactive.txt
deleted file mode 100644
index 23e978afef..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_interactive.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 tab "다중 인증"
-e50 tab "프롬프트"
-e55 button "Codex Spark 할당량"
-e56 button "한도 도달 계정 일시 중지"
-e59 button "할당량 새로고침"
-e66 button "리셋 크레딧 1개"
-e70 button "이 계정을 다음에 사용"
-e71 button "일시 중지"
-e76 combobox "이 계정의 선택 순서"
-e80 button "추가"
-e85 button "리셋 크레딧 1개"
-e88 button "이 계정을 다음에 사용"
-e89 button "일시 중지"
-e92 button "별칭 편집"
-e93 button "삭제 — "
-e96 combobox "이 계정의 선택 순서"
-e102 button "리셋 크레딧 1개"
-e105 button "이 계정을 다음에 사용"
-e106 button "일시 중지"
-e109 button "별칭 편집"
-e110 button "삭제 — "
-e113 combobox "이 계정의 선택 순서"
-e119 button "리셋 크레딧 0개"
-e123 button "이 계정을 다음에 사용"
-e124 button "일시 중지"
-e127 button "별칭 편집"
-e128 button "삭제 — "
-e131 combobox "이 계정의 선택 순서"
-e137 button "리셋 크레딧 1개"
-e140 button "이 계정을 다음에 사용"
-e141 button "일시 중지"
-e144 button "별칭 편집"
-e145 button "삭제 — "
-e148 combobox "이 계정의 선택 순서"
-e152 combobox "로테이션 전략"
-e155 button "고급 설정"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/codex-set_text.txt
deleted file mode 100644
index 92e164e55c..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/codex-set_text.txt
+++ /dev/null
@@ -1,115 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-다중 인증
-프롬프트
-Codex 인증
-Codex Spark 할당량
-한도 도달 계정 일시 중지
-할당량 새로고침
-OpenAI 계정 모드
-풀 모드
-
-메인 로그인과 사용 가능한 추가 계정이 여기에서 순환됩니다.
-
-메인 계정
-1
-현재
-이 계정을 다음에 사용
-일시 중지
-앱 로그인
- · pro
-선택 순서
-기본 (0)
-숫자가 클수록 먼저 사용됩니다. 위에 있는 계정이 모두 소진되거나 사용할 수 없을 때에만 더 낮은 숫자로 넘어갑니다.
-주간
-리셋
-9월 7일
-11:46
-26%
-계정 풀
-추가
-
-pro
-1
-이 계정을 다음에 사용
-일시 중지
-별칭 편집
- · pro · ID: account-
-선택 순서
-기본 (0)
-숫자가 클수록 먼저 사용됩니다. 위에 있는 계정이 모두 소진되거나 사용할 수 없을 때에만 더 낮은 숫자로 넘어갑니다.
-주간
-리셋
-9월 7일
-11:28
-26%
-
-team
-1
-이 계정을 다음에 사용
-일시 중지
-별칭 편집
- · team · ID: account-
-선택 순서
-기본 (0)
-숫자가 클수록 먼저 사용됩니다. 위에 있는 계정이 모두 소진되거나 사용할 수 없을 때에만 더 낮은 숫자로 넘어갑니다.
-5시간
-리셋
-오늘
-06:37
-0%
-주간
-리셋
-9월 8일
-01:13
-6%
-
-go
-0
-선택됨
-이 계정을 다음에 사용
-일시 중지
-별칭 편집
- · go · ID: account-
-선택 순서
-기본 (0)
-숫자가 클수록 먼저 사용됩니다. 위에 있는 계정이 모두 소진되거나 사용할 수 없을 때에만 더 낮은 숫자로 넘어갑니다.
-30일
-리셋
-10월 1일
-08:49
-0%
-
-pro
-1
-이 계정을 다음에 사용
-일시 중지
-별칭 편집
- · pro · ID: account-
-선택 순서
-기본 (0)
-숫자가 클수록 먼저 사용됩니다. 위에 있는 계정이 모두 소진되거나 사용할 수 없을 때에만 더 낮은 숫자로 넘어갑니다.
-주간
-리셋
-9월 7일
-11:37
-77%
-로테이션 전략
-OpenCodex가 새 작업/바인딩 없는 작업에 계정을 배정하는 방식입니다.
-할당량 전략은 사용량 임계값을 넘으면 기존 작업의 다음 요청도 다른 계정에 다시 바인딩할 수 있습니다.
-새 작업/바인딩 없는 작업은 현재 계정 바인딩이 없는 요청입니다. 기존에 보이던 작업도 프록시나 어피니티 상태가 초기화되면 바인딩이 없어질 수 있습니다.
-할당량
-고급 설정
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_1440.png
deleted file mode 100644
index 8810d82d43..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_interactive.txt
deleted file mode 100644
index 065cfbd95a..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_interactive.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e51 tab "개요"
-e52 tab "활성 프로바이더"
-e53 tab "사용 가능한 모델"
-e56 button "서브에이전트"
-e58 radio "v1"
-e59 radio "base"
-e60 radio "v2"
-e62 button "재부팅 후에도 opencodex가 자동으로 준비됩니다"
-e64 combobox "서브에이전트 위임"
-e67 button "설정 열기"
-e69 button "지금 동기화"
-e72 button "업데이트 확인"
-e74 button "Codex 실행 시 opencodex 시작"
-e76 combobox "모델"
-e80 button "응답 실시간 스트리밍"
-e82 combobox "모델"
-e85 combobox "비전 사이드카 — 추론 강도"
-e88 button "고급 설정"
-e90 button "쉐도우 호출 가로채기"
-e92 button "쉐도우 호출 가로채기"
-e93 combobox "대체 모델"
-e97 button "작업 완료 후 재시작"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_1440.png
deleted file mode 100644
index 85c0a995fe..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_interactive.txt
deleted file mode 100644
index f3cfb8af75..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_interactive.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e51 tab "개요"
-e52 tab "활성 프로바이더"
-e53 tab "사용 가능한 모델"
-e56 searchbox "모델 검색…"
-e57 button "Anthropic Claude 13"
-e58 button "Cursor 40"
-e59 button "Google Antigravity 7"
-e60 button "Kimi 9"
-e61 button "Lidge 1"
-e62 button "Muse Code 2"
-e63 button "OpenAI (Codex login) 7"
-e64 button "OpenCode Free 9"
-e65 button "xAI Grok 8"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_text.txt
deleted file mode 100644
index 9ce296daab..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_models_text.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-대시보드
-
-로컬 opencodex 프록시와 프로바이더, 그리고 Codex로 라우팅되는 모델의 실시간 상태입니다.
-
-개요
-활성 프로바이더
-사용 가능한 모델
-사용 가능한 모델
-96
-Anthropic Claude
-13
-Cursor
-40
-Google Antigravity
-7
-Kimi
-9
-Lidge
-1
-Muse Code
-2
-OpenAI (Codex login)
-7
-OpenCode Free
-9
-xAI Grok
-8
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_1440.png
deleted file mode 100644
index 2f558b4bd0..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_interactive.txt
deleted file mode 100644
index dce46c0e44..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_interactive.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e51 tab "개요"
-e52 tab "활성 프로바이더"
-e53 tab "사용 가능한 모델"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_text.txt
deleted file mode 100644
index dfdcd5942b..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_providers_text.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-대시보드
-
-로컬 opencodex 프록시와 프로바이더, 그리고 Codex로 라우팅되는 모델의 실시간 상태입니다.
-
-개요
-활성 프로바이더
-사용 가능한 모델
-활성 프로바이더
-9
-이름 어댑터 Base URL 모델
-OpenAI (Codex login) openai-responses https://chatgpt.com/backend-api/codex —
-Anthropic Claude anthropic https://api.anthropic.com claude-sonnet-5
-xAI Grok openai-chat https://api.x.ai/v1 grok-4.6
-Cursor cursor https://api2.cursor.sh auto
-Google Antigravity google https://daily-cloudcode-pa.googleapis.com gemini-3.7-flash
-OpenCode Free openai-chat https://opencode.ai/zen/v1 —
-Lidge openai-chat http://100.100.125.116:8081/v1 qwen3.8-27b-nvfp4
-Muse Code openai-responses https://api.meta.ai/v1 muse-spark-1.3
-Kimi openai-chat https://api.kimi.com/coding/v1 kimi-k2.7-code
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/dashboard_text.txt
deleted file mode 100644
index 98d59d4004..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/dashboard_text.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-대시보드
-
-로컬 opencodex 프록시와 프로바이더, 그리고 Codex로 라우팅되는 모델의 실시간 상태입니다.
-
-개요
-활성 프로바이더
-사용 가능한 모델
-서브에이전트
-v1
-base
-v2
-상태
-온라인
-버전
-2.42.0
-가동 시간
-1시간 42분
-프로바이더
-9
-토큰 (30일)
-515.1억
-커버리지 99%
-재부팅 후에도 opencodex가 자동으로 준비됩니다
-서브에이전트 위임
-없음
-설정 열기
-모델 동기화
-연결해둔 프로바이더를 기준으로 Codex 모델 카탈로그를 다시 씁니다.
-지금 동기화
-Codex 실행 시 opencodex 시작
-설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.
-웹 검색 사이드카
-라우팅 모델의 웹 검색에 쓸 백엔드와 모델을 고릅니다.
-gpt-5.6-luna
-응답 실시간 스트리밍
-비전 사이드카
-텍스트 전용 라우팅 모델이 이미지를 읽을 때 쓸 백엔드와 모델을 고릅니다.
-gpt-5.6-luna
-low
-고급 설정
-쉐도우 호출 가로채기
-⚠ 5.6-luna
-—
-메모리 관찰
-진행 중 요청
-3
-작업 완료 후 재시작
-경고 임계값 대비
-rss
-1.1 GiB / 4.0 GiB
-임계값의 28%
-상주 메모리 (RSS)
-1.1 GiB
-JS 힙 사용량
-213.8 MiB
-아레나 74.8 MiB
-JSC 힙
-213.8 MiB
-시간당 관측 변화
-+98.5 MiB/시간
-상세 정보
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/integrations_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/integrations_1440.png
deleted file mode 100644
index 3e04aece42..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/integrations_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/integrations_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/integrations_interactive.txt
deleted file mode 100644
index cd24707d99..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/integrations_interactive.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e51 tab "개요"
-e52 tab "API 키"
-e53 tab "Codex"
-e54 tab "Claude"
-e55 tab "Grok Build"
-e56 tab "Cursor"
-e57 tab "OpenCode"
-e58 tab "Pi"
-e59 tab "OMP"
-e60 tab "Hermes"
-e61 tab "OpenClaw"
-e62 tab "Kimi Code"
-e63 tab "Gajae Code"
-e64 tab "DSH"
-e65 tab "MiniMax Code"
-e66 tab "ZCode"
-e67 tab "Prime Agent"
-e68 tab "Aside"
-e78 button "모두 해제…"
-e82 button "키 관리"
-e87 button "Codex"
-e90 button "해제"
-e91 button "설정"
-e94 button "Claude"
-e97 button "해제"
-e98 button "설정"
-e101 button "Claude Desktop"
-e104 button "해제"
-e105 button "설정"
-e108 button "Grok Build"
-e111 button "해제"
-e112 button "설정"
-e115 button "Cursor"
-e118 button "설정"
-e121 button "OpenCode"
-e124 button "적용"
-e125 button "설정"
-e128 button "Pi"
-e131 button "적용"
-e132 button "설정"
-e135 button "OMP"
-e138 button "적용"
-e139 button "설정"
-e142 button "Hermes"
-e145 button "적용"
-e146 button "설정"
-e149 button "OpenClaw"
-e152 button "적용"
-e153 button "설정"
-e156 button "Kimi Code"
-e159 button "적용"
-e160 button "설정"
-e163 button "Gajae Code"
-e166 button "적용"
-e167 button "설정"
-e170 button "DSH"
-e173 button "적용"
-e174 button "설정"
-e177 button "MiniMax Code"
-e180 button "적용"
-e181 button "설정"
-e184 button "ZCode"
-e187 button "해제"
-e188 button "설정"
-e191 button "Prime Agent"
-e194 button "적용"
-e195 button "설정"
-e198 button "Aside"
-e201 button "해제"
-e202 button "설정"
-e207 button "되돌리기"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/integrations_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/integrations_text.txt
deleted file mode 100644
index b46f9dde21..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/integrations_text.txt
+++ /dev/null
@@ -1,163 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-연동
-
-클라이언트를 opencodex에 연결하고 자격 증명과 설정 복원을 관리합니다.
-
-개요
-API 키
-Codex
-Claude
-Grok Build
-Cursor
-OpenCode
-Pi
-OMP
-Hermes
-OpenClaw
-Kimi Code
-Gajae Code
-DSH
-MiniMax Code
-ZCode
-Prime Agent
-Aside
-감지된 클라이언트
-10
-설정된 클라이언트
-6
-업데이트 필요
-2
-마지막 변경
-9/3/2026, 7:09:00 PM
-모두 해제…
-클라이언트
-API 키
-
-발급된 키 없음
-
-키 관리
-
-적용하면 먼저 백업을 보관한 뒤 opencodex 제공자 블록 하나만 씁니다. 해제는 그 블록만 제거하며 보관된 스냅샷으로 복원할 수 있습니다.
-
-Codex
-적용됨
-
-Codex 요청이 이 프록시를 지납니다
-
-설정
-Claude
-적용됨
-
-자동 (Claude 인증 감지)
-
-설정
-Claude Desktop
-적용됨
-
-Desktop이 이 프로필로 실행됩니다
-
-설정
-Grok Build
-적용됨
-
-모델 17개 연결됨
-
-설정
-Cursor
-미적용
-
-Private Inference 설치됨, 아직 요청 없음
-
-설정
-OpenCode
-미적용
-
-/Users/jun/.config/opencode/opencode.json
-
-설정
-Pi
-미적용
-
-/Users/jun/.pi/agent/models.json
-
-설정
-OMP
-미설치
-
-/Users/jun/.omp/agent/models.yml
-
-설정
-Hermes
-미설치
-
-/Users/jun/.hermes/config.yaml
-
-설정
-OpenClaw
-미설치
-
-/Users/jun/.openclaw/openclaw.json
-
-설정
-Kimi Code
-미설치
-
-/Users/jun/.kimi-code/config.toml
-
-설정
-Gajae Code
-미적용
-
-/Users/jun/.gjc/agent/models.yml
-
-설정
-DSH
-미설치
-
-/Users/jun/.dsh/settings.yaml
-
-설정
-MiniMax Code
-미설치
-
-/Users/jun/.minimax/config.yaml
-
-설정
-ZCode
-업데이트 필요
-
-/Users/jun/.zcode/v2/config.json
-
-설정
-Prime Agent
-미설치
-
-/Users/jun/.prime/agent/models.json
-
-설정
-Aside
-업데이트 필요
-
-/Users/jun/.aside/u/0/models.json
-
-설정
-복원 센터
-적용
-aside
-9/3/2026, 7:09:00 PM
-되돌리기
-이전 작업
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/logs_1440.png
deleted file mode 100644
index 1aa4004332..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/logs_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_1440.png
deleted file mode 100644
index a8594e0974..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_interactive.txt
deleted file mode 100644
index bfe5ae5086..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_interactive.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e50 tab "로그"
-e51 tab "디버그"
-e53 button "새로고침"
-e56 checkbox "Follow"
-e59 button "Provider debug"
-e61 button "Usage 추출"
-e63 button "주입 로그"
-e65 button "Claude 인바운드"
-e67 button "런타임 재정의 해제"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_text.txt
deleted file mode 100644
index cd34f19587..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/logs_debug_text.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-로그&디버그
-로그
-디버그
-새로고침
-Follow
-
-선택적 provider transport 및 usage 추출 진단. 요청 오류와 502는 로그 탭에 표시됩니다.
-
-Provider debug
-Usage 추출
-주입 로그
-Claude 인바운드
-런타임 재정의 해제
-디버그 로깅 꺼짐
-위 카드에서 Provider debug 또는 Usage extraction을 켜세요. 프록시로 요청을 보낸 뒤 라인이 표시됩니다.
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/logs_interactive.txt
deleted file mode 100644
index 9ad8f3c7ce..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/logs_interactive.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 checkbox "자동 새로고침"
-e52 tab "로그"
-e53 tab "디버그"
-e58 radio "전체"
-e59 radio "Claude"
-e60 radio "Codex"
-e61 radio "Grok"
-e62 checkbox "가로챈 헬퍼만"
-e64 searchbox "대화"
-e66 searchbox "모델"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/logs_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/logs_text.txt
deleted file mode 100644
index 6e4f4aa182..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/logs_text.txt
+++ /dev/null
@@ -1,425 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-로그&디버그
-자동 새로고침
-로그
-디버그
-
-로컬 opencodex 프록시를 거친 최근 요청입니다. 최신순.
-
-표면
-전체
-Claude
-Codex
-Grok
-가로챈 헬퍼만
-대화
-모델
-시간 토큰 tok/s ~$ 모델 추론 강도 프로바이더 상태 요청 소요 시간
-
-2026. 9. 4.
-오전 1:44:55
-
-37.6만
-c 37.5만
- 23.9 약 US$0.1233
-k3[1m]
-
-high
-reasoning_effort=high
- Kimi
-200
-상세보기
-
-ocx-6911ee1ea81fafd776faea80362db066
- 22500ms
-
-2026. 9. 4.
-오전 1:45:07
-
-30.2만
-c 30.1만
-w 626
- 83.2 약 US$0.1118
-claude-fable-5-1
-
-high
- Anthropic Claude
-200
-상세보기
-
-ocx-30f494d499b7262c7a380ca30e4fbd26
- 6900ms
-
-2026. 9. 4.
-오전 1:45:06
-
-9.3만
-c 8.1만
- 36.3 약 US$0.1044
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-18a158710a383bc7e1c0ffd863af57e0
- 6333ms
-
-2026. 9. 4.
-오전 1:44:58
-
-8.2만
-c 7.7만
- 37.7 약 US$0.0682
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-580a3282939be78166a8f838cdc2adef
- 7566ms
-
-2026. 9. 4.
-오전 1:44:53
-
-7.7만
-c 7.4만
- 34.1 약 US$0.0582
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-b90ea8f6328ee50214e2564cd8ca88cf
- 5429ms
-
-2026. 9. 4.
-오전 1:44:21
-
-37.6만
-c 37.3만
- 24.5 약 US$0.1303
-k3[1m]
-
-high
-reasoning_effort=high
- Kimi
-200
-상세보기
-
-ocx-ad5123ab098f605baff623a6384d07f0
- 32904ms
-
-2026. 9. 4.
-오전 1:44:47
-
-7.5만
-c 7.3만
- 32.8 약 US$0.0472
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-d068d7a7725f801d192bd09cc541392e
- 5698ms
-
-2026. 9. 4.
-오전 1:44:37
-
-30.2만
-c 28.3만
-w 1.8만
- 63.7 약 US$0.3371
-claude-fable-5-1
-
-high
- Anthropic Claude
-200
-상세보기
-
-ocx-555838039f421c3a2ee797f55a83bd8d
- 14187ms
-
-2026. 9. 4.
-오전 1:44:20
-
-13.6만
- 9.0 약 US$0.2736
-grok-4.6
-
-high
-reasoning_effort=high
- xAI Grok
-200
-상세보기
-
-ocx-041ab155bd347cc2420844ab34bab725
- 31000ms
-
-2026. 9. 4.
-오전 1:44:33
-
-12.3만
-c 12.2만
- 47.0 약 US$0.0837
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-6598f1236217e2c5b87ade3b005eb95c
- 13712ms
-
-2026. 9. 4.
-오전 1:44:39
-
-7.4만
-c 6.8만
- 40.2 약 US$0.0701
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-eb23f84cb6113fcbd2dcb658a58e60a1
- 7889ms
-
-2026. 9. 4.
-오전 1:44:33
-
-6.9만
-c 6.1만
- 34.7 약 US$0.0737
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-f956cfb8d20c0b130b2a73f4d6138c61
- 5969ms
-
-2026. 9. 4.
-오전 1:41:27
-
-22.7만
-c 20.5만
- 53.8 약 US$0.4651
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-38df259bf529696880baab8045bcdafc
- 190239ms
-
-2026. 9. 4.
-오전 1:44:26
-
-6.1만
-c 5.5만
- 40.4 약 US$0.0686
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-44dfd4e7aba688c641521838c389148b
- 6585ms
-
-2026. 9. 4.
-오전 1:44:21
-
-12.2만
-c 9.4만
- 44.6 약 US$0.2019
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-0891d2369df2f0b331107d9a08f3e46d
- 11760ms
-
-2026. 9. 4.
-오전 1:44:26
-
-28.4만
-c 28.3만
-w 322
- 32.9 약 US$0.0788
-claude-fable-5-1
-
-high
- Anthropic Claude
-200
-상세보기
-
-ocx-4a742f56bfc688c30629b797afef353a
- 2428ms
-
-2026. 9. 4.
-오전 1:44:18
-
-5.5만
-c 5.4만
- 38.2 약 US$0.0386
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-760aa18797bf2188f8f250ca3aeafd10
- 7506ms
-
-2026. 9. 4.
-오전 1:44:17
-
-15.8만
-c 15.3만
-w 3764
- 56.2 약 US$0.1089
-claude-opus-5
-
-high
- Anthropic Claude
-200
-상세보기
-
-ocx-8342f0af832e94bdcab5a1a5ff8fcb5c
- 6170ms
-
-2026. 9. 4.
-오전 1:43:46
-
-37.4만
-c 37.2만
- 23.1 약 US$0.1263
-k3[1m]
-
-high
-reasoning_effort=high
- Kimi
-200
-상세보기
-
-ocx-5d537e4bd727c92e0fcb79927752b609
- 35081ms
-
-2026. 9. 4.
-오전 1:44:13
-
-12.3만
-c 12.1만
- 36.6 약 US$0.0788
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-79c39d63269db9e84255898e8ea430d5
- 7057ms
-
-2026. 9. 4.
-오전 1:43:53
-
-12.9만
-c 12.3만
- 9.6 약 US$0.0741
-grok-4.6
-
-high
-reasoning_effort=high
- xAI Grok
-200
-상세보기
-
-ocx-7b057b63f89af62d683a3c5dbc59d62e
- 26562ms
-
-2026. 9. 4.
-오전 1:44:11
-
-5.5만
-c 4.5만
- 24.6 약 US$0.0742
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-9941898d08022add80e70a657a073304
- 7146ms
-
-2026. 9. 4.
-오전 1:44:07
-
-15.4만
-c 15.3만
-w 253
- 88.5 약 US$0.0977
-claude-opus-5
-
-high
- Anthropic Claude
-200
-상세보기
-
-ocx-a65529911ee077c45ad458f9d33b4513
- 8811ms
-
-2026. 9. 4.
-오전 1:44:06
-
-12.2만
-c 12만
- 35.8 약 US$0.0754
-gpt-5.6-sol
-
-medium
- Openai P3b640f
-200
-상세보기
-
-ocx-8fdeaeb96af5249fabb4effce6e9c69c
- 7449ms
-
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/models_1440.png
deleted file mode 100644
index 0a23491b65..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/models_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/models_combos_1440.png
deleted file mode 100644
index 14a96d1399..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_combos_interactive.txt
deleted file mode 100644
index d6bc2d5998..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_interactive.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 button "Codex 모델 목록 새로고침"
-e53 button "Codex 모델 목록 새로고침"
-e55 tab "모델20/96 표시"
-e56 tab "콤보0"
-e57 tab "라우팅 (beta)"
-e58 tab "호환성"
-e64 button "콤보 추가"
-e67 textbox "콤보 또는 대상 검색…"
-e69 button "콤보 만들기"
-e71 tab "설정"
-e72 tab "정보"
-e75 textbox "콤보 ID"
-e78 textbox "공개 모델 이름"
-e80 checkbox "네이티브 OpenAI 별칭"
-e84 textbox "표시 이름"
-e88 radio "장애 조치"
-e89 radio "라운드로빈"
-e92 combobox "기본 추론 수준"
-e93 option "없음 (대상 기본값)"
-e94 option "low"
-e95 option "medium"
-e96 option "high"
-e97 option "xhigh"
-e98 option "max"
-e99 option "ultra"
-e102 button "드래그하여 순서 변경"
-e103 button "위로"
-e104 button "아래로"
-e105 combobox "프로바이더"
-e106 option "프로바이더 선택…"
-e107 option "Anthropic Claude"
-e108 option "Cursor"
-e109 option "Google Antigravity"
-e110 option "Kimi"
-e111 option "Muse Code"
-e112 option "OpenAI (Codex login)"
-e113 option "OpenCode Free"
-e114 option "xAI Grok"
-e115 combobox "모델"
-e116 option "먼저 프로바이더를 선택하세요…"
-e118 button "삭제"
-e120 button "대상 추가"
-e127 button "이미지 / 멀티모달"
-e130 button "적응형 추론 단계"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_combos_text.txt
deleted file mode 100644
index bda7a2cec9..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_combos_text.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-모델
-Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.
-Codex 모델 목록 새로고침
-모델20/96 표시
-콤보0
-라우팅 (beta)
-호환성
-
-여러 모델을 하나의 id로 묶어 순서대로 응답하게 합니다. failover로 대상을 연결하거나 분산 전략으로 부하를 나눕니다.
-
-콤보
-0
-콤보 추가
-콤보 추가
-콤보 만들기
-설정
-정보
-콤보 ID
-
-내부 콤보 ID입니다. 생성 후에도 변경할 수 있습니다.
-
-공개 모델 이름
-
-선택 사항입니다. 접두사 없는 이름, vendor/model 같은 사용자 지정 접두사를 사용하거나 비워 두어 combo/를 사용할 수 있습니다.
-
- 네이티브 OpenAI 별칭
-
-이 콤보가 지원되는 비수식 OpenAI 네이티브 모델 ID를 사용합니다. 계정/프로바이더 수식 OpenAI 경로는 별도로 유지됩니다.
-
-표시 이름
-
-모델 선택기에 표시할 이름입니다. 네이티브 OpenAI 별칭을 사용할 때 필수입니다.
-
-전략
-장애 조치
-라운드로빈
-
-대상을 순서대로 시도합니다. 재시도 가능한 오류(한도, 장애, 구독 게이트)면 다음으로 넘어갑니다.
-
-기본 추론 수준
-없음 (대상 기본값)
-low
-medium
-high
-xhigh
-max
-ultra
-
-클라이언트가 추론 수준을 생략한 경우에만 사용합니다. 옵션은 선택한 대상이 광고하는 수준의 교집합입니다.
-
-대상
-프로바이더 선택…
-Anthropic Claude
-Cursor
-Google Antigravity
-Kimi
-Muse Code
-OpenAI (Codex login)
-OpenCode Free
-xAI Grok
-먼저 프로바이더를 선택하세요…
-할당량 알 수 없음
-대상 추가
-
-순서가 중요합니다 — 첫 번째가 기본입니다.
-
-기능
-이미지 / 멀티모달
-
-선택한 모든 대상이 이미지 입력을 지원해야 사용할 수 있습니다.
-
-적응형 추론 단계
-
-끔: 추론 단계를 조절할 수 없는 대상이 하나라도 있으면 콤보 전체의 선택기가 사라집니다. 켬: 그런 대상도 그대로 쓰면서, 선택기에는 나머지 대상이 공통으로 지원하는 단계가 남습니다.
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_1440.png
deleted file mode 100644
index a8368fd723..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_interactive.txt
deleted file mode 100644
index 05efdc798f..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_interactive.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 button "Codex 모델 목록 새로고침"
-e53 button "Codex 모델 목록 새로고침"
-e55 tab "모델20/96 표시"
-e56 tab "콤보"
-e57 tab "라우팅 (beta)"
-e58 tab "호환성"
-e61 button "새로고침"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_text.txt
deleted file mode 100644
index eb45a13330..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_compatibility_text.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-모델
-Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.
-Codex 모델 목록 새로고침
-모델20/96 표시
-콤보
-라우팅 (beta)
-호환성
-
-랩 프로젝션 증거의 읽기 전용 호환성 판정 행렬.
-
-새로고침
-랩 프로젝션을 사용할 수 없습니다. 먼저 적합성 또는 라이브 프로브를 실행하세요.
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_interactive.txt
deleted file mode 100644
index fcbee9930f..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_interactive.txt
+++ /dev/null
@@ -1,144 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 button "Codex 모델 목록 새로고침"
-e53 button "Codex 모델 목록 새로고침"
-e55 tab "모델20/96 표시"
-e56 tab "콤보"
-e57 tab "라우팅 (beta)"
-e58 tab "호환성"
-e63 button "모든 프로바이더 20/96 표시"
-e64 button "OpenAI (Codex login) 3/7 표시"
-e65 button "Anthropic Claude 3/13 표시"
-e66 button "Cursor 6/40 표시"
-e67 button "Google Antigravity 2/7 표시"
-e68 button "Kimi 1/9 표시"
-e69 button "Muse Code 2/2 표시"
-e70 button "OpenCode Free 1/9 표시"
-e71 button "xAI Grok 1/8 표시"
-e74 button "새 모델을 비활성화 상태로 추가"
-e75 button "기본 별칭을 전체에 사용"
-e76 button "별칭"
-e78 button "Codex 앱의 백그라운드 호출(gpt-5.6-luna, 제목·커밋 메시지)을 가로채 선택한 모델로 바꿉니다."
-e80 button "쉐도우 호출 가로채기"
-e81 combobox "쉐도우 호출 가로채기"
-e86 radio "v1"
-e87 radio "base"
-e88 radio "v2"
-e89 button "서브에이전트"
-e91 combobox "기본 창 / 상한"
-e94 button "전체 적용"
-e96 button "모두 접기"
-e97 button "모두 펼치기"
-e98 button "openai OpenAI 네이티브 3/7 표시"
-e101 button "공급자 별칭 편집"
-e103 button "기본 별칭 사용"
-e104 button "커스텀 모델 추가"
-e105 button "모두 켜기"
-e106 button "모두 끄기"
-e107 button "기본 창 / 상한"
-e108 combobox "기본 1.05M"
-e111 button "사용자 지정 창"
-e112 button "anthropic 3/13 표시 신규 4개, 꺼짐"
-e115 button "공급자 별칭 편집"
-e117 button "기본 별칭 사용"
-e118 button "커스텀 모델 추가"
-e120 radio "프리셋"
-e121 radio "전체"
-e122 button "모두 켜기"
-e123 button "모두 끄기"
-e124 button "기본 창 / 상한"
-e125 combobox "기본 1M"
-e128 button "사용자 지정 창"
-e129 button "cursor 6/40 표시 신규 3개, 꺼짐"
-e132 button "공급자 별칭 편집"
-e134 button "기본 별칭 사용"
-e135 button "커스텀 모델 추가"
-e136 button "모두 켜기"
-e137 button "모두 끄기"
-e138 button "기본 창 / 상한"
-e139 combobox "기본 1,048,576"
-e142 button "사용자 지정 창"
-e143 button "google-antigravity 2/7 표시 신규 1개, 꺼짐"
-e146 button "공급자 별칭 편집"
-e148 button "기본 별칭 사용"
-e149 button "커스텀 모델 추가"
-e150 button "모두 켜기"
-e151 button "모두 끄기"
-e152 button "기본 창 / 상한"
-e153 combobox "기본 1,048,576"
-e156 button "사용자 지정 창"
-e157 button "kimi 1/9 표시"
-e160 button "공급자 별칭 편집"
-e162 button "기본 별칭 사용"
-e163 button "커스텀 모델 추가"
-e164 button "모두 켜기"
-e165 button "모두 끄기"
-e166 button "기본 창 / 상한"
-e167 combobox "기본 1,048,576"
-e170 button "사용자 지정 창"
-e173 radio "끔"
-e174 radio "켬"
-e175 button "kimi/k3[1m]"
-e177 button "모델 별칭 편집"
-e179 button "kimi/k3"
-e181 button "모델 별칭 편집"
-e183 button "kimi/k3-256k"
-e185 button "모델 별칭 편집"
-e187 button "kimi/kimi-for-coding"
-e189 button "모델 별칭 편집"
-e191 button "kimi/kimi-for-coding-highspeed"
-e193 button "모델 별칭 편집"
-e195 button "kimi/kimi-k2.5"
-e197 button "모델 별칭 편집"
-e199 button "kimi/kimi-k2.6"
-e201 button "모델 별칭 편집"
-e203 button "kimi/kimi-k2.7-code"
-e205 button "모델 별칭 편집"
-e207 button "kimi/kimi-k2.7-code-highspeed"
-e209 button "모델 별칭 편집"
-e211 button "meta-muse 2/2 표시"
-e214 button "공급자 별칭 편집"
-e216 button "기본 별칭 사용"
-e217 button "커스텀 모델 추가"
-e218 button "모두 켜기"
-e219 button "모두 끄기"
-e220 button "기본 창 / 상한"
-e221 combobox "기본 1,048,576"
-e224 button "사용자 지정 창"
-e227 radio "끔"
-e228 radio "켬"
-e229 button "meta-muse/muse-spark-1.3"
-e231 button "모델 별칭 편집"
-e233 button "meta-muse/muse-spark-1.3-contributor"
-e235 button "모델 별칭 편집"
-e237 button "opencode-free 1/9 표시 신규 2개, 꺼짐"
-e240 button "공급자 별칭 편집"
-e242 button "기본 별칭 사용"
-e243 button "커스텀 모델 추가"
-e244 button "모두 켜기"
-e245 button "모두 끄기"
-e246 button "기본 창 / 상한"
-e247 combobox "기본 350k"
-e250 button "사용자 지정 창"
-e251 button "xai 1/8 표시 신규 1개, 꺼짐"
-e254 button "공급자 별칭 편집"
-e256 button "기본 별칭 사용"
-e257 button "커스텀 모델 추가"
-e258 button "모두 켜기"
-e259 button "모두 끄기"
-e260 button "기본 창 / 상한"
-e261 combobox "기본 1M"
-e264 button "사용자 지정 창"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/models_routing_1440.png
deleted file mode 100644
index c938d63d0e..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_routing_interactive.txt
deleted file mode 100644
index a39bea8892..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_interactive.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 button "Codex 모델 목록 새로고침"
-e53 button "Codex 모델 목록 새로고침"
-e55 tab "모델20/96 표시"
-e56 tab "콤보0"
-e57 tab "라우팅 (beta)0"
-e58 tab "호환성"
-e61 button "프로필 만들기"
-e62 button "재시도"
-e65 spinbutton "요청 컨텍스트 창(토큰)"
-e66 checkbox "요청에 도구 필요"
-e68 checkbox "요청에 이미지 입력 필요"
-e70 checkbox "요청에 구조화된 출력 필요"
-e72 button "후보 평가"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_routing_text.txt
deleted file mode 100644
index 8edb6e619a..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_routing_text.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-모델
-Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.
-Codex 모델 목록 새로고침
-모델20/96 표시
-콤보0
-라우팅 (beta)0
-호환성
-
-정책 프로필, dry-run 평가, 그리고 근거가 남는 라우팅 분석입니다.
-
-+
-프로필 만들기
-재시도
-드라이런 평가
-요청 컨텍스트 창(토큰)
-요청에 도구 필요
-요청에 이미지 입력 필요
-요청에 구조화된 출력 필요
-후보 평가
-라우팅 분석
-
-분석이 아직 없습니다. 먼저 요청을 보내세요.
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/models_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/models_text.txt
deleted file mode 100644
index 2482b4a6f8..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/models_text.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-모델
-Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.
-Codex 모델 목록 새로고침
-모델20/96 표시
-콤보
-라우팅 (beta)
-호환성
-
-Codex가 보는 모델을 켜고 끕니다 — 네이티브 GPT passthrough와 라우팅된 모델을 프로바이더별로 묶어 보여줍니다(헤더를 클릭하면 접힘). 숨긴 모델은 카탈로그와 선택기에서 빠지지만 정확한 id로 직접 호출할 수 있습니다. 변경 사항은 다음 Codex 턴에 적용됩니다 — opencodex가 Codex의 5분 모델 캐시를 무효화하므로 재시작이 필요 없습니다.
-
-프로바이더
-8
-모든 프로바이더
-20/96 표시
-OpenAI (Codex login)
-3/7 표시
-Anthropic Claude
-3/13 표시
-Cursor
-6/40 표시
-Google Antigravity
-2/7 표시
-Kimi
-1/9 표시
-Muse Code
-2/2 표시
-OpenCode Free
-1/9 표시
-xAI Grok
-1/8 표시
-새 모델을 비활성화 상태로 추가
-별칭
-쉐도우 호출 가로채기 ⓘ
-⚠ 5.6-luna →
-—
-서브에이전트
-v1
-base
-v2
-기본 창 / 상한
-350k
-라우팅된 모든 프로바이더에 350k 기본 창을 켭니다. 중계가 context_window / context_length 를 주지 않으면 이 값이 실제 Codex 창이 됩니다. 모델 하나만 손으로 쓰려면 같은 줄의 「사용자 지정 창」을 쓰세요. 네이티브 프로바이더는 영향을 받지 않습니다.
-커스텀 2개
-피커 순서: Subagents에서 지정한 순서 → 나머지 라우팅 모델(프로바이더, 모델 ID 순 알파벳 정렬) → 네이티브 모델. 노출 토글은 모델을 필터링할 뿐 이 순서를 바꾸지 않습니다.
-모두 접기
-모두 펼치기
-openai
-OpenAI 네이티브
-3/7 표시
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1.05M
-사용자 지정 창
-anthropic
-3/13 표시
-신규 4개, 꺼짐
-기본 별칭 사용
-+
-커스텀 모델 추가
-프리셋
-전체
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1M
-사용자 지정 창
-cursor
-6/40 표시
-신규 3개, 꺼짐
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1,048,576
-사용자 지정 창
-google-antigravity
-2/7 표시
-신규 1개, 꺼짐
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1,048,576
-사용자 지정 창
-kimi
-1/9 표시
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1,048,576
-사용자 지정 창
-새 모델 정책
-끔
-켬
-kimi/k3[1m]
-kimi/k3
-kimi/k3-256k
-kimi/kimi-for-coding
-kimi/kimi-for-coding-highspeed
-kimi/kimi-k2.5
-kimi/kimi-k2.6
-kimi/kimi-k2.7-code
-kimi/kimi-k2.7-code-highspeed
-meta-muse
-2/2 표시
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1,048,576
-사용자 지정 창
-새 모델 정책
-끔
-켬
-meta-muse/muse-spark-1.3
-meta-muse/muse-spark-1.3-contributor
-opencode-free
-1/9 표시
-신규 2개, 꺼짐
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-350k
-사용자 지정 창
-xai
-1/8 표시
-신규 1개, 꺼짐
-기본 별칭 사용
-+
-커스텀 모델 추가
-모두 켜기
-모두 끄기
-기본 창 / 상한
-1M
-사용자 지정 창
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/providers_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/providers_1440.png
deleted file mode 100644
index f9f618d4dd..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/providers_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/providers_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/providers_interactive.txt
deleted file mode 100644
index 20c00cf244..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/providers_interactive.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e49 button "프로바이더 추가"
-e53 searchbox "프로바이더 검색…"
-e54 button "프로바이더 필터"
-e57 option "Anthropic Claude 선택 — 준비됨"
-e58 option "Cursor 선택 — 준비됨"
-e59 option "Google Antigravity 선택 — 준비됨"
-e60 option "Kimi 선택 — 준비됨"
-e61 option "Muse Code 선택 — 준비됨"
-e62 option "OpenAI (Codex login) 선택 — 준비됨"
-e63 option "OpenCode Free 선택 — 준비됨 · 무료"
-e64 option "xAI Grok 선택 — 준비됨 · 기본"
-e66 option "Lidge 선택 — 비활성"
-e70 button "JSON 편집"
-e74 button "Cursor 방금 전 전 확인 자사 모델 9월 17일, 01:54 초기화 5% 사용 API 사용량 9월 17일, 01:54 초기화 55% 사용 30일 한도 9월 17일, 01:54 초기화 12% 사용"
-e75 button "Anthropic Claude 방금 전 전 확인 5시간 한도 5시간 후 초기화 2% 사용 주간 한도 내일 08:00 초기화 55% 사용 Fable 내일 08:00 초기화 50% 사용"
-e82 button "Kimi 방금 전 전 확인 5시간 한도 4시간 후 초기화 21% 사용 주간 한도 9월 9일, 23:22 초기화 10% 사용"
-e83 button "Google Antigravity 방금 전 전 확인 Gem 5시간 후 초기화 1% 사용 Cla 5시간 후 초기화 0% 사용"
-e84 button "xAI Grok 방금 전 전 확인 주간 한도 9월 10일, 19:26 초기화 0% 사용"
-e87 button "Anthropic Claude 94.7k건 요청"
-e88 button "OpenAI (Codex login) 84.1k건 요청"
-e89 button "xAI Grok 16.5k건 요청"
-e90 button "Kimi 4.6k건 요청"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/providers_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/providers_text.txt
deleted file mode 100644
index 67ae32256f..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/providers_text.txt
+++ /dev/null
@@ -1,125 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-프로바이더
-프로바이더 추가
-준비됨
-8
-Anthropic Claude
-모델 13개
-Cursor
-모델 40개
-Google Antigravity
-모델 7개
-Kimi
-모델 9개
-Muse Code
-모델 2개
-OpenAI (Codex login)
-
-OpenCode Free
-무료
-모델 9개
-xAI Grok
-모델 8개
-비활성
-1
-L
-Lidge
-모델 1개
-프로바이더 개요
-
-모든 모델 프로바이더를 한곳에서 관리합니다.
-
-JSON 편집
-8
-준비됨
-0
-설정 필요
-1
-비활성
-사용량 제한
-Cursor
-방금 전 전 확인
-자사 모델
-9월 17일, 01:54 초기화
-5% 사용
-API 사용량
-9월 17일, 01:54 초기화
-55% 사용
-30일 한도
-9월 17일, 01:54 초기화
-12% 사용
-Anthropic Claude
-방금 전 전 확인
-5시간 한도
-5시간 후 초기화
-2% 사용
-주간 한도
-내일 08:00 초기화
-55% 사용
-Fable
-내일 08:00 초기화
-50% 사용
-OpenAI (Codex login)
-방금 전 전 확인
-설정 가중치 기반 풀 추정치
-5시간 한도
-일부만
-0% 사용
-주간 한도
-일부만
-42% 사용
-30일 한도
-일부만
-0% 사용
-다음 용량 회복 · 주간 · 2026. 9. 7. 오전 11:28
-+8.5% 풀 용량
-현재 유효 계정 · go
-30일 한도
-10월 1일, 08:49 초기화
-0% 사용
-보정되지 않은 요금제 1개는 기본 좌석 가중치로 계산되어, 이 추정치가 실제보다 낮을 수 있습니다
-일부 기간의 범위가 불완전합니다: 5개 계정에서 표시된 모든 한도 기간을 확인할 수 없습니다
-Kimi
-방금 전 전 확인
-5시간 한도
-4시간 후 초기화
-21% 사용
-주간 한도
-9월 9일, 23:22 초기화
-10% 사용
-Google Antigravity
-방금 전 전 확인
-Gem
-5시간 후 초기화
-1% 사용
-Cla
-5시간 후 초기화
-0% 사용
-xAI Grok
-방금 전 전 확인
-주간 한도
-9월 10일, 19:26 초기화
-0% 사용
-최근 사용
-Anthropic Claude
-94.7k건 요청
-OpenAI (Codex login)
-84.1k건 요청
-xAI Grok
-16.5k건 요청
-Kimi
-4.6k건 요청
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/startup_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/startup_1440.png
deleted file mode 100644
index b81fb5d36c..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/startup_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/startup_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/startup_interactive.txt
deleted file mode 100644
index 203e84bfe1..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/startup_interactive.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e50 button "대시보드로 돌아가기"
-e51 button "새로고침"
-e57 button "복사"
-e69 button "Codex launcher shim - 설치하기"
-e75 button "복사"
-e78 button "복사"
-e81 button "복사"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/startup_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/startup_text.txt
deleted file mode 100644
index f5a48bd9d1..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/startup_text.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-시작 안전성
-
-재부팅 후 로컬 프록시 라우팅이 재연결 반복으로 이어지기 전에 Codex가 opencodex에 연결될 수 있는지 확인합니다.
-
-대시보드로 돌아가기
-새로고침
-
-OpenCodex가 Codex 0.153.0-alpha.5을(를) 사용해 일부 reasoning effort 옵션이 숨겨졌습니다(제거됨: minimal).
-
-ocx sync
-복사
-재부팅 보호됨
-재부팅 후에도 opencodex가 자동으로 준비됩니다
-
-현재 라우팅과 시작 방식이 일치합니다. 재부팅 후 ocx start를 수동으로 실행할 필요가 없습니다.
-
-Codex 라우팅
-로컬 프록시
-재부팅 보호
-백그라운드 서비스
-필요 시 자동 시작
-켜짐
-보호 상태 상세
-darwin
-백그라운드 서비스
-로그인할 때 시작하고 프록시가 중단되면 다시 실행합니다.
-사용 가능
-Codex launcher shim
-지원되는 Codex 스크립트 런처가 시작될 때 ocx ensure를 실행합니다.
-설치되지 않음
-설치하기
-복구 방법
-
-위의 원클릭 설치를 사용하거나 수동 복구 명령을 복사할 수 있습니다. Codex Desktop과 Windows 실행 파일에는 백그라운드 서비스를 권장합니다.
-
-권장: 영구 백그라운드 서비스
-ocx service repair
-복사
-대안: CLI launcher shim
-ocx codex-shim install
-복사
-안전 전환: Codex 네이티브 라우팅 복구
-ocx restore
-복사
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/storage_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/storage_1440.png
deleted file mode 100644
index 1c27eaf9f0..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/storage_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/storage_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/storage_interactive.txt
deleted file mode 100644
index 8d1f9e8682..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/storage_interactive.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e50 button "다시 스캔"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/storage_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/storage_text.txt
deleted file mode 100644
index 04364200fc..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/storage_text.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-저장소
-다시 스캔
-
-CODEX_HOME 사용량을 확인합니다. 정리는 활성 세션을 건드리지 않습니다.
-
-저장소 스캔 중…
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/subagents_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/subagents_1440.png
deleted file mode 100644
index 854ab4bfb8..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/subagents_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/subagents_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/subagents_interactive.txt
deleted file mode 100644
index 4804ad74d1..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/subagents_interactive.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e50 tab "추천5/5"
-e51 tab "모델21"
-e52 tab "설정"
-e61 button "xai/grok-4.6 위로 이동"
-e63 button "xai/grok-4.6 아래로 이동"
-e65 button "xai/grok-4.6 삭제"
-e68 button "gpt-5.6-sol 위로 이동"
-e70 button "gpt-5.6-sol 아래로 이동"
-e72 button "gpt-5.6-sol 삭제"
-e75 button "gpt-5.6-terra 위로 이동"
-e77 button "gpt-5.6-terra 아래로 이동"
-e79 button "gpt-5.6-terra 삭제"
-e82 button "gpt-5.6-luna 위로 이동"
-e84 button "gpt-5.6-luna 아래로 이동"
-e86 button "gpt-5.6-luna 삭제"
-e89 button "gpt-5.5 위로 이동"
-e91 button "gpt-5.5 아래로 이동"
-e93 button "gpt-5.5 삭제"
-e95 button "저장"
-e99 textbox "모델 검색(네이티브 gpt + 라우팅)…"
-e101 button "gpt-5.6-sol을(를) 추천에서 제거"
-e104 button "gpt-5.6-terra을(를) 추천에서 제거"
-e107 button "gpt-5.6-luna을(를) 추천에서 제거"
-e110 button "anthropic/claude-fable-5-1을(를) 추천에 추가"
-e113 button "anthropic/claude-opus-4-6을(를) 추천에 추가"
-e116 button "anthropic/claude-opus-5을(를) 추천에 추가"
-e119 button "cursor/claude-fable-5-1을(를) 추천에 추가"
-e122 button "cursor/gemini-3.6-flash을(를) 추천에 추가"
-e125 button "cursor/gemini-3.7-flash을(를) 추천에 추가"
-e128 button "cursor/gemini-3.8-flash을(를) 추천에 추가"
-e131 button "cursor/grok-4.6을(를) 추천에 추가"
-e134 button "cursor/kimi-k3을(를) 추천에 추가"
-e137 button "google-antigravity/claude-opus-4-6-thinking을(를) 추천에 추가"
-e140 button "google-antigravity/gemini-3.8-flash을(를) 추천에 추가"
-e143 button "kimi/k3[1m]을(를) 추천에 추가"
-e146 button "meta-muse/muse-spark-1.3을(를) 추천에 추가"
-e149 button "meta-muse/muse-spark-1.3-contributor을(를) 추천에 추가"
-e152 button "opencode-free/muse-spark-1.2-contributor-free을(를) 추천에 추가"
-e155 button "xai/grok-4.6을(를) 추천에서 제거"
-e158 button "lidge/qwen3.8-27b-nvfp4을(를) 추천에 추가"
-e161 button "gpt-5.5을(를) 추천에서 제거"
-e166 combobox "서브에이전트 위임"
-e170 button "Codex 설정에도 기본값으로 저장"
-e172 button "일 나누는 방법 알려주기"
-e174 button "울트라 모드"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/subagents_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/subagents_text.txt
deleted file mode 100644
index 8932e64cc9..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/subagents_text.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-서브에이전트
-추천5/5
-모델21
-설정
-추천
-5/5
-
-여기서 선택해 표시된 순서가 Codex 모델 피커 최상단 1~5위와 spawn_agent의 기본 모델 후보를 결정합니다.
-
-1
-xai/grok-4.6
-2
-gpt-5.6-sol
-3
-gpt-5.6-terra
-4
-gpt-5.6-luna
-5
-gpt-5.5
-저장
-모델
-21
-2
-gpt-5.6-sol
-3
-gpt-5.6-terra
-4
-gpt-5.6-luna
-anthropic/claude-fable-5-1
-anthropic/claude-opus-4-6
-anthropic/claude-opus-5
-cursor/claude-fable-5-1
-cursor/gemini-3.6-flash
-cursor/gemini-3.7-flash
-cursor/gemini-3.8-flash
-cursor/grok-4.6
-cursor/kimi-k3
-google-antigravity/claude-opus-4-6-thinking
-google-antigravity/gemini-3.8-flash
-kimi/k3[1m]
-meta-muse/muse-spark-1.3
-meta-muse/muse-spark-1.3-contributor
-opencode-free/muse-spark-1.2-contributor-free
-1
-xai/grok-4.6
-lidge/qwen3.8-27b-nvfp4
-5
-gpt-5.5
-설정
-먼저 부를 모델
-Codex가 일을 나눠 맡길 때 가장 먼저 부를 모델입니다. 위 추천 목록이 부를 수 있는 후보라면, 여기서 고른 모델이 그중 1순위가 됩니다.
-없음
-Codex 설정에도 기본값으로 저장
-켜면 위에서 고른 모델이 Codex 설정 파일에 저장돼, 새로 시작하는 작업도 처음부터 그 모델을 씁니다. 끄면 여기서만 기억합니다. 반영은 다음 동기화나 재시작 때이고, 직접 적어둔 [agents] 설정은 그대로 둡니다.
-일 나누는 방법 알려주기
-Codex에게 "일을 이렇게 나눠 맡기면 된다"는 짧은 쪽지를 붙여 보냅니다. v2에서는 쓸 수 있는 모델 목록과 우선 모델을 알려주고, v1에서는 추론 강도가 max나 ultra일 때만 동작합니다. 끄면 아무 쪽지도 붙지 않습니다.
-울트라 모드
-모든 모델과 reasoning effort에서 Proactive 멀티에이전트 위임 정책을 켭니다 (reasoning effort 자체는 변경하지 않음). config.toml에 features.multi_agent_v2.multi_agent_mode_hint_text를 기록합니다.
-v2 멀티에이전트 서피스가 필요합니다 — 먼저 multi_agent_v2를 켜고 서브에이전트 모드에서 v2를 선택하세요.
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/usage_1440.png b/devlog/_plan/260904_dashboard_minimal/assets/usage_1440.png
deleted file mode 100644
index 498569b4f5..0000000000
Binary files a/devlog/_plan/260904_dashboard_minimal/assets/usage_1440.png and /dev/null differ
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/usage_interactive.txt b/devlog/_plan/260904_dashboard_minimal/assets/usage_interactive.txt
deleted file mode 100644
index de4e976be7..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/usage_interactive.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-e5 button "대시보드"
-e8 button "Codex 설정"
-e11 button "프로바이더"
-e14 button "모델"
-e17 button "서브에이전트"
-e20 button "로그&디버그"
-e23 button "사용량"
-e26 button "저장소"
-e29 button "연동"
-e32 combobox "언어"
-e38 button "프록시 중지"
-e40 button "Codex 모델 목록 새로고침"
-e42 link "GitHub"
-e45 button "GitHub 스타 완료"
-e46 button "업데이트 확인"
-e50 button "전체"
-e51 button "Codex"
-e52 button "Claude"
-e53 button "Grok"
-e55 button "사용 가능한 기록"
-e56 button "30일"
-e57 button "7일"
-e60 tab "개요231928"
-e61 tab "모델66"
-e62 tab "프로바이더19"
-e63 tab "커버리지 상세99%"
-e72 textbox "모델 검색…"
diff --git a/devlog/_plan/260904_dashboard_minimal/assets/usage_text.txt b/devlog/_plan/260904_dashboard_minimal/assets/usage_text.txt
deleted file mode 100644
index bc9a16d608..0000000000
--- a/devlog/_plan/260904_dashboard_minimal/assets/usage_text.txt
+++ /dev/null
@@ -1,256 +0,0 @@
-opencodex
-v2.42.0
-대시보드
-Codex 설정
-프로바이더
-모델
-서브에이전트
-로그&디버그
-사용량
-저장소
-연동
-한국어
-시스템
-프록시
-GitHub
-사용량
-전체
-Codex
-Claude
-Grok
-사용 가능한 기록
-30일
-7일
-
-프록시의 로컬 토큰 집계입니다. 누락된 사용량은 0으로 표시하지 않습니다.
-
-개요231928
-모델66
-프로바이더19
-커버리지 상세99%
-요청
-231928
-측정됨
-229025
-총 토큰
-515.1억
-캐시 히트 토큰
-497.9억
-캐시 생성: 6.1억
-커버리지
-99%
-활동일
-30
-API 정가 환산치 (이 기간)
-~US$38,986.1775
-결제 영수증이 아닙니다. 구독 사용량 또는 프로바이더 크레딧이 대신 적용될 수 있습니다.
-비용 산정 불가 7432건 제외
-일별 활동
-Aug
-Sep
-Oct
-Nov
-Dec
-Jan
-Feb
-Mar
-Apr
-May
-Jun
-Jul
-Aug
-월
-수
-금
-적음
-많음
-모델
-모델 프로바이더 요청 측정됨 토큰 비율
-claude-opus-5 Anthropic Claude 72724 72593 284억
-
-
-gpt-5.6-sol OpenAI (Codex login) 70222 69384 113.9억
-
-claude-fable-5 Anthropic Claude 12246 12183 35.7억
-
-claude-fable-5-1 Anthropic Claude 5182 5156 17.6억
-
-grok-4.6 xAI Grok 15461 15361 17.3억
-
-claude-opus-4-6 Anthropic Claude 4461 4448 9.3억
-
-k3[1m] Kimi 3824 3758 7.5억
-
-
-gpt-5.6-terra OpenAI (Codex login) 6693 6604 7.5억
-
-gemini-3.7-flash Google Antigravity 3185 3145 4.8억
-
-x-preview-f-free OpenCode Free 1946 1865 4.4억
-
-stealth/ox-alpha OpenRouter 2126 2102 3.5억
-
-
-gpt-5.6-luna OpenAI (Codex login) 6030 5079 2.9억
-
-grok-4.5 xAI Grok 1011 1001 1.7억
-
-gemini-3.8-flash Google Antigravity 1105 1105 1.2억
-
-gpt-5.5 OpenAI (Codex login) 864 862 1억
-
-qwen3.8-max-preview Alibaba Token Plan (Intl) 337 336 8588.3만
-
-anthropic/claude-opus-5 Kimi 758 754 8274.7만
-
-claude-opus-5 Kiro 21651 21444 4101.1만
-
-gemini-3.6-flash Google Antigravity 88 88 2830.5만
-
-grok-4.6 Cursor 304 291 2137.1만
-
-qwen3.8-27b-nvfp4 Lidge 168 102 562.5만
-
-gpt-5.3-codex-spark OpenAI (Codex login) 274 265 514.5만
-
-kimi-k3 OpenCode Go 83 79 480.4만
-
-claude-opus-4-6-thinking Google Antigravity 61 61 322.1만
-
-kimi-k3-1m Cursor 48 34 215.6만
-
-deepseek-v4-pro Alibaba Token Plan (Intl) 33 33 196.3만
-
-anthropic/claude-fable-5 Kimi 9 8 191.4만
-
-cursor/grok-4.5 Kimi 24 24 177만
-
-gemini-3.7-flash-high Google Antigravity 11 10 160.5만
-
-qwen3.8-max Alibaba Token Plan (Intl) 13 13 84.4만
-
-gpt-5.4-mini OpenAI (Codex login) 26 25 83.5만
-
-grok-4.5 Cursor 13 13 80.1만
-
-kimi-k3 Cursor 26 26 61.2만
-
-claude-opus-4.6 Kiro 665 662 50.6만
-
-deepseek-v4-flash DeepSeek 16 16 32.7만
-
-anthropic/claude-opus-4-6 Kimi 6 5 27.8만
-
-gemini-3.7-flash Cursor 5 5 14.8만
-
-muse-spark-1.3-contributor Muse Code 7 7 12.4만
-
-k3 Kimi 3 3 6.8만
-
-glm-5.3 Cursor 4 4 5.6만
-
-gemini-3.5-flash Cursor 3 3 4.4만
-
-claude-sonnet-4-5 Anthropic Claude 7 7 3.4만
-
-claude-3-haiku-20240307 Anthropic Claude 49 42 1.5만
-
-unpriced-model Unpriced Provider 7 7 770
-
-no-such-model No Such Provider 7 7 770
-
-muse-spark-1.3 Muse Code 1 1 227
-
-gemini-3.6-flash Kimi 4 4 141
-
-qwen3.8-27b-nvfp4 Kimi 1 1 59
-
-gemini-3.5-flash-high Kimi 1 1 41
-
-gemini-3.7-flash-tiered Kimi 2 2 38
-
-policy/does-not-exist Kimi 1 1 38
-
-gemini-3.6-flash-tiered Kimi 1 1 19
-
-google/gemini-3.7-flash Zenmux 1 1 1
-
-unknown Unknown 119 0 0
-
-gpt-image-2 OpenAI (Codex login) 3 0 0
-
-gpt-live OpenAI (Codex login) 3 0 0
-
-gpt-6-astra OpenAI (Codex login) 2 0 0
-
-gpt-5.6-cyber OpenAI (Codex login) 2 0 0
-
-claude-opus-5 Anthropic Native 1 0 0
-
-
-gpt-daybreak-blue-latest OpenAI (Codex login) 1 0 0
-
-
-gpt-5.6-sol Kiro 1 0 0
-
-gpt-5.7-astra OpenAI (Codex login) 1 0 0
-
-gpt-6 OpenAI (Codex login) 1 0 0
-
-mewfour xAI Grok 1 0 0
-
-astra OpenAI (Codex login) 1 0 0
-
-mewfour OpenAI (Codex login) 1 0 0
-프로바이더
-프로바이더 요청 측정됨 토큰 비율
-Anthropic Claude 94669 94429 346.5억
-
-OpenAI (Codex login) 84124 82219 125.4억
-
-xAI Grok 16473 16362 18.9억
-
-Kimi 4634 4562 8.4억
-
-Google Antigravity 4450 4409 6.3억
-
-OpenCode Free 1946 1865 4.4억
-
-OpenRouter 2126 2102 3.5억
-
-Alibaba Token Plan (Intl) 383 382 8869만
-
-Kiro 22317 22106 4151.6만
-
-Cursor 403 376 2518.8만
-
-Lidge 168 102 562.5만
-
-OpenCode Go 83 79 480.4만
-
-DeepSeek 16 16 32.7만
-
-Muse Code 8 8 12.4만
-
-Unpriced Provider 7 7 770
-
-No Such Provider 7 7 770
-
-Zenmux 1 1 1
-
-Unknown 119 0 0
-
-Anthropic Native 1 0 0
-커버리지 상세
-측정됨
-229025
-제공자 보고
-206539
-추정
-22486
-미보고
-2903
-미지원
-0
-
-측정됨 항목은 제공자 보고와 추정 토큰 수치를 함께 포함합니다. 미보고/미지원 요청은 추적만 하고 0으로 환산하지 않습니다.
diff --git a/devlog/_plan/260904_provider_quota_refresh/000_plan.md b/devlog/_plan/260904_provider_quota_refresh/000_plan.md
index e37cdca4c2..9a378ce965 100644
--- a/devlog/_plan/260904_provider_quota_refresh/000_plan.md
+++ b/devlog/_plan/260904_provider_quota_refresh/000_plan.md
@@ -1,7 +1,6 @@
# Provider quota refresh affordance + Meta usage visibility
-Unit opened 2026-09-04. Two defects reported against the live Providers dashboard
-on `http://localhost:10100/#providers`:
+Unit opened 2026-09-04. Two defects reported against the live Providers dashboard:
1. Only the Codex account pool has a "Refresh quotas" button. Every other provider
— anthropic, xai, cursor, google-antigravity, meta-muse — offers the operator no
@@ -9,7 +8,7 @@ on `http://localhost:10100/#providers`:
2. Meta Muse shows no quota on the provider Usage tab even though the proxy has an
observation for it.
-## Evidence gathered at P (live proxy, port 10100, v2.42.0, pid 73184)
+## Evidence gathered at P (live proxy, v2.42.0)
`GET /api/provider-quotas` returns six reports, and `meta-muse` is one of them:
@@ -77,6 +76,7 @@ config save, provider add/remove. There is no operator-initiated path. The
`bun x tsc --noEmit`, `bun run lint:gui` only.
- Push with `--no-verify`; branch `codex/260904-provider-quota-refresh`; target `dev`.
- A GUI-mentioning PR requires a screenshot in the description (`enforce-target`).
-- The live proxy on port 10100 is the user's working service. Read it, restart it
- only when a rebuild must be picked up, never repoint or reconfigure it.
+- Verification must use an isolated scratch instance. Do not restart, repoint or
+ reconfigure the user's working proxy. The completed isolation record supersedes
+ the original working-service restart plan.
- `refresh=1` must never cause a passive provider to spend an inference turn.
diff --git a/devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md b/devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md
index a8c4168b63..29fdc19756 100644
--- a/devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md
+++ b/devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md
@@ -8,32 +8,34 @@ phase is the evidence phase.
1. `bun run build:gui` — the service serves `gui/dist`, so an unbuilt change is
invisible no matter how green the tests are.
-2. `ocx service restart` — picks up the server-side `observed` flag. Confirm a new
- pid and fresh uptime on `/healthz`, and that the port is still 10100. The service
- is the user's own; restart it, never repoint or reconfigure it.
-3. `curl /api/provider-quotas` with the admin token — the meta-muse row must now
+2. Load the rebuilt code in the isolated scratch instance and confirm its identity
+ and fresh uptime on `/healthz`. The completed isolation record supersedes the
+ original `ocx service restart` plan; do not restart, repoint or reconfigure the
+ user's working proxy.
+3. Query the scratch instance's `/api/provider-quotas` with its admin token — the meta-muse row must now
carry `"observed": true`. This is the wire-level proof, checked before the UI so a
blank screen can be attributed correctly.
-## Browser verification (`aside-jun`, CLI repl on the signed-in profile)
+## Browser verification (aside CLI repl on the signed-in profile)
The dashboard is loopback and needs no login, so `aside repl` is the right surface:
one invocation is one session, it throws on a bad path instead of skipping, and the
screenshots land as real files. A whole inspect-act-verify flow must fit in a single
invocation because bindings do not persist between calls.
-Shots to capture into `devlog/_plan/260904_provider_quota_refresh/assets/`:
+The planned capture set covered the Usage quota display, the Usage and Accounts
+refresh controls, and the post-click success state. The completed record in
+`031_live_verification_record.md` preserves the observed outcomes.
-| File | Content |
-|------|---------|
-| `010_meta_usage_quota.png` | meta-muse → Usage tab with both windows and the observation age |
-| `020_usage_refresh_button.png` | the Usage rate-limits header with its refresh control |
-| `030_accounts_refresh_button.png` | the Accounts tab refresh control for an OAuth provider |
-| `040_refresh_result.png` | the post-click success status |
+Those live captures were subsequently removed from the current tree under one
+retention rule for both surfaces: account and usage screenshots from a real
+operator profile are unnecessary once the behavioral evidence is recorded in
+text. The planned filename list is also retired; it differed from the delivered
+filenames and must not be treated as an asset inventory.
-Aside writes under `~/.aside/u/0/`; Codex copies the files into the repository. Every
-`aside` invocation runs under `perl -e 'alarm shift; exec @ARGV' 300` because macOS
-has no `timeout` and the bare spelling exits 127 without ever starting the run.
+The plan required each `aside` invocation to run under
+`perl -e 'alarm shift; exec @ARGV' 300` because macOS has no `timeout` and the bare
+spelling exits 127 without starting the run.
## Push and PR
diff --git a/devlog/_plan/260904_provider_quota_refresh/031_live_verification_record.md b/devlog/_plan/260904_provider_quota_refresh/031_live_verification_record.md
index cda6fdbe9e..3dfbafb318 100644
--- a/devlog/_plan/260904_provider_quota_refresh/031_live_verification_record.md
+++ b/devlog/_plan/260904_provider_quota_refresh/031_live_verification_record.md
@@ -1,20 +1,14 @@
# Live verification record — 2026-09-04
Both defects were reproduced and then confirmed fixed against a running proxy serving the
-built GUI. Screenshots in `assets/`.
+built GUI. The observations below preserve that historical verification.
## Isolation
-The user's own proxy runs on port 10100 from
-`/Users/jun/Developer/new/700_projects/opencodex` under launchd — a different checkout
-from this worktree, so restarting it would NOT have loaded this change, and repointing it
-is out of bounds. Verification therefore ran on a scratch instance:
-
-- `OPENCODEX_HOME` = a `mktemp -d` directory holding only `config.json` (three providers),
- `auth.json`, and `provider-account-quota-cache.json` copied from the real home.
-- port 10399, started with `bun run src/cli/index.ts start --port 10399` from this worktree.
-- Port 10100 was confirmed untouched afterwards: same pid 73184, uptime still climbing.
-- The scratch home was moved to Trash when finished.
+Verification ran against an isolated scratch instance. The existing proxy used a
+separate checkout and was left untouched; its process identity and increasing
+uptime were confirmed afterward. The scratch home was moved to Trash when
+verification finished.
## Wire evidence
@@ -46,17 +40,16 @@ The refresh control was exercised, not merely rendered:
- Usage tab: clicking `Refresh quotas` produced `status: "Quotas refreshed"` and the age
line re-derived from `5h ago` to `6h ago` — the read really happened.
-- Accounts tab (anthropic, three pooled accounts): the control appears beside
+- Accounts tab (pooled OAuth provider): the control appears beside
`Add account` and reported `Quotas refreshed` after a real forced read.
-## Assets
+## Capture retention
-| File | Content |
-|---|---|
-| `010_meta_usage_quota.png` | Muse Code → Usage with both windows and the refresh control |
-| `020_usage_refresh_result.png` | the same tab after a click, showing the success status |
-| `030_accounts_refresh_button.png` | Accounts tab control for a pooled OAuth provider |
-| `040_accounts_refresh_result.png` | Accounts tab after a click |
+The Accounts and Usage captures were subsequently removed from the current tree.
+Both came from a real operator profile; retaining either surface is unnecessary
+for the behavioral evidence above. This applies the same retention rule to both
+surfaces without claiming that the Usage captures were independently cleared of
+personal information. Git history is unchanged.
## CI (PR #3448, head 232afdd97)
diff --git a/devlog/_plan/260904_provider_quota_refresh/assets/010_meta_usage_quota.png b/devlog/_plan/260904_provider_quota_refresh/assets/010_meta_usage_quota.png
deleted file mode 100644
index f36ca63dd7..0000000000
Binary files a/devlog/_plan/260904_provider_quota_refresh/assets/010_meta_usage_quota.png and /dev/null differ
diff --git a/devlog/_plan/260904_provider_quota_refresh/assets/020_usage_refresh_result.png b/devlog/_plan/260904_provider_quota_refresh/assets/020_usage_refresh_result.png
deleted file mode 100644
index 944b12533e..0000000000
Binary files a/devlog/_plan/260904_provider_quota_refresh/assets/020_usage_refresh_result.png and /dev/null differ
diff --git a/devlog/_plan/260904_provider_quota_refresh/assets/030_accounts_refresh_button.png b/devlog/_plan/260904_provider_quota_refresh/assets/030_accounts_refresh_button.png
deleted file mode 100644
index 986fa60ad6..0000000000
Binary files a/devlog/_plan/260904_provider_quota_refresh/assets/030_accounts_refresh_button.png and /dev/null differ
diff --git a/devlog/_plan/260904_provider_quota_refresh/assets/040_accounts_refresh_result.png b/devlog/_plan/260904_provider_quota_refresh/assets/040_accounts_refresh_result.png
deleted file mode 100644
index ef6c83693f..0000000000
Binary files a/devlog/_plan/260904_provider_quota_refresh/assets/040_accounts_refresh_result.png and /dev/null differ
diff --git a/devlog/_plan/260904_raycast_integration/000_plan.md b/devlog/_plan/260904_raycast_integration/000_plan.md
new file mode 100644
index 0000000000..c98701a2cd
--- /dev/null
+++ b/devlog/_plan/260904_raycast_integration/000_plan.md
@@ -0,0 +1,121 @@
+# Raycast Custom Providers integration — plan
+
+Raycast (Pro-only) reads `~/.config/raycast/ai/providers.yaml` and watches it, so a
+file-toggle client is the right shape. Spec: https://manual.raycast.com/ai/custom-providers.
+
+Decisions taken with the maintainer:
+
+1. Install signal is `~/.config/raycast/ai` (the directory Raycast creates on
+ "Reveal Providers Config"), not `Raycast.app`.
+2. A non-Pro plan is a warning in status/GUI, never a refusal.
+3. Every exported model declares `tools: supported: true` (same stance as Hermes:
+ every routed model is tool-capable).
+4. Array ownership goes into the shared merge/classifier layer as a path-segment
+ selector rather than a Raycast-only patcher. `structure/09_client-integrations.md`
+ forbids a special case that lives only in the writer or only in status; a
+ selector segment that `readPath`/`setPath`/`deletePath` all understand is the
+ one way both keep agreeing.
+
+## Raycast file shape
+
+```yaml
+providers:
+ - id: opencodex # <- our one owned sequence item
+ name: OpenCodex
+ base_url: http://127.0.0.1:10100/v1
+ models:
+ - id: anthropic/claude-opus-5
+ name: Claude Opus 5
+ context: 200000
+ abilities:
+ temperature: { supported: true }
+ vision: { supported: true }
+ system_message: { supported: true }
+ tools: { supported: true }
+ reasoning_effort: { supported: false }
+```
+
+No `api_keys`: loopback is unauthenticated and the file has no env interpolation,
+so the client is `loopbackOnly: true`.
+
+## Pro signal (macOS)
+
+`defaults read com.raycast.macos.v1 subscriptions_active` → `1` / `0`. Read via
+`Bun.spawnSync`, not by parsing the binary plist (cfprefsd caches). Windows: `unknown`.
+
+## Work packages (disjoint files, run in parallel)
+
+| WP | Files |
+|---|---|
+| 1 merge selector | `src/integrations/merge.ts`, `src/integrations/state.ts`, `tests/integrations-merge.test.ts` |
+| 2 client | `src/clients/config-export.ts`, `src/integrations/registry.ts`, `src/cli/registry.ts`, `src/cli/help.ts`, `tests/raycast-client.test.ts`, list-assertion tests |
+| 3 sync fan-out | `src/integrations/owned-refresh.ts`, `src/cli/dispatch.ts`, `src/server/management/config-routes.ts`, `src/cli/index.ts`, `tests/sync-client-integrations.test.ts` |
+| 4 detect + API + GUI | `src/integrations/raycast-detect.ts`, `src/server/management/integration-routes.ts`, `src/cli/integrations.ts`, `gui/**`, i18n |
+| 5 docs | `docs-site/**` |
+
+### WP1 — `[field=value]` path segment
+
+```ts
+// merge.ts
+const ARRAY_SELECTOR = /^\[([A-Za-z_][A-Za-z0-9_]*)=([^\]]+)\]$/u;
+export type PathSegment = { kind: "key"; key: string } | { kind: "select"; field: string; value: string };
+export function parseSegment(raw: string): PathSegment;
+export class AmbiguousSelectorError extends Error {}
+```
+
+- `setPath`: a `select` segment addresses the element of an array whose
+ `item[field] === value`. Missing parent → `[]` is created (recorded by
+ `createdContainerPaths`). Match found → replace in place; none → push; ≥2 →
+ throw `AmbiguousSelectorError` (writer maps it to `unsafe` alongside
+ `UnserializableValueError`).
+- `deletePath`: splice the match; an emptied array we created is pruned by the
+ existing `createdContainers` walk.
+- `state.ts readPath`: `select` → `Array.prototype.find`. Because the classifier
+ and the writer share this one function, status and mutation cannot disagree.
+- `blockedContainerPath`: a non-array, non-undefined value where a `select`
+ segment expects an array is blocked (`providers: {}` written by the user).
+- `createdContainerPaths`: unchanged join rule; a `select` segment is never a
+ container prefix on its own.
+- A key-only path is byte-for-byte the old behaviour; the twelve existing clients
+ do not change.
+
+### WP2 — client registration
+
+`config-export.ts`: `"raycast"` in `ExportClientId`; `raycastAiDir(env, home)` =
+`join(home, ".config", "raycast", "ai")` (Raycast ignores XDG; same path on Windows);
+`raycastConfigPath` = `…/providers.yaml`; types `RaycastAbility`,
+`RaycastModelEntry`, `RaycastProviderEntry`, `RaycastGeneratedConfig`;
+`buildRaycastClientConfig(ctx)` over `normalizeExportModels(ctx.models)` with
+`exportModelLabel(model)` as `name`, `contextWindow` → `context`, abilities:
+`temperature: !(reasoningEfforts?.length)`, `vision: inputModalities?.includes("image") ?? false`,
+`system_message: true`, `tools: true`, `reasoning_effort: (reasoningEfforts?.length ?? 0) > 0`.
+`buildRaycastContribution` = `singleFragment("raycast", ["providers", "[id=opencodex]"], providers[0])`.
+`summarizeRaycast` finds the `opencodex` item. `EXPORT_CLIENTS.raycast`:
+`filename: "raycast-providers.yaml"`, `format: "yaml"`, `apiKeyEnv: ""`, `loopbackOnly: true`.
+
+`registry.ts`: `configPath: raycastConfigPath`, `detectDir: raycastAiDir`, no
+`sourcePreservingYaml` (that patcher handles block-map leaves only), no `writerLock`.
+
+### WP3 — sync fan-out
+
+Raycast joins the shared `refreshOwnedCatalogIntegrations` coordinator. Model
+selection changes use its default `["pi", "aside", "raycast"]` set;
+`POST /api/sync` uses `["mcode", "pi", "aside", "raycast"]`; direct CLI sync
+updates `["mcode", "pi", "raycast"]` locally and keeps Aside behind its
+server-owned multi-profile route. Startup and ensure refresh the owned Raycast
+catalog after the Codex catalog publishes, using the live port.
+
+### WP4 — detection, API, GUI
+
+`raycast-detect.ts` mirrors `cursor-detect.ts` (injectable deps, read-only):
+`RaycastPlan = "pro" | "free" | "unknown"`, `detectRaycast(deps)` →
+`{ appPath, aiDirPresent, plan }`. `GET /api/client-integrations/raycast`
+adds `raycast: { plan, appPath, aiDirPresent }` to the envelope (only for this
+client). `ocx integration client status --client raycast` prints `plan`. GUI:
+every surface in `devlog/_fin/260831_aside_client_and_integrations_ux/002_registration_checklist.md`
+plus one `RaycastPlanNotice` shown when `plan !== "pro"` or `!aiDirPresent`.
+
+### WP5 — docs
+
+`guides/integrations.md` row + paragraph (Pro, reveal-first), `reference/cli/agents.md`,
+translated locales, `bun run build` in `docs-site`.
diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_plan/260907_code_mode_host_contract/000_plan.md
new file mode 100644
index 0000000000..0f9a8057fb
--- /dev/null
+++ b/devlog/_plan/260907_code_mode_host_contract/000_plan.md
@@ -0,0 +1,197 @@
+# 000 — Code-mode host contract for routed models: plan
+
+Revision 2 after audit round 1 (gpt-6-astra explorer, VERDICT: FAIL, 8 blockers). Synthesis and
+dispositions are in the "Audit round 1" section at the end; the body below is the amended plan.
+
+## Loop-spec
+
+- Loop archetype: satisfy-spec repair (verifier-defined). No optimization loop.
+- Trigger: xai/grok-4.6 retrospective (2026-09-07) on a routed native-Responses Codex session. The
+ model hit Codex host contracts that OpenCodex neither states before the first call nor explains
+ after the failure, then abandoned the right tools for shell heredocs and sleep loops.
+- Goal: a routed non-OpenAI model in Codex code mode learns the host's argument shape and waiting
+ protocol up front, and when it still trips, the exec result names the rule it broke.
+- Non-goals: rewriting model JavaScript; new payload repair (`apply-patch-envelope.ts`,
+ `code-mode-helper-compat.ts`, `bridge.ts`, `parser.ts` untouched); OpenAI/ChatGPT destinations
+ or compaction requests; Lab; GUI; version bumps; annotation on Anthropic/Google/OpenAI-chat/
+ command-code result paths (they have no exec-result seam today). No local test suite, typecheck,
+ build, or install in this worktree (user instruction). Merge/release out of scope.
+- Verifier: hosted `.github/workflows/ci.yml` on the exact head of each pushed work-phase (PR
+ `pull_request` trigger; test shards 1-4 + `gates` typecheck/privacy). Local: NOT RUN.
+- Stop condition: PR ready-for-review against `dev` with exact-head CI green and receipt bound.
+- Memory artifact: this unit, the bound goalplan
+ `.codexclaw/goalplans/code-mode-host-contract-for-routed-models-shared/`, and the PR body.
+- Expected terminal outcomes: DONE (PR open, CI green); NOOP ruled out below; BLOCKED if
+ GitHub/CI fails after retries; UNSAFE if a change would rewrite JavaScript or widen a fail-open
+ write; NEEDS_HUMAN for merge.
+- Escalation: main reclaims a slice after two distinct agents fail its packet; pushing a slice to
+ a worker requires a P-phase amendment. Every dispatch uses `gpt-6-astra`, reasoning `high`.
+- HOTL bounds: write scope is this worktree on `codex/code-mode-host-contract`; push of that branch
+ and PR creation are authorized by the user; no token or wall-clock budget was set.
+
+## Incident and live host evidence
+
+Host strings were read from the installed Codex 0.153.2 binaries (`strings -n 8` on `codex` and
+`codex-code-mode-host`) and then re-probed live from this session's own code-mode isolate:
+
+| Probe (`tools.apply_patch` argument) | Host result |
+|---|---|
+| `{ input: "*** Begin Patch…" }` (object) | throws `tool \`apply_patch\` expects a string input` |
+| `"*** Begin Patch ***\n…\n*** End Patch ***"` (decorated) | throws `apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'` |
+| `"\n\n*** Begin Patch\n…"` (leading newlines) | ACCEPTED, file written |
+| `" *** Begin Patch\n…"` (indented) | ACCEPTED, file written |
+| `"…*** End Patch\n\n"` (trailing newlines) | ACCEPTED |
+| `import x from "y"` in the isolate | `Unsupported import in exec: ` (host string; capital U) |
+
+So the Grok report's "blank line before the template literal" was not itself the rejection; the
+"first line" error fires for a decorated marker, a code fence, prose, or any non-marker first
+token. The pre-call sentence and recovery hints below describe exactly that and do not claim the
+host rejects surrounding whitespace.
+
+The fourth contract has no error string: a shell `for i in 1..20; sleep 1` inside one
+`exec_command` simply blocks the call, while the host's own protocol is to let the call return a
+`session_id` and poll with `tools.write_stdin({session_id, chars: ""})`.
+
+After the two apply_patch rejections the model stopped using apply_patch entirely — the pattern
+`devlog/_fin/260813_260813-nudge-apply-patch-forbid/` recorded: once the tool feels broken, routed
+models fall back to `python3`/`cat <` |
+| two `*** End Patch` lines (envelope pasted twice) | throws `The last line of the patch must be '*** End Patch'` |
+
+Conclusion carried into the wording: the host strips surrounding whitespace before checking the
+marker lines, so "no leading newline" is not a rule. The rule is that the first non-blank line is
+exactly `*** Begin Patch` and the last is exactly `*** End Patch`, undecorated.
+
+## Long-running command protocol
+
+The `exec_command` schema in this session: `yield_time_ms` "Wait before yielding output. Defaults to
+10000 ms; effective range is 250-30000 ms"; `session_id` "Session identifier to pass to write_stdin
+when the process is still running". `write_stdin`: `chars` "Defaults to empty, which polls without
+writing"; empty polls wait 5000-300000 ms. A shell `for i in 1..20; sleep 1` inside one call
+produces no error string; it simply spends the call's yield budget blocked.
+
+## Isolate globals
+
+The `exec` description in this session lists `exit`, `text`, `image`, `audio`, `generatedImage`,
+`store`/`load`, `notify`, `setTimeout`/`clearTimeout`, `ALL_TOOLS`, `yield_control`, plus `tools.*`.
+The list varies by client version, which is why the pre-call sentence names a few examples and
+defers to the description rather than enumerating.
+
diff --git a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md
new file mode 100644
index 0000000000..c6d7e6b9aa
--- /dev/null
+++ b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md
@@ -0,0 +1,186 @@
+# 010 — wp1: pre-call host contract sentence and its three injection sites
+
+Depends on 000_plan.md (rev 2). Class C2. Anchors verified against ec799db26. Ends with an
+authorized push and a draft PR so exact-head CI exists for this and later heads.
+
+## MODIFY `src/adapters/exec-tool-result-normalize.ts`
+
+Insert after the `CODE_MODE_RESULT_ECHO_SENTENCE` declaration (its closing `;` is at line 116):
+
+```ts
+
+/**
+ * Host rules a routed model most often breaks on its first code-mode edit or wait, stated BEFORE
+ * the call. Wording tracks the Codex host (0.153.2), probed live on 2026-09-07: a non-string
+ * argument to `apply_patch` throws "expects a string input"; a body whose first line is not the
+ * bare marker (decorated `*** Begin Patch ***`, a code fence, prose) throws "The first line of the
+ * patch must be '*** Begin Patch'" — surrounding newlines are tolerated; ES imports throw
+ * "Unsupported import in exec"; a command that outlives `yield_time_ms` returns `session_id` for
+ * `write_stdin` polling. xai/grok-4.6 hit the first two, abandoned apply_patch for heredoc writes,
+ * blocked a turn in a shell sleep loop, and died once on an import. None of that is repairable in
+ * the proxy (devlog/_plan/260905_apply_patch_envelope_gap/010 MODE B); it is a contract the proxy
+ * had not stated.
+ */
+export const CODE_MODE_HOST_CONTRACT_SENTENCE =
+ "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the patch text opens with the bare marker line `*** Begin Patch` and closes with the bare marker line `*** End Patch`, written without a code fence, prose, or extra asterisks on those lines (blank lines or indentation around the markers are tolerated; a decorated or missing marker is rejected). The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop.";
+```
+
+## MODIFY `src/adapters/tool-catalog-nudge.ts`
+
+Line 8 BEFORE:
+```ts
+import { CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize";
+```
+AFTER:
+```ts
+import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize";
+```
+
+Line 124 is one 1035-byte string ending in `rejected by Codex before the file is touched."`.
+BEFORE (tail):
+```ts
+OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched."
+```
+AFTER (tail):
+```ts
+OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched. " + CODE_MODE_HOST_CONTRACT_SENTENCE
+```
+The flat-catalog branch (`"If a listed tool exposes nested helpers such as a tools.* API…"`) is unchanged.
+
+## MODIFY `src/adapters/cursor/tool-guidance.ts`
+
+Line 2 BEFORE:
+```ts
+import { CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize";
+```
+AFTER:
+```ts
+import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize";
+```
+
+Lines 189-191 BEFORE (4-space indent as in source):
+```ts
+ codeMode
+ ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers."
+ : undefined,
+```
+AFTER:
+```ts
+ codeMode
+ ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers. " + CODE_MODE_HOST_CONTRACT_SENTENCE
+ : undefined,
+```
+
+## MODIFY `src/adapters/responses-code-mode.ts`
+
+Line 3 BEFORE:
+```ts
+import { CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize";
+```
+AFTER:
+```ts
+import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize";
+```
+
+Insert before `/** Native routed Responses needs the same first-call/output contract… */` (line 32):
+```ts
+/** Append each sentence a replayed instructions string does not already carry, in order. */
+function appendMissing(instructions: string, sentences: readonly string[]): string {
+ return sentences.reduce(
+ (acc, sentence) => acc.includes(sentence) ? acc : [acc, sentence].filter(Boolean).join("\n\n"),
+ instructions,
+ );
+}
+```
+
+Lines 45-46 BEFORE (4-space indent):
+```ts
+ instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE)
+ ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"),
+```
+AFTER:
+```ts
+ instructions: appendMissing(instructions, [CODE_MODE_RESULT_ECHO_SENTENCE, CODE_MODE_HOST_CONTRACT_SENTENCE]),
+```
+
+The exec `input` parameter description (line 27) keeps only the echo sentence; the contract belongs in
+`instructions`, which the existing test asserts byte-exactly.
+
+Activation: routed native Responses request whose visible catalog has a bare freeform `exec` and no
+bare shell bridge, non-OpenAI destination, not a compaction request (gate at lines 35-37).
+Observable: `wire.instructions` ends with the contract sentence.
+
+## TESTS (in place; no new file in wp1)
+
+`tests/adapters/tool-catalog-nudge.test.ts`
+- Line 7 import becomes `import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize";`
+- In `"defines nested helper names as non-callable unless separately listed"` append:
+```ts
+ // The host contract rides the same code-mode branch as the echo rule (Grok 2026-09-07).
+ expect(note).toContain(CODE_MODE_HOST_CONTRACT_SENTENCE);
+ expect(note).toContain("takes exactly one string");
+ expect(note).toContain("write_stdin({session_id, chars: \"\"})");
+```
+- In `"keeps the generic nested-helper parent-tool rule when exec is not listed"` append:
+```ts
+ expect(note).not.toContain("Host contract for the nested helpers");
+```
+
+`tests/providers/cursor/cursor-tool-definitions.test.ts`
+- In `"teaches the nested-helper contract instead of a top-level shell bridge"` (starts line 754) append
+ after the `"OpenCodex does not rewrite JavaScript inside exec"` assertion:
+```ts
+ expect(note).toContain("Host contract for the nested helpers");
+ expect(note).toContain("takes exactly one string");
+ expect(note).toContain("write_stdin");
+```
+- In `"keeps flat-catalog shell-bridge guidance when a bare bridge is advertised"` append:
+```ts
+ expect(note).not.toContain("Host contract for the nested helpers");
+```
+
+`tests/responses/openai-responses-passthrough.test.ts`
+- Line 6 import adds `CODE_MODE_HOST_CONTRACT_SENTENCE`.
+- Line 54 BEFORE:
+```ts
+ expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}`);
+```
+ AFTER:
+```ts
+ expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`);
+```
+- New test after `"does not duplicate instructions or explain an unpaired or unrelated result"`:
+```ts
+ test("a replayed body that already carries the echo rule gains only the missing contract sentence", () => {
+ const body = { ...raw(), instructions: `Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}` };
+ const parsed = parseRequest(body);
+ const first = normalizeResponsesCodeMode(body, parsed, routed) as typeof body;
+ expect(first.instructions).toBe(`${body.instructions}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`);
+ expect(first.instructions.split(CODE_MODE_RESULT_ECHO_SENTENCE).length).toBe(2);
+ const second = normalizeResponsesCodeMode(first, parsed, routed) as typeof body;
+ expect(second.instructions).toBe(first.instructions);
+ });
+```
+- In `"official OpenAI and non-code-mode catalogs remain untouched"`, inside the `for (const native…)` loop
+ append `expect(JSON.stringify(wire)).not.toContain("Host contract for the nested helpers");`.
+
+`tests/providers/kiro/kiro-adapter.test.ts`
+- In `"names ALL_TOOLS when a freeform exec is advertised without a bare shell bridge"` (line 1817) append:
+```ts
+ // Survives Kiro's 16 384-char injected-instruction bound on the real wire prompt.
+ expect(content).toContain("Host contract for the nested helpers");
+```
+
+## Delivery for this phase
+
+`git add` only the files above; `git diff --cached --stat` first; commit `--no-verify`; then
+`git push --no-verify -u origin codex/code-mode-host-contract` and
+`gh pr create --draft --base dev --title "fix(code-mode): state the host contract for nested helpers and annotate host failures" --body-file .tmp/pr-body.md`
+(body per template; Verification section says local checks NOT RUN, hosted CI is the verifier;
+wp2/wp3 will extend it).
+
+## Verification (C, hosted only)
+
+NOT RUN locally by instruction. Poll `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion,name`
+in short `exec_command` calls; when the Cross-platform CI run for `git rev-parse HEAD` completes,
+`cxc receipt test --session --cwd -- gh run view --exit-status`.
diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md
new file mode 100644
index 0000000000..86430340c0
--- /dev/null
+++ b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md
@@ -0,0 +1,388 @@
+# 020 — wp2: post-hoc annotation of host failures on exec results
+
+Depends on 010 (same module, same wording). Class C2. Anchors verified against ec799db26 plus
+the wp1 delta. Ends with an authorized push; the draft PR from wp1 picks up the new head.
+
+## MODIFY `src/adapters/exec-tool-result-normalize.ts`
+
+Insert after `CODE_MODE_HOST_CONTRACT_SENTENCE` (added in wp1):
+
+```ts
+
+/**
+ * Post-hoc half of the host contract: the four host strings a routed model reads inside a
+ * non-error exec result, each paired with the rule it broke. Matched case-insensitively because
+ * the host writes "Unsupported import in exec: " while Cursor's earlier marker was
+ * lowercase; one table, one owner, so this text and the pre-call sentence cannot drift.
+ */
+export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [
+ {
+ marker: "expects a string input",
+ guidance: "tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.",
+ },
+ {
+ marker: "the first line of the patch must be",
+ guidance: "The patch text must open with the bare marker line `*** Begin Patch`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).",
+ },
+ {
+ marker: "the last line of the patch must be",
+ guidance: "The patch text must close with the bare marker line `*** End Patch`: no trailing text or extra asterisks on that line (blank lines after it are tolerated).",
+ },
+ {
+ marker: "unsupported import in exec",
+ guidance: "Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.",
+ },
+];
+
+/** Prefix of every recovery line this module appends; callers use it to recognise replayed annotations. */
+export const CODE_MODE_HOST_RECOVERY_PREFIX = "[recovery: ";
+
+/** Namespaces under which Cursor displays Codex's own Responses tools (see cursor/tool-naming.ts). */
+const CODEX_RESPONSES_DISPLAY_NAMESPACES: ReadonlySet = new Set(["opencodex-responses", "mcp__opencodex-responses"]);
+/** Flattened spellings of the same code-mode exec when a client folds the namespace into the name. */
+const CODEX_CODE_MODE_EXEC_ALIASES: ReadonlySet = new Set(["exec", "mcp__opencodex-responses__exec", "mcp_opencodex-responses_exec"]);
+
+/**
+ * The code-mode `exec` tool by NAME — bare, or under Codex's own `opencodex-responses` display
+ * namespace, matched exactly. The four host strings above originate only in that isolate, so flat
+ * shell bridges (`exec_command`, `shell`, …) and every other namespace (`mcp__docker`,
+ * `mcp__foreign-opencodex-responses`) are excluded: an unrelated server's output that quotes the
+ * phrase must not receive Codex guidance. Narrower than `isCodexExecBridgeTool` on purpose; the
+ * empty-output repair keeps the wider gate. Callers that KNOW the catalog shape (Kiro's
+ * `codeModeExecName`, the Responses body gate) add that check on top; this predicate alone cannot
+ * tell a structured tool named `exec` from the freeform one.
+ */
+export function isCodexCodeModeExecResult(toolName?: string, toolNamespace?: string): boolean {
+ if (!toolName) return false;
+ const lower = toolName.toLowerCase();
+ if (toolNamespace !== undefined) return CODEX_RESPONSES_DISPLAY_NAMESPACES.has(toolNamespace) && lower === "exec";
+ return CODEX_CODE_MODE_EXEC_ALIASES.has(lower);
+}
+
+/**
+ * Append a one-line recovery hint when a code-mode exec result carries a known host failure string.
+ * Returns undefined when the tool is not the code-mode exec, no marker matches, or a recovery line is
+ * already present (a replayed annotated result must not grow a second one). Never touches error
+ * status: the host already decided whether the call failed.
+ */
+export function annotateCodeModeHostFailure(
+ text: string,
+ options: { toolName?: string; toolNamespace?: string } = {},
+): string | undefined {
+ if (!isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) return undefined;
+ if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return undefined;
+ const lower = text.toLowerCase();
+ const hit = CODE_MODE_HOST_FAILURE_GUIDANCE.find(({ marker }) => lower.includes(marker));
+ return hit ? `${text}\n${CODE_MODE_HOST_RECOVERY_PREFIX}${hit.guidance}]` : undefined;
+}
+```
+
+Flat shell tools are deliberately not annotated: the strings come from the code-mode host, and the
+"flat catalogs untouched" statement in the docs is therefore literally true.
+
+## MODIFY `src/adapters/responses-code-mode.ts`
+
+Line 3 import gains `annotateCodeModeHostFailure`.
+
+Line 55 BEFORE (6-space indent):
+```ts
+ const normalized = text === undefined ? undefined : normalizeEmptyExecToolResultText(text, { toolName: "exec" });
+```
+AFTER:
+```ts
+ const normalized = text === undefined
+ ? undefined
+ : normalizeEmptyExecToolResultText(text, { toolName: "exec" })
+ ?? annotateCodeModeHostFailure(text, { toolName: "exec" });
+```
+Activation: paired `custom_tool_call_output` whose text contains `\`apply_patch\` expects a string input`;
+observable: output ends with the recovery line, `input[0]` is the same object reference.
+
+## MODIFY `src/adapters/kiro.ts`
+
+Line 47 BEFORE:
+```ts
+import { EMPTY_EXEC_OUTPUT_MESSAGE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize";
+```
+AFTER:
+```ts
+import { EMPTY_EXEC_OUTPUT_MESSAGE, annotateCodeModeHostFailure, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize";
+```
+
+Lines 758-771 BEFORE (6-space indent):
+```ts
+ const normalizedExecText = normalizeEmptyExecToolResultText(text, {
+ toolName: tr.toolName,
+ toolNamespace: tr.toolNamespace,
+ });
+ const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE);
+ const images = extractKiroImages(tr.content);
+ const toolUseId = normalizeToolId(tr.toolCallId);
+ const call = priorCalls.get(toolUseId);
+ if (!call || call.rawId !== tr.toolCallId) {
+ throw new Error(`Kiro history contains an orphaned tool result for call ${JSON.stringify(tr.toolCallId)}`);
+ }
+ // Keep real whitespace and failed wrappers, but no empty-success wrapper boilerplate.
+ const rawGroupText = text.length > 0 && (!text.trim() || normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE)
+ ? text : undefined;
+```
+AFTER:
+```ts
+ const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace };
+ const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions);
+ // A host failure string inside a non-empty exec result gets the rule it broke appended, but
+ // only when this request's emitted catalog is genuinely code mode (`codeModeExecName` above):
+ // a structured tool named exec, or exec beside a shell bridge, never ran the isolate. This is
+ // the only substitution the grouping path below also carries: whitespace and empty/failed
+ // wrappers keep their existing raw policy.
+ const annotatedExecText = normalizedExecText === undefined && codeModeExecName !== undefined
+ ? annotateCodeModeHostFailure(text, execOptions)
+ : undefined;
+ const resultText = normalizedExecText ?? annotatedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE);
+ const images = extractKiroImages(tr.content);
+ const toolUseId = normalizeToolId(tr.toolCallId);
+ const call = priorCalls.get(toolUseId);
+ if (!call || call.rawId !== tr.toolCallId) {
+ throw new Error(`Kiro history contains an orphaned tool result for call ${JSON.stringify(tr.toolCallId)}`);
+ }
+ // Keep real whitespace and failed wrappers, but no empty-success wrapper boilerplate.
+ const rawGroupText = text.length > 0 && (!text.trim() || normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE)
+ ? (annotatedExecText ?? text) : undefined;
+```
+`annotatedExecText` is defined only when `normalizedExecText` is undefined, i.e. the text is neither an
+empty-success nor a failed-empty wrapper, so every existing grouping expectation
+(`kiro-adapter.test.ts:1209` whitespace, `1252` raw failed wrapper) is unchanged by construction.
+
+## MODIFY `src/adapters/cursor/tool-result-normalize.ts`
+
+Imports (lines 12-18) gain `CODE_MODE_HOST_RECOVERY_PREFIX`, `annotateCodeModeHostFailure` and
+`isCodexCodeModeExecResult`. `RUNTIME_FAILURE_GUIDANCE` (lines 50-67) and its
+loop (lines 107-113) stay byte-identical: Cursor's marker semantics, case sensitivity and
+`isError:true` policy are its own.
+
+Lines 97-106 BEFORE (2-space indent):
+```ts
+ if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) {
+ return {
+ // A `Script failed` wrapper is empty but NOT a success: reporting it as an empty success
+ // would erase the only failure signal. Text classification stays separate from Cursor's
+ // isError policy, which the Computer Use branch above owns.
+ text: isFailedEmptyExecWrapper(text.trim()) ? FAILED_EXEC_OUTPUT_MESSAGE : EMPTY_EXEC_OUTPUT_MESSAGE,
+ isError: false,
+ changed: true,
+ };
+ }
+```
+AFTER (append one branch directly after that block):
+```ts
+ if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) {
+ return {
+ // A `Script failed` wrapper is empty but NOT a success: reporting it as an empty success
+ // would erase the only failure signal. Text classification stays separate from Cursor's
+ // isError policy, which the Computer Use branch above owns.
+ text: isFailedEmptyExecWrapper(text.trim()) ? FAILED_EXEC_OUTPUT_MESSAGE : EMPTY_EXEC_OUTPUT_MESSAGE,
+ isError: false,
+ changed: true,
+ };
+ }
+ // A host failure string inside a code-mode exec result gets the rule it broke appended, with
+ // Cursor's isError decision left exactly as the caller passed it. A replayed result that already
+ // carries a recovery line returns here unchanged: falling through would let the legacy loop
+ // below match the lowercase import marker a second time and flip isError.
+ if (isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) {
+ if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return { text, isError, changed: false };
+ const hostFailure = annotateCodeModeHostFailure(text, options);
+ if (hostFailure !== undefined) return { text: hostFailure, isError, changed: true };
+ }
+```
+The existing `unsupported import in exec` row in `RUNTIME_FAILURE_GUIDANCE` still serves node_repl /
+Computer Use tools; for the code-mode exec the new branch runs first, carries the shared hint, and
+terminates replay before the legacy loop can see it.
+
+## NEW `tests/adapters/exec-tool-result-normalize.test.ts`
+
+```ts
+import { describe, expect, test } from "bun:test";
+import {
+ CODE_MODE_HOST_CONTRACT_SENTENCE,
+ CODE_MODE_HOST_FAILURE_GUIDANCE,
+ annotateCodeModeHostFailure,
+} from "../../src/adapters/exec-tool-result-normalize";
+
+// Live host strings (Codex 0.153.2, probed 2026-09-07) and the rule each one names. The pre-call
+// sentence and these rows are one contract in one module; a model must never be told one thing
+// before the call and another after.
+describe("code-mode host failure annotation", () => {
+ test.each(CODE_MODE_HOST_FAILURE_GUIDANCE.map(row => [row.marker, row.guidance] as const))(
+ "annotates an exec result carrying %p regardless of case",
+ (marker, guidance) => {
+ const text = `Script failed\nWall time 0.1 seconds\nOutput:\nError: ${marker.toUpperCase()}`;
+ expect(annotateCodeModeHostFailure(text, { toolName: "exec" })).toBe(`${text}\n[recovery: ${guidance}]`);
+ },
+ );
+
+ test("matches the host's real capitalisation and argument text", () => {
+ expect(annotateCodeModeHostFailure("Unsupported import in exec: node:fs", { toolName: "exec" })).toContain("injected globals");
+ expect(annotateCodeModeHostFailure("Script error:\ntool `apply_patch` expects a string input", { toolName: "exec" })).toContain("exactly one string");
+ expect(annotateCodeModeHostFailure(
+ "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'",
+ { toolName: "exec" },
+ )).toContain("bare marker line `*** Begin Patch`");
+ });
+
+ test("leaves non-exec tools, shell bridges, foreign namespaces, non-matching text and already-annotated text alone", () => {
+ expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined();
+ // Flat shell bridges never run the isolate, so the four strings cannot be theirs.
+ expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command" })).toBeUndefined();
+ // A foreign MCP server's own exec is not Codex's, even when its output quotes the phrase, and a
+ // namespace that merely CONTAINS the provider name is still foreign.
+ expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__docker" })).toBeUndefined();
+ expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__foreign-opencodex-responses" })).toBeUndefined();
+ // Codex's own display namespaces and flattened aliases for the same code-mode tool still count.
+ for (const options of [
+ { toolName: "exec", toolNamespace: "opencodex-responses" },
+ { toolName: "exec", toolNamespace: "mcp__opencodex-responses" },
+ { toolName: "mcp__opencodex-responses__exec" },
+ { toolName: "mcp_opencodex-responses_exec" },
+ ]) {
+ expect(annotateCodeModeHostFailure("expects a string input", options)).toContain("[recovery:");
+ }
+ expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined();
+ const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" });
+ if (!once) throw new Error("expected one annotation");
+ expect(annotateCodeModeHostFailure(once, { toolName: "exec" })).toBeUndefined();
+ });
+
+ test("every failure row is a rule the pre-call sentence already states", () => {
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("takes exactly one string");
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** Begin Patch`");
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** End Patch`");
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("no `import`");
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("write_stdin");
+ // Never shows the decorated marker as a copyable literal (same rule as the nudge tests).
+ expect(CODE_MODE_HOST_CONTRACT_SENTENCE).not.toContain("*** Begin Patch ***");
+ });
+});
+```
+
+Register in `scripts/test-layout/layout.json` `explicit` between
+`"empty-tool-output-annotation.test.ts": "adapters",` (line 620) and its successor:
+`"exec-tool-result-normalize.test.ts": "adapters",`; same key/value in
+`tests/fixtures/test-layout-expected.json` in alphabetical position. The name matches no regex seed
+(`"adapters"` seed is `^(?:bridge\.test\.ts|buffered|identity|run|tool|translator)-`), so the explicit
+entry is required and `tests/test-layout-tooling.test.ts` names it if missing.
+
+## Updated tests
+
+`tests/responses/openai-responses-passthrough.test.ts` — add inside the code-mode describe:
+```ts
+ test("annotates a paired exec result that carries a host failure string without touching the program", () => {
+ const failure = "Script failed\nWall time 0.1 seconds\nOutput:\nScript error:\ntool `apply_patch` expects a string input";
+ const body = raw(failure);
+ const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body);
+ expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`);
+ expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input);
+ // Replayed history already carrying the hint is not annotated twice: the output item and the
+ // program keep their identity, and a second pass over the normalized body is a deep no-op.
+ const replayed = raw(wire.input[1].output);
+ const once = normalizeResponsesCodeMode(replayed, parseRequest(replayed), routed) as typeof replayed;
+ expect(once.input[1]).toBe(replayed.input[1]);
+ expect(once.input[0]).toBe(replayed.input[0]);
+ expect(normalizeResponsesCodeMode(once, parseRequest(once), routed)).toEqual(once);
+ });
+```
+
+`tests/providers/kiro/kiro-adapter.test.ts`
+- After `"an empty code-mode exec result carries the actionable reason…"` (line 323) add:
+```ts
+ test("a code-mode exec result carrying a host failure string names the broken rule", async () => {
+ // freeform: the Kiro seam annotates only when the emitted catalog is genuinely code mode.
+ const execTool = { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } };
+ const failure = "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'";
+ const messages = [
+ { role: "user", content: "run it" },
+ { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] },
+ { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false },
+ ];
+ const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, [execTool]));
+ const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage
+ .userInputMessageContext.toolResults[0].content[0].text;
+ expect(resultText).toBe(`${failure}\n[recovery: The patch text must open with the bare marker line \`*** Begin Patch\`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).]`);
+ });
+
+ test("a host failure string on a non-code-mode catalog stays raw", async () => {
+ const failure = "tool `apply_patch` expects a string input";
+ const messages = [
+ { role: "user", content: "run it" },
+ { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] },
+ { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false },
+ ];
+ for (const tools of [
+ // A structured tool that merely shares the name exec.
+ [{ name: "exec", description: "Run a shell string", parameters: { type: "object" } }],
+ // Freeform exec beside a bare shell bridge is the flat-catalog shape, not code mode.
+ [
+ { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } },
+ { name: "exec_command", description: "Run", parameters: { type: "object" } },
+ ],
+ ]) {
+ const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, tools));
+ const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage
+ .userInputMessageContext.toolResults[0].content[0].text;
+ expect(resultText).toBe(failure);
+ }
+ });
+```
+- In the grouped-result table (the `execResult` cases around lines 1195-1262) add one case:
+```ts
+ {
+ name: "host failure chunk in a multi group carries its recovery line beside raw siblings",
+ id: "call-host-failure-multi",
+ results: [execResult("call-host-failure-multi", " "), execResult("call-host-failure-multi", "tool `apply_patch` expects a string input"), execResult("call-host-failure-multi", failedExecWrapper)],
+ content: [{ text: " " }, { text: "tool `apply_patch` expects a string input\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]" }, { text: failedExecWrapper }],
+ status: "success",
+ forbidden: [EMPTY_EXEC_OUTPUT_MESSAGE, FAILED_EXEC_OUTPUT_MESSAGE, KIRO_EMPTY_TOOL_RESULT_MESSAGE],
+ },
+```
+ This drives the grouping path with whitespace, an annotated chunk and a raw failed wrapper in one
+ group — the exact combination blocker 1 said the single-result test could not exercise.
+
+`tests/providers/cursor/cursor-toolresult-normalize.test.ts` — add after the `test.each` runtime-failure table:
+```ts
+ test.each(["Unsupported import in exec: node:fs", "unsupported import in exec: node:fs"])(
+ "a code-mode exec result carrying %p gains the shared hint, keeps its isError, and is not re-annotated on replay",
+ (payload) => {
+ const out = normalizeCursorToolResultText(payload, { toolName: "exec" });
+ expect(out.changed).toBe(true);
+ expect(out.isError).toBe(false);
+ expect(out.text).toBe(`${payload}\n[recovery: Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.]`);
+ // Replay through Responses history arrives with isError=false; the legacy lowercase marker
+ // row must not get a second look at it.
+ const replay = normalizeCursorToolResultText(out.text, { toolName: "exec", isError: false });
+ expect(replay).toEqual({ text: out.text, isError: false, changed: false });
+ },
+ );
+
+ test("the legacy node_repl import row keeps its own isError policy", () => {
+ const out = normalizeCursorToolResultText("unsupported import in exec", { toolName: "js", toolNamespace: "mcp__node_repl" });
+ expect(out.isError).toBe(true);
+ expect(out.text).toContain("injected globals");
+ });
+
+ test("a non-exec tool whose successful output merely mentions a host phrase stays byte-identical", () => {
+ const doc = "The docs say apply_patch expects a string input.";
+ const out = normalizeCursorToolResultText(doc, { toolName: "read_file" });
+ expect(out.changed).toBe(false);
+ expect(out.isError).toBe(false);
+ expect(out.text).toBe(doc);
+ });
+```
+
+## Delivery for this phase
+
+Stage only the files above (`git diff --cached --stat` first); commit `--no-verify`; push `--no-verify`.
+
+## Verification (C, hosted only)
+
+NOT RUN locally. Exact-head Cross-platform CI on the wp2 head; receipt via
+`cxc receipt test --session --cwd -- gh run view --exit-status`.
diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md
new file mode 100644
index 0000000000..8bd40668e0
--- /dev/null
+++ b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md
@@ -0,0 +1,83 @@
+# 030 — wp3: SoT sync, ready-for-review, exact-head CI receipt
+
+Depends on 020. Class C2 for the docs. Push and PR creation are authorized by the user for this
+branch ("no verify로 푸시", "pr올려봐"); the draft PR already exists from wp1. Merge is not authorized.
+
+## MODIFY `structure/04_transports-and-sidecars.md`
+
+Insert after the paragraph that ends "…or reconstruct output that the code-mode host never
+emitted." (line 331), before the `[Decision Log]` that begins "목적과 의도: Keep Codex hosted web
+search usable on xAI's public Responses endpoint…":
+
+```
+Routed code-mode turns also carry the host contract for the nested helpers, stated in the same three
+injection sites as the result-emission rule (shared catalog nudge, Cursor code-mode guidance, native
+routed Responses instructions): `tools.apply_patch` takes one string that opens and closes with the
+bare patch marker lines (blank lines or indentation around them are tolerated; a decorated or missing
+marker is rejected), the isolate has no `import`/`require`, and a command that outlives
+`yield_time_ms` is polled through `write_stdin` with empty `chars` rather than a shell sleep loop.
+When a code-mode exec result still carries one of the host's failure strings ("expects a string
+input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported
+import in exec"), the native routed Responses, Kiro, and Cursor result paths append a one-line
+recovery hint naming the broken rule; flat shell bridges and foreign MCP namespaces are never
+annotated, Responses and Kiro additionally require the request's verified code-mode catalog, Cursor
+matches the exact `exec` name under its `opencodex-responses` provider without catalog context, and
+Cursor's error classification and Kiro's whitespace and failed-wrapper grouping are unchanged. Both
+halves live in `src/adapters/exec-tool-result-normalize.ts`
+so the pre-call and post-hoc wording cannot drift. This guidance and annotation change rewrites
+neither the model's JavaScript nor its patch payload; the existing name-alias delimiter
+normalization in `src/responses/code-mode-helper-compat.ts` is unchanged, and the host still rejects a
+malformed call exactly as before. Anthropic, Google, OpenAI-chat and command-code result paths
+have no exec-result seam today and are not annotated.
+
+[Decision Log]
+- 목적과 의도: Stop routed models from abandoning `apply_patch` after the Codex host rejects an object argument or a decorated marker, and from blocking a turn in a shell sleep loop when the host offers `session_id` polling.
+- 기존 구현 및 제약 조건: The shared nudge, Cursor guidance and native Responses instructions already carry the result-emission rule from `exec-tool-result-normalize.ts`, but none stated the helper's argument type, the marker rule, the import ban, or the polling protocol; `260905_apply_patch_envelope_gap` refused to rewrite JavaScript bodies (MODE B), so payload repair is off the table.
+- 검토한 주요 대안: Repair the argument shape inside the proxy (rejected: same body ambiguity as MODE B and it turns a rejected write into a performed one); Cursor-only guidance (rejected: the incident was native routed Responses on xAI); annotate every adapter's tool results (rejected: Anthropic/Google/OpenAI-chat/command-code have no exec-result seam and would need a new one).
+- 선택한 방식: One pre-call sentence and one marker→recovery table in the module that already owns the echo pair; inject the sentence at the three existing code-mode sites; annotate at the three existing exec-result seams with an exec-gated, idempotent helper that never changes error status.
+- 다른 대안 대신 이 방식을 선택한 이유: The safe repair for a host contract the model broke is to state it before the call and name it after the failure; keeping both halves in one file is what keeps them consistent.
+- 장점, 단점 및 영향: Code-mode system prompts grow by roughly 600 characters on routed turns; OpenAI destinations, flat catalogs and compaction requests are untouched. An exec result that legitimately prints one of the four phrases gains a recovery line, which is additive text and never an error flip. The effect on the live Grok defect rate is unmeasured until a re-probe.
+```
+
+## MODIFY `docs-site/src/content/docs/guides/codex-integration.md`
+
+Insert after the paragraph ending "…and unrelated native custom payloads stay unchanged." (line 331):
+
+```
+Routed code-mode turns are also told the host's rules for the nested helpers before the first
+call: `tools.apply_patch` takes one string that opens and closes with the bare patch marker lines,
+the isolate has no `import`, and long-running commands are polled through `write_stdin`. When a
+code-mode exec result on the native routed Responses, Kiro, or Cursor path still carries one of the host's
+failure messages, opencodex appends a one-line hint naming the rule. This change does not rewrite
+the model's code or its patch text.
+```
+
+Translated locales (7 files) are not edited; the English source gains a paragraph they do not
+contradict.
+
+## Delivery steps (t3b)
+
+1. Stage only `structure/04_transports-and-sidecars.md`, `docs-site/.../codex-integration.md` and this unit's
+ devlog; inspect `git diff --cached --stat`; commit `--no-verify`; `git push --no-verify`.
+2. Rewrite the PR body (`gh pr edit --body-file .tmp/pr-body.md`) to the final template: Summary
+ (problem, before/after, the four host strings), Verification (hosted CI run ids per head; local
+ suite/typecheck/build NOT RUN by instruction), Checklist ticked truthfully. No `gui` mention.
+3. Poll `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion,name`
+ in short `exec_command` calls (each < 30 s) until the Cross-platform CI run whose `headSha` equals
+ `git rev-parse HEAD` completes; `gh run watch` is not used inside one call.
+4. Receipt at phase C: `cxc receipt test --session --cwd -- gh run view --exit-status`.
+5. `gh pr ready ` only after that receipt exists. If the head moves later, a fresh run and fresh
+ receipt are required before any further ready claim.
+
+## Verification (C)
+
+- `gh run view --exit-status` exit 0 on the exact head; `gh pr view --json headRefOid` equals HEAD.
+- `gh pr checks ` lists test 1/4..4/4, gates, storage policy, api usage as pass.
+- Local suite / typecheck / build: NOT RUN (instruction).
+
+## D record
+
+Append `040_delivery_record.md` with PR number, head SHA, CI run id, per-job results, what did not
+improve (LOOP-PESSIMIST-01: prose cannot force compliance; effect on real Grok defect rate is
+unmeasured until a live re-probe), and the residual: Anthropic/Google/OpenAI-chat/command-code
+tool-result paths do not annotate host failures because they have no exec-result seam today.
diff --git a/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md b/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md
new file mode 100644
index 0000000000..3c2b28e23d
--- /dev/null
+++ b/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md
@@ -0,0 +1,100 @@
+# 040 — Delivery record: code-mode host contract
+
+Recorded 2026-09-07 from GitHub PR and Actions API responses. This records the delivery requested
+by [030_docs_and_delivery.md](030_docs_and_delivery.md#d-record).
+
+## Delivered revision and CI identity
+
+- [PR #3854](https://github.com/lidge-jun/opencodex/pull/3854) is merged into `dev`;
+ GitHub records `merged_at: 2026-09-07T06:41:03Z`.
+- Final PR head: `6bdcba5bff4196debf3cd159c7af3d34e35a24e0`.
+- Merge commit: `ece556a6ed32dc811bd660ddd8ef9e829512457a`.
+- [Pre-merge CI run 34090946313](https://github.com/lidge-jun/opencodex/actions/runs/34090946313),
+ attempt 1: `event: pull_request`, `head_sha: 6bdcba5bff4196debf3cd159c7af3d34e35a24e0`,
+ `status: completed`, `conclusion: success`; updated `2026-09-07T06:39:04Z`.
+- [Merge-head CI run 34091933836](https://github.com/lidge-jun/opencodex/actions/runs/34091933836), attempt 1:
+ `event: push`, `head_sha: ece556a6ed32dc811bd660ddd8ef9e829512457a`,
+ `status: completed`, `conclusion: success`; updated `2026-09-07T06:50:18Z`.
+
+The pre-merge run matches the final PR head; the later push run matches the merge commit.
+These are distinct CI records. This API check does not attest that the separate local receipt
+required by 030 was recorded.
+
+## Per-job results
+
+Each run has 21 completed jobs: 19 success, 2 skipped. Every job has the same conclusion in both
+runs. Names below are the literal Actions job names; each evidence link identifies its own run.
+
+| Job | Conclusion in both runs | Pre-merge evidence | Merge-head evidence |
+|---|---|---|---|
+| `select windows runner` | success | [job 101644191502](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644191502) | [job 101647069433](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647069433) |
+| `changes` | success | [job 101644191303](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644191303) | [job 101647069779](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647069779) |
+| `windows ${{ matrix.shard }}/6` | skipped | [job 101644212182](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644212182) | [job 101647096144](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647096144) |
+| `macos 1/2` | success | [job 101644233998](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233998) | [job 101647111898](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111898) |
+| `api usage` | success | [job 101644234038](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234038) | [job 101647111914](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111914) |
+| `storage policy` | success | [job 101644234034](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234034) | [job 101647111922](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111922) |
+| `docker smoke` | success | [job 101644234277](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234277) | [job 101647111928](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111928) |
+| `keyring ubuntu` | success | [job 101644234063](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234063) | [job 101647111929](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111929) |
+| `test 3/4` | success | [job 101644234103](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234103) | [job 101647111932](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111932) |
+| `test 4/4` | success | [job 101644234047](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234047) | [job 101647111936](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111936) |
+| `keyring macos` | success | [job 101644233982](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233982) | [job 101647111942](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111942) |
+| `test 1/4` | success | [job 101644234139](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234139) | [job 101647111951](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111951) |
+| `gates` | success | [job 101644233985](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233985) | [job 101647111970](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111970) |
+| `keyring windows` | success | [job 101644234037](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234037) | [job 101647111972](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111972) |
+| `macos 2/2` | success | [job 101644234066](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234066) | [job 101647111974](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111974) |
+| `npm-global ubuntu-latest` | success | [job 101644234059](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234059) | [job 101647111980](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111980) |
+| `npm-global windows-latest` | success | [job 101644234098](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234098) | [job 101647111990](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111990) |
+| `test 2/4` | success | [job 101644234167](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234167) | [job 101647112003](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112003) |
+| `npm-global macos-latest` | success | [job 101644234033](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234033) | [job 101647112012](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112012) |
+| `macos control` | skipped | [job 101644235362](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644235362) | [job 101647112696](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112696) |
+| `ci` | success | [job 101646588871](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101646588871) | [job 101649082610](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101649082610) |
+
+The Windows full-suite matrix was **SKIPPED in both runs**. Windows keyring create/read/delete smoke and
+npm-global packaging/install/help smoke passed; those focused passes do not establish Windows
+full-suite coverage. The `ci` aggregate accepts successful or skipped prerequisites, so its green
+result does not turn skipped jobs into passes. On the merge-head run, `gates` includes successful Typecheck, GUI tests,
+Privacy scan, skill-surface check, release-helper syntax check, and CLI help smoke; its GUI lint,
+GUI build, and dashboard-preview steps were skipped.
+
+Evidence retrieval (read-only):
+
+```sh
+gh api repos/lidge-jun/opencodex/pulls/3854
+gh api repos/lidge-jun/opencodex/actions/runs/34090946313
+gh api 'repos/lidge-jun/opencodex/actions/runs/34090946313/jobs?per_page=100'
+gh api repos/lidge-jun/opencodex/actions/runs/34091933836
+gh api 'repos/lidge-jun/opencodex/actions/runs/34091933836/jobs?per_page=100'
+```
+
+## Limits and residuals
+
+The delivered scope is the pre-call guidance and post-hoc recovery annotations described in
+[030](030_docs_and_delivery.md). Guidance cannot force model compliance, repair the model's
+JavaScript or patch payload, or replace the host's validation. The effect on the live Grok defect
+rate remains **unmeasured** until a live re-probe; CI success is not a defect-rate measurement.
+
+Anthropic, Google, OpenAI-chat, and command-code tool-result paths still lack exec-result
+annotation seams and do not annotate these host failures. Existing coverage is limited to native
+routed Responses, Kiro, and Cursor.
+
+Two public review threads were **OPEN / UNRESOLVED in the recorded 2026-09-07 audit snapshot**: GitHub's review-thread API returned
+`isResolved: false` for both on 2026-09-07. The merge and green CI do not resolve these findings.
+Source inspected for that snapshot was read at worktree HEAD `0fd3408b99994f74bd509975df7ee89823ddfecd`:
+
+- [discussion_r3947178410](https://github.com/lidge-jun/opencodex/pull/3854#discussion_r3947178410):
+ `src/adapters/exec-tool-result-normalize.ts:196` searches arbitrary output for a marker substring.
+ Successful output from a command such as `rg` or `cat` can therefore receive a misleading
+ recovery hint when it quotes that phrase, even though the command did not fail. The requested
+ host-error status/envelope or exact diagnostic check remains unimplemented at this anchor.
+- [discussion_r3947178418](https://github.com/lidge-jun/opencodex/pull/3854#discussion_r3947178418):
+ `src/adapters/cursor/tool-result-normalize.ts:114` gates annotation on tool name/namespace
+ without request-catalog or freeform provenance. A structured tool named `exec` can receive
+ unrelated host guidance. The requested code-mode provenance check remains unimplemented at
+ this anchor.
+
+These limitations were also recorded in [000](000_plan.md). Recording them here is not a fix,
+review resolution, or claim that successful output is left byte-identical.
+
+Local runtime, tests, typecheck, build, and install: **NOT RUN** by instruction. No live model
+re-probe was performed for this record. The remote results above belong to the recorded PR head
+and merge commit and do not validate later candidate documentation or test patches.
diff --git a/devlog/_plan/260907_lane_c/000_plan.md b/devlog/_plan/260907_lane_c/000_plan.md
new file mode 100644
index 0000000000..d26120ae29
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/000_plan.md
@@ -0,0 +1,7 @@
+# Lane C release train roadmap
+
+Satisfy-spec HOTL, explicitly delegated by release-train main task. Goal: prepare five manual dependent PRs for main-session landing. No merge/release/publish/main/preview changes; no local tests, typecheck, build or install. All such checks NOT RUN. Remote Cross-platform CI dispatch lane=all at top head is the verifier. Stop after exact-head green CI, Astra review verdicts, screenshots, credit and SHA handoff; unresolved material blockers are reported with evidence. No user-specified token/cost/time bound. Tools: local scoped git/files, gh read/PR/push/CI, Astra explorer audits and browser inspection. New security findings stay in .tmp/lane-c. Main owns config-routes.ts; no edits there. Escalate cross-owner collisions; reclaim delegated slices after two distinct worker failures.
+
+Dependency order: roadmap → 3839 → 3841 → 3863 → 3860 → 3252/1533 → top CI and handoff. Lower-layer commit subjects include [skip ci]; stack:null. Every carry uses cherry-pick -x and source PR author Co-authored-by. Existing configuration field contracts are reused. Rollback is revert of a layer with descendant cascade, within main-authorized integration. Current source and read-only git/gh are evidence; no claimed local execution of product verifiers. Public original diffs are recorded in decade documents; private audit notes stay in scratch.
+
+Main steering: all gui/src/i18n/*.ts are append-only multiwriter; C adds namespaced keys at feature-section ends, never edits/deletes existing keys. Final cascade resolves append collisions.
diff --git a/devlog/_plan/260907_lane_c/010_web_search.md b/devlog/_plan/260907_lane_c/010_web_search.md
new file mode 100644
index 0000000000..ccb7217ea3
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/010_web_search.md
@@ -0,0 +1,155 @@
+# 3839 implementation contract
+
+Carry public source patch with -x. Add deterministic 64KiB SSE and HTTP error-body regressions including cancel that never settles. Preserve complete prefix frames and discard incomplete tail. Tests use public run/parse APIs and controlled byte streams.
+
+Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative.
+
+## Public source diff (MODIFY/NEW paths)
+
+```diff
+diff --git a/src/web-search/anthropic-executor.ts b/src/web-search/anthropic-executor.ts
+index 1eb206afa..cd3893900 100644
+--- a/src/web-search/anthropic-executor.ts
++++ b/src/web-search/anthropic-executor.ts
+@@ -5,7 +5,11 @@ import { CLAUDE_CODE_HEADERS, claudeCodeSessionId } from "../adapters/client-fin
+ import { signalWithTimeout, cancelBodyOnAbort } from "../lib/abort";
+ import { sidecarEnter } from "../lib/sidecar-tracker";
+ import { applyUpstreamRecoveryInit, fetchWithResetRetry } from "../lib/upstream-retry";
+-import type { WebSearchSource } from "./parse";
++import {
++ MAX_SIDECAR_RESPONSE_BYTES,
++ cancelReaderWithoutWaiting,
++ type WebSearchSource,
++} from "./parse";
+ import { BASE_INSTRUCTION, IMAGE_INSTRUCTION, type SidecarOutcome, type SidecarSettings } from "./executor";
+
+ /** Hardcoded per-turn search bound handed to the server tool (mirrors the loop's maxSearches intent). */
+@@ -17,6 +21,33 @@ function isRec(v: unknown): v is Record {
+ return !!v && typeof v === "object" && !Array.isArray(v);
+ }
+
++/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */
++async function readBoundedText(res: Response): Promise {
++ if (!res.body) return "";
++ const reader = res.body.getReader();
++ const decoder = new TextDecoder();
++ let out = "";
++ let seen = 0;
++ try {
++ for (;;) {
++ const { done, value } = await reader.read();
++ if (done) break;
++ const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen;
++ const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining);
++ seen += accepted.byteLength;
++ out += decoder.decode(accepted, { stream: true });
++ if (seen >= MAX_SIDECAR_RESPONSE_BYTES) {
++ cancelReaderWithoutWaiting(reader, "sidecar error body byte limit reached");
++ break;
++ }
++ }
++ out += decoder.decode();
++ } catch {
++ /* a failed error-body read must not mask the HTTP status we are about to report */
++ }
++ return out;
++}
++
+ /**
+ * Fold an Anthropic Messages SSE stream (a web_search_20250305 turn) into a WebSearchResult.
+ *
+@@ -41,6 +72,7 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise): void => {
+ const type = typeof data.type === "string" ? data.type : "";
+@@ -82,15 +114,27 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) {
++ // Keep the frames already folded above, drop the unterminated tail, and do not wait on
++ // upstream teardown.
++ cancelReaderWithoutWaiting(reader, "sidecar response byte limit reached");
++ buffer = "";
++ break;
++ }
+ }
+ // Flush the decoder and process any final unterminated frame (a stream that ends without \n\n).
+ buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n");
+@@ -177,7 +221,9 @@ export async function runAnthropicWebSearch(
+ // (found investigating #1419).
+ const detachBodyGuard = cancelBodyOnAbort(res.body, linkedSignal.signal);
+ if (!res.ok) {
+- const t = await res.text().catch(() => "");
++ // Untrusted upstream error bodies are only used for an auth-failure message, so read a
++ // bounded prefix instead of buffering an arbitrarily large response.
++ const t = await readBoundedText(res);
+ detachBodyGuard();
+ console.warn(`[web-search] anthropic sidecar HTTP ${res.status} for query "${query.slice(0, 80)}" (${Date.now() - t0}ms)`);
+ if (res.status === 401) {
+diff --git a/src/web-search/parse.ts b/src/web-search/parse.ts
+index 757c309f3..7ba5d2607 100644
+--- a/src/web-search/parse.ts
++++ b/src/web-search/parse.ts
+@@ -193,7 +193,7 @@ function fromOutputArray(output: OutputItem[], seen: Set): WebSearchResu
+ return { text, sources };
+ }
+
+-function cancelReaderWithoutWaiting(
++export function cancelReaderWithoutWaiting(
+ reader: ReadableStreamDefaultReader,
+ reason: string,
+ ): void {
+diff --git a/tests/web-search/web-search-anthropic.test.ts b/tests/web-search/web-search-anthropic.test.ts
+index f5b7f1df2..33f2616cc 100644
+--- a/tests/web-search/web-search-anthropic.test.ts
++++ b/tests/web-search/web-search-anthropic.test.ts
+@@ -130,6 +130,27 @@ describe("parseAnthropicSidecarSSE", () => {
+ expect(out.error).toBeDefined();
+ });
+
++ test("an unterminated frame cannot buffer the stream without bound", async () => {
++ // A sidecar that never emits a frame separator: without a cap the parser would accumulate
++ // the whole stream in memory before it could fold anything.
++ let produced = 0;
++ let cancelled = false;
++ const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`);
++ const body = new ReadableStream({
++ pull(c) {
++ if (produced > 8 * 1024 * 1024) { c.close(); return; }
++ produced += chunk.byteLength;
++ c.enqueue(chunk);
++ },
++ cancel() { cancelled = true; },
++ });
++ const out = await parseAnthropicSidecarSSE(new Response(body, { status: 200 }));
++ expect(cancelled).toBe(true);
++ // The cap stops the read long before the producer would have finished on its own.
++ expect(produced).toBeLessThan(1024 * 1024);
++ expect(out.text).toBe("");
++ });
++
+ test("empty results (content:[]) with answer text is a success, not an error", async () => {
+ const res = sseResponse([
+ { type: "content_block_start", index: 0, content_block: { type: "web_search_tool_result", tool_use_id: "srvtoolu_3", content: [] } },
+
+```
diff --git a/devlog/_plan/260907_lane_c/020_vision.md b/devlog/_plan/260907_lane_c/020_vision.md
new file mode 100644
index 0000000000..9dab5d18e2
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/020_vision.md
@@ -0,0 +1,135 @@
+# 3841 implementation contract
+
+Carry public source patch with -x. Add 64KiB HTTP error-body and non-settling cancel regressions. Preserve complete description frames before cap; discard unfinished frame even at exact cap; retain downstream clamp. No credential-policy changes.
+
+Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative.
+
+## Public source diff (MODIFY/NEW paths)
+
+```diff
+diff --git a/src/vision/anthropic-describe.ts b/src/vision/anthropic-describe.ts
+index 4f41017ef..280096f03 100644
+--- a/src/vision/anthropic-describe.ts
++++ b/src/vision/anthropic-describe.ts
+@@ -10,6 +10,8 @@ import type { DescribeOutcome, VisionSettings } from "./describe";
+ const ANTHROPIC_VISION_MAX_TOKENS = 1024;
+ const ALLOWED_IMAGE_MIME = new Set(["image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif"]);
+ const MAX_IMAGE_BYTES = 20 * 1024 * 1024;
++/** Bound the sidecar SSE stream and its untrusted error body; the description is clamped downstream. */
++const MAX_SIDECAR_RESPONSE_BYTES = 64 * 1024;
+ const DESCRIBE_INSTRUCTION =
+ "You are a vision describer for a text-only model that cannot see the image. Describe the image " +
+ "thoroughly and factually so that model can fully reason about it: transcribe any visible text " +
+@@ -43,6 +45,34 @@ function buildImageBlock(imageUrl: string): { block?: AnthropicImageBlock; error
+ return { error: "unsupported image URL scheme (expected data: or https:)" };
+ }
+
++/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */
++async function readBoundedText(res: Response): Promise {
++ if (!res.body) return "";
++ const reader = res.body.getReader();
++ const decoder = new TextDecoder();
++ let out = "";
++ let seen = 0;
++ try {
++ for (;;) {
++ const { done, value } = await reader.read();
++ if (done) break;
++ const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen;
++ const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining);
++ seen += accepted.byteLength;
++ out += decoder.decode(accepted, { stream: true });
++ if (seen >= MAX_SIDECAR_RESPONSE_BYTES) {
++ try { void reader.cancel("vision sidecar error body byte limit reached").catch(() => undefined); }
++ catch { /* best-effort body teardown */ }
++ break;
++ }
++ }
++ out += decoder.decode();
++ } catch {
++ /* a failed error-body read must not mask the HTTP status we are about to report */
++ }
++ return out;
++}
++
+ /** Fold Anthropic Messages text deltas into one description. Malformed frames are ignored. */
+ export async function parseAnthropicVisionSSE(res: Response): Promise {
+ if (!res.body) return { text: "", error: "anthropic vision sidecar returned no response body" };
+@@ -52,6 +82,7 @@ export async function parseAnthropicVisionSSE(res: Response): Promise {
+ let dataLine = "";
+@@ -76,12 +107,24 @@ export async function parseAnthropicVisionSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) {
++ // Keep the frames folded above, drop the unterminated tail, and do not wait on teardown.
++ try { void reader.cancel("vision sidecar response byte limit reached").catch(() => undefined); }
++ catch { /* best-effort body teardown */ }
++ buffer = "";
++ break;
++ }
+ }
+ buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n");
+ if (buffer.trim()) processFrame(buffer);
+@@ -164,7 +207,8 @@ export async function describeImageAnthropic(
+ { abortSignal: linkedSignal.signal, label: "vision-sidecar-anthropic" },
+ );
+ if (!res.ok) {
+- const responseText = await res.text().catch(() => "");
++ // The body is untrusted and only feeds one auth-failure message, so read a bounded prefix.
++ const responseText = await readBoundedText(res);
+ console.warn(`[vision] anthropic sidecar HTTP ${res.status} (${Date.now() - startedAt}ms)`);
+ if (res.status === 401) {
+ return { text: "", error: `anthropic vision sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(new Error(responseText))}` };
+diff --git a/tests/vision/vision-anthropic.test.ts b/tests/vision/vision-anthropic.test.ts
+index ee4b01b42..30ed17af9 100644
+--- a/tests/vision/vision-anthropic.test.ts
++++ b/tests/vision/vision-anthropic.test.ts
+@@ -225,6 +225,27 @@ describe("Anthropic vision executor", () => {
+ expect(result).toEqual({ text: "first second" });
+ });
+
++ test("an unterminated frame cannot buffer the stream without bound", async () => {
++ // A sidecar that never emits a frame separator: without a cap the parser accumulates the
++ // whole response in memory before it can fold anything.
++ let produced = 0;
++ let cancelled = false;
++ const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`);
++ const body = new ReadableStream({
++ pull(c) {
++ if (produced > 8 * 1024 * 1024) { c.close(); return; }
++ produced += chunk.byteLength;
++ c.enqueue(chunk);
++ },
++ cancel() { cancelled = true; },
++ });
++ const out = await parseAnthropicVisionSSE(new Response(body, { status: 200 }));
++ expect(cancelled).toBe(true);
++ // The cap stops the read long before the producer would have finished on its own.
++ expect(produced).toBeLessThan(1024 * 1024);
++ expect(out.text).toBe("");
++ });
++
+ test("malformed and terminal-error streams degrade to explicit errors", async () => {
+ const malformed = await parseAnthropicVisionSSE(sseResponse(["{not-json", { type: "message_stop" }]));
+ expect(malformed.text).toBe("");
+
+```
diff --git a/devlog/_plan/260907_lane_c/030_health.md b/devlog/_plan/260907_lane_c/030_health.md
new file mode 100644
index 0000000000..eaeb4bbcd6
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/030_health.md
@@ -0,0 +1,123 @@
+# 3863 implementation contract
+
+Carry with -x excluding config-routes.ts. getStartupHealthSnapshot returns fresh cached value unchanged; stale/empty read schedules refresh and returns immediately. Catch rejected or synchronously thrown detached probe and retain stale conservative health; invalidation generation cannot overwrite newer reading. Replace 100ms production settings assertion with controlled probe fixtures. Exact route wiring remains main responsibility.
+
+Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative.
+
+## Public source diff (MODIFY/NEW paths)
+
+```diff
+diff --git a/src/server/management/config-routes.ts b/src/server/management/config-routes.ts
+index 4d551a886..9ddd02300 100644
+--- a/src/server/management/config-routes.ts
++++ b/src/server/management/config-routes.ts
+@@ -107,7 +107,7 @@ import type { PersistedUsageAttempt } from "../../usage/log";
+ import { isAllowedRequestOrigin, jsonResponse, providerManagementConfigError, publicProviderBaseUrl, safeConfigDTO } from "../auth-cors";
+ import { withProviderServiceTierDTO } from "./provider-capability-config";
+ import { applySystemEnvToggle } from "../system-env";
+-import { getCachedStartupHealth, invalidateStartupHealthCache } from "../startup-health-cache";
++import { getCachedStartupHealth, getStartupHealthSnapshot, invalidateStartupHealthCache } from "../startup-health-cache";
+ import { runWindowsTrayAction } from "../windows-tray-control";
+ import { runStartupInstallAction, type StartupInstallAction } from "../startup-action-control";
+ import { displayCodexRuntimePath, effortClampAppliesToRuntime, loadLastEffortClamp, resolveCodexRuntime } from "../../codex/runtime";
+@@ -329,7 +329,9 @@ export async function handleConfigRoutes(ctx: ManagementContext): Promise Promise;
+ }
+
++/**
++ * Return the last completed probe immediately and refresh it in the background.
++ *
++ * Settings are consumed by several dashboard controls. They must not block on a
++ * Windows service-manager probe; the dedicated /api/startup-health route owns
++ * the fresh, bounded diagnostic read.
++ */
++export function getStartupHealthSnapshot(
++ config: Pick,
++ deps: StartupHealthCacheDeps = {},
++): StartupHealth {
++ const now = deps.now ?? Date.now;
++ if (!cached || now() - cached.timestamp >= CACHE_TTL_MS) refreshInBackground(config, deps);
++ return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config);
++}
++
+ export function markStartupHealthDiagnosticStale(value: StartupHealth): StartupHealth {
+ if (!value.localRoutingDependency) return { ...value, diagnosticStale: true };
+ return {
+diff --git a/tests/service/autostart-health.test.ts b/tests/service/autostart-health.test.ts
+index 639f1b34c..48bb7b539 100644
+--- a/tests/service/autostart-health.test.ts
++++ b/tests/service/autostart-health.test.ts
+@@ -3,7 +3,7 @@ import { deriveStartupHealth, formatStartupRoutingDetail, startupHealthSummary }
+ import { unusedProxyWarningLines } from "../../src/cli/status";
+ import { classifyCodexRouting, hasInjectedCodexRouting } from "../../src/codex/inject";
+ import { handleManagementAPI } from "../../src/server/management-api";
+-import { getCachedStartupHealth, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache";
++import { getCachedStartupHealth, getStartupHealthSnapshot, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache";
+ import type { OcxConfig } from "../../src/types";
+
+ const base = {
+@@ -277,6 +277,43 @@ describe("Codex startup health", () => {
+ await pendingProbe;
+ invalidateStartupHealthCache();
+ });
++
++ test("settings snapshot starts a probe without waiting for it", async () => {
++ invalidateStartupHealthCache();
++ let releaseProbe!: (value: ReturnType) => void;
++ const pendingProbe = new Promise>(resolve => {
++ releaseProbe = resolve;
++ });
++
++ const health = getStartupHealthSnapshot(
++ { codexAutoStart: true },
++ { probe: async () => pendingProbe },
++ );
++
++ expect(health.diagnosticStale).toBe(true);
++ releaseProbe(deriveStartupHealth({ ...base, routingKind: "native" }));
++ await pendingProbe;
++ invalidateStartupHealthCache();
++ });
++
++ test("settings GET uses the non-blocking startup-health snapshot in production", async () => {
++ invalidateStartupHealthCache();
++ const url = new URL("http://localhost/api/settings");
++
++ const response = await Promise.race([
++ handleManagementAPI(
++ new Request(url),
++ url,
++ { port: 10100, providers: {}, defaultProvider: "openai", codexAutoStart: true } as OcxConfig,
++ ),
++ new Promise(resolve => setTimeout(() => resolve(null), 100)),
++ ]);
++
++ expect(response?.status).toBe(200);
++ const body = await response!.json() as { startupHealth?: { diagnosticStale?: boolean } };
++ expect(body.startupHealth?.diagnosticStale).toBe(true);
++ invalidateStartupHealthCache();
++ });
+ });
+ import { ManagementRequest as Request } from "../helpers/management-auth";
+
+
+```
+
+## Main-owned route handoff
+
+At current dev, settings GET uses `startupHealth: await readStartupHealth(config)` at `src/server/management/config-routes.ts:332`. M changes only this settings read to the exported immediate snapshot and retains the dedicated `/api/startup-health` bounded read. Settings PUT at line 625 is separately present; it must remain reviewed explicitly rather than blindly replaced. C does not modify either call site.
diff --git a/devlog/_plan/260907_lane_c/040_desktop.md b/devlog/_plan/260907_lane_c/040_desktop.md
new file mode 100644
index 0000000000..4eb4ebffd5
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/040_desktop.md
@@ -0,0 +1,408 @@
+# 3860 implementation contract
+
+Carry source patch plus skipped-sync correction with -x. Default false/absent OFF, true remains true; persist preference before sync and surface sync failures. All nine locales and existing screenshot. Independent auth boundary review confirms remote admission/upstream credentials unchanged.
+
+Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative.
+
+## Public source diff (MODIFY/NEW paths)
+
+```diff
+diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md
+index 7d66e72c3..ff2df04fd 100644
+--- a/docs-site/src/content/docs/guides/codex-integration.md
++++ b/docs-site/src/content/docs/guides/codex-integration.md
+@@ -215,6 +215,15 @@ HTTP/SSE.
+
+ ### Authless Codex Desktop (opt-in)
+
++In **Dashboard → Overview**, **Open Codex without signing in** controls this existing
++opt-in preference. The switch defaults to **off** when the setting is absent or false;
++an existing explicit `codexDesktopAuthless: true` stays enabled. The dashboard saves
++the preference and runs a full sync. Restart Codex Desktop after changing it.
++If synchronization fails, the saved preference remains and the dashboard shows the error;
++retry **Sync** before restarting. Account-gated Desktop features may be unavailable
++when enabled. Upstream credentials, local eligibility, remote admission authentication
++and user-owned gateway settings retain their existing requirements.
++
+ Codex Desktop shows its ChatGPT login screen whenever the active provider requires OpenAI auth. If
+ your OpenCodex setup never uses ChatGPT credentials (routed providers only, or a blocked
+ `chatgpt.com`), you can opt out of that gate:
+diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts
+index 5faab4b35..495104bd4 100644
+--- a/gui/src/i18n/de.ts
++++ b/gui/src/i18n/de.ts
+@@ -299,6 +299,8 @@ export const de: Record = {
+ "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.",
+ "dash.codexAutoStart": "opencodex mit Codex starten",
+ "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.",
++ "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen",
++ "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.",
+ "dash.searchModel": "Such-Sidecar-Modell",
+ "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.",
+ "dash.searchReasoning": "Such-Reasoning-Aufwand",
+diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts
+index c71208942..22a380785 100644
+--- a/gui/src/i18n/en.ts
++++ b/gui/src/i18n/en.ts
+@@ -311,6 +311,8 @@ export const en = {
+ "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.",
+ "dash.codexAutoStart": "Start opencodex with Codex",
+ "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.",
++ "dash.codexDesktopAuthless": "Open Codex without signing in",
++ "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.",
+ "dash.searchModel": "Search sidecar model",
+ "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.",
+ "dash.searchReasoning": "Search reasoning effort",
+diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts
+index e1b3519ef..9f0f26517 100644
+--- a/gui/src/i18n/fr.ts
++++ b/gui/src/i18n/fr.ts
+@@ -301,6 +301,8 @@ export const fr: Record = {
+ "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.",
+ "dash.codexAutoStart": "Démarrer opencodex avec Codex",
+ "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.",
++ "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter",
++ "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.",
+ "dash.searchModel": "Modèle auxiliaire de recherche",
+ "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.",
+ "dash.searchReasoning": "Effort de raisonnement pour la recherche",
+diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts
+index cf9483158..55a6fe249 100644
+--- a/gui/src/i18n/ja.ts
++++ b/gui/src/i18n/ja.ts
+@@ -308,6 +308,8 @@ export const ja: Record = {
+ "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。",
+ "dash.codexAutoStart": "Codex と一緒に opencodex を起動",
+ "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。",
++ "dash.codexDesktopAuthless": "ログインせずに Codex を開く",
++ "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。",
+ "dash.searchModel": "検索サイドカーモデル",
+ "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。",
+ "dash.searchReasoning": "検索の推論負荷",
+diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts
+index c1959482b..19285b150 100644
+--- a/gui/src/i18n/ko.ts
++++ b/gui/src/i18n/ko.ts
+@@ -303,6 +303,8 @@ export const ko: Record = {
+ "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.",
+ "dash.codexAutoStart": "Codex 실행 시 opencodex 시작",
+ "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.",
++ "dash.codexDesktopAuthless": "로그인 없이 Codex 열기",
++ "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.",
+ "dash.searchModel": "서치 사이드카 모델",
+ "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.",
+ "dash.searchReasoning": "서치 추론 강도",
+diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts
+index 0109f5ebd..87704912a 100644
+--- a/gui/src/i18n/ru.ts
++++ b/gui/src/i18n/ru.ts
+@@ -308,6 +308,8 @@ export const ru: Record = {
+ "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.",
+ "dash.codexAutoStart": "Запускать opencodex вместе с Codex",
+ "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.",
++ "dash.codexDesktopAuthless": "Открывать Codex без входа",
++ "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.",
+ "dash.searchModel": "Модель сайдкара поиска",
+ "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.",
+ "dash.searchReasoning": "Уровень рассуждений для поиска",
+diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts
+index fa8b8e9c2..807eeae32 100644
+--- a/gui/src/i18n/tr.ts
++++ b/gui/src/i18n/tr.ts
+@@ -309,6 +309,8 @@ export const tr: Record = {
+ "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.",
+ "dash.codexAutoStart": "opencodex'i Codex ile başlat",
+ "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.",
++ "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat",
++ "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.",
+ "dash.searchModel": "Arama yan araç modeli",
+ "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.",
+ "dash.searchReasoning": "Arama akıl yürütme çabası",
+diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts
+index 3bc246543..62e1f0711 100644
+--- a/gui/src/i18n/zh-TW.ts
++++ b/gui/src/i18n/zh-TW.ts
+@@ -200,6 +200,8 @@ export const zhTW: Record = {
+ "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。",
+ "dash.codexAutoStart": "隨 Codex 啟動 opencodex",
+ "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。",
++ "dash.codexDesktopAuthless": "無需登入即可開啟 Codex",
++ "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。",
+ "dash.searchModel": "搜尋附屬模型",
+ "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。",
+ "dash.searchReasoning": "搜尋推理強度",
+diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts
+index b10c48688..994691442 100644
+--- a/gui/src/i18n/zh.ts
++++ b/gui/src/i18n/zh.ts
+@@ -303,6 +303,8 @@ export const zh: Record = {
+ "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。",
+ "dash.codexAutoStart": "随 Codex 启动 opencodex",
+ "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。",
++ "dash.codexDesktopAuthless": "无需登录即可打开 Codex",
++ "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。",
+ "dash.searchModel": "搜索附属模型",
+ "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。",
+ "dash.searchReasoning": "搜索推理强度",
+diff --git a/gui/src/pages/dashboard-overview-sections.tsx b/gui/src/pages/dashboard-overview-sections.tsx
+index 8da531f97..6606c4f56 100644
+--- a/gui/src/pages/dashboard-overview-sections.tsx
++++ b/gui/src/pages/dashboard-overview-sections.tsx
+@@ -163,7 +163,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) {
+
+ export function DashboardMaintenancePanel({ d }: { d: Dash }) {
+ const {
+- t, runSync, syncing, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen,
++ t, runSync, syncing, settingsSaving, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen,
+ syncResult, syncError, updateJob, reconnecting, clearSyncFeedback,
+ } = d;
+ const syncHoldsWarning = !!syncResult && (
+@@ -211,7 +211,7 @@ export function DashboardMaintenancePanel({ d }: { d: Dash }) {
+
{t("dash.syncModelsHint")}
+
+
+-
+
+
++
++
++
++
{t("dash.codexDesktopAuthless")}
++
{t("dash.codexDesktopAuthlessHint")}
++ {settings?.catalogRefreshPending &&
{t("codexAuth.catalogRefreshPending")}
}
++
++
++
++
++
++
++
+
+ {/* Both sidecar cards wear the DashboardInjectionPanel shell: the PANEL is
+ the flex row, copy left, controls right. */}
+diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts
+index 0793a7def..d24051028 100644
+--- a/gui/src/pages/dashboard-shared.ts
++++ b/gui/src/pages/dashboard-shared.ts
+@@ -48,6 +48,8 @@ export interface ProviderInfo { name: string; adapter: string; baseUrl: string;
+ export interface ModelInfo { id: string; provider: string; namespaced: string; owned_by?: string; reasoningEfforts?: string[] }
+ export interface SettingsData {
+ codexAutoStart: boolean;
++ codexDesktopAuthless?: boolean;
++ catalogRefreshPending?: boolean;
+ /** Whether a login may open a browser on the machine running the proxy. */
+ oauthOpenBrowser?: boolean;
+ port: number;
+diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts
+index 6f84950ce..6da776ea1 100644
+--- a/gui/src/pages/use-dashboard-data.ts
++++ b/gui/src/pages/use-dashboard-data.ts
+@@ -607,23 +607,24 @@ export function useDashboardData(apiBase: string) {
+ finally { setInjectionSaving(false); }
+ };
+
+- const toggleCodexAutoStart = async () => {
+- if (!settings || settingsSaving) return;
+- const next = !settings.codexAutoStart;
++ const toggleCodexSetting = async (key: "codexAutoStart" | "codexDesktopAuthless") => {
++ if (!settings || settingsSaving || syncing) return;
++ const next = !(settings[key] ?? (key === "codexAutoStart"));
+ setSettingsSaving(true);
+ settingsMutationInFlightRef.current = true;
+- setSettings({ ...settings, codexAutoStart: next });
++ setSettings({ ...settings, [key]: next });
+ try {
+ const res = await fetch(`${apiBase}/api/settings`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+- body: JSON.stringify({ codexAutoStart: next }),
++ body: JSON.stringify({ [key]: next }),
+ });
+- const data = await requireJson<{ codexAutoStart: boolean; startupHealth?: SettingsData["startupHealth"] }>(res, "save failed");
++ const data = await requireJson(res, "save failed");
+ settingsMutationEpochRef.current += 1;
+- setSettings(prev => prev ? { ...prev, codexAutoStart: data.codexAutoStart, startupHealth: data.startupHealth ?? prev.startupHealth } : prev);
++ setSettings(prev => prev ? { ...prev, [key]: data[key], catalogRefreshPending: key === "codexDesktopAuthless" ? data.catalogRefreshPending : prev.catalogRefreshPending, startupHealth: data.startupHealth ?? prev.startupHealth } : prev);
++ if (key === "codexDesktopAuthless") await runSync();
+ } catch {
+- setSettings(prev => prev ? { ...prev, codexAutoStart: !next } : prev);
++ setSettings(prev => prev ? { ...prev, [key]: !next } : prev);
+ setError(true);
+ } finally {
+ settingsMutationInFlightRef.current = false;
+@@ -631,6 +632,9 @@ export function useDashboardData(apiBase: string) {
+ }
+ };
+
++ const toggleCodexAutoStart = () => toggleCodexSetting("codexAutoStart");
++ const toggleCodexDesktopAuthless = () => toggleCodexSetting("codexDesktopAuthless");
++
+ // Clears the sync result/error in this hook. The dashboard toast owns its own dismissal
+ // timer but must publish the dismissal here: syncResult/syncError live above the dashboard
+ // tabs, so a component-local flag alone would let a stale result remount as a fresh toast
+@@ -649,6 +653,7 @@ export function useDashboardData(apiBase: string) {
+ const res = await fetch(`${apiBase}/api/sync`, { method: "POST" });
+ const data = await requireJson(res, "sync failed");
+ setSyncResult(data);
++ setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev);
+ if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped);
+ } catch (err) {
+ setSyncError(err instanceof Error ? err.message : String(err));
+@@ -789,7 +794,7 @@ export function useDashboardData(apiBase: string) {
+ effortCapHelpTriggerRef, updateTriggerRef, maHelpTriggerRef, shadowCallHelpTriggerRef,
+ effortCapHelpDialogRef, updateDialogRef, maHelpDialogRef, shadowCallHelpDialogRef,
+ filteredGroups, sidecarModels, visionModels,
+- saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, runSync, clearSyncFeedback,
++ saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, toggleCodexDesktopAuthless, runSync, clearSyncFeedback,
+ fetchUpdateCheck, closeUpdateDialog, openUpdateDialog, changeUpdateChannel, runUpdate,
+ };
+ }
+diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx
+index dc762de58..994a40912 100644
+--- a/gui/tests/vision-sidecar-dashboard.test.tsx
++++ b/gui/tests/vision-sidecar-dashboard.test.tsx
+@@ -12,7 +12,7 @@ import { LanguageProvider } from "../src/i18n/provider";
+ import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections";
+ import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared";
+ import { mergeSidecarSetting } from "../src/pages/dashboard-shared";
+-import type { useDashboardData } from "../src/pages/use-dashboard-data";
++import { useDashboardData } from "../src/pages/use-dashboard-data";
+
+ const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const;
+ let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>;
+@@ -382,4 +382,79 @@ test("model and reasoning saves still omit enabled, limit, and timeout", async (
+ expect(patches).toHaveLength(2);
+ expect(patches[1]).toEqual({ vision: { reasoning: "high" } });
+ assertVisionControlFieldsOmitted(patches[1]!);
+-});
+\ No newline at end of file
++});
++
++test("Desktop login switch defaults off, preserves explicit opt-in, and disables while saving", async () => {
++ const { d } = harness();
++ let clicks = 0;
++ d.toggleCodexDesktopAuthless = async () => { clicks += 1; };
++ d.settings = { codexAutoStart: true, port: 10100, hostname: "127.0.0.1" };
++ await mount(d);
++ const toggle = () => host.querySelector(`button[aria-label="${en["dash.codexDesktopAuthless"]}"]`)!;
++ expect(toggle().getAttribute("aria-pressed")).toBe("false");
++ d.settings.codexDesktopAuthless = true;
++ await mount(d);
++ expect(toggle().getAttribute("aria-pressed")).toBe("true");
++ await act(async () => { toggle().click(); });
++ expect(clicks).toBe(1);
++ d.settings.codexDesktopAuthless = false;
++ d.settings.catalogRefreshPending = true;
++ d.settingsSaving = true;
++ await mount(d);
++ expect(toggle().getAttribute("aria-pressed")).toBe("false");
++ expect(toggle().disabled).toBe(true);
++ expect(host.textContent).toContain(en["codexAuth.catalogRefreshPending"]);
++});
++
++
++test.each([undefined, false, true])("Desktop login preference %s persists before full sync; sync failure keeps the saved preference", async (initial) => {
++ const originalFetch = globalThis.fetch;
++ const writes: Array<{ path: string; body: unknown }> = [];
++ let latest: Dash | undefined;
++ let saved = initial;
++ const apiBase = `/authless-test-${String(initial)}`;
++ globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
++ const path = String(input);
++ if (init?.method === "PUT") {
++ const body = JSON.parse(String(init.body));
++ writes.push({ path, body });
++ if (body.codexDesktopAuthless !== undefined) {
++ saved = body.codexDesktopAuthless;
++ return Response.json({ codexDesktopAuthless: saved, catalogRefreshPending: true });
++ }
++ return Response.json({ codexAutoStart: body.codexAutoStart, catalogRefreshPending: false });
++ }
++ if (path.endsWith("/api/sync")) {
++ writes.push({ path, body: null });
++ return Response.json({ error: "sync unavailable" }, { status: 503 });
++ }
++ if (path.endsWith("/api/settings")) {
++ return Response.json({ codexAutoStart: true, codexDesktopAuthless: saved, port: 10100, hostname: "127.0.0.1" });
++ }
++ return Response.json({}, { status: 503 });
++ }) as typeof fetch;
++ function Harness() { latest = useDashboardData(apiBase); return null; }
++ try {
++ const { createRoot } = await import("react-dom/client");
++ await act(async () => {
++ root = createRoot(host);
++ root.render();
++ });
++ expect(latest?.settings?.codexDesktopAuthless).toBe(initial);
++ await act(async () => { await latest!.toggleCodexDesktopAuthless(); });
++ expect(writes).toEqual([
++ { path: `${apiBase}/api/settings`, body: { codexDesktopAuthless: !initial } },
++ { path: `${apiBase}/api/sync`, body: null },
++ ]);
++ expect(latest?.settings?.codexDesktopAuthless).toBe(!initial);
++ expect(latest?.syncError).toBe("sync unavailable");
++ expect(latest?.settings?.catalogRefreshPending).toBe(true);
++ await act(async () => { await latest!.toggleCodexAutoStart(); });
++ expect(latest?.settings?.codexAutoStart).toBe(false);
++ expect(latest?.settings?.catalogRefreshPending).toBe(true);
++ } finally {
++ await act(async () => { root?.unmount(); });
++ root = null;
++ globalThis.fetch = originalFetch;
++ }
++});
+diff --git a/tests/codex-integration/codex-inject.test.ts b/tests/codex-integration/codex-inject.test.ts
+index 84ac5f67b..b6be3c2f6 100644
+--- a/tests/codex-integration/codex-inject.test.ts
++++ b/tests/codex-integration/codex-inject.test.ts
+@@ -31,8 +31,8 @@ describe("Codex config injection", () => {
+ });
+
+ describe("authless Codex Desktop opt-in (#1107)", () => {
+- test("default target on loopback stays Design B and byte-identical", () => {
+- const target = standaloneCodexRoutingTarget(10100, {});
++ test.each([undefined, false])("disabled preference %s on loopback stays Design B and byte-identical", (codexDesktopAuthless) => {
++ const target = standaloneCodexRoutingTarget(10100, { codexDesktopAuthless });
+ expect(target.desktopAuthless).toBeUndefined();
+ expect(buildProfileFile(target, null)).toBe(buildProfileFile(10100, null));
+ expect(buildProviderTableBlock(target)).toContain("requires_openai_auth = true");
+
+```
+
+Audit amendment: clear catalogRefreshPending only if sync status is affirmative success, not HTTP 200 skipped. Add skipped/no-write regression.
+
+## Lane E documentation handoff
+
+After run 34106956362 reported a GUI lint failure, include the separately prepared code-mode host-rule translations in the seven fr/ja/ko/ru/tr/zh-cn/zh-tw Codex integration guides. The patch adds 51 documentation lines matching the existing English paragraph; it does not modify runtime code or provider guides. Apply on the Desktop layer, record `docs handoff from lane E` and `[skip ci]` in its own commit, then cascade the fallback layer and dispatch the top CI again. Local documentation install/build remains NOT RUN.
diff --git a/devlog/_plan/260907_lane_c/050_fallback.md b/devlog/_plan/260907_lane_c/050_fallback.md
new file mode 100644
index 0000000000..6bf165a96c
--- /dev/null
+++ b/devlog/_plan/260907_lane_c/050_fallback.md
@@ -0,0 +1,368 @@
+# 3252 implementation contract
+
+Carry source commits with -x. Preserve configured fallback models absent from availability. Add focused GUI tests for add/remove/reorder/save and unavailable model round-trip. Reuse existing /api/v2 (enabled, multiAgentMode, keepNativeChatGptOnV1) and report recovery enabled/eligibility as unknown when the server does not expose it, never fabricate recovery settings state for contextual native-parent/routed-child V2 guidance. Never infer all workflows are native; warn conditionally, show disabled/eligible/experimental/unknown state truthfully, link issue 92. No roster-reuse switch. Update all locales and codex-integration docs; actual UI screenshot. New PR body is valid Markdown, removes unsupported roster-switch claims.
+
+Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative.
+
+## Public source diff (MODIFY/NEW paths)
+
+```diff
+diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx
+index 46c0447a7..7c3b0e942 100644
+--- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx
++++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx
+@@ -28,6 +28,13 @@ export interface SubagentDelegationSectionProps {
+ onUltraModeSave: (patch: UltraModePatch) => void;
+ ultraLoadFailed: boolean;
+ onUltraModeRetry: () => void;
++ fallback: string[];
++ fallbackPollMs: number;
++ fallbackBusy: boolean;
++ availableModels: string[];
++ onFallbackChange: (models: string[]) => void;
++ onFallbackPollMsChange: (pollMs: number) => void;
++ onFallbackSave: () => void;
+ }
+
+ export default function SubagentDelegationSection({
+@@ -44,6 +51,7 @@ export default function SubagentDelegationSection({
+ onUltraModeSave,
+ ultraLoadFailed,
+ onUltraModeRetry,
++ fallback, fallbackPollMs, fallbackBusy, availableModels, onFallbackChange, onFallbackPollMsChange, onFallbackSave,
+ }: SubagentDelegationSectionProps) {
+ const t = useT();
+ // A present empty/whitespace hint is an upstream override that suppresses the
+@@ -97,6 +105,31 @@ export default function SubagentDelegationSection({
+
+diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts
+index 429379396..2bb0b10c1 100644
+--- a/gui/src/i18n/de.ts
++++ b/gui/src/i18n/de.ts
+@@ -672,6 +672,12 @@ export const de: Record = {
+ "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?",
+ "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden",
+ "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.",
++ "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten",
++ "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.",
++ "sub.fallbackAdd": "Fallback-Modell hinzufügen…",
++ "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung",
++ "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.",
++ "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden",
+ "logs.title": "Anfrage-Protokolle",
+ "logs.tabLogs": "Protokolle",
+ "logs.tabDebug": "Diagnose",
+diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts
+index 9cbf8699f..e1346616a 100644
+--- a/gui/src/i18n/en.ts
++++ b/gui/src/i18n/en.ts
+@@ -315,6 +315,12 @@ export const en = {
+ "dash.visionTimeout": "Timeout",
+ "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.",
+ "dash.visionAdvancedPopover": "Advanced vision settings",
++ "sub.fallbackLabel": "Sub-agent fallback chain",
++ "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.",
++ "sub.fallbackAdd": "Add fallback model…",
++ "sub.fallbackPoll": "Availability check interval",
++ "sub.fallbackSaved": "Sub-agent fallback settings saved.",
++ "sub.fallbackSaveFailed": "Failed to save fallback settings",
+ "dash.shadowCallIntercept": "Shadow Call Intercept",
+ "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.",
+ "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.",
+diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts
+index ec171e627..d5d29b0be 100644
+--- a/gui/src/i18n/fr.ts
++++ b/gui/src/i18n/fr.ts
+@@ -305,6 +305,12 @@ export const fr: Record = {
+ "dash.visionTimeout": "Délai d’expiration",
+ "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.",
+ "dash.visionAdvancedPopover": "Paramètres de vision avancés",
++ "sub.fallbackLabel": "Chaîne de secours des sous-agents",
++ "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.",
++ "sub.fallbackAdd": "Ajouter un modèle de secours…",
++ "sub.fallbackPoll": "Intervalle de vérification de disponibilité",
++ "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.",
++ "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours",
+ "dash.shadowCallIntercept": "Interception des appels fantômes",
+ "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.",
+ "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.",
+diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts
+index c71bd7a04..747438bdc 100644
+--- a/gui/src/i18n/ja.ts
++++ b/gui/src/i18n/ja.ts
+@@ -632,6 +632,12 @@ export const ja: Record = {
+ "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?",
+ "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました",
+ "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。",
++ "sub.fallbackLabel": "サブエージェントのフォールバックチェーン",
++ "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。",
++ "sub.fallbackAdd": "フォールバックモデルを追加…",
++ "sub.fallbackPoll": "利用可能性チェック間隔",
++ "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。",
++ "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました",
+
+ // logs
+ "logs.title": "リクエストログ",
+diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts
+index 63ac30442..ecc0e4560 100644
+--- a/gui/src/i18n/ko.ts
++++ b/gui/src/i18n/ko.ts
+@@ -689,6 +689,12 @@ export const ko: Record = {
+ "sub.ultraModeLoadFail": "울트라 모드 설정을 불러오지 못했습니다 — 프록시가 실행 중인가요?",
+ "sub.ultraModeSaveFail": "울트라 모드 설정 저장에 실패했습니다",
+ "sub.ultraModeSaved": "울트라 모드가 저장되었습니다. 새 Codex 세션부터 적용됩니다.",
++ "sub.fallbackLabel": "서브에이전트 폴백 체인",
++ "sub.fallbackHint": "서브에이전트 모델을 사용할 수 없거나 실패할 때 순서대로 시도할 모델입니다.",
++ "sub.fallbackAdd": "폴백 모델 추가…",
++ "sub.fallbackPoll": "가용성 확인 간격",
++ "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.",
++ "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다",
+
+ // logs
+ "logs.title": "요청 로그",
+diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts
+index 9f220ba2b..852eb4467 100644
+--- a/gui/src/i18n/ru.ts
++++ b/gui/src/i18n/ru.ts
+@@ -687,6 +687,12 @@ export const ru: Record = {
+ "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?",
+ "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима",
+ "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.",
++ "sub.fallbackLabel": "Цепочка резервных моделей субагента",
++ "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.",
++ "sub.fallbackAdd": "Добавить резервную модель…",
++ "sub.fallbackPoll": "Интервал проверки доступности",
++ "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.",
++ "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей",
+
+ // logs
+ "logs.title": "Журнал запросов",
+diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts
+index aee152cd3..71d9e7313 100644
+--- a/gui/src/i18n/tr.ts
++++ b/gui/src/i18n/tr.ts
+@@ -694,6 +694,12 @@ export const tr: Record = {
+ "sub.ultraModeLoadFail": "Ultra modu ayarları yüklenemedi — proxy çalışıyor mu?",
+ "sub.ultraModeSaveFail": "Ultra modu ayarları kaydedilemedi",
+ "sub.ultraModeSaved": "Ultra modu kaydedildi. Yeni Codex oturumlarına uygulanır.",
++ "sub.fallbackLabel": "Alt ajan yedek zinciri",
++ "sub.fallbackHint": "Alt ajan modeli kullanılamadığında veya başarısız olduğunda sırayla denenecek modeller.",
++ "sub.fallbackAdd": "Yedek model ekle…",
++ "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı",
++ "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.",
++ "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi",
+
+ // logs
+ "logs.title": "İstek Günlükleri",
+diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts
+index 39c9e2f0b..50659c2e6 100644
+--- a/gui/src/i18n/zh-TW.ts
++++ b/gui/src/i18n/zh-TW.ts
+@@ -541,6 +541,12 @@ export const zhTW: Record = {
+ "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?",
+ "sub.ultraModeSaveFail": "儲存超級模式設定失敗",
+ "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。",
++ "sub.fallbackLabel": "子代理備援鏈",
++ "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。",
++ "sub.fallbackAdd": "新增備援模型…",
++ "sub.fallbackPoll": "可用性檢查間隔",
++ "sub.fallbackSaved": "子代理備援設定已儲存。",
++ "sub.fallbackSaveFailed": "備援設定儲存失敗",
+ "logs.title": "請求日誌",
+ "logs.tabLogs": "日誌",
+ "logs.tabDebug": "除錯",
+diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts
+index 1ba4cabfa..ded94d699 100644
+--- a/gui/src/i18n/zh.ts
++++ b/gui/src/i18n/zh.ts
+@@ -682,6 +682,12 @@ export const zh: Record = {
+ "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?",
+ "sub.ultraModeSaveFail": "保存超级模式设置失败",
+ "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。",
++ "sub.fallbackLabel": "子代理回退链",
++ "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。",
++ "sub.fallbackAdd": "添加回退模型…",
++ "sub.fallbackPoll": "可用性检查间隔",
++ "sub.fallbackSaved": "子代理回退设置已保存。",
++ "sub.fallbackSaveFailed": "保存回退设置失败",
+
+ // logs
+ "logs.title": "请求日志",
+diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx
+index 6b54d39ff..299c9306f 100644
+--- a/gui/src/pages/Subagents.tsx
++++ b/gui/src/pages/Subagents.tsx
+@@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface";
+ import { DataSurfaceSkeleton } from "../components/data-surface";
+ import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation";
+
+-type CachedSubagents = { available: string[]; chosen: string[] };
++type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number };
+
+ function seedSubagents(cacheKey: string): CachedSubagents | null {
+ return readSessionListCache(cacheKey);
+@@ -19,6 +19,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
+ const cacheKey = `ocx.subagents.v1:${apiBase}`;
+ const cached = seedSubagents(cacheKey);
+ const [chosen, setChosen] = useState(() => cached?.chosen ?? []);
++ const [fallback, setFallback] = useState(() => cached?.fallback ?? []);
++ const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000);
++ const [fallbackBusy, setFallbackBusy] = useState(false);
+ const [status, setStatus] = useState("");
+ const [ok, setOk] = useState(false);
+ const [busy, setBusy] = useState(false);
+@@ -117,16 +120,24 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
+ const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => {
+ // The resource layer's deadline abort must reach the wire — a signal dropped
+ // here is a store that can only settle by race timeout.
+- const res = await fetch(`${apiBase}/api/subagent-models`, { signal });
+- const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(res, t("sub.loadFail"));
+- if (!response) throw new Error(t("sub.loadFail"));
+- const available = response.available ?? [];
++ const [rosterRes, fallbackRes] = await Promise.all([
++ fetch(`${apiBase}/api/subagent-models`, { signal }),
++ fetch(`${apiBase}/api/subagent-model-fallback`, { signal }),
++ ]);
++ const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(rosterRes, t("sub.loadFail"));
++ const fallbackResponse = await readJsonOrThrow<{ available?: string[]; models?: string[]; pollMs?: number }>(fallbackRes, t("sub.loadFail"));
++ if (!response || !fallbackResponse) throw new Error(t("sub.loadFail"));
++ const available = response.available ?? fallbackResponse.available ?? [];
+ const availableSet = new Set(available);
+ const next = {
+ available,
+ chosen: (response.chosen ?? []).filter(model => availableSet.has(model)),
++ fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)),
++ pollMs: fallbackResponse.pollMs ?? 60000,
+ };
+ setChosen(next.chosen);
++ setFallback(next.fallback);
++ setFallbackPollMs(next.pollMs);
+ writeSessionListCache(cacheKey, next);
+ return next;
+ }, [apiBase, cacheKey, t]);
+@@ -174,7 +185,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
+ const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed"));
+ const applied = d?.applied ?? chosen;
+ if (d?.applied) setChosen(d.applied);
+- writeSessionListCache(cacheKey, { available, chosen: applied });
++ writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs });
+ setOk(true);
+ setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" }));
+ } catch (error) {
+@@ -186,6 +197,28 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
+ }
+ };
+
++ const saveFallback = async () => {
++ if (fallbackBusy) return;
++ setFallbackBusy(true);
++ try {
++ const r = await fetch(`${apiBase}/api/subagent-model-fallback`, {
++ method: "PUT",
++ headers: { "Content-Type": "application/json" },
++ body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }),
++ });
++ const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed"));
++ if (d?.models) setFallback(d.models);
++ if (d?.pollMs) setFallbackPollMs(d.pollMs);
++ setOk(true);
++ setStatus(t("sub.fallbackSaved"));
++ } catch (error) {
++ setOk(false);
++ setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError"));
++ } finally {
++ setFallbackBusy(false);
++ }
++ };
++
+ // The skeleton owns the live region while this resource has no content yet.
+ if (state.showSkeleton && !snapshot) {
+ return ;
+@@ -214,7 +247,13 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
+ busy={busy}
+ onToggle={toggle}
+ onMove={move}
+- onSave={() => { void save(); }}
++ onSave={() => { void save(); }}
++ fallback={fallback}
++ fallbackPollMs={fallbackPollMs}
++ fallbackBusy={fallbackBusy}
++ onFallbackChange={setFallback}
++ onFallbackPollMsChange={setFallbackPollMs}
++ onFallbackSave={() => { void saveFallback(); }}
+ delegation={{
+ model: delegation.model,
+ effort: delegation.effort,
+
+```
+
+Audit amendment: cache server-confirmed fallback values after fallback Save; roster Save preserves committed fallback snapshot, never draft. Add independent-save and remount regressions. Existing dashboard density, CSS tokens, Select and icon library retained; no concept art needed for utility editor.
diff --git a/devlog/_plan/260907_lane_d/000_plan.md b/devlog/_plan/260907_lane_d/000_plan.md
new file mode 100644
index 0000000000..97f6761463
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/000_plan.md
@@ -0,0 +1,32 @@
+# Lane D release-train roadmap
+
+Satisfy-spec HOTL for delegated recommendations #16 → #17 → #15 → #21 → #25.
+Goal: independently audited manual dependent PRs ready for main-session integration.
+Scope: Claude outbound, display-name dialog, usage costs/overlays/summary, usage GUI,
+plus directly required CLI/API/tests/docs. i18n files are append-only shared per main's
+2026-09-07 correction. No other lane-owned files; no merge/release/main/preview.
+No local test/typecheck/build/install. Remote ci.yml lane=all at final top SHA is
+sole product verifier. Local source and diff checks are not execution evidence.
+No user token or wall-clock bound supplied. Use existing repo/GitHub authorization.
+Stop: top-head green with reviewer verdicts and layer PR/SHA evidence; otherwise
+record exact DEFER/BLOCKED reasons without claiming implementation passes.
+Memory/evidence: this unit plus .tmp/lane-d for review drafts. Unpublished security
+material stays in scratch. Reclaim failed delegated work after two distinct agents;
+other-lane file collision requires main coordination.
+
+## Dependency and publication map
+
+| Phase | Item | Outcome | Branch |
+|---|---|---|---|
+| 0 | Roadmap | Lock all diff plans before code | first layer docs |
+| 1 | #3719 slice | Legacy redacted-before-signed SSE/JSON parity | codex/260907-d1-thinking |
+| 2 | receipt guard | Prevent new intent while recovery is pending | codex/260907-d2-receipt |
+| 3 | #3817 | Exact account identity resolves provider overlays | codex/260907-d3-account-prices |
+| 4 | #3667 | Price editor + CLI + authoritative explicit zero | codex/260907-d4-price-editor |
+| 5 | #3379 slice / #2956 | Inclusive custom usage bounds + GUI | codex/260907-d5-usage-ranges |
+| 6 | readiness | Fresh top CI, screenshots and implementation audits | top branch |
+
+All lower subjects include [skip ci]; every push uses --no-verify. Native stack null.
+Only phase 6 dispatches ci.yml lane=all; failures get Astra-high exact-log diagnosis,
+fixes on their owning layer and rebase --update-refs cascade. Main alone merges.
+#3719 and #3379 stay open. #2956 credit uses verified GitHub author identity.
diff --git a/devlog/_plan/260907_lane_d/001_roadmap_audit.md b/devlog/_plan/260907_lane_d/001_roadmap_audit.md
new file mode 100644
index 0000000000..c14a08d2da
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/001_roadmap_audit.md
@@ -0,0 +1,16 @@
+# Roadmap audit resolution
+
+Astra Herschel (01a07b2b-5148-73c0-a067-a13485ab32c9) returned
+GO-WITH-FIXES with four bounded roadmap corrections. All are incorporated in
+040_price_editor.md and 050_usage_ranges.md: register management routes; persist
+manual-price display state; filter individual ledger entries before daily aggregation;
+preserve apiKeyId and scan consistency; define milliseconds and explicit window bounds.
+
+Astra Dirac identified two thinking design blockers, recorded in 010 for re-audit:
+item ownership and simultaneous reasoning/frame retention. Astra Ohm limits the account
+mapping to evidenced Codex identities and requires consistent tier-namespace resolution.
+The first implementation phase must finish those fold-backs before code changes.
+
+Only documentation has changed. Source references were inspected; product tests,
+typecheck, builds and installs are NOT RUN by delegation instruction. Product acceptance
+remains open until top-head Cross-platform CI executes lane=all.
diff --git a/devlog/_plan/260907_lane_d/010_thinking.md b/devlog/_plan/260907_lane_d/010_thinking.md
new file mode 100644
index 0000000000..f2bb7e18bf
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/010_thinking.md
@@ -0,0 +1,26 @@
+# 010 Thinking ordering
+MODIFY src/claude/outbound.ts ensureBlock/closeOpenBlock and reasoning done.
+Before: thinking start/deltas are emitted immediately; done closes thinking then red.
+After: retain already-budgeted thinking text, defer its start/index/delta until close;
+reasoning done emits red blocks before flushing pending signed thinking. Preserve text
+and tool order, hidden env.txt non-disclosure, genuine signature and budget release.
+MODIFY tests/claude-integration/claude-outbound.test.ts: compare collected SSE against
+literal expected content and JSON for combined envelopes with preceding deltas,
+multiple summary parts/red blocks, text prefix, signed-only, red-only. Check sequential
+non-overlapping block indices and cancellation/overflow existing assertions.
+Independent Astra audit must resolve streaming latency and allocation implications.
+
+Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI.
+
+## A audit fold-back
+Astra Dirac found two blockers: unmatched-item reordering and closure memory overlap.
+Track bounded reasoningItemKey separately from part identity; flush on changed explicit
+item identity, and close unrelated pending thinking before another item's red blocks.
+Only same identity (including both omitted) reorders red before pending thinking.
+Retain thinkingBuf through signature emission as before;
+queued frame budget stays authoritative, never weakened. Add near-limit valid control,
+shared-budget collector control, overflow/cancel regressions. Deferred thinking is an
+accepted visible-latency tradeoff; text/tool frames remain live with incremental-reader
+coverage. Late done after a different emitted block cannot reorder earlier content.
+
+Re-audit Dirac: VERDICT PASS, blockers=0. Accept tight artificial budget capacity reduction; retain original overflow assertions and production limits.
diff --git a/devlog/_plan/260907_lane_d/020_receipt.md b/devlog/_plan/260907_lane_d/020_receipt.md
new file mode 100644
index 0000000000..97568c39a8
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/020_receipt.md
@@ -0,0 +1,17 @@
+# 020 Display-name receipt recovery
+MODIFY gui/src/components/ModelDisplayNameDialog.tsx.
+Before: input/reset enabled whenever saving=false; input onEdit clears recovery.
+After: new mutationOutcomeUnknown prop from Models.tsx recovery.confirmed===false
+disables draft editing and reset, submit retains
+read/retry action. Handler guards prevent synthetic events bypassing disabled controls.
+Close/cancel stays available. This is bounded UI recovery, not server request ordering.
+MODIFY gui/tests/models-display-name-editor.test.tsx: unknown receipt cannot replace intent; retry recovers; confirmed saved:true
+and ordinary validation error remain
+editable. Screenshot changed disabled input/reset with retry available.
+
+Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI.
+
+Implementation: unknown outcome guards input/reset handlers and submit, and focuses Retry
+when saving fails without a receipt. Saved:true remains editable. Transport/body failure
+matrix attempts a replacement intent and asserts no second PUT before read-only retry.
+Astra Herschel plan verdict PASS. Screenshots and product execution await top CI artifact.
diff --git a/devlog/_plan/260907_lane_d/030_account_prices.md b/devlog/_plan/260907_lane_d/030_account_prices.md
new file mode 100644
index 0000000000..2ac6e9ccf4
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/030_account_prices.md
@@ -0,0 +1,27 @@
+# 030 Account price identity
+MODIFY src/usage/user-cost-overlays.ts registry refresh and signature/version.
+Before: configured provider set and overlay rows only.
+After: exact account identifiers/log labels from config mapped to established provider
+identity. Include mapping in signature for memo and aggregate cache invalidation.
+MODIFY src/usage/cost.ts resolveMatchedPrice: exact configured namespace and exact
+user overlay precede account identity; unresolved suffix is never guessed/stripped.
+MODIFY tests/usage/usage-cost.test.ts or existing provider-overlay tests: custom account
+id, qualified id, stable log label, configured collision, unrelated hyphenated provider,
+account rename/removal invalidation. Account aliases never become identity authority.
+Audit determines precise supported historical labels from actual producer evidence.
+
+Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI.
+
+Astra Ohm audit corrections: config-only identity mapping supports selectable Codex
+accounts, effective codexAccountLogLabel, exact ID compatibility aliases, and built-in
+main/__main__. Generic OAuth stores are separate and excluded; no free-form inference.
+Use exact configured provider before canonical account identity, exact override first.
+Apply same namespace for context/priority/lower-bound modifiers, preserving attribution.
+Include sorted mapping in version signature, but aliases/plan/reordering stay no-ops.
+
+Implementation: exact selectable account IDs, effective labels and main forms are resolved
+from config at overlay refresh. Only identity changes bump cache versions. Exact configured
+providers and explicit user rows remain isolated; context/Fast/lower-bound use the selected
+price namespace while request attribution is unchanged. Existing memo fast path is retained.
+Regression fixtures cover mappings, collisions, ignored aliases/invalid rows, add/remove/
+label invalidation, presentation no-ops, estimate/attempt/combo and tier parity.
diff --git a/devlog/_plan/260907_lane_d/040_price_editor.md b/devlog/_plan/260907_lane_d/040_price_editor.md
new file mode 100644
index 0000000000..8d79b2160e
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/040_price_editor.md
@@ -0,0 +1,44 @@
+# 040 Manual price editor
+MODIFY src/usage/cost.ts userOverlayMatch: valid operator all-zero row returns user
+price, while generated catalog zeros keep unknown/fallback semantics.
+MODIFY src/server/management/model-routes.ts: exact-provider model-costs GET/PUT,
+validate four finite nonnegative bounded rates or null reset, preserve siblings,
+rollback on persist failure, no routing/catalog mutation required for price-only edits.
+MODIFY src/cli/models-runtime.ts, models-runtime-subcommands.ts and capabilities.ts:
+models set-price provider/model --input N --output N [--cache-read N --cache-write N]
+or --auto. GET for show and PUT for set/reset through existing management client.
+ADD gui/src/components/ModelPriceDialog.tsx; MODIFY Models.tsx and models-shared.ts
+only as needed: edit action, load exact saved override, inputs 4 rates USD/1M,
+save/reset and manual indicator. Reuse dialog/fetch/i18n patterns. All locale keys
+append-only pricing.override.*. Add endpoint, CLI, estimator and GUI regressions;
+register new test files in both append-only layout manifests. Public docs and generated
+CLI surface map mirror actual capability entries; source-generation commands NOT RUN
+locally so map is updated by its source contract without claiming verification.
+
+Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI.
+
+A fold-back: add GET/PUT entries in src/server/management/route-registry.ts.
+Reuse providerModelCostsConfigError. GET returns sanitized per-provider modelCosts map;
+Models owns a typed map loaded with catalog or dedicated GET, so manual badges survive
+reload. CLI omitted cache-read/cache-write rates default to zero, explicitly documented.
+
+P revalidation/API contract: GET /api/providers/{provider}/model-costs returns
+{provider,modelCosts}; PUT accepts {modelId,cost:Cost4|null}, returns
+{ok:true,provider,modelId,cost}. Null deletes only that model key. Models API adds
+manualPricing boolean on applicable rows so badges survive reload, while the dialog
+GET owns editable rates. CLI models price reads; models set-price writes/resets.
+Same C2 phase splits disjoint workers: backend API/CLI/model-row/tests; frontend dialog/
+Models/types/i18n/tests; main owns explicit-zero cost semantics, docs and manifests.
+No worker commits/pushes/runs local checks. Main integrates once both return.
+Main granted D exactly the zero sentence in all seven translated providers config
+reference pages; leave all other sections to E/M. New i18n keys are append-only.
+
+Implementation checkpoint: GET/PUT editor and two CLI verbs share the four-rate store;
+manualPricing is emitted only for exact stored overrides. All-zero user prices are
+known-zero estimates while catalog zero fallbacks remain unchanged. API/CLI and dialog
+regressions cover persistence, reset, sibling isolation, invalid input and unknown receipts.
+All 9 locale catalogs gained matching append-only keys. Seven existing configuration
+rows (English plus six translations) had only the zero sentence updated; zh-tw has no
+modelCosts row on this baseline and was left untouched. CLI surface regenerated by its
+own generator, not a build or test. New backend test names appended to both manifests.
+Local suites/typecheck/build/install NOT RUN; final top CI and screenshot remain open.
diff --git a/devlog/_plan/260907_lane_d/050_usage_ranges.md b/devlog/_plan/260907_lane_d/050_usage_ranges.md
new file mode 100644
index 0000000000..e08d758e5b
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/050_usage_ranges.md
@@ -0,0 +1,49 @@
+# 050 Custom usage windows
+REIMPLEMENT range slice from PR #2956 with Manson2438 credit; do not carry offline reports.
+ADD src/usage/time-range.ts strict timestamp parser and inclusive since/until bounds;
+MODIFY summary.ts accumulator interface to support bounded windows without poisoning
+preset daily aggregates. Use stream ledger filtering for partial days if compact daily
+partitions cannot answer exact boundaries. Reject malformed/reversed bounds at API/CLI.
+MODIFY src/server/management/logs-usage-routes.ts custom-window path before preset cache,
+stream/filter into isolated accumulator preserving surface/provider/model and truncation
+metadata. Do not persist normalized ledger rows. Include bounds in response.
+MODIFY CLI observe/capabilities usage flags and GUI Usage.tsx custom datetime inputs,
+independent draft/applied bounds, cache key includes bounds, grid anchored to effective
+window, clear returns to preset. All locale keys append-only usage.range.*.
+Tests: inclusive boundaries, partial same-day, reversed/invalid, empty ledger, existing
+provider/model/surface filters, preset cache after custom query; GUI apply/clear/errors.
+Public API/CLI docs describe epoch/ISO contract and local datetime conversion.
+
+Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI.
+
+A fold-back: immutable window option on createUsageSummaryAccumulator; add() checks
+inclusive bounds AFTER recording whole-scan snapshot timestamps but BEFORE partitioning.
+clone preserves window. summarize uses window endpoint for grid, actual now for generatedAt;
+retain 366-day grid cap. Custom queries use isolated row-unique accumulator via existing
+getFilteredUsageAggregate with window in key. Reuse overlay/timezone revision restart
+and scanner identity controls. Preserve apiKeyId and current filter echo alongside all
+other filters. USAGE_RANGES remains preset-only; response range stays selected preset
+with customWindow:true, since/until explicit bounds (bounds override preset). API accepts
+integer epoch milliseconds or full ISO-8601 with timezone only; require both bounds;
+reject negative/unsafe/date-invalid/reversed, never normalize overflow dates.
+MODIFY src/cli/usage-report.ts heading prints since/until for customWindow responses.
+GUI datetime values become epoch ms locally; end selected minute includes 59.999s.
+
+P revalidation: custom windows always filter rows before aggregation. Introduce exported
+UsageTimeWindow {since:number,until:number} and immutable optional accumulator window;
+snapshot timestamps update first, clone retains the window, summary returns customWindow:true
+and exact since/until while actual generatedAt stays now. Partition/day filtering must not
+drop the partial first day. Grid uses local calendar day boundaries and caps at 366 days.
+getFilteredUsageAggregate accepts window, keys both bounds, passes window to factory and
+reuses existing revision/timezone/overlay guards. Only-window queries preserve account rows.
+GUI skips held/session report caching for custom windows (arbitrary keys must not grow the
+preset cache); useDataSurface key still includes bounds and unsubscribed stores already evict.
+Workers split backend/API/CLI/tests and GUI/i18n/tests; main owns docs/manifests/generated map.
+
+Implementation checkpoint: shared strict ISO/epoch-ms parser, immutable per-entry window,
+window-keyed filtered cache, API and CLI inclusive bounds, exact interval heading, and
+localized Usage date/time controls are implemented. Custom GUI reports bypass held caches;
+calendar grid stays within the server's bounded days. Tests cover partial/inclusive bounds,
+filters/accounts, cache invalidation, clone/snapshot behavior, empty/error responses and UI
+apply/clear/stale-response paths. New parser test registered in both manifests. ISO fractions
+beyond millisecond precision reject instead of truncating. Product execution NOT RUN locally.
diff --git a/devlog/_plan/260907_lane_d/060_delivery.md b/devlog/_plan/260907_lane_d/060_delivery.md
new file mode 100644
index 0000000000..38bcb1c80a
--- /dev/null
+++ b/devlog/_plan/260907_lane_d/060_delivery.md
@@ -0,0 +1,24 @@
+# 060 Remote verification and delivery
+
+Consume D5's implementation checkpoint. Resolve remaining independent review feedback on
+its owning layer, cascade all dependent refs, and preserve contributor trailers. Detailed
+unpublished security-review notes stay in scratch. Reconcile A's added reasoning-envelope
+budget arguments with D1 ordering when A reaches dev; preserve both changes.
+
+Fetch fresh dev before final dispatch. Run only the top branch's ci.yml workflow with
+lane=all; require successful actual platform jobs including Windows on the exact head.
+Download its dashboard-preview artifact and verify build-commit/build-gui-tree markers.
+Capture the changed dialogs and custom Usage range with synthetic data through the existing
+browser capability; publish proof images separately so evidence does not change tested code.
+
+Create D2-D5 PRs with the required template, screenshot, manual chain table and native
+stack:null proof. Attach independent implementation/security verdicts and top CI URL to
+each PR. Leave all merges and original issue/PR closure actions to the main task.
+Local product tests/typecheck/build/install remain NOT RUN. D closes only when exact-head
+remote evidence and the requested handoff table are complete.
+
+Calendar audit fold-back: custom heatmaps iterate the server's returned civil dates,
+using UTC only for weekday/month layout; they do not step a local midnight cursor.
+The server's backward calendar walk resets midnight after decrement and explicitly
+advances to the prior existing local day if a whole-day timezone jump prevented progress.
+Regressions pin America/Santiago (2026-09-05..07) and Pacific/Apia (2011-12-29..31).
diff --git a/devlog/_plan/260907_next_release_recommendations/000_plan.md b/devlog/_plan/260907_next_release_recommendations/000_plan.md
new file mode 100644
index 0000000000..3febda57ea
--- /dev/null
+++ b/devlog/_plan/260907_next_release_recommendations/000_plan.md
@@ -0,0 +1,28 @@
+# 000 — Plan: next-release recommendation report (wp1)
+
+Unit: devlog/_plan/260907_next_release_recommendations
+Class: C2 (docs-only deliverable; research via read-only explorer lanes)
+Goal: rank 10–30 items to land on `dev` before the release after v2.46.0 (dev open at 2.47.0).
+
+## Diff-level plan
+- Write scope: this directory only (000_plan.md, 010_recommendations.md). No src/gui/docs-site edits.
+- Branch: codex/260907-next-release-recommendations (local commit only; no push/merge).
+- Lanes (each an independent astra-high explorer, read-only):
+ - L1 non-draft (`review-ready` label) PRs: #3858 #3845 #3843 #3840 #3839 #3837 (+ #3748 #3742 enhancement review-ready; #2805 maintainer-sponsored)
+ - L2 draft bug PRs + small feature: #3863 #3862 #3860 (open, feature) #3856 #3849 #3848 #3841 #3838 #3769 (+ hygiene-blocked flags)
+ - L3 open bug issues without PR: #3807 #3782 #3781 #3775 #3765 #3761 #3719 #3675 #3661 #3657 #3644 #3522 #3506 #3464 #3433
+ - L4 open enhancement issues + older draft feature PRs worth carrying: #3859 #3817 #3729 #3630 #3573 #3266 #3336 #3389 #2280/#2279 #3652 #3635 #2805
+ - L5 devlog/_plan residual work (units dated 260905–260907, plus older units with open TODOs)
+ - L6 post-2.46.0 regressions: dev CI status, main..dev delta, release follow-up notes in devlog/_fin/260907_release_246
+ - L7 catch-all PRs (audit round 1 blocker 1): #3833 #3810 #3741 #3738 #3709 #3663 #3648 #3639 #3532 #3463 #3458 #3451 #3350 #3349 #3340 #3283 #3282 #3252 #3080 #3025 #3010 #2956 #2921 #2881 #2562 #2527 #2462 #2366 #2362 #2355 #2351 #2244 #2230 #2213 #2033 #1645
+ - L8 catch-all issues (audit round 1 blocker 2): #3777 #3774 #3705 #3667 #3666 #3494 #3459 #3417 #3379 #3377 #3376 #3375 #3320 #3255 #3245 #3191 #2894 #2834 #2811 #2730 #2511 #2495 #2455 #2358 #1811 #1782 #1711 #1533 #1416 #1213 #95 (L3 already covers #3861 #3857 #3855 #3846)
+ - Inventory reconciliation: 010 must carry a dated appendix listing every open PR (59 at audit time) and open issue (57) with lane + disposition, so coverage is checkable by diffing against `gh pr list`/`gh issue list`.
+- Each lane returns: per item -> disposition, risk class, evidence anchors (path:line / URL), overlap notes, effort.
+- Main session merges lane returns, dedups, ranks, writes 010_recommendations.md.
+
+## Acceptance (from goalplan c-1..c-3; tightened after audit round 1)
+- 10–30 ranked items. Each item has: source id, disposition, risk class, effort, ≥1 evidence anchor gathered this session (GitHub URL or path:line), and a one-line ranking rationale under the stated criteria (user impact × risk × effort × contributor-credit cost).
+- Appendix reconciles the full open PR/issue inventory (every number appears once with lane + disposition); overlaps between PRs and issues are recorded as explicit pairs.
+- `bun run privacy:scan` exit 0 on the report commit; commit contains only the two files in this directory (`git show --stat` as proof).
+- ≥5 anchors spot-checked live by the main session, with the anchor, command, and result recorded in 010's verification section.
+- Security: only already-public evidence (existing issues/PRs/diffs) may be cited; no new weakness is written here (AGENTS.md security working notes).
diff --git a/devlog/_plan/260907_next_release_recommendations/010_recommendations.md b/devlog/_plan/260907_next_release_recommendations/010_recommendations.md
new file mode 100644
index 0000000000..696c974057
--- /dev/null
+++ b/devlog/_plan/260907_next_release_recommendations/010_recommendations.md
@@ -0,0 +1,227 @@
+# 010 — Next-release landing recommendations (dev after v2.46.0)
+
+Snapshot: 2026-09-07, `origin/dev@ece556a6e` (package 2.47.0). Latest exact-head Cross-platform CI on dev: success
+(run 34091933836; Windows full suite dispatch-only by policy). No open 2.46 regression issue found; #3782 is the only
+open 2.45-tagged report and predates 2.45.
+
+Method: eight read-only astra-high explorer lanes (L1–L8 in 000_plan.md) over every open PR (59) and issue (57),
+plus devlog/_plan 2609xx residuals and devlog/_fin/260907_release_246. All evidence below was gathered this session
+from live GitHub/git; behind-dev counts are exact-SHA comparisons against `ece556a6e`. Dispositions are
+maintainer-facing judgments, not merge approvals. Carrying any contributor PR requires `cherry-pick -x` plus a
+surviving `Co-authored-by` trailer (AGENTS.md "Landing another author's work").
+
+Ranking criteria: user impact × inverse risk class × inverse effort × contributor-credit cost of waiting.
+Effort: S ≤ half day, M ≤ 2 days, L > 2 days.
+
+## Ranked list (27 items)
+
+| # | Source | What | Cat. | Disposition | Risk / Effort | Rationale | Evidence |
+|---|---|---|---|---|---|---|---|
+| 1 | PR #3862 → #3861 (Ingwannu) | Admit reasoning-envelope allocations before materialization | bug | LAND_WITH_FIX (security sign-off + Windows-shard evidence) | C4 / M | Availability hardening, maintainer-authored, exact-head `ci: SUCCESS` (run 34098616286); 9 behind; draft. Highest-priority review. | `src/responses/reasoning-envelope.ts:70` at head `9bcb7748f`: `activeBudget.reserveTransient(8 * encryptedContent.length, …)`; #3861 "The unchanged base fails nine admission regressions" |
+| 2 | PR #3858 → #3857 (makesomethingshit) | Pi/OpenCode Go session affinity through native Chat and bridges | bug | LAND_WITH_FIX (reconcile readiness contradiction, classify residual failures) | C3 / M | 0 behind, review-ready, strong header-capture tests. Body still says "Readiness remains blocked" while boxes are 4/4 — verify before merge. | `src/server/chat-completions.ts:174` (dev) `return handleNativeChatCompletions({`; PR diff `compat: { sendSessionAffinityHeaders: true }` |
+| 3 | PR #3840 (chilung-cgu) | Route Responses-only Copilot GPT/Grok/MAI models correctly | bug | LAND_AS_IS (after ancestry refresh + head CI) | C2 / S | 13 behind, all 4 threads resolved, endpoint-capture tests 5 models × 3 inbound formats. | `src/providers/registry.ts:3084` at head: `"gpt-6-astra": "openai-responses",` |
+| 4 | PR #3863 (x3M3x) | Dashboard settings load no longer blocks on Windows health probe | bug | LAND_WITH_FIX (keep fresh cache non-stale; handle probe rejection; controlled timing test) | C2 / S | 0 behind; mechanism substantiated; one CodeRabbit finding open. Windows user pain. | head `startup-health-cache.ts:66`: `return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config);`; discussion_r3948034138 |
+| 5 | PR #3837 (luvs01) | Gate Kiro request diagnostics behind debug check | bug | LAND_WITH_FIX (isolate `OCX_DEBUG` in test) | C1 / S | 25 behind; CHANGES_REQUESTED by Ingwannu with one concrete test fix. | pullrequestreview-5127337985 "One test correction is needed before approval."; discussion_r3945935220 |
+| 6 | PR #3843 (luvs01) | Bound streaming citation-marker span | bug | LAND_WITH_FIX (same-delta malformed text must be emitted verbatim + regression) | C2 / S | 25 behind; one unresolved major finding contradicts findings-resolved box. | head `src/responses/citation-markers.ts:78`: `MAX_STREAMING_MARKER_SPAN_LENGTH = 4_096`; discussion_r3946034145 |
+| 7 | PR #3845 (luvs01) | Refuse keychain restore across provider ownership | bug | LAND_AS_IS (explicit credential-security review) | C4 / S | 25 behind; small, tests cover foreign-ref rejection and own-account restore. | head `src/providers/key-store.ts:202`: `const foreign = refs.filter(ref => !keychainReferenceBelongsToProvider(ref, name));` |
+| 8 | PR #3839 + #3841 (luvs01) | Bound Anthropic web-search and vision sidecar SSE/error bodies (pair) | bug | LAND_WITH_FIX (error-body cap + cancellation tests; pin partial-description behavior) | C4 / S each | Same 64 KiB policy, disjoint files; land as a pair. #3841 is draft 0/4, #3839 review-ready. | `src/web-search/anthropic-executor.ts:226` `readBoundedText(res)`; `src/vision/anthropic-describe.ts:14` `MAX_SIDECAR_RESPONSE_BYTES = 64 * 1024` |
+| 9 | PR #3860 (RobinBially) | Opt-in Codex Desktop sign-in toggle in GUI | feature | LAND_AS_IS (security review; default OFF) | C4 / S | Became review-ready 4/4 during this session, 0 behind, screenshot present, replaces #3689. | PR body "an explicit opt-in, default **OFF**"; issuecomment-5567316521 |
+| 10 | PR #3849 → #3781 (hualiny) | Admit Mihomo IPv6 fake-IP under TUN transparency exception | bug | LAND_WITH_FIX (IPv6-only path + `NO_PROXY` negative tests; SSRF boundary review) | C4 / S | 11 behind (over 10-commit readiness tolerance), 0/4 boxes; narrow patch; complements landed #3799. | head `src/lib/provider-outbound.ts:147`: `const allowMihomoIpv6FakeIp = (effectiveProxy !== null && !noProxyMatches(parsed))` |
+| 11 | PR #3856 → #3855 (terrytan95) | Sustain quota window activation after reset | bug | LAND_WITH_FIX (maintainer sponsorship clears `unsponsored_surface`; serial with #3848) | C4 / M | 0 behind, 3/4 boxes, hygiene-blocked only by sponsorship gate; overlaps #3848 in `auth-api.ts`/`quota-auto-refresh.ts`. | dev `src/codex/quota-auto-refresh.ts:103`: `await warmCodexAccount(await getValidCodexToken(accountId));`; issuecomment-5565953215 "hygiene: unsponsored_surface" |
+| 12 | PR #3838 (jpierrevd) | Lower Codex-private input items Console Go rejects | bug | LAND_WITH_FIX (parent-namespace child identity; keep nameless built-ins; two regressions) | C3 / M | 25 behind, 0/4; author reports 400→200 on 70-item replay. Complements #3858. Commit author identity generic — resolve before carry. | head `src/adapters/opencode-go.ts:83`: `const kept = (tool.tools as unknown[]).filter(child => claim(child));`; issuecomment-5564388455 |
+| 13 | PR #2033 (louis-tepe) | Expose web-search sidecar enabled status in GET/PUT | bug | REIMPLEMENT (two serialization lines + regression; Co-authored-by) | C1 / S | 1364 behind but omission confirmed on dev; cheapest credit-preserving carry in the backlog. | PR #2033 (draft, gates PASS); L7 confirmed omission on `origin/dev` management routes |
+| 14 | PR #3532 (Ingwannu) | Make CI completion audit fail closed (devlog docs) | hygiene | LAND_WITH_FIX (refresh onto dev; verify current gate names) | C0 / S | Non-draft, two doc files, 829 behind but docs-only. | PR #3532 head CI SUCCESS (runtime jobs skipped) |
+| 15 | Issue #3817 (rrmlima) | Apply base-provider price overlays to all account log labels | bug | LAND_WITH_FIX (implement: use account→provider identity, no suffix stripping) | C2 / M | Cost-reporting correctness for pool users; bounded in `src/usage/cost.ts`. | dev `src/usage/cost.ts:193` comment on suffix/base-provider pricing boundary |
+| 16 | Issue #3719 residual (lidge-jun) | Streaming reverses signed/redacted thinking order vs JSON | bug | REIMPLEMENT (ordering parity + tests incl. preceding deltas) | C4 / M | Concrete, explicitly deferred in release-246 review; separate from the larger replay/cache acceptance work (DEFER). | `devlog/_fin/260907_release_246/020_progress.md:9` "explicit deferral, not a fix"; dev `src/claude/outbound.ts:569` `closeOpenBlock();` before red loop at 575; JSON emits red first at 823 |
+| 17 | release-246 follow-up | Display-name editor unknown-receipt recovery guard | bug | REIMPLEMENT (bounded recovery guard) | C2 / M | P2 label-only follow-up recorded at release; reversible. | `devlog/_fin/260907_release_246/090_delivery.md:29`; `ModelDisplayNameDialog.tsx:140` `disabled={saving}`; discussion_r3946496126 |
+| 18 | release-246 follow-up | Publication-aware registry-smoke recovery in release.yml | hygiene | REIMPLEMENT (no republish; treat accepted publish + smoke timeout as recoverable) | C4 / M | Both 2.45/2.46 release runs hit the 5-minute smoke timeout; manual recovery each time. Release-surface → security review. | `.github/workflows/release.yml:355` `for attempt in $(seq 1 30); do`, `:363 sleep 10`; 090_delivery.md:27 |
+| 19 | release-246 follow-ups (bundle) | Raycast unsupported-platform copy + CLI text assertions + 7 provider-locale editor sections + French integrations prose | hygiene | REIMPLEMENT (one docs/CLI PR) | C1 / S–M | All named at release close; zero runtime risk. | 090_delivery.md:29; discussion_r3946497677, r3946496225, r3946496426, r3946496024; `raycast-detect.ts:108` |
+| 20 | 260907_code_mode_host_contract + #3782 docs | Append `040_delivery_record.md` for #3854; qualify Claude Desktop `/model` workaround; translate new code-mode paragraph (7 locales) | hygiene | LAND_WITH_FIX (docs only) | C0 / S | Closes the open unit and answers #3782 honestly (client-owned failure). | `devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md:80` and `:55`; `docs-site/src/content/docs/guides/claude-code.md:312`; #3782 issuecomment-5565317534 |
+| 21 | Issue #3667 (nordz0r) | Manual price override editor/CLI over existing `modelCosts` | feature | REIMPLEMENT (expose existing store; resolve explicit-zero semantics) | C2 / M | Backend already exists; UI/CLI gap only. Pairs with #15. | dev `src/usage/user-cost-overlays.ts:240-250` `const costs = provider?.modelCosts;` |
+| 22 | Issue #1533 (Zbyy0311) | Explain native-parent/routed-child V2 compatibility state in GUI | feature | REIMPLEMENT (state-aware guidance near preferred worker; no routing change) | C2 / S | Long-open UX ask, small, reads existing agent-settings API. | dev `src/server/management/agent-settings-routes.ts:248` |
+| 23 | PR #3252 (x3M3x) | GUI editor for existing sub-agent fallback API | feature | LAND_WITH_FIX (repair JSON-encoded body; drop roster-switch claims; keep unavailable configured models; focused GUI tests) | C2 / M | 175 behind, hygiene-blocked by body format; overlaps #22's surface — land #22 guidance inside this panel. | PR #3252 gates FAIL (body) |
+| 24 | Issue #3774 (leonclab) | Drag-and-drop `modelPickerOrder` | feature | REIMPLEMENT (on top of landed presets #3801) | C3 / M | Presets landed; DnD residual; define native/featured row behavior first. | dev `gui/src/model-picker-order.ts:56`; `gui/src/pages/Models.tsx:1823` |
+| 25 | Issue #3379 usage-range slice ← PR #2956 (Manson2438) | Custom usage time ranges (slice only; not offline reports/picker) | feature | REIMPLEMENT slice with Co-authored-by | C2 / M | #2956 is 1304 behind/DIRTY; the range slice is small on current code. | dev `src/usage/summary.ts:15` `USAGE_RANGES = ["today", "7d", "30d", "all"]`; `gui/src/pages/Usage.tsx:14` |
+| 26 | PR #3769 residual (ideabib) | Native compact 404 → routed compaction fallback (quota half already landed via #3791) | bug | REIMPLEMENT residual only (canonical-forward streaming test) | C4 / M | 180 behind, DIRTY, 3 unresolved threads; do not re-land the quota classifier. | discussion_r3943911361 "Add a canonical-forward streaming fallback test."; #3795 closed against v2.46.0 |
+| 27 | PR #3336 (Liang-Psych) | Per-model pinned reasoning-effort overrides | feature | LAND_WITH_FIX (carry; adapt to current tests/docs) | C3 / M | 980 behind, 3/4 boxes, earlier cap/key findings fixed. Strongest older contributor carry; last in this batch because of drift. | head `src/server/chat-native.ts:165` `applyChatEffortCap(...)` |
+
+Suggested batching: items 1–8 first (bug fixes, all S/M, mostly review-ready), then 9–13 (C4 small + carries), then
+14–20 (docs/release hygiene, can run in parallel), then 21–27 (feature slices as capacity allows). Serialize #11 → #3848
+(item in DEFER) on `src/codex/auth-api.ts`; serialize #2 → #12 on OpenCode Go adapter; land #22 inside #23's panel.
+
+## Overlap pairs recorded
+
+#3861↔#3862; #3857↔#3858; #3855↔#3856; #3846↔#3848 (both touch `auth-api.ts`, `quota-auto-refresh.ts`);
+#3781↔#3849; #3459↔#3463; #2894↔#2921↔#3741; #3376↔#2881↔#3856; #3375↔#2562↔#3283↔#3738; #3377↔#3282;
+#3379↔#2956; #1533↔#3252; #3667↔#3817↔#3666; #3630↔#3729; #2279↔#2280↔#3336; #3839↔#3841 (pair);
+#3858↔#3838 (OpenCode Go); #3840↔#2805↔#3838 (registry); #3765↔#3433↔#3719 (cache/replay).
+
+## DEFER (needs evidence, sponsorship, or a dedicated train — not for this release)
+
+Issues awaiting reporter/field evidence: #3807 (raw synthetic repro), #3782 (client-owned; docs only in #20), #3775
+(gateway capability), #3765/#3433 (matched cache identity evidence), #3657 (transport boundary), #3644 (categorized
+TUN/system-proxy A/B), #3522 (same-process ACL evidence), #3661 (encrypted multipart contract), #3320/#3245 (needs-info).
+PRs needing security review or coordination: #3848 (61 files, LAND_WITH_FIX after #3856 and sponsorship), #3742 (Cursor
+pool kernel, stale verification SHA), #3748 (telemetry ledger, 221 behind), #3833 (Command Code credential refs),
+#3463, #3389, #3652, #3635 (REIMPLEMENT later), #2921, #2280, #2366, #2362, #2355, #2213, #2230, #1645, #3741, #3738,
+#3709, #3663, #3639, #3451, #3350/#3349/#3340 (provider train), #3282, #3080, #2562, #2956 (beyond the #25 slice).
+Issues DEFER: #3666, #3630, #2279, #1711, #3777, #3859, #3573, #3266, #3729, #3417, #3459, #2894, #3761, #3506.
+devlog residuals DEFER: #3719 replay/cache acceptance, #3348-B cooldown persistence, #3383 Windows temp proposal,
+split-train 840/850 evidence, image roundtrip remote/OCR, macOS client-connect stall instrumentation.
+
+## NOT_NOW (explicit)
+
+#3810 (Go runtime line; AGENTS.md "New work does not go here"), #2805 (1488 behind, CONFLICTING → REIMPLEMENT as scoped
+carries later), #3458, #3025, #3010, #2881, #2527, #2462, #2351, #2244, #3283, #3648; issues #3705, #3494, #3377,
+#3376, #3375, #3255, #3191, #2834, #2811, #2730, #2511, #2495, #2455, #2358, #1811, #1782, #1416, #1213, #95, #3464,
+#3675, #3506; devlog: #3348-C/quota cooldown/raw-key signature, split-train modularization debt, apply-patch envelope
+quotation tradeoff, Windows full-suite gate restoration (#1059 closed policy).
+
+## Verification (main session, live)
+
+Anchor spot-check on `origin/dev@ece556a6e` via `git show origin/dev: | sed -n p`:
+
+| Anchor | Result |
+|---|---|
+| `src/server/chat-completions.ts:174` | match: `return handleNativeChatCompletions({` |
+| `src/codex/quota-auto-refresh.ts:103` | match: `await warmCodexAccount(await getValidCodexToken(accountId));` |
+| `src/usage/summary.ts:15` | match: `USAGE_RANGES = ["today", "7d", "30d", "all"]` |
+| `src/web-search/index.ts:223` | match: `if (!parsed._webSearch || isPassthrough) return undefined;` |
+| `.github/workflows/release.yml:355` | match: `for attempt in $(seq 1 30); do` |
+| `src/claude/outbound.ts:569` | match: `closeOpenBlock();` |
+| `src/server/request-decompress.ts:22` | match: `MAX_DECOMPRESSED_BODY_BYTES = 256 * 1024 * 1024` |
+| `src/usage/cost.ts:193` | near: line is the comment block the lane paraphrased |
+| `src/responses/citation-markers.ts:78`, `src/server/relay.ts:462` | PR-head anchors (#3843, #3652), not dev; dev line differs as expected |
+
+GitHub state re-read: #3860 draft=false labels enhancement,review-ready head 0f21769f3; #3837 reviewDecision
+CHANGES_REQUESTED head d5d711a7b; #3858 draft=false review-ready head 23d869350; #3862 draft=true head 9bcb7748f;
+#3856 labels bug, intake: hygiene-blocked; #2033 draft, title "Expose web search sidecar enabled status".
+
+`bun run privacy:scan` on the report commit: see 000_plan.md acceptance; result recorded in the D attest.
+
+## Appendix A — open PR inventory (59) with lane and disposition
+
+| PR | Lane | Disposition |
+|---|---|---|
+| 3863 | L2 | LAND_WITH_FIX (#4) |
+| 3862 | L2 | LAND_WITH_FIX (#1) |
+| 3860 | L2 | LAND_AS_IS (#9) |
+| 3858 | L1 | LAND_WITH_FIX (#2) |
+| 3856 | L2 | LAND_WITH_FIX (#11) |
+| 3849 | L2 | LAND_WITH_FIX (#10) |
+| 3848 | L2 | DEFER (after #3856; sponsorship) |
+| 3845 | L1 | LAND_AS_IS (#7) |
+| 3843 | L1 | LAND_WITH_FIX (#6) |
+| 3841 | L2 | LAND_WITH_FIX (#8) |
+| 3840 | L1 | LAND_AS_IS (#3) |
+| 3839 | L1 | LAND_WITH_FIX (#8) |
+| 3838 | L2 | LAND_WITH_FIX (#12) |
+| 3837 | L1 | LAND_WITH_FIX (#5) |
+| 3833 | L4/L7 | DEFER (credential refs review) |
+| 3810 | L4/L7 | NOT_NOW |
+| 3769 | L2 | REIMPLEMENT residual (#26) |
+| 3748 | L1 | DEFER |
+| 3742 | L1 | DEFER |
+| 3741 | L7 | DEFER |
+| 3738 | L7 | DEFER |
+| 3709 | L7 | DEFER |
+| 3663 | L7 | DEFER |
+| 3652 | L4 | DEFER |
+| 3648 | L7 | NOT_NOW |
+| 3639 | L7 | DEFER |
+| 3635 | L4 | REIMPLEMENT later (DEFER) |
+| 3532 | L7 | LAND_WITH_FIX (#14) |
+| 3463 | L4/L7 | DEFER |
+| 3458 | L7 | NOT_NOW |
+| 3451 | L7 | DEFER |
+| 3389 | L4 | DEFER |
+| 3350 | L7 | DEFER |
+| 3349 | L7 | DEFER |
+| 3340 | L7 | DEFER |
+| 3336 | L4 | LAND_WITH_FIX (#27) |
+| 3283 | L7 | NOT_NOW |
+| 3282 | L7 | DEFER |
+| 3252 | L7 | LAND_WITH_FIX (#23) |
+| 3080 | L7 | DEFER |
+| 3025 | L7 | NOT_NOW |
+| 3010 | L7 | NOT_NOW |
+| 2956 | L5/L7 | DEFER (slice via #25) |
+| 2921 | L4/L7 | DEFER |
+| 2881 | L7 | NOT_NOW |
+| 2805 | L1 | NOT_NOW (REIMPLEMENT as carries later) |
+| 2562 | L7 | DEFER |
+| 2527 | L7 | NOT_NOW |
+| 2462 | L7 | NOT_NOW |
+| 2366 | L7 | DEFER |
+| 2362 | L7 | DEFER |
+| 2355 | L7 | DEFER |
+| 2351 | L7 | NOT_NOW |
+| 2280 | L4 | DEFER |
+| 2244 | L7 | NOT_NOW |
+| 2230 | L7 | DEFER |
+| 2213 | L7 | DEFER |
+| 2033 | L7 | REIMPLEMENT (#13) |
+| 1645 | L7 | DEFER |
+
+## Appendix B — open issue inventory (57) with lane and disposition
+
+| Issue | Lane | Disposition |
+|---|---|---|
+| 3861 | L3 | via PR #3862 (#1) |
+| 3859 | L4 | DEFER |
+| 3857 | L3 | via PR #3858 (#2) |
+| 3855 | L3 | via PR #3856 (#11) |
+| 3846 | L3 | via PR #3848 (DEFER) |
+| 3817 | L4 | LAND_WITH_FIX (#15) |
+| 3807 | L3/L5 | DEFER (repro) |
+| 3782 | L3/L6 | DEFER; docs in #20 |
+| 3781 | L3 | via PR #3849 (#10) |
+| 3777 | L4/L8 | DEFER |
+| 3775 | L3/L5 | DEFER |
+| 3774 | L4/L8 | REIMPLEMENT (#24) |
+| 3765 | L3 | DEFER |
+| 3761 | L3/L5 | DEFER |
+| 3729 | L4 | DEFER |
+| 3719 | L3/L5 | REIMPLEMENT ordering (#16); rest DEFER |
+| 3705 | L8 | NOT_NOW |
+| 3675 | L3 | NOT_NOW |
+| 3667 | L4/L8 | REIMPLEMENT (#21) |
+| 3666 | L4/L8 | DEFER |
+| 3661 | L3 | DEFER |
+| 3657 | L3 | DEFER |
+| 3644 | L3/L5 | DEFER |
+| 3630 | L4 | DEFER |
+| 3573 | L4 | DEFER |
+| 3522 | L3/L5 | DEFER |
+| 3506 | L3/L5 | DEFER |
+| 3494 | L8 | NOT_NOW |
+| 3464 | L3 | NOT_NOW |
+| 3459 | L4/L8 | DEFER (via #3463) |
+| 3433 | L3/L5 | DEFER |
+| 3417 | L4/L8 | NOT_NOW |
+| 3379 | L8 | REIMPLEMENT slice (#25) |
+| 3377 | L8 | NOT_NOW |
+| 3376 | L8 | NOT_NOW |
+| 3375 | L8 | NOT_NOW |
+| 3320 | L5/L8 | NOT_NOW (needs-info) |
+| 3266 | L4 | DEFER |
+| 3255 | L8 | NOT_NOW (needs-info) |
+| 3245 | L5/L8 | NOT_NOW (needs-info) |
+| 3191 | L8 | NOT_NOW |
+| 2894 | L4/L8 | DEFER |
+| 2834 | L8 | NOT_NOW |
+| 2811 | L8 | NOT_NOW |
+| 2730 | L8 | NOT_NOW |
+| 2511 | L8 | NOT_NOW |
+| 2495 | L8 | NOT_NOW |
+| 2455 | L8 | NOT_NOW |
+| 2358 | L8 | NOT_NOW |
+| 2279 | L4 | DEFER |
+| 1811 | L8 | NOT_NOW (needs-info) |
+| 1782 | L8 | NOT_NOW (needs-info) |
+| 1711 | L4/L8 | DEFER |
+| 1533 | L8 | REIMPLEMENT (#22) |
+| 1416 | L8 | NOT_NOW |
+| 1213 | L8 | NOT_NOW |
+| 95 | L8 | NOT_NOW (roadmap) |
+
diff --git a/devlog/_plan/260907_platform_validation/000_plan.md b/devlog/_plan/260907_platform_validation/000_plan.md
new file mode 100644
index 0000000000..d1b3cb632f
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/000_plan.md
@@ -0,0 +1,31 @@
+# Platform verification follow-up
+
+Baseline: dev `137d6a7270e7ecfb1c791993800a17c0e30022d9` (2026-09-07).
+
+## Objective and authority
+
+Satisfy the existing platform contracts for #3383, #3449, #3522 and #3573. The owner requested ordinary manual PRs, top-of-stack CI first, lower-layer CI only to diagnose a failed final run, no local test suites, push with --no-verify, admin merge after verification, and original contributor credit in commit trailers. No native GitHub stack registration. No publish, release, global settings changes, admission-limit increases, ACL relaxation, or speculative recovery policy.
+
+The initial assigned checkout contains unrelated dirty work and is preserved. Work lives in an isolated worktree. No SessionStart FSM binding is available in the supplied context; this record documents the work without claiming automatic loop continuation is armed.
+
+## Evidence and scope
+
+Dockerfile, compose.yaml, docker/bootstrap-token.ts and the source-build guide already exist. Cross-platform CI has no real image build/start/recreate check. #3522 requires same-process Windows recovery evidence; #3573 requires actual rejected compact-byte evidence. Existing diagnostics must be checked before adding anything. PR #3383 is a mixed historical source: only Windows temp/teardown residuals are in scope, not picker controls.
+
+Original Docker contributor: Buseong Kim , verified from original #3421 commit metadata. Carry this identity in commit trailers.
+
+## Dependency map
+
+1. `010_oauth_teardown.md`: drain the asynchronous ACL fixture before deletion.
+2. `020_container_smoke.md`: executable isolated container acceptance probe.
+3. `030_container_ci.md`: CI consumes that probe and gates its result.
+4. `035_body_diagnostics.md`: distinguish declared size, observed lower bound, and decoded size without changing admission.
+5. `040_residual_evidence.md`: settle the Windows/spill/compact residuals; implement only a proven narrow gap through a plan amendment, otherwise preserve open status.
+
+The manual review chain contains the independent OAuth fixture carry, bounded body diagnostics, the container probe, then its dependent CI integration. Independent code is prepared in disjoint files; the top CI validates their combined tree. Existing workflow triggers remain honest: final branch workflow_dispatch supplies the complete integration result; lower PR runs are not represented as passed if skipped/cancelled. Every implemented layer is reviewed, and final head is pinned before CI. After successful final CI, merge bottom-up using merge commits so reviewed commit ancestry survives. Revalidate the resulting integration and distinguish unrelated concurrent dev changes.
+
+## Verification and completion
+
+Local suites and typecheck are NOT RUN by owner instruction. Syntax and read-only diff checks are allowed. The real verifier is GitHub Cross-platform CI on the final branch, including the new Docker job. A failed final run is diagnosed on the smallest affected scope; do not repeatedly run passing gates. Independent Astra high review covers functionality and workflow/security boundaries. Security working notes remain in scratch, not this public unit.
+
+Completion means verified deliverable PRs merged with commit attribution, plus explicit no-op/blocked disposition for unavailable field evidence. It does not mean every original issue is fixed. New product/security policy choices remain outside scope. Evidence and final outcome are appended to this unit; workflow run URLs and SHAs are preserved.
diff --git a/devlog/_plan/260907_platform_validation/001_plan_audit.md b/devlog/_plan/260907_platform_validation/001_plan_audit.md
new file mode 100644
index 0000000000..96ac86c266
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/001_plan_audit.md
@@ -0,0 +1,5 @@
+# Plan audit disposition
+
+Independent Astra high reviewer: NEAR-PASS. OAuth teardown and bounded body diagnostics passed within scope. Three Docker/CI conditions were incorporated before implementation: explicit final lane=all executed-job inventory; isolated project/image/port and bounded cleanup; concrete readiness/admission/catalog/persistence checks before and after actual replacement.
+
+Main judgment: pass with those amendments. Scope remains unchanged: existing Docker contract verification, test-fixture teardown, bounded diagnostics. Live spill recovery and exact historical compact-body proof remain deferred. No local suites or typecheck were run.
diff --git a/devlog/_plan/260907_platform_validation/010_oauth_teardown.md b/devlog/_plan/260907_platform_validation/010_oauth_teardown.md
new file mode 100644
index 0000000000..d4ee405020
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/010_oauth_teardown.md
@@ -0,0 +1,14 @@
+# OAuth fixture teardown carry
+
+Original source: #3383 commit 51726d2c7c58146defdd6088aefa2b95a1e58553.
+Original contributor: x3M3x (Git commit metadata).
+
+## Concrete delta
+
+MODIFY `tests/oauth/oauth-store-multi.test.ts` only: import flushConfigDirHardeningForTests and the async ICACLS test runner; stub synchronous and asynchronous runners consistently in setup. Change teardown to await the tracked hardening work before resetting runners/caches, restoring OPENCODEX_HOME, or removing the fixture. Preserve removeTreeWithRetry and all production semantics. Add a deterministic held-async-runner regression against the actual cleanup routine if the existing fixture seams allow it without a new production test API.
+
+Production path proof: store reads call hardenConfigDir; config/paths tracks asynchronous directory hardening; resetHardenedStateForTests clears caches but does not drain those jobs. Deletion retries alone do not ensure ordering. The prior carry #3258 only replaced the removal function.
+
+## Acceptance
+
+No real asynchronous ICACLS escapes the fixture runner. Cleanup waits while a controlled ACL flight is unresolved and only deletes/restores environment after completion. The same OAuth test file passes in final Linux/macOS/Windows CI. Local tests/typecheck are NOT RUN by owner instruction. No numeric-open-flags change is included without current Bun reproduction. No new API/auth policy, credentials, or production runtime change.
diff --git a/devlog/_plan/260907_platform_validation/020_container_smoke.md b/devlog/_plan/260907_platform_validation/020_container_smoke.md
new file mode 100644
index 0000000000..17d7139d35
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/020_container_smoke.md
@@ -0,0 +1,25 @@
+# Container smoke executable
+
+## File delta
+
+NEW `scripts/ci/docker-smoke.ts`: bounded Bun-native TypeScript probe for the existing source-build Compose contract. Reuse the canonical compatibility generator and docker/bootstrap-token.ts; do not add an alternative token writer or deployment configuration. The probe creates a unique temporary Compose project and image, builds the actual Dockerfile, bootstraps a freshly generated throwaway token through stdin, starts the hub, verifies health and data-plane admission, recreates the container on the same named volumes, and verifies persistent state again. Cleanup is limited to the unique test project and its generated artifacts. Never use an operator project, host home, provider credentials, global docker prune, or real upstream inference.
+
+MODIFY owning documentation only as needed to explain the CI acceptance scope and its limits; no claim of upstream-provider validation.
+
+## Acceptance
+
+- Real image builds from the checkout with a generated compatibility manifest.
+- Read-only/non-root Compose service becomes healthy; requests without a token are refused.
+- A synthetic catalog in the separate Codex volume is served with the throwaway token, proving admission and persistence without provider access.
+- /readyz succeeds separately from liveness, token reinitialization fails without replacement, and effective container restrictions are verified.
+- Token/config/catalog persist across an actual container replacement (different container id, same volumes).
+- Failures and cleanup are bounded; token/body contents never appear in logs.
+- Existing Docker settings and defaults remain unchanged.
+
+Run only in final remote CI. Locally perform source/static inspection, not the smoke or a test suite. Read the current lifecycle/API contracts before implementing assertions.
+
+## Audit amendments
+
+Use explicit unique project on every Compose command, unique image tag via a temporary override, controlled Compose environment, and loopback ephemeral host port. Preserve pre-existing generated files; cleanup must fail the probe if it cannot remove its own project resources. Bound every child, output capture and cleanup; terminate/reap timed-out children. Never print raw runtime logs or complete inspect output.
+
+Before/after replacement: require readyz 200 with status ready; authenticated catalog 200 with exact synthetic fixture; missing/wrong token 401 for catalog, Responses and compact. Second bootstrap must fail and preserve the original token while rejecting the proposed replacement. Verify different container IDs, identical named-volume identities and persistent config/catalog evidence without reseeding; check effective non-root UID and read-only root.
diff --git a/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md b/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md
new file mode 100644
index 0000000000..c86f4fc765
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md
@@ -0,0 +1,10 @@
+# Container lifecycle mode
+
+Amendment after real Docker recreation verification. Docker supervises the foreground hub and must retain persisted routed state across replacement.
+
+MODIFY Dockerfile runtime ENV: set existing OCX_SERVICE=1, with no service manager installation or privilege change. Preserve image digest, foreground CMD, listener authentication, separate writable homes and read-only root.
+MODIFY scripts/ci/docker-smoke.ts: assert the actual container process receives service lifecycle mode. Retain the routed synthetic slug and exact token/catalog/config hashes across graceful recreation.
+MODIFY tests/service/container-bootstrap.test.ts: include the runtime ENV declaration in the existing packaging contract.
+MODIFY docs-site/src/content/docs/guides/remote-hub.md: document service-mode foreground lifecycle, Compose restart/recreation, and the limit on other dashboard restart paths.
+
+Independent Astra high lifecycle/security review accepted the bounded packaging change. Actual remote CLI comparison confirmed preservation with service mode. Final image CI must prove the same real container lifecycle; no local tests or Docker execution. This does not change shared CLI cleanup, restart policy, or authentication code.
diff --git a/devlog/_plan/260907_platform_validation/030_container_ci.md b/devlog/_plan/260907_platform_validation/030_container_ci.md
new file mode 100644
index 0000000000..28f3e08fc9
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/030_container_ci.md
@@ -0,0 +1,21 @@
+# Container CI integration
+
+Depends on the committed probe from phase 1.
+
+## File delta
+
+MODIFY `.github/workflows/ci.yml`: include Dockerfile, compose.yaml, .dockerignore and docker/** in relevant scope detection; add an ubuntu-latest Docker smoke job using the existing pinned checkout and setup-project-bun action; invoke the script after installing required project dependencies if the generator needs them. Preserve read-only workflow permissions and persist-credentials false. Add the job to aggregate ci needs so failures cannot silently pass. No registry publishing, credentials, native stack integration or changes to existing suite retry/concurrency policy.
+
+MODIFY `tests/ci-workflows/ci-workflows.test.ts`: extend the existing source-oracle checks for scope paths, direct aggregate dependency, pinned actions, and actual probe invocation. Keep existing domain/layout registration unchanged by using the owning test file.
+
+MODIFY `docs-site/src/content/docs/guides/remote-hub.md`: describe image lifecycle validation and separate readiness/provider-auth limitations.
+
+## Acceptance and verifier
+
+Final-branch Cross-platform CI workflow_dispatch must run the smoke and the existing platform gates. The Docker job's failures must reach ci. Local suite/typecheck NOT RUN per owner. Independent review checks full workflow event, permission, input, credential, and cleanup boundaries before publishing. Existing source-oracle tests execute remotely in CI.
+
+Publish branches with --no-verify; do not claim lower-layer CI if only the final tree was tested. Final failure permits narrower runs. User authorized admin merge of verified layers; original author names/emails come from source commit metadata and are included as Co-authored-by trailers.
+
+## Final execution inventory
+
+Dispatch existing Cross-platform CI with lane=all on the immutable final head. Record each expected job and actual conclusion: Docker, four Linux shards, storage-policy, api-usage, gates, two macOS shards, macos-control, six Windows shards, keyring jobs, any selected npm packaging jobs, and ci. Aggregate green alone does not prove Windows or Docker ran. Explain legitimate scope skips instead of counting them as tests.
diff --git a/devlog/_plan/260907_platform_validation/035_body_diagnostics.md b/devlog/_plan/260907_platform_validation/035_body_diagnostics.md
new file mode 100644
index 0000000000..5165526583
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/035_body_diagnostics.md
@@ -0,0 +1,17 @@
+# Bounded inbound-body diagnostic semantics
+
+Issue #3573 requests usable size evidence. The existing error stores a byte value but returns only the admission limit; the byte value currently mixes declared length, observed wire bytes, an artificial limit+1 lower bound, and exact decoded length.
+
+## File delta
+
+MODIFY `src/server/request-decompress.ts`: extend DecompressedBodyTooLargeError with a closed measurement category and retained limit, preserving existing constructor call compatibility. Annotate existing throw sites: declared_wire, observed_wire_lower_bound, decoded_exact, decoded_lower_bound. Append a bounded numeric/category suffix to the current message so existing core.ts error mapping carries it. No request body, path, headers, item counts, further inflate/read, admission-limit changes, or new retry semantics.
+
+MODIFY `tests/usage/request-decompress.test.ts`: extend small-cap fixtures to verify identity/gzip/zstd/deflate and declared/fragmented input semantics. In particular, limit+1 remains a lower bound, never exact size. Verify HTTP 413 and existing error code/type through existing handler mapping. Preserve stream cancellation.
+
+MODIFY `docs-site/src/content/docs/reference/proxy-formats.md`: explain wire declared length vs measured/lower-bound diagnostics, separately from compact-response limits. State that Bun listener rejection may happen before application diagnostics and that this does not measure the exact historical compact payload.
+
+## Acceptance
+
+Unchanged 256 MiB listener/decoder limit and rejection classification. No context-window wording that causes errors.ts to reclassify the failure. Message remains bounded, only fixed categories and finite numeric values. Negative tests run in final remote CI; no local test/typecheck. Keep #3573 open pending exact real compact evidence.
+
+This is a new diagnostic refinement of an issue, not a carry of a new contributor PR. Credit reporter @nowhere1975 in commit prose without inventing name/email. Any borrowed existing PR patches must additionally retain their actual git author trailers.
diff --git a/devlog/_plan/260907_platform_validation/040_residual_evidence.md b/devlog/_plan/260907_platform_validation/040_residual_evidence.md
new file mode 100644
index 0000000000..f5466a4d38
--- /dev/null
+++ b/devlog/_plan/260907_platform_validation/040_residual_evidence.md
@@ -0,0 +1,15 @@
+# Windows and request diagnostic residuals
+
+## Read-only targets
+
+- #3383: inspect current PR and merged descendants for Windows temp creation and OAuth teardown. Confirm current source behavior and test coverage before proposing a residual patch. No picker UI changes.
+- #3522: inspect response spill telemetry and fresh-versus-memoized timeout handling. The acceptance is recovery within the same affected Windows process; generic synthetic success does not prove the reported process recovered.
+- #3573: inspect decompression rejection diagnostics and exact latest issue measurements. Serialized journal size and normal requests after raising a cap do not prove the rejected compact payload size or compact success.
+
+## Conditional delta
+
+No production edit is pre-approved by this document without a source-grounded residual. If the existing code covers the measurement, record the missing field evidence and leave the issue open. If a specific content-free diagnostic is missing, amend with exact files, field flow and negative assertions before implementation. Never change admission caps, parse a rejected body to count items, relax ACLs, clear memo state, or choose a new recovery/retry policy.
+
+## Completion
+
+Record source/commit evidence, original contributor attribution where code is carried, and a separate status per candidate: already implemented, proven patch delivered, or blocked on field evidence. Do not close an original feature PR or issue merely because one residual probe passes.
diff --git a/devlog/_plan/260907_release_note_prefix/010_implementation.md b/devlog/_plan/260907_release_note_prefix/010_implementation.md
new file mode 100644
index 0000000000..ebc3fbf229
--- /dev/null
+++ b/devlog/_plan/260907_release_note_prefix/010_implementation.md
@@ -0,0 +1,25 @@
+# Issue #3895: implementation plan
+
+Satisfy-spec work, triggered by issue #3895 and the request to implement separate draft PRs. Goal: remove the exact leading enforcement marker from release summaries and full changelogs. Non-goals: changing workflow enforcement, publishing a release, modifying historical releases, or generic bracket stripping. Stop after verified draft PR; report unresolved gates. Escalate if renderer changes require workflow/security-policy changes. This file records plan and evidence.
+
+Class C2: pure formatting behavior, without modifying release authorization or execution. Independent branch from 522ce5f8c.
+
+File map:
+- MODIFY scripts/release-notes.ts: introduce a private exact-prefix normalization helper next to cleanPrTitle. Trim whitespace, remove one leading "[WRONG BRANCH] " marker, retain the rest. Call it before conventional-prefix parsing and for full-changelog titles. Preserve conventional prefixes and author/PR attribution in changelog entries.
+- MODIFY tests/ci-workflows/release-notes.test.ts: helper expected scope/casing; complete renderer on generated and carried notes; same-scope grouping; preservation of unrelated bracket tags, nonleading marker, author and PR references. Assert both category and Changelog output.
+- MODIFY structure/06_docs-and-release.md: record known-marker handling and preservation of original conventional titles in full changelogs.
+
+Verification: release-notes tests directly import changed helpers; typecheck covers src only and is not represented as script type checking; full prepush is required by scripts/AGENTS.md; privacy scan. Baseline on unchanged code: 71 passed. Regression expectations come from the published issue, not from cleanPrTitle itself.
+
+Audit: cleaning only cleanPrTitle was rejected because changelog emits the raw title. General bracket normalization would remove meaningful content. Private helper is shared by exactly two consumers and adds no runtime dependency. Explicit maintainer review for release-related changes remains pending at draft handoff.
+
+## Verification before draft publication
+
+- `bun install --frozen-lockfile`: passed; lockfile unchanged.
+- Before the production change, four new assertions failed for marker leakage: helper cleanup, delta renderer, carried renderer, and same-scope grouping. Existing baseline: 71 passed.
+- `bun test tests/ci-workflows/release-notes.test.ts`: 81 passed, 0 failed after expanding preservation cases.
+- `bun run typecheck`: passed during prepush.
+- `bun x tsc --ignoreConfig --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --skipLibCheck --types bun scripts/release-notes.ts`: passed; this explicitly covers the script outside the root tsconfig.
+- `bun run privacy:scan`: passed.
+- `bun run prepush`: not green. The parallel test lane exceeded its repository-defined 900-second deadline and exited 124; later lanes/stages did not run. Eleven failures were emitted before termination: six timeout cases across combo management, Claude messages, loopback injection, integration restore and Responses overflow; one Claude compatibility assertion failure; four Aside file-symlink EPERM cases. The full suite is incomplete, and no successful full-suite count is claimed. These files are outside the renderer change; causes other than the explicit symlink errors remain unverified. Raw local evidence is in ignored `.tmp/prepush.log`.
+- Focused independent review found no concrete production blocker; it was limited and did not replace maintainer security review or complete-suite verification. Linux and macOS were not run locally.
diff --git a/devlog/_plan/260907_release_train/000_plan.md b/devlog/_plan/260907_release_train/000_plan.md
new file mode 100644
index 0000000000..fc5510ad37
--- /dev/null
+++ b/devlog/_plan/260907_release_train/000_plan.md
@@ -0,0 +1,76 @@
+# 000 — Release train 260907: land ranked recommendations on dev (loop-in-loop)
+
+Source of items: `devlog/_plan/260907_next_release_recommendations/010_recommendations.md` (27 ranked items).
+Base: `origin/dev@ece556a6e` (2.47.0). Goalplan: `release-train-260907-land-ranked-recommendations`.
+Class: C4 (release train; admin merges; contributor credit). Full PABCD per work-phase; delegated threads run their own cxc-loop.
+
+## Common rules (verbatim for every lane, main and delegated)
+
+1. No local test suite, typecheck, build, or install. Label them NOT RUN. Remote CI is the only verifier.
+2. `git push --no-verify` always.
+3. Manual dependent PR chains only (`stack: null`; never GitHub native stacks). Every commit on lower layers carries `[skip ci]` in its
+ subject (GitHub suppresses `pull_request` runs only when the PR HEAD commit carries it); the chain's top head runs Cross-platform CI via
+ `gh workflow run ci.yml --ref -f lane=all` so the Windows shards are included (ordinary PR runs skip them).
+4. If top-head CI is red: dispatch astra-high explorer subagents to diagnose the exact job log, fix sequentially on the owning layer,
+ cascade (`git rebase --update-refs`), rerun top-head CI. Never weaken a production assertion; controlled baseline + failing mutant for timing changes.
+5. Integration = the Track 2/3 procedure (rollout 01a0778a-b74a / 01a0778a-c620): the chain is verified once at its top head; lower PRs are
+ merged bottom-up into `dev` as history-only steps whose cumulative tree at the top equals the CI-tested tree (`git rev-parse ^{tree}`
+ vs tested `^{tree}` after the last merge; if dev advanced, cascade + rerun top CI first). Preconditions per merge: fresh `git fetch origin dev`,
+ PR head/base/repo refreshed, no unresolved non-outdated threads, no outstanding maintainer CHANGES_REQUESTED, required gates (enforce-target,
+ hygiene, label) green on the head, actor = lidge-jun (admin). The PR body records the MAINTAINERS.md integration decision and the exact top-head
+ CI run id ("maintainer integration, not self-approval"). `delete_branch_on_merge=true` → retarget the immediate child to `dev` before merging its parent.
+ Authorization for rule 1 and admin merge: the user's instruction in this thread ("로컬 스위트 금지 … no verify로 푸시 … 하위는 ci돌리지 않고 가장 상위만").
+ Pre-merge (prospective) check, before the first merge of a chain: pin every layer head SHA; compute the expected cumulative tree by
+ `git merge-tree --write-tree origin/dev ` (or a scratch merge in a temp worktree) and require it to equal the tested `^{tree}`
+ (i.e. dev has not advanced under the chain; if it has, cascade and rerun top CI). Intermediate layers become real `dev` states, so each
+ layer must be standalone-correct (own thesis, builds in isolation by construction of the chain). Post-merge: compare the final merge's
+ tree to the tested tree; expected advancement from the chain's own merges is the only allowed delta.
+6. Immediately after each landing: comment on the original PR and issue with the landing SHA. Close the original PR always (superseded/carried).
+ Close the issue only when the item fully resolves it; for slices (#3719 ordering, #3379 ranges, #3782 docs, #3774 DnD, #3769 residual) comment
+ with the landed slice and the explicit residual, keep the issue open. Use `Closes #n` in PR bodies only for full resolutions.
+7. Contributor credit: `git cherry-pick -x` for carried commits; every carried/reimplemented change carries a `Co-authored-by: ` trailer resolved from the PR author (not the generic commit author). CREDITS.md must not grow.
+8. PR body follows `.github/PULL_REQUEST_TEMPLATE.md` (Summary, Verification with NOT RUN labels, Checklist) plus the manual chain table. GUI-touching PRs include a screenshot.
+9. Ancestry proof after merge: `git fetch origin dev && git merge-base --is-ancestor FETCH_HEAD` → 0.
+10. Security surfaces (auth, credentials, workflows, release.yml) get an independent astra explorer review before merge; the review verdict is pasted into the PR.
+
+## Lane split (disjoint write sets; conflicting items share a lane)
+
+| Lane | Owner | Items (rank) | Primary files | Chain shape |
+|---|---|---|---|---|
+| M (main, this thread) | main session | #3 #3840 Copilot routing · #12 #3838 OpenCode Go input items (moved from A: shares `registry.ts`) · #5 #3837 Kiro debug gate · #6 #3843 citation span · #7 #3845 keychain restore · #14 #3532 docs (bottom, docs-only) · #13 #2033 web-search enabled (top) | `src/providers/registry.ts`, `src/adapters/opencode-go.ts`, `src/adapters/kiro*`, `src/responses/citation-markers.ts`, `src/providers/key-store.ts`, `src/server/management/config-routes.ts` (M owns; C's #3863 must not touch it — its settings change lives in `startup-health-cache.ts`/settings route only), `docs-site/.../guides/providers.md` (M owns; A's #3858 provider-guide hunk is re-applied by M after A lands), devlog | 7-layer chain: #3532 → #3840 → #3838 → #3837 → #3843 → #3845 → #2033 (top) |
+| A (delegated) | thread A | #1 #3862 reasoning envelope admission · #2 #3858 Pi session affinity · #26 #3769 residual compact fallback | `src/responses/reasoning-envelope.ts`, translator budget, `src/server/chat-completions.ts`, `src/server/chat-native.ts`, `src/clients/config-export.ts`, `src/server/responses/core.ts` (A owns), compaction fallback | 3-layer chain: #3862 → #3858 → #3769. Windows shards required for #3862 (dispatch lane=all). Do NOT edit `docs-site/.../guides/providers.md` — hand the hunk to M in the final report. |
+| B (delegated) | thread B | #11 #3856 quota activation · #10 #3849 Mihomo IPv6 · #3848 (#3846) DEFER by default; attempt only after #3856 lands and only the runtime slice without GUI i18n/docs (i18n + `codex-integration.md` belong to C) | `src/codex/quota-auto-refresh.ts`, `src/codex/auth-api.ts`, `src/lib/provider-outbound.ts`, `src/types/config.ts` (B owns; E's #3336 config field is added by E after B lands) | chain #3856 → #3849 |
+| C (delegated) | thread C | #8 #3839+#3841 sidecar bounds · #4 #3863 Windows health probe · #9 #3860 Desktop sign-in toggle · #23 #3252 subagent fallback GUI (+ #22 #1533 guidance inside it) | `src/web-search/anthropic-executor.ts`, `src/vision/anthropic-describe.ts`, `src/server/startup-health-cache.ts`, settings route (not `config-routes.ts` — if #3863 needs it, coordinate through main), `gui/src/i18n/*.ts` (C owns all i18n edits), `docs-site/.../guides/codex-integration.md` (C owns), agent-settings GUI | chain #3839 → #3841 → #3863 → #3860 → #3252 |
+| D (delegated) | thread D | #16 #3719 thinking order parity (slice; issue stays open) · #17 display-name receipt guard · #15 #3817 price overlay · #21 #3667 price editor · #25 #3379 usage ranges slice (←#2956; issue stays open) | `src/claude/outbound.ts`, `gui/.../ModelDisplayNameDialog.tsx`, `src/usage/cost.ts`, `src/usage/user-cost-overlays.ts`, `src/usage/summary.ts`, `gui/src/pages/Usage.tsx` | chain in that order |
+| E (delegated) | thread E | #18 release.yml smoke recovery · #19 Raycast/locale docs bundle · #20 code-mode delivery record + Desktop /model docs + translations · #24 #3774 picker DnD (slice; issue stays open) · #27 #3336 pinned effort (waits for A on `core.ts` and B on `config.ts`; rebase onto dev after both land) | `.github/workflows/release.yml`, docs-site locales (not the two guide files owned by M/C), devlog, `gui/src/model-picker-order.ts`, `src/server/chat-native.ts` (after A) | release.yml as its own PR (security review); docs chain; #3774 separate PR; #3336 last |
+
+Single-owner files (audit round 1): `registry.ts`, `config-routes.ts`, `guides/providers.md` → M; `responses/core.ts` → A; `types/config.ts` → B;
+`gui/src/i18n/*`, `guides/codex-integration.md` → C. Ownership transfers: `core.ts` and `config.ts` transfer to E once A's and B's chains are
+ancestors of `dev` (E verifies with `git merge-base --is-ancestor` before editing). Cross-lane prerequisites (executable handoffs):
+- A#3858 lands before M#3838 (both touch OpenCode Go); M rebases its chain onto dev after A reports landing and re-applies A's `providers.md` hunk.
+- #3863's `config-routes.ts` wiring (replace the blocking startup-health read) is implemented by M as a layer in M's chain after C reports its
+ `startup-health-cache.ts` layer landed; C ships the cache/probe change with the existing route call unchanged and names the exact call site in its report.
+- E#3336 after A and B; E#3774/#18/#19/#20 have no prerequisites.
+Shared manifests `tests/fixtures/test-layout-expected.json` + `scripts/test-layout/layout.json` are explicitly multi-writer (append-only); the lane
+that cascades last resolves. Amendment (wp1, lane D report): `gui/src/i18n/*.ts` are also multi-writer append-only — each lane adds its own
+feature-namespaced keys at the end of the relevant section in every locale (gui/AGENTS.md), never edits or removes existing keys; C's exclusive
+ownership is withdrawn. Lane B additionally owns `docs-site/**/getting-started/how-it-works.mdx` (en, ja, ko, ru, zh-cn) for the #3856 carry only.
+Write sets are otherwise disjoint. Any lane that must touch another lane's owned file stops and reports to main instead of editing.
+
+## Delegated thread packet (sent verbatim with lane-specific rows)
+
+TASK: run cxc-loop (HOTL) in your own worktree to land lane items on dev. SCOPE: the files above plus their tests/docs. MUST DO: common rules 1–10;
+PABCD per layer with an independent astra explorer audit; report landing SHAs, CI run ids, closed PR/issue links. MUST NOT: touch other lanes' files, release,
+publish, native stacks, local suites, force-push without lease. PROOF: ancestry command output, CI run URL, closure comment URLs. RETURN: a final message
+with a table item → disposition → SHA → CI → closures, and DEFER reasons.
+
+## Merge serialization
+
+Main session is the only actor that admin-merges. Delegated threads bring a chain to "top-head CI green + review pasted" and report; the main session
+refreshes dev, re-checks tree equality, merges bottom-up, retargets children, closes originals. If dev advanced under a chain, the owning thread cascades and reruns top CI before merge.
+
+## Acceptance (goalplan c-1..c-4)
+
+Every attempted item landed with ancestry proof or DEFER/BLOCKED with reason; each merged chain has an exact-head CI run id; original PRs closed with SHA
+comments and credit trailers, issues closed only on full resolution (slices commented and kept open per rule 6); final readiness doc `090_readiness.md`
+committed with privacy:scan exit 0.
diff --git a/devlog/_plan/260907_release_train/010_wp1_execution.md b/devlog/_plan/260907_release_train/010_wp1_execution.md
new file mode 100644
index 0000000000..064568391d
--- /dev/null
+++ b/devlog/_plan/260907_release_train/010_wp1_execution.md
@@ -0,0 +1,62 @@
+# 010 — wp1 execution log (main lane M + dispatch)
+
+## Dispatch (2026-09-07 ~09:20Z)
+Threads created (gpt-6-astra, high): A 01a07b28-06e1-77e3-a323-1e400fd777ca, B 01a07b28-06f3-7cd0-ba8a-c646d4dc5c11,
+C 01a07b28-0793-7ff1-abb6-adbbb31d1c72, D 01a07b28-072f-7b93-b840-0f0f16b0ec33, E 01a07b28-06f3-7cd0-ba8a-c62b1f7d1d94.
+Ownership amendments accepted during wp1: B owns how-it-works.mdx (en+4) for #3856; i18n is append-only multi-writer;
+E owns reference/configuration/providers.md locales for #19; D owns the single modelCosts zero sentence in those files for #3667.
+
+## Main lane M chain (PRs #3865 → #3870)
+| Layer | PR | Branch | Head | Source | Notes |
+|---|---|---|---|---|---|
+| 1 | #3865 | codex/rt-m1-3532 | f1604c6b2 | #3532 Ingwannu | cherry-pick -x, [skip ci] |
+| 2 | #3866 | codex/rt-m2-3840 | 98564bdbf | #3840 chilung-cgu | 5 commits squashed (merge commit in source), [skip ci] |
+| 3 | #3867 | codex/rt-m3-3837 | 6061dcce0 | #3837 luvs01 | + test isolation fix for discussion_r3945935220 |
+| 4 | #3868 | codex/rt-m4-3843 | 00b74c720 | #3843 luvs01 | + same-delta fix for discussion_r3946034145 |
+| 5 | #3869 | codex/rt-m5-3845 | 924b65799 | #3845 luvs01 | security review PASS pasted in PR body |
+| 6 | #3870 | codex/rt-m6-2033 | 6eadb1658 | #2033 louis-tepe (reimplemented) | top; amended after first top CI |
+
+Independent chain review (astra explorer): PASS, no blockers; security review of #3845 PASS.
+
+Top CI history:
+- run 34105730157 @911047281: test 2/4 FAIL — `tests/vision/vision-anthropic.test.ts:342` exact-equality on webSearch body lacked the new `enabled` key (two assertions). Fixed in 6eadb1658 (amend of layer 6). Run cancelled.
+- run 34106345180 @6eadb1658 (workflow_dispatch lane=all): queued behind a 60+ run backlog (all lanes dispatching simultaneously). Duplicate pull_request run 34106351272 cancelled.
+
+## Lane status (from wait_threads snapshots)
+- A: chain #3879 → #3880 → #3881 published, three-layer source/security audits PASS, top fa9c1ee68 CI queued.
+- B: chain #3871 (#3856) → #3872 (#3849); top CI: Linux test 3/4 failure under analysis by lane B.
+- C: chain c1…c5 (#3839, #3841, #3863, #3860, #3252) with GUI re-audit PASS; top 8f8ac0d82 CI requested.
+- D: #3877 (#3719 ordering) + name-guard layer + price overlay in progress; audits PASS on first two.
+- E: #3864 (#18 release.yml) CI in progress with security audit; #19/#20 handoff patches prepared against ece556a6e.
+
+
+## Landing (wp1 D, 2026-09-07 ~10:40Z)
+| Layer | PR | Merge SHA | Original closed |
+|---|---|---|---|
+| 1 | #3865 | 7f2fb922c | #3532 |
+| 2 | #3866 | dcec71715 | #3840 |
+| 3 | #3867 | 0ef7d2906 | #3837 |
+| 4 | #3868 | 99451df82 | #3843 |
+| 5 | #3869 | 0719457d1 | #3845 |
+| 6 | #3870 | d00615d56 | #2033 |
+
+Chain-top CI: run 34106345180 @6eadb1658 (lane=all) success, aggregate `ci` success. Prospective merge tree `git merge-tree --write-tree origin/dev codex/rt-m6-2033` = 7621cac89 = tested tree; post-merge `origin/dev^{tree}` = 7621cac89. Every layer head and d00615d56 are ancestors of fetched dev. Stale CodeRabbit trailer findings on #3869/#3870 replied (heads carry trailers). Lanes notified of the new dev head; A told that M#3838 follows A#3858.
+
+
+## wp2 amendments (user instruction, 2026-09-07 ~10:50Z)
+- CI runner saturation: all queued Cross-platform runs cancelled; one chain at a time. Order: B → A → M7 (#3882) → C → E #3864 → D → E rest.
+- Per-chain gate excludes Windows shards and macos control; they run once on the final release-train head (wp3).
+- Lane B landed: #3871 (62fe747af) → #3872 (ddee5e8b4); tree 58536270a == tested; run 34111578200 (Linux 1/2/4, macOS 1/2, gates, policy, api, keyring, npm, docker green; test 3/4 = prompt-text-probe timing flake, untouched by B; Windows/control cancelled by policy). Closed #3856, #3849, issue #3855; #3781 slice comment.
+- Lane A landed: #3879 (b0bcb4b10) → #3880 (dac7e28c4) → #3881 (76436a3ee); tree d4f095822 == tested; run 34113638182 (all non-Windows/control jobs green). Closed #3862/#3858/#3769, issues #3861/#3857.
+- M7 #3882 (citation whole-string/streaming parity, found by lane A composition audit) merged 6389787dc; M8 #3888 (providers.md hunk from A) merged 522ce5f8c; run 34114667385 green on non-Windows/control jobs.
+- Slot order now: C → E #3864 → D → E docs/#3774/#3336.
+- Lane C landed: #3873 (f46a7f49c) → #3874 (3f07e09bc) → #3875 (686cb127c) → #3876 (2eec04fe1) → #3878 (d0fca4a9b); tree e0b0e5886 == tested; run 34116228181 aggregate ci success (attempt 2 after a macos 1/2 20-min hang in codex-inject-write-lock; cause unproven, no code change). Closed #3839/#3841/#3860/#3252, issue #1533. #3863 reopened: contributor widened it mid-train (retitled, +2 commits) — only the original health-cache commit landed via #3875.
+- Lane E #3864 (release.yml registry-smoke recovery, security review PASS) merged f4a4b468f; run 34119094967 green on non-Windows/control jobs.
+- Slot order now: D → E docs (#3883/#3884) → #3887 → #3892 → final Windows/control run on the train head.
+- Lane D landed: #3877 (4fe4ad8df) → #3902 (d05250de5) → #3903 (cb1113f6d) → #3904 (29405d314) → #3905 (da707ccb6); tree ded24302f == tested; run 34120761219 (non-Windows/control jobs green; two CI-found repairs: react-compiler EffectSetState in ModelPriceDialog, GUI test alert selectors). Closed issues #3817/#3667, PR #2956 (slice); #3719/#3379 slice comments, kept open.
+- Remaining: E docs (#3883/#3884, run 34121907231) → #3887 (#3774 DnD) → #3892 (#3336) → final Windows/control run on train head.
+- Lane E docs landed: #3883 (1649247c1) → #3884 (74089fdc3); tree c415b6abd == prospective merge tree (differs from tested 986ae11d only by D's landed files; shared locale reference files auto-merged in disjoint sections). run 34121907231. #3782 commented (docs caveat, stays open).
+- Lane E #3887 (#3774 DnD slice) merged 1e188b787; tree 139cade3f == tested; run 34124333662 (two CI-found repairs: EffectSetState lint in ModelPickerOrderEditor, stale-GET fixtures). #3774 slice comment, stays open.
+- Remaining: #3892 (#3336) → final Windows/control run on train head → wp3 readiness doc.
+- Lane E #3892 (#3336 carry + pricing-PUT race fix) merged f802f7112; tree 402b8e750 == tested; run 34126879673. Closed #3336.
+- All chains landed. Final train head dev f802f7112; full lane=all (Windows 6 + macos control) dispatched: run 34127950924.
diff --git a/devlog/_plan/260907_release_train/090_readiness.md b/devlog/_plan/260907_release_train/090_readiness.md
new file mode 100644
index 0000000000..adf2363842
--- /dev/null
+++ b/devlog/_plan/260907_release_train/090_readiness.md
@@ -0,0 +1,69 @@
+# 090 — Release-train readiness (dev after v2.46.0)
+
+Train head: `origin/dev@f802f7112` (2.47.0). Base: `ece556a6e`. Delta: 28 PR merges, 207 files, +11,450 / −491.
+Source plan: `010_recommendations.md` (27 ranked items). Execution log: `010_wp1_execution.md`.
+
+Policy (user instruction, this train): no local suites/typecheck/build/install (NOT RUN); `--no-verify` pushes; manual dependent chains (`stack: null`);
+one chain's top head on Cross-platform CI at a time; per-chain gate = Linux 4 + macOS 2 + gates/storage/api/keyring ×3/npm ×3/docker;
+Windows 6 shards + macos control once on the final train head; admin merges recorded in each PR body with exact-head evidence;
+originals closed with landing SHA and `Co-authored-by` trailers on every carried/reimplemented commit.
+
+## Landed (ranked item → merge)
+
+| # | Item | Landed via | Merge SHA | Chain-top CI | Original disposition |
+|---|---|---|---|---|---|
+| 1 | #3862 reasoning-envelope admission (Ingwannu) | #3879 | b0bcb4b10 | 34113638182 | PR closed; #3861 closed |
+| 2 | #3858 Pi/OpenCode Go affinity (makesomethingshit) | #3880 (+ docs #3888 522ce5f8c) | dac7e28c4 | 34113638182 / 34114667385 | PR closed; #3857 closed |
+| 3 | #3840 Copilot Responses-only routing (chilung-cgu) | #3866 | dcec71715 | 34106345180 | PR closed |
+| 4 | #3863 Windows health probe (x3M3x) — original commit only | #3875 | 686cb127c | 34116228181 | PR reopened: contributor widened scope mid-train (+2 commits) |
+| 5 | #3837 Kiro debug gate (luvs01) + test isolation | #3867 | 0ef7d2906 | 34106345180 | PR closed |
+| 6 | #3843 citation span bound (luvs01) + same-delta fix; parity follow-up | #3868, #3882 | 99451df82, 6389787dc | 34106345180 / 34114667385 | PR closed |
+| 7 | #3845 keychain restore ownership (luvs01), security review PASS | #3869 | 0719457d1 | 34106345180 | PR closed |
+| 8 | #3839 + #3841 Anthropic sidecar bounds (luvs01) | #3873, #3874 | f46a7f49c, 3f07e09bc | 34116228181 | PRs closed |
+| 9 | #3860 Desktop sign-in opt-in, default OFF (RobinBially) | #3876 | 2eec04fe1 | 34116228181 | PR closed |
+| 10 | #3849 Mihomo IPv6 fake-IP TUN (hualiny) | #3872 | ddee5e8b4 | 34111578200 | PR closed; #3781 slice comment, open |
+| 11 | #3856 quota window activation (terrytan95) | #3871 | 62fe747af | 34111578200 | PR closed; #3855 closed |
+| 12 | #3838 OpenCode Go input items (jpierrevd) | — | — | — | **DEFER**: planned as M layer after A#3858; not started (see Remaining) |
+| 13 | #2033 web-search enabled state (louis-tepe) reimplemented | #3870 | d00615d56 | 34106345180 | PR closed |
+| 14 | #3532 CI audit docs (Ingwannu) | #3865 | 7f2fb922c | 34106345180 | PR closed |
+| 15 | #3817 price overlay identity (rrmlima) | #3903 | cb1113f6d | 34120761219 | issue closed |
+| 16 | #3719 thinking order parity (slice) | #3877 | 4fe4ad8df | 34120761219 | issue slice comment, open |
+| 17 | display-name receipt guard | #3902 | d05250de5 | 34120761219 | — |
+| 18 | release.yml smoke recovery, security review PASS | #3864 | f4a4b468f | 34119094967 | — |
+| 19 | Raycast/CLI/locale docs bundle | #3883 | 1649247c1 | 34121907231 | — |
+| 20 | code-mode record + Desktop /model caveat + translations | #3884 | 74089fdc3 | 34121907231 | #3782 commented, open |
+| 21 | #3667 manual price editor (nordz0r) | #3904 | 29405d314 | 34120761219 | issue closed |
+| 22 | #1533 V2 compatibility guidance (Zbyy0311) | #3878 | d0fca4a9b | 34116228181 | issue closed |
+| 23 | #3252 sub-agent fallback GUI (x3M3x) | #3878 | d0fca4a9b | 34116228181 | PR closed |
+| 24 | #3774 picker drag-and-drop (leonclab, slice) | #3887 | 1e188b787 | 34124333662 | issue slice comment, open |
+| 25 | #3379 usage ranges slice (from #2956, Manson2438) | #3905 | da707ccb6 | 34120761219 | #2956 closed; #3379 slice comment, open |
+| 26 | #3769 residual compact fallback (ideabib) | #3881 | 76436a3ee | 34113638182 | PR closed |
+| 27 | #3336 pinned reasoning effort (Liang-Psych) + pricing-PUT race fix | #3892 | f802f7112 | 34126879673 | PR closed |
+
+26 of 27 items landed (item 12 deferred). Every merge SHA above is an ancestor of `origin/dev@f802f7112`; every chain's post-merge dev tree
+equalled its CI-tested tree (or, for the E docs chain, the prospective `git merge-tree` result after D landed).
+
+## Final train-head CI (Windows + macos control)
+
+Run 34127950924 @f802f7112 (workflow_dispatch, lane=all): Linux 4/4, macOS 1/2 + 2/2, Windows 6/6, gates, storage policy, api usage,
+keyring ×3, npm-global ×3, docker smoke = success. `macos control` attempt 1 failed on one test
+(`tests/responses/responses-state.test.ts:1552` "shutdown fallback prices the job-owned superseded generation before publishing":
+ETIMEDOUT from an 80 ms wall-clock fallback reserve that the test does not freeze; 21,404 pass / 1 fail). Independent diagnosis: FLAKE —
+the train did not touch `src/responses/state.ts`, the test, spill/ACL helpers or translator-budget; the same job passed on ece556a6e and on the
+C chain head. The failed job alone was rerun (attempt 2) but was cancelled by ref concurrency when an unrelated docs PR (#3910, 8bc9e4ee2, SPONSORS.md + README) pushed to dev at 14:06Z. A fresh lane=all dispatch on dev@8bc9e4ee2 (f802f7112 + that docs-only commit) — run 34131381795 — passed every job: Linux 4/4, macOS 1/2 + 2/2, **macos control**, **Windows 6/6**, gates, storage policy, api usage, keyring ×3, npm-global ×3, docker smoke, aggregate ci = success. That run is the final train-head evidence.
+
+## Remaining / deferred
+
+- Item 12 #3838 (OpenCode Go input-item normalization, jpierrevd): not carried — DEFER to the next train; needs the parent-namespace child identity and
+ nameless built-in fixes from the review, on top of #3880.
+- #3863 (x3M3x): reopened; the contributor widened it (combo capabilities, archive retention, health-refresh rejection guard). Only the original
+ startup-health-cache commit landed (#3875). Contributor to rebase onto dev for the rest.
+- #3848 (#3846, shaun0927): DEFER by plan (sponsorship + 61-file scope); untouched.
+- Slices kept open: #3719 (live replay/cache acceptance), #3379 (selector rename), #3774 (native/featured rows), #3781 (authenticated TUN acceptance), #3782 (client-owned).
+- Known pre-existing flake to fix separately: `responses-state.test.ts` shutdown-fallback test should freeze `Date.now()` like its neighbour at :1494.
+
+## Release readiness
+
+dev@8bc9e4ee2 (train head f802f7112 + docs #3910) is release-candidate ready: full matrix green on run 34131381795. Version line is already 2.47.0 (opened in #3850).
+Promotion to preview/main and npm publish are outside this train's scope.
+
diff --git a/devlog/_plan/260907_release_train_b/000_plan.md b/devlog/_plan/260907_release_train_b/000_plan.md
new file mode 100644
index 0000000000..be31f8e242
--- /dev/null
+++ b/devlog/_plan/260907_release_train_b/000_plan.md
@@ -0,0 +1,11 @@
+# Lane B delivery roadmap
+
+Satisfy-spec HOTL, triggered by delegated release-train packet. Goal: prepare a manual #3856 -> #3849 carry chain for main-session integration. No merges, releases, installs, local tests/typechecks/builds, native stacks, or edits to other lane files. Resources: existing git/gh and astra reviewers; user set no token/cost/time limit. Stop after exact top-head remote CI success, independent security verdicts, and handoff evidence. BLOCKED means a concrete unresolved owner/security/CI condition; #3848 is DEFER until #3856 lands. Main reclaims after two distinct failed leaf packets; new worker scope requires plan amendment.
+
+Memory/evidence: this neutral roadmap, `.tmp/lane-b/` for all security work notes, `.codexclaw/` for FSM/goalplan. Escalate cross-lane conflicts to main. How-it-works English/ja/ko/ru/zh-cn ownership was explicitly assigned to B by main. No automatic peer writes beyond collision coordination.
+
+1. Docs-only roadmap audit and lock.
+2. Carry quota activation original commits with cherry-pick -x and contributor trailers; inspect default-off, identity and pending-state contracts. Lower layer code verification is deferred to top CI by explicit user instruction; its D certifies carry preparation, not runtime success.
+3. Carry Mihomo transport commit plus IPv6-only and canonical NO_PROXY/unsafe companion regressions. Publish manual chain, independently review final implementation, dispatch ci.yml lane=all only on top. Repair lower layers sequentially and cascade with rebase --update-refs.
+
+Verifier: gh workflow run ci.yml --ref codex/260907-b-mihomo-ipv6 -f lane=all; read exact head SHA and every job including Windows shards. Local product commands NOT RUN by user instruction. Inspect workflow definitions instead of executing local verifiers. No claims of live TUN validation; deterministic resolver/pinned transport tests are remote CI proof.
diff --git a/devlog/_plan/260907_release_train_b/010_carry.md b/devlog/_plan/260907_release_train_b/010_carry.md
new file mode 100644
index 0000000000..cde8f79785
--- /dev/null
+++ b/devlog/_plan/260907_release_train_b/010_carry.md
@@ -0,0 +1,3 @@
+# Quota activation carry
+
+Detailed working plan: `.tmp/lane-b/010_carry.md` (gitignored security work space). Public source and contributor provenance are recorded in the roadmap. Only published outcomes will be added here.
diff --git a/devlog/_plan/260907_release_train_b/020_carry.md b/devlog/_plan/260907_release_train_b/020_carry.md
new file mode 100644
index 0000000000..10d853e99e
--- /dev/null
+++ b/devlog/_plan/260907_release_train_b/020_carry.md
@@ -0,0 +1,3 @@
+# Mihomo IPv6 carry
+
+Detailed working plan: `.tmp/lane-b/020_carry.md` (gitignored security work space). Public source and contributor provenance are recorded in the roadmap. Only published outcomes will be added here.
diff --git a/devlog/_plan/260907_router_selection_capture/010_implementation.md b/devlog/_plan/260907_router_selection_capture/010_implementation.md
new file mode 100644
index 0000000000..9ec8b3422f
--- /dev/null
+++ b/devlog/_plan/260907_router_selection_capture/010_implementation.md
@@ -0,0 +1,32 @@
+# Issue #3894: implementation plan
+
+Satisfy-spec work, triggered by issue #3894 and the request to implement separate draft PRs. Goal: remove the direct router/selection mutation dependency. Non-goals: changing key resolution/failover or eliminating all transitive router cycles. Stop after verified draft PR; report unresolved gates. Escalate if extraction requires behavioral changes. This file records plan and evidence.
+
+Class C2: one pure helper extracted in the existing provider module convention. Independent branch from 522ce5f8c.
+
+Current map: router imports api-key-selection for capture; api-key-selection imports router for route resolution. Existing direct helper callers: router and matchesSelection. No package exports change.
+Chosen map: both modules import api-key-selection-capture; the old api-key-selection export forwards the same function. New leaf uses only existing OcxProviderConfig and ProviderApiKeySelection type imports.
+Rejected alternative: extracting routedProviderConfig would move broad routing dependencies. Other existing transitive cycles stay outside scope.
+
+File map:
+- NEW src/providers/api-key-selection-capture.ts: the existing function body unchanged, plus the two type-only imports.
+- MODIFY src/providers/api-key-selection.ts: replace local implementation with named import and compatibility re-export.
+- MODIFY src/router.ts: change capture import to the leaf.
+- NEW tests/providers/api-key-selection-capture.test.ts: selected/unmatched/missing/duplicate pool cases, immutable snapshot, old-export identity, and Bun-parsed runtime import boundary for leaf and router. Parse actual source, exclude erased type imports; no whole-router acyclicity assertion.
+- MODIFY scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json: register the new test using existing providers domain entries.
+- MODIFY structure/01_runtime.md: document the helper ownership and preserved stateful selection direction.
+
+Verification: helper tests; key-failover, provider-key-store and core-lab-boundary tests; test-layout guards; typecheck; privacy scan. Baseline focused run on unchanged code: 49 passed. Conditional test cases have concrete provider objects; boundary regression returns offending imports rather than scanning prose.
+
+Audit: extraction is a functional dependency with no mutable globals and no changed auth behavior. Old export is preserved. A boundary test targets this exact scope; broad graph cycles are not called fixed.
+
+## Verification before draft publication
+
+- `bun install --frozen-lockfile`: passed; lockfile unchanged.
+- Baseline key-failover/provider-key-store/Lab-boundary run: 49 passed.
+- Restoring the old router import made the new boundary regression fail; restoring the extraction returned it to green.
+- `bun test tests/providers/api-key-selection-capture.test.ts tests/adapters/key-failover.test.ts tests/providers/provider-key-store.test.ts tests/lab/core-lab-boundary.test.ts tests/test-layout.test.ts tests/test-layout-tooling.test.ts`: 73 passed, 0 failed.
+- `bun run typecheck`: passed.
+- `bun run privacy:scan`: passed.
+- Review scope covers the 10-line pure helper, two consumers, compatibility re-export, 7 new tests, two layout entries, and the runtime ownership row. No other router cycle is claimed resolved.
+- Whole-suite/maintainer approval is not attested; this is a draft handoff.
diff --git a/devlog/_plan/260907_sponsor_branches/000_plan.md b/devlog/_plan/260907_sponsor_branches/000_plan.md
new file mode 100644
index 0000000000..cea5e924af
--- /dev/null
+++ b/devlog/_plan/260907_sponsor_branches/000_plan.md
@@ -0,0 +1,41 @@
+# 260907 sponsor branches
+
+Goal: two sponsor branches from `origin/dev` (`8bc9e4ee2`, which carries SPONSORS.md and the README
+Sponsors section), each ending in an open PR against `dev`. Neither merges here.
+
+## Shared mechanism (010, applied identically on both branches)
+
+- `ProviderRegistryEntry.sponsor?: { tier: "main" | "standard"; url: string }`.
+- `DerivedProviderPreset.sponsor?: "main" | "standard"` via `entryToPreset`.
+- `deriveProviderPresets()` keeps registry order; sorting is the picker's job.
+- GUI catalog (`provider-presets.ts` + `ProviderCatalog.tsx`): sponsors first, alphabetical by label
+ among sponsors (Main before Standard), then the existing usage/label order. Sponsor rows get a
+ `Sponsor` chip (`badge-accent`) before the auth badge. i18n key `modal.badge.sponsor` in all
+ nine locales.
+- CLI `ocx provider presets` prints `(sponsor)` after the label for sponsor rows.
+- Tests: derive test for the field, catalog ordering test for pinning + chip.
+
+## OrcaRouter (020)
+
+- Registry: `sponsor: { tier: "standard", url: "https://www.orcarouter.ai/?utm_source=opencodex" }`
+ on the existing `orcarouter` entry. PKCE lands separately via #3908 (author akf66), untouched.
+- README: first Standard row, uncomment the table. Logo `assets/sponsors/orcarouter.png` (from
+ `gui/public/provider-icons/orcarouter.svg` rendered to PNG), blurb from the sponsor if delivered,
+ else a neutral maintainer-written 60-word blurb marked for replacement.
+- docs-site providers guide: OrcaRouter paragraph in section 3.
+- Screenshots: dashboard Providers tab picker with OrcaRouter pinned, README section render.
+
+## PackyCode (030)
+
+- Registry: new `packycode` entry, `openai-chat`, baseUrl `https://cf.api.fan/v1` (from
+ docs.packyapi.com Codex/Kimi guides; `/v1/models` answers 401 without a key so the host is live),
+ `dashboardUrl https://www.packyapi.com/register?aff=k5KT`, sponsor standard. Model list from
+ the docs token groups: Codex group (gpt-5.5, gpt-5.1-codex), CC group (claude), seeded conservatively.
+- Icon: `gui/public/provider-icons/packycode.svg` from packyapi.com favicon.
+- README: Standard row with the sponsor's EN blurb and the ZH blurb beneath.
+- docs-site providers guide paragraph; screenshots as above.
+
+## Order
+
+010 on `sponsors/orcarouter`, cherry-picked to `sponsors/packycode`, then 020 and 030 in
+parallel. Each branch: privacy:scan, typecheck, focused tests, push `--no-verify`, PR with template.
diff --git a/devlog/_plan/260907_sponsor_branches/010_phase1.md b/devlog/_plan/260907_sponsor_branches/010_phase1.md
new file mode 100644
index 0000000000..d95bdaf334
--- /dev/null
+++ b/devlog/_plan/260907_sponsor_branches/010_phase1.md
@@ -0,0 +1,3 @@
+# 010 shared sponsor mechanism
+
+See 000_plan.md section Shared mechanism. Diff targets: src/types/provider.ts (registry entry type), src/providers/derive.ts, gui/src/components/provider-catalog/provider-presets.ts, ProviderCatalog.tsx, gui/src/i18n/*.ts, src/cli/provider-runtime.ts, tests.
diff --git a/devlog/_plan/260907_sponsor_branches/020_phase2.md b/devlog/_plan/260907_sponsor_branches/020_phase2.md
new file mode 100644
index 0000000000..5a718d7605
--- /dev/null
+++ b/devlog/_plan/260907_sponsor_branches/020_phase2.md
@@ -0,0 +1,3 @@
+# 020 OrcaRouter branch
+
+See 000_plan.md section OrcaRouter.
diff --git a/devlog/_plan/260907_sponsor_branches/030_phase3.md b/devlog/_plan/260907_sponsor_branches/030_phase3.md
new file mode 100644
index 0000000000..3f83c5eff2
--- /dev/null
+++ b/devlog/_plan/260907_sponsor_branches/030_phase3.md
@@ -0,0 +1,3 @@
+# 030 PackyCode branch
+
+See 000_plan.md section PackyCode.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/000_plan.md b/devlog/_plan/260908_a_stack_responses_compat/000_plan.md
new file mode 100644
index 0000000000..3a22b2d98f
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/000_plan.md
@@ -0,0 +1,103 @@
+# 000 — a_stack_responses_compat: Plan
+
+## Objective
+
+Land four Responses-compatibility changes on `dev` as one manual dependent branch
+chain whose tip carries all of them, so a single CI run certifies the whole set.
+Three layers carry existing contributor pull requests; one is new work for an
+issue that has no pull request.
+
+| Layer | Source | Author to preserve | Subject |
+|---|---|---|---|
+| 1 | PR #3906, commit `11c498b6c` | MohamadSabree8 | Muse Spark Contributor Free tiers keep unsupported `web_search` fields |
+| 2 | PR #3886, commit `83c1d9b12` | cb8010d6 | Spark streams end `adapter_eof` when the Responses Lite header is present |
+| 3 | Issue #3922, new work | — | Claude optional tool parameters become strict on Responses routes |
+| 4 | PR #3917, commit `2430724e5` | mashfromband | Routed destinations reject Codex `agent_message` with 422 |
+
+Evidence base: four read-only `gpt-6-astra` explorer lanes read the current tree at
+`2abf071e0` and returned quoted `path:line` anchors, reproduced in each phase doc.
+
+## Loop-spec
+
+- Loop archetype: satisfy-spec. Each layer has a stated correct behavior; there is
+ no metric to optimize.
+- Trigger: maintainer request to execute workstream A as a stack.
+- Goal: the tip merged into `dev`, children settled with authors preserved, linked
+ issues closed.
+- Non-goals: registry `modelWireDefaults` for the `-free` ids; setting the Lite
+ header to `"false"` instead of removing it; PR #3838's tool-promotion,
+ `customToolWireName` export and `statelessResponses` work; any other open PR;
+ `main`/`preview` promotion.
+- Verifier: the single Cross-platform CI run on the tip pull request's head SHA.
+ It runs the repository's own workflow over the cumulative tree, so it observes
+ every file changed by all four layers.
+- Write scope: `src/adapters/openai-responses.ts`, `src/adapters/opencode-go.ts` ->
+ `src/adapters/routed-agent-messages.ts`, `src/claude/inbound-content-options.ts`,
+ their regressions, the two test-layout registries,
+ `docs-site/src/content/docs/reference/adapters.md`,
+ `docs-site/src/content/docs/reference/configuration/providers.md`, and this unit.
+- Budget: no local suite runs at all (instructed). Wall-clock bound is the CI run
+ plus merge; a red tip after one bounded repair attempt is BLOCKED, not DONE.
+- Stop condition: the stack landed on `dev`, proven for the merge method actually
+ used (see 050): original-tip ancestry for a merge commit, or landed-commit
+ ancestry plus per-path content equality for squash and rebase.
+- Memory artifact: this unit, plus the goalplan at
+ `.codexclaw/goalplans/deliver-opencodex-workstream-a-responses-compati/`.
+- Escalation: a finding that changes a carried author's intended behavior, or a
+ provider that rejects an explicit `strict: false`, returns to the maintainer.
+
+## Constraints (from the requesting maintainer)
+
+- No local product suite, typecheck, build or install runs in this session. Every
+ such check is recorded `NOT RUN`.
+- Every push uses `--no-verify`.
+- CI triggers on the stack tip only. When that one run is green, the tip merges
+ into `dev`; the remaining pull requests are then settled and the issues closed.
+- Carried work keeps its original author through a `Co-authored-by` trailer.
+
+## Why tip-only CI is achievable
+
+`.github/workflows/ci.yml` declares `pull_request: {}` with no base filter, and
+`push: branches: [main, preview, dev]`. Pushing `codex/a-stack-l1..l3` starts no
+workflow: those refs are not integration branches and no pull request points at
+them. Opening exactly one pull request, for layer 4 against `dev`, produces
+exactly one Cross-platform CI run whose head contains all four layers.
+
+## Base and chain
+
+Base: `origin/dev` = `942c028735d39b2ad410b1baa95670984e16576d`.
+
+```
+codex/a-stack-l4-routed-agentmsg (tip, the only pull request) -> base dev
+codex/a-stack-l3-claude-strict
+codex/a-stack-l2-spark-lite
+codex/a-stack-l1-muse-free
+origin/dev 942c02873
+```
+
+An ordinary dependent branch chain. GitHub native stacks are not used and were
+not requested.
+
+## Work-phase map (one phase = one full PABCD cycle)
+
+| WP | Doc | Slice | Depends on |
+|----|-----|-------|------------|
+| wp0 | 000 | This roadmap (docs only) | — |
+| wp1 | 010 | Layer 1, carry #3906 | wp0 |
+| wp2 | 020 | Layer 2, carry #3886 | wp1 |
+| wp3 | 030 | Layer 3, implement #3922 | wp2 |
+| wp4 | 040 | Layer 4, carry #3917 | wp3 |
+| wp5 | 050 | Publish, one CI run, merge, settle | wp4 |
+
+Ordering follows textual adjacency in `src/adapters/openai-responses.ts`, which
+layers 1, 2 and 4 all touch at distinct hunks (≈2125, ≈2503, ≈2366 and its import).
+Layer 3 touches `src/claude/inbound-content-options.ts` only.
+
+## Terminal outcomes
+
+- DONE — the stack landed on `dev` with the merge-method-specific proof recorded,
+ children settled with authors preserved, issues #3885/#3922/#3911 closed.
+- BLOCKED — CI red on the tip after a bounded repair attempt, or an unmet merge
+ requirement.
+- NEEDS_HUMAN — an audit finding that would change a carried author's intended
+ behavior beyond what the issue asks.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/010_phase1.md b/devlog/_plan/260908_a_stack_responses_compat/010_phase1.md
new file mode 100644
index 0000000000..85f9e11d3d
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/010_phase1.md
@@ -0,0 +1,62 @@
+# 010 — Phase 1: carry PR #3906 (Muse Spark Contributor Free web_search strip)
+
+Branch `codex/a-stack-l1-muse-free`, based on `origin/dev` `942c02873`.
+Carried commit `11c498b6c62ae9f7c5b0d25ca24fc6612f607a5c` by MohamadSabree8.
+
+## Problem
+
+`stripMuseSparkUnsupportedWebSearchFields` removes `search_content_types` and
+`indexed_web_access` from a Codex `web_search` tool before it reaches the Zen
+Responses wire, because that gateway 400s on them. The model guard only lists the
+two paid contributor ids, so the two Contributor Free ids ride the same wire and
+same gateway contract but keep the rejected fields.
+
+## MODIFY map
+
+`src/adapters/openai-responses.ts` — the constant at 2125-2128.
+
+Before:
+
+```ts
+const MUSE_SPARK_WEB_SEARCH_STRICT_MODELS = new Set([
+ "muse-spark-1.3-contributor",
+ "muse-spark-1.2-contributor",
+]);
+```
+
+After:
+
+```ts
+const MUSE_SPARK_WEB_SEARCH_STRICT_MODELS = new Set([
+ "muse-spark-1.3-contributor",
+ "muse-spark-1.3-contributor-free",
+ "muse-spark-1.2-contributor",
+ "muse-spark-1.2-contributor-free",
+]);
+```
+
+Nothing else changes. The consumer at 2148, its model guard at 2155
+(`if (!MUSE_SPARK_WEB_SEARCH_STRICT_MODELS.has(modelId.trim().toLowerCase())) return body;`),
+the destination guard at 2159-2164 and the call site at 2451 are untouched.
+
+## TESTS
+
+`tests/providers/muse-spark-web-search-compat.test.ts` — add free-tier cases that
+mirror the paid-tier assertions already in the file:
+
+- top-level `tools`: type stays `web_search`, `search_context_size` preserved,
+ `search_content_types` and `indexed_web_access` absent (mirrors 81-87, 131-137);
+- nested `input[].additional_tools.tools`: same removal (mirrors 106-114, 150-158);
+- `web_search_preview` untouched for the free ids (mirrors 90-97, 140-147).
+
+## Known limit (recorded, not fixed here)
+
+`src/providers/registry.ts:1685-1690` maps only the paid ids in
+`modelWireDefaults`, so the `-free` ids do not select the Responses wire
+automatically; this fix applies when that wire is chosen explicitly. Changing the
+registry is out of scope, matching the carried pull request.
+
+## Verification (C)
+
+No local command. The layer is verified by the single tip CI run described in 050.
+Local suites: NOT RUN by instruction.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/020_phase2.md b/devlog/_plan/260908_a_stack_responses_compat/020_phase2.md
new file mode 100644
index 0000000000..13b4cc949c
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/020_phase2.md
@@ -0,0 +1,73 @@
+# 020 — Phase 2: carry PR #3886 (disable Responses Lite transport for Spark)
+
+Branch `codex/a-stack-l2-spark-lite`, based on layer 1.
+Carried commit `83c1d9b129b80d4f65a797fd61a2026deb8c8123` by cb8010d6.
+
+## Problem
+
+Issue #3885: with `x-openai-internal-codex-responses-lite: true`, the canonical
+backend opens a `gpt-5.3-codex-spark` SSE response and closes it before a terminal
+event, which the adapter reports as `response.incomplete` / `adapter_eof`. The same
+request without that header completes.
+
+## MODIFY map
+
+`src/adapters/openai-responses.ts` — inside the canonical-forward block, before
+the existing routing-hint work. Line numbers here are against the pinned base
+`942c02873` (block at 2503-2513); layer 1 adds two lines above it, so on this
+branch the block sits at 2505-2515.
+
+After:
+
+```ts
+ if (isCanonicalOpenAiForwardProvider(provider)) {
+ // Spark closes Responses Lite streams before a terminal completion. Select compatibility
+ // from the final wire model so aliases cannot leave the caller or a static header enabled.
+ if (isPlainObject(finalBody) && finalBody.model === "gpt-5.3-codex-spark") {
+ for (const name of Object.keys(headers)) {
+ if (name.toLowerCase() === CODEX_RESPONSES_LITE_HEADER) delete headers[name];
+ }
+ }
+ const routingHeaders = new Headers(headers);
+ applyCodexRoutingHint(routingHeaders, finalBody);
+```
+
+`finalBody` is computed at 2494-2502 and serialized at 2523 on the pinned base
+(2496-2504 and 2525 on this branch), so it is the actual wire model.
+`parsed.modelId` can differ; the existing test at 187-188 pins that distinction
+deliberately. Keying on `finalBody.model` therefore also covers aliases. The loop
+removes every case spelling, which matters because static provider headers merge
+in at 2315 and 2353 on the pinned base (2317 and 2355 here) with arbitrary casing.
+
+## Scope of the fix, and what it does not cover (audit finding 1)
+
+The independent audit established a real boundary, verified against source:
+
+- **Covered.** Removing the header fixes the reported defect on the HTTP header
+ replay path, including the HTTP fallback: `prepareCodexHttpInit()` recomputes
+ only the routing hint (`src/server/responses/codex-ws-request.ts:46-52`) and
+ `httpInit` carries the header-deleted request forward (`:68`).
+- **Not covered.** On the WebSocket path, `codex-ws-request.ts:30-33` writes
+ `client_metadata[CODEX_RESPONSES_LITE_METADATA_KEY]` only when the header is
+ present and reads `"true"`/`"false"`. Deleting the header leaves any
+ pre-existing `client_metadata` Lite value in the body untouched, and that value
+ reaches the frame at `:71` and the pool reuse key at
+ `codex-ws-pool.ts:53-55`.
+
+Setting the header to `"false"` instead of deleting it would also cover the WS
+case, but that expands the carried author's diff beyond issue #3885 and changes
+socket reuse identity. This phase carries the author's delete-only form and
+records the WS metadata case as unresolved rather than silently expanding scope.
+The tip pull request states this limit explicitly so the residual is visible.
+
+## TESTS
+
+`tests/codex-integration/codex-metadata-integrity.test.ts`, beside the mixed-case
+test at 171: Spark wire model with a caller-provided Lite header, with a
+mixed-case static header, and with `parsed.modelId` set to an alias while the
+serialized model is Spark; `gpt-5.6-sol` keeps the header. Existing guards at 185,
+211, 225 and 267 stay intact.
+
+## Verification (C)
+
+No local command. Verified by the single tip CI run in 050. Local suites: NOT RUN.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/030_phase3.md b/devlog/_plan/260908_a_stack_responses_compat/030_phase3.md
new file mode 100644
index 0000000000..c0e6a00b3f
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/030_phase3.md
@@ -0,0 +1,141 @@
+# 030 — Phase 3: fix issue #3922 (Claude tool strict default on Responses routes)
+
+Branch `codex/a-stack-l3-claude-strict`, based on layer 2. New work; no existing
+pull request. This is the only layer authored here.
+
+## Problem
+
+When Claude Code sends a custom tool without an explicit `strict`, the
+Messages -> Responses translation emits a function tool that also omits `strict`.
+The Responses API treats an omitted `strict` as an attempt to normalize the schema
+into strict mode, so parameters that the Anthropic `input_schema` marks optional
+are treated as required upstream, and a tool call that omits them fails. Anthropic
+requires an explicit `strict: true` to opt in, so the two defaults disagree.
+
+## MODIFY map
+
+`src/claude/inbound-content-options.ts` — `toolsToResponses`, the function-tool
+branch at 26-33.
+
+Before:
+
+```ts
+ if (typeof raw.name === "string" && raw.name.length > 0 && isRec(raw.input_schema)) {
+ out.push({
+ type: "function",
+ name: raw.name,
+ ...(typeof raw.description === "string" ? { description: raw.description } : {}),
+ parameters: raw.input_schema as Record,
+ });
+ continue;
+ }
+```
+
+After:
+
+```ts
+ if (typeof raw.name === "string" && raw.name.length > 0 && isRec(raw.input_schema)) {
+ out.push({
+ type: "function",
+ name: raw.name,
+ ...(typeof raw.description === "string" ? { description: raw.description } : {}),
+ parameters: raw.input_schema as Record,
+ // Anthropic opts into strict tool use explicitly, while Responses normalizes
+ // an omitted strict into strict mode. Carry the source intent rather than the
+ // destination default, so an optional input_schema parameter stays optional.
+ strict: typeof raw.strict === "boolean" ? raw.strict : false,
+ });
+ continue;
+ }
+```
+
+The value is derived from the source tool rather than hardcoded, so an explicit
+`strict: true` or `strict: false` from the client survives translation, which is
+what issue #3922 asks for.
+
+## How the existing strict-tool admission policy relates (audit finding 2)
+
+An earlier draft of this document described `src/claude/compatibility.ts:102`
+backwards. What that line actually does:
+
+```ts
+if (tool.strict === true) codes.add("strict_tools");
+```
+
+`strict_tools` is listed as an incompatible feature at `compatibility.ts:16`, and
+`analyzeClaudeCompatibility` (`compatibility.ts:179`) returns `"reject"` for an
+incompatible request under enforce mode (decision expression at `:189`), which
+`src/server/claude-messages.ts:733-740` applies **before**
+translation. So an explicit `strict: true` is already refused in enforce mode and
+only reaches translation on the default and shadow paths.
+
+This phase does not change that policy. Detection reads the **source** Anthropic
+tool before translation, so emitting a default `strict: false` downstream adds no
+new rejection; `tests/claude-integration/claude-compatibility.test.ts:73-78`
+already covers the explicit-false allow case, and `:24` lists strict tools among
+rejected features.
+
+## Propagation (independently traced twice, no further change needed)
+
+- `src/claude/inbound-content-options.ts:26-32` builds the tool.
+- `src/claude/inbound.ts:350-351` assigns it to `body.tools`.
+- `src/server/claude-messages.ts:875,897` serializes that body into the internal
+ Responses request; `src/server/responses/core.ts:3160` parses it.
+- `src/responses/schema.ts:114` accepts `strict`; `parser-tools.ts:63` preserves an
+ explicit value including `false`.
+- `src/responses/parser.ts:570` keeps `_rawBody`, and
+ `src/adapters/openai-responses.ts:2362-2364` starts from it. Canonical-field
+ stripping only removes `external_web_access`/`defer_loading` (`:189-200`) and
+ schema normalization spreads the tool (`{ ...tool, parameters }`, `:648-658`),
+ so `strict` reaches `JSON.stringify(finalBody)` at `:2523`.
+
+## Boundaries
+
+- Hosted `web_search` leaves the function at 22-24, before this branch, so it gains
+ no `strict` field.
+- Native Anthropic passthrough never reaches translation:
+ `src/server/claude-messages.ts:721-722` returns from `anthropicNativePassthrough`
+ before the translation call at 757.
+- Other Anthropic server tools still drop at 35.
+
+## Schema promise, stated precisely (audit finding 4)
+
+At translation, `parameters` is the caller's `input_schema` reference
+(`inbound-content-options.ts:31`), so `properties`, `required` and nested schemas
+are unchanged there. That is not a promise of a byte-identical schema on every
+outbound route: `openai-responses.ts:651` runs `normalizeXaiToolParameters`, `:657`
+supplies a root `type: "object"` when absent, `responses-code-mode.ts:23-27` can
+rewrite an `exec` parameter description, and Azure Chat sanitizes at
+`openai-chat.ts:1359-1361`. The regression asserts an unchanged schema through the
+ordinary OpenAI Responses route.
+
+Adding the field also shifts fallback cache-cohort hashes, because translated tool
+definitions participate in the hash at `src/claude/inbound.ts:386-392`. That is a
+cohort change, not a correctness change.
+
+## Known risk
+
+The same translated tools feed translated Chat Completions routes, where
+`openai-chat.ts:1343` forwards an explicit `strict`; Azure deletes it at `:1364`,
+and `tests/providers/azure-model-router-tool-schema.test.ts:42` already pins that
+absence. No repository-declared rejection of an explicit `strict: false` was found,
+but universal upstream acceptance is not proven. A provider rejecting it is an
+escalation.
+
+## TESTS
+
+`tests/claude-integration/claude-inbound.test.ts`:
+
+- **Update the existing assertion at 80-83.** It is an exact `toEqual` on the
+ translated `Read` tool and will fail once `strict` is present; the expected
+ object gains `strict: false`.
+- Keep `expect(tools[1]).toEqual({ type: "web_search" })` at 84 unchanged.
+- New cases: omitted `strict` -> `false`; explicit `false` -> preserved; explicit
+ `true` -> preserved; an `input_schema` with one required and one optional
+ property keeps its `required` array through `parseRequest`.
+- Assert the three values on the **serialized adapter output**, not only the
+ translator return, so the wire body is what is pinned.
+
+## Verification (C)
+
+No local command. Verified by the single tip CI run in 050. Local suites: NOT RUN.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/040_phase4.md b/devlog/_plan/260908_a_stack_responses_compat/040_phase4.md
new file mode 100644
index 0000000000..b5a0f94be3
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/040_phase4.md
@@ -0,0 +1,121 @@
+# 040 — Phase 4: carry PR #3917 (routed agent_message conversion), stack tip
+
+Branch `codex/a-stack-l4-routed-agentmsg`, based on layer 3. This branch is the
+stack tip and the only one with a pull request.
+Carried commit `2430724e57e0950bde4b006c0175a2d5c70a0baf` by mashfromband.
+
+## Problem
+
+Codex writes every sub-agent reply into the rollout as an `agent_message` input
+item, which is private to the ChatGPT Codex schema, so it is replayed in the input
+of every later turn of that thread. The routed Responses destinations reported in
+#3911 and #3907 reject the whole body with
+`422 unknown item type "agent_message"`. 422 is a client error, so nothing fails
+over and the thread stays broken. The plaintext conversion already existed but was
+scoped to the OpenCode Go destination, and nothing in those reports is specific to
+that destination.
+
+## MODIFY / RENAME map
+
+1. `src/adapters/opencode-go.ts` -> `src/adapters/routed-agent-messages.ts`.
+ `isOpenCodeGo` is deleted; its only production consumer is the call site below.
+ `normalizeOpenCodeGoAgentMessages` becomes `normalizeRoutedAgentMessages` with
+ the algorithm unchanged, including the fail-closed check that every content part
+ is `input_text`/`input_image`/`input_file`.
+
+2. `src/adapters/openai-responses.ts:1` and `:2366`.
+
+ Before:
+
+ ```ts
+ import { isOpenCodeGo, normalizeOpenCodeGoAgentMessages } from "./opencode-go";
+ ...
+ if (!forward && isOpenCodeGo(provider.baseUrl)) outBody = normalizeOpenCodeGoAgentMessages(outBody);
+ ```
+
+ After:
+
+ ```ts
+ import { normalizeRoutedAgentMessages } from "./routed-agent-messages";
+ ...
+ if (!forward) outBody = normalizeRoutedAgentMessages(outBody);
+ ```
+
+ `forward` is `provider.authMode === "forward"` (2356). All forward destinations
+ retain the existing behavior and keep the item unchanged.
+
+3. `tests/providers/opencode-go-agent-messages.test.ts` ->
+ `tests/adapters/routed-agent-messages.test.ts`, with the two Go-specific
+ expectations (54, 120-122) changed from `agent_message` to the converted
+ `message`/`user` shape for arbitrary routed URLs.
+
+4. `tests/responses/responses-opaque-blob-recovery.test.ts` — the four assertions
+ at 553, 583, 611 and 754. That fixture is `authMode: "key"` (163-164), so its
+ retried item is now converted. Opaque-blob recovery repairs an undecryptable part
+ into `[encrypted content omitted]`, which leaves the item fully plaintext; on a
+ routed retry it is converted too, which is what lets the retry be accepted.
+ Expected object becomes:
+
+ ```ts
+ {
+ type: "message",
+ role: "user",
+ content: [
+ { type: "input_text", text: 'Agent message {"author":"/root/child_task","recipient":"/root"}' },
+ { type: "input_text", text: "Message Type: MESSAGE\nTask name: /root\nSender: /root/child_task\nPayload:" },
+ { type: "input_text", text: "[encrypted content omitted]" },
+ ],
+ }
+ ```
+
+ The `authMode: "forward"` case in the same file is untouched.
+
+5. Both test-layout registries, because the test basename and directory change:
+ `scripts/test-layout/layout.json:917` and
+ `tests/fixtures/test-layout-expected.json:752` drop
+ `"opencode-go-agent-messages.test.ts": "providers"` and gain
+ `"routed-agent-messages.test.ts": "adapters"`.
+ `tests/test-layout-tooling.test.ts:250` compares the two tables exactly, so
+ missing either one fails.
+
+6. `docs-site/src/content/docs/reference/adapters.md` and
+ `docs-site/src/content/docs/reference/configuration/providers.md`, whose wording
+ describes the conversion as Go-specific, as in the carried pull request. The
+ carried text's universal "any routed destination" phrasing is narrowed to the
+ observed non-forward destinations rather than copied unchanged.
+
+## Preserved behavior
+
+Forward destinations, ciphertext and unknown part types (the `every` guard),
+replay immutability and no-op reference identity, the identity prefix text, and
+the session-header assertion at 55 of the moved test.
+
+## PR #3838 boundary
+
+#3838 stays open and independent. Its `normalizeOpenCodeGoAdditionalTools`
+promotion, `customToolWireName` export and `statelessResponses` registry flag are
+unrelated to this conversion. Its mixed-content policy drops ciphertext and unknown
+parts whenever plaintext survives, which contradicts the fail-closed retention kept
+here; it is not carried.
+
+## Verification (C)
+
+No local command. Verified by the single tip CI run in 050. Local suites: NOT RUN.
+
+
+## Which destinations actually change (audit finding 5)
+
+`src/types/provider.ts:449` declares `authMode?: "key" | "forward" | "oauth" | "local"`.
+Because the new gate is `!forward` and `forward` is `provider.authMode === "forward"`
+(`openai-responses.ts:2356`), the conversion now applies to **key, oauth, local and
+undefined** whenever this adapter is selected. Every forward destination is
+unchanged, including noncanonical forward gateways; the built-in ChatGPT
+destination is forward (`src/providers/registry.ts:1200-1204`), so its native items
+stay intact.
+
+No repository-declared non-forward destination requires plaintext `agent_message`
+preservation. Authentication mode alone cannot prove what an arbitrary custom
+upstream accepts, so the carried claim that *every* routed destination rejects the
+item is stated here as the observed pattern rather than a proven universal.
+Regression coverage adds a non-forward mode beyond the carried key/forward
+fixtures.
diff --git a/devlog/_plan/260908_a_stack_responses_compat/050_phase5.md b/devlog/_plan/260908_a_stack_responses_compat/050_phase5.md
new file mode 100644
index 0000000000..97b928d92c
--- /dev/null
+++ b/devlog/_plan/260908_a_stack_responses_compat/050_phase5.md
@@ -0,0 +1,95 @@
+# 050 — Phase 5: publish, single CI run, merge, settle
+
+## Publication
+
+Push all four branches with `--no-verify`, in chain order:
+
+```
+git push --no-verify origin codex/a-stack-l1-muse-free
+git push --no-verify origin codex/a-stack-l2-spark-lite
+git push --no-verify origin codex/a-stack-l3-claude-strict
+git push --no-verify origin codex/a-stack-l4-routed-agentmsg
+```
+
+Pushing l1-l3 starts no workflow: `.github/workflows/ci.yml` limits its `push`
+trigger to `[main, preview, dev]`, and no pull request points at those refs.
+
+## The single pull request
+
+Open exactly one pull request: `codex/a-stack-l4-routed-agentmsg` -> `dev`. Its
+head contains all four layers, so the one Cross-platform CI run it starts is
+cumulative evidence for the whole stack. The description follows
+`.github/PULL_REQUEST_TEMPLATE.md` (Summary, Verification, Checklist), states that
+local suites were NOT RUN by maintainer instruction with CI as the verification
+gate, and names every carried pull request and issue.
+
+Author preservation: each carried commit keeps its original author through a
+`Co-authored-by` trailer that survives a squash, satisfying
+`missing_coauthor_credit` in `.github/scripts/pr-carry-attribution.cjs`:
+
+- `Co-authored-by: MohamadSabree8 `
+- `Co-authored-by: R <53855466+cb8010d6@users.noreply.github.com>`
+- `Co-authored-by: mashfromband `
+
+## Merge gate
+
+Merge only when the tip's Cross-platform CI is green on the exact head SHA of the
+pull request. Skipped, cancelled or queued jobs are not passing evidence, and a
+green run on an earlier head does not certify a newer one. After merging, fetch
+`origin/dev` and prove landing in the way the chosen merge method allows.
+
+The method decides the proof, and only one of the three preserves the tip SHA:
+
+- **Create a merge commit.** The tip SHA itself becomes reachable from `dev`, so
+ `git merge-base --is-ancestor origin/dev` exits 0 and is sufficient.
+- **Squash and merge.** GitHub writes one new commit, so the tip SHA never becomes
+ an ancestor and that check would fail on a successful merge.
+- **Rebase and merge.** GitHub replays the commits onto `dev` with new SHAs, so the
+ original tip SHA is likewise not an ancestor.
+
+For the two rewriting methods, identify the landed commit or commits on `dev`
+first, then prove landing by content and attribution rather than by the original
+SHA:
+
+- `git diff origin/dev -- ` is empty;
+- `git merge-base --is-ancestor origin/dev` exits 0 for the landed
+ commit;
+- the landed record carries all three `Co-authored-by` trailers.
+
+Record the method used together with its matching proof, rather than asserting
+ancestry of the original tip generically.
+
+## Settlement
+
+Once the change is confirmed on `dev`:
+
+- PRs #3906, #3886 and #3917 — comment that the work landed on `dev` through the
+ stack tip, name the merge commit, and close them. Their authors are already
+ preserved in the trailers.
+- Issues #3885 (Spark `adapter_eof`), #3922 (Claude tool strict) and #3911
+ (routed `agent_message` 422) — close, since PRs target `dev` and GitHub only
+ auto-closes on merges into the default branch.
+- PR #3838 stays open; its residual work is unrelated to this stack.
+
+## Verification (C)
+
+The tip CI run identified by its run id and head SHA, with every required job
+reporting success, plus the merge-method-specific landing proof above against a
+freshly fetched `origin/dev`. Local suites: NOT RUN by maintainer instruction.
+
+
+## Merge readiness is broader than one workflow (audit finding 7)
+
+The single tip CI run is the verification evidence this session produces, but it is
+not by itself the whole merge gate. `MAINTAINERS.md:57-69` also requires the
+applicable required checks, resolution of outstanding maintainer objections, and
+applicable security review. The `dev`-only maintainer-integration path still
+records the decision and the exact-head evidence. Anything in that set that this
+session cannot satisfy is reported rather than assumed.
+
+## Attribution is added, not inherited
+
+The three carried commits do **not** already contain `Co-authored-by` trailers in
+their original messages. The trailers listed above are added when the commits are
+carried onto the stack, and their presence is verified on the final squash-surviving
+record before the children are closed.
diff --git a/devlog/_plan/260908_d_group_test_infra_stack/000_plan.md b/devlog/_plan/260908_d_group_test_infra_stack/000_plan.md
new file mode 100644
index 0000000000..35b2a65c67
--- /dev/null
+++ b/devlog/_plan/260908_d_group_test_infra_stack/000_plan.md
@@ -0,0 +1,113 @@
+# D-group test-infrastructure delivery as a single-CI manual stack
+
+## Objective
+
+Land the two D-group test-infrastructure items on `dev` as one dependency-ordered
+branch chain whose **tip is the only pull request**, so the cumulative tree is
+verified by exactly one Cross-platform CI run. Merge the tip once that run is
+green, then settle the original pull requests and any linked issues.
+
+| Layer | Source | Content |
+|---|---|---|
+| 1 (bottom) | PR #3924 by @luvs01 | `scripts/test.ts` keeps captured lane output after a timeout; runner regressions; contributing note |
+| 2 (tip) | PR #3930 by @luvs01 | `tests/providers/cursor/cursor-stream-health.test.ts` load-scaled watchdog budgets |
+
+Both source pull requests carry exactly one commit each, authored by `luvs01`
+(`27862058+luvs01@users.noreply.github.com`), so `git cherry-pick -x` preserves
+authorship without needing a reconstructed `Co-authored-by` trailer. The trailer is
+added to the tip pull-request description anyway, because the repository squashes
+and `.github/scripts/pr-carry-attribution.cjs` reads the trailer, not prose.
+
+## Why a stack, and why only one pull request
+
+`.github/workflows/ci.yml` triggers on a bare `pull_request:` with no base-branch
+filter. That is deliberate — the comment in the file records that a
+`branches: [main, dev]` filter once silently excluded stacked child pull requests.
+The consequence for this unit is mechanical: **every open pull request starts a
+Cross-platform CI run**, whatever its base. A two-pull-request stack therefore costs
+two runs, and a child pull request based on the parent's head costs one more.
+
+The only way to get a single run covering both changes is to give the stack exactly
+one pull request, at the tip, based on `dev`. The lower layer is pushed as a branch
+for provenance and review navigation, and never gets a pull request of its own.
+Pushing a branch does not start CI either: `ci.yml`'s `push:` trigger is pinned to
+`branches: [main, preview, dev]`, and this stack pushes neither.
+
+The tip run covers the PR-enabled producers, not every job in the file. `changes`
+sets `ci: true` for `tests/**` and `scripts/**` (`ci.yml:193-194`), which this stack
+touches, so the four Linux shards, `gates`, `storage policy`, `api usage`,
+`platform-macos`, `keyring` and `docker smoke` all execute. Three job families do
+**not** run on a pull request and must never be reported as passing evidence:
+
+| Job | Guard | Status on this PR |
+|---|---|---|
+| `windows /6` | `github.event_name == 'workflow_dispatch' && (inputs.lane == '' \|\| inputs.lane == 'all')` (`ci.yml:742-743`) | SKIPPED BY WORKFLOW |
+| `macos control` | `github.event_name == 'workflow_dispatch'` (`ci.yml:633`) | SKIPPED BY WORKFLOW |
+| `npm-global ` | `needs.changes.outputs.packaging == 'true'` (`ci.yml:943`); the packaging allowlist (`ci.yml:215-229`) excludes all four files | SKIPPED BY WORKFLOW |
+
+That exclusion is acceptable for this unit: nothing here ships in the package tree,
+and `scripts/test.ts` is the test runner rather than runtime source. The Windows
+lane is dispatch-only for every ordinary pull request in this repository, so
+requiring it here would be a new policy, not this unit's job.
+
+## Dependency order
+
+Layer 1 is the runner change; layer 2 is a fixture that the runner executes. Ordering
+them the other way would put a test-timing change under an unverified runner. The
+order is a build-order statement, not an effort estimate.
+
+## Work phases
+
+| Phase | Outcome |
+|---|---|
+| wp0 | This roadmap: stack shape, single-trigger proof, merge/close order, attribution |
+| wp1 | Build both layers locally on fresh `origin/dev` with `cherry-pick -x` |
+| wp2 | Push both branches with `--no-verify`; open exactly one pull request (tip → `dev`) |
+| wp3 | Record tip CI, merge the tip, settle #3924/#3930 and linked issues |
+
+Diff-level detail for each phase: `010_phase1_stack_build.md`,
+`020_phase2_publish.md`, `030_phase3_merge_and_settle.md`.
+
+## Constraints in force
+
+The owner set these for this unit, and they override the repository's default
+verification habits:
+
+- **No local suite.** No `bun run test`, `bun test`, `bun run test:changed`,
+ `bun run typecheck`, or build used as a gate. Every such row is recorded
+ `NOT RUN (owner instruction)`, never as a pass.
+- **Push with `--no-verify`.** Local hooks are skipped by instruction.
+- **CI on the tip only.** Never open a pull request for a lower layer.
+- **One green run, then merge.** The tip's exact head SHA is the product gate.
+- **Preserve original authorship** for carried work.
+- **Close linked issues** at the moment the change is on `dev`.
+
+## Verification model
+
+The product evidence is the hosted Cross-platform CI run on the tip's exact head
+SHA — run id, head SHA, per-job conclusions — read as a job matrix, not as the
+aggregate `ci` summary alone. The three dispatch-only or packaging-gated job
+families above are recorded SKIPPED BY WORKFLOW.
+
+Merge additionally requires the current gate checks to be green on that same head:
+`enforce-target` and `hygiene` (`enforce-pr-target.yml:679-692` folds deterministic
+hygiene failures into its verdict; `pr-hygiene.yml:236-238` fails and labels on a
+violation), plus resolution of any actionable automated review finding.
+
+Landing evidence is the squash SHA GitHub returns, proven to be an ancestor of
+fetched `origin/dev`, with its tree compared against the reviewed tip. Local checks
+are `NOT RUN` by instruction and are never reported as passing.
+
+A verifier honesty note, since this unit's plan names commands it will not run:
+`bun run test` would observe `scripts/test.ts` and both test files, and
+`bun run typecheck` would observe `scripts/test.ts`. Both are in scope for the
+change and both are withheld by owner instruction, so their acceptance rows are
+delegated to hosted CI rather than claimed locally.
+
+## Terminal outcomes
+
+- **DONE** — tip CI green on its exact head, tip merged into `dev`, #3924 and #3930
+ settled with authorship preserved, linked issues closed, evidence recorded.
+- **BLOCKED** — a required merge right is missing, or CI fails for a cause outside
+ these four files.
+- **NEEDS_HUMAN** — a policy decision beyond restoring existing behavior.
diff --git a/devlog/_plan/260908_d_group_test_infra_stack/001_audit_record.md b/devlog/_plan/260908_d_group_test_infra_stack/001_audit_record.md
new file mode 100644
index 0000000000..b668981357
--- /dev/null
+++ b/devlog/_plan/260908_d_group_test_infra_stack/001_audit_record.md
@@ -0,0 +1,53 @@
+# Audit record — roadmap gate
+
+An independent reviewer (a separate context, `gpt-6-astra` at high effort) audited
+the roadmap before any branch was built. Three rounds ran; the first two failed.
+The findings are recorded here because they changed the plan, and because two of
+them would have produced a false completion claim.
+
+## Round 1 — FAIL, four blocking defects
+
+1. **Overstated CI coverage.** The plan promised platform and packaging coverage
+ from the tip pull-request run. In fact `windows /6` and `macos control` are
+ `workflow_dispatch`-only (`ci.yml:633`, `742-743`), and `npm-global` needs
+ `packaging == 'true'`, which the packaging allowlist (`ci.yml:215-229`) does not
+ set for any of the four files. Fixed by adding an explicit RUN vs
+ SKIPPED BY WORKFLOW matrix and forbidding the skipped families from being
+ reported as passes.
+2. **CI success treated as sufficient for merge.** `enforce-target` folds
+ deterministic hygiene failures into its verdict (`enforce-pr-target.yml:679-692`)
+ and `pr-hygiene` fails and labels on a violation (`pr-hygiene.yml:236-238`).
+ `MAINTAINERS.md:61` also requires the integration decision and exact-head
+ verification to be recorded. Fixed by adding those gates and the record step.
+3. **Wrong ancestry object.** The plan checked whether the tip commit was an
+ ancestor of `dev`. A squash merge never makes the tip an ancestor, so that check
+ would have failed on a perfectly good landing — or worse, been waved through.
+ Fixed by recording the squash SHA GitHub returns and testing that.
+4. **Attribution assumed rather than controlled.** The repository sets
+ `squash_merge_commit_message: COMMIT_MESSAGES`, so the pull-request description
+ is not the landed message. A description trailer satisfies the hygiene checker
+ and still leaves the contributor uncredited in the commit. Fixed by supplying the
+ squash body explicitly and verifying the landed trailer before closing anything.
+
+## Round 2 — FAIL, two blocking defects
+
+1. **Missing administrator bypass.** `Protect dev` requires an approving review and
+ code-owner review, so the merge call is refused without `--admin`. The plan named
+ the policy exception without naming the mechanism that exercises it.
+2. **Bot findings mistaken for all findings.** The gate covered automated review
+ findings but not human ones. `MAINTAINERS.md:62-64` requires outstanding
+ maintainer change requests to be resolved or explicitly withdrawn.
+
+## Round 3 — PASS
+
+The reviewer set the phase-1 acceptance bar: freshly fetched base SHA, both
+constructed commit SHAs, evidence that layer 1 follows the base and layer 2 follows
+layer 1, both authors reading `luvs01`, both `-x` provenance lines, per-layer and
+cumulative name/numstat comparisons, blob comparisons against the source pull
+requests, and the roadmap commit accounted for separately so it stays out of the
+four-file implementation delta.
+
+## Standing note
+
+Local suite, typecheck and build are **NOT RUN** for this unit by owner
+instruction. That is a recorded absence of evidence, not a pass.
diff --git a/devlog/_plan/260908_d_group_test_infra_stack/010_phase1_stack_build.md b/devlog/_plan/260908_d_group_test_infra_stack/010_phase1_stack_build.md
new file mode 100644
index 0000000000..003cd0ad82
--- /dev/null
+++ b/devlog/_plan/260908_d_group_test_infra_stack/010_phase1_stack_build.md
@@ -0,0 +1,54 @@
+# Phase 1 — Build the stack locally
+
+Base: fetched `origin/dev`. Both source commits live in the `luvs01` remote
+(`https://github.com/luvs01/opencodex.git`), already configured in this checkout.
+
+## Commands
+
+```sh
+git fetch origin dev
+git fetch luvs01 e24163231edeaa09a30a99ca1746e3b573af78ae 141077f7270e2f2a0564fb036d091f0cf793b784
+
+# Layer 1 — PR #3924
+git switch -c codex/260908-d-group-l1-test-runner-output origin/dev
+git cherry-pick -x e24163231edeaa09a30a99ca1746e3b573af78ae
+
+# Layer 2 — PR #3930, tip
+git switch -c codex/260908-d-group-l2-cursor-watchdog
+git cherry-pick -x 141077f7270e2f2a0564fb036d091f0cf793b784
+```
+
+`cherry-pick -x` keeps the original author identity
+(`luvs01 <27862058+luvs01@users.noreply.github.com`>) and appends the
+`(cherry picked from commit ...)` provenance line. No `Co-authored-by` trailer is
+needed on the commits themselves because authorship is not being reassigned. The
+trailer goes in the tip pull-request description for hygiene acceptance; phase 3
+separately supplies and verifies the trailer on the landed squash commit, which is
+the only thing GitHub reads for contributor credit.
+
+## Expected change map
+
+| Layer | File | Change |
+|---|---|---|
+| 1 | `scripts/test.ts` | +81 −8 — incremental capture, retained output on timeout, bounded drain, incomplete-capture exit policy |
+| 1 | `tests/ci-workflows/test-runner.test.ts` | +147 −1 — regressions for timeout/failure/success output, split UTF-8, open pipes, read failure |
+| 1 | `docs-site/src/content/docs/contributing.md` | +6 — documents the timeout and incomplete-capture behavior |
+| 2 | `tests/providers/cursor/cursor-stream-health.test.ts` | +59 −26 — one scaled silence budget S, 2S heartbeat-only, ≥3S observed progress after first received text |
+
+Cumulative tip versus `origin/dev`: exactly those four files.
+
+## Conflict expectation
+
+None. The two file sets are disjoint, and the Cursor test file plus its
+`tests/helpers/ci-watchdog.ts` import carry identical blob SHAs at `dev` and at
+#3924's head (`dc7b572bf1` and `f8adcfe3d9`), so layer 2's preimage is unchanged by
+layer 1.
+
+## Acceptance
+
+- `git log --format='%an <%ae>'` on both new commits reports `luvs01`.
+- `git diff --name-only origin/dev..tip` lists exactly the four files above.
+- `git diff --stat` matches the per-file counts in the table.
+- Each cherry-picked tree is byte-identical to the source PR head's version of its files.
+
+Local suite: NOT RUN (owner instruction).
diff --git a/devlog/_plan/260908_d_group_test_infra_stack/020_phase2_publish.md b/devlog/_plan/260908_d_group_test_infra_stack/020_phase2_publish.md
new file mode 100644
index 0000000000..2af6acab12
--- /dev/null
+++ b/devlog/_plan/260908_d_group_test_infra_stack/020_phase2_publish.md
@@ -0,0 +1,92 @@
+# Phase 2 — Publish the stack, one pull request only
+
+## Push
+
+```sh
+git push --no-verify origin codex/260908-d-group-l1-test-runner-output
+git push --no-verify origin codex/260908-d-group-l2-cursor-watchdog
+```
+
+`--no-verify` is the owner's instruction for this unit. Neither push starts
+Cross-platform CI: `ci.yml`'s `push:` trigger is limited to
+`branches: [main, preview, dev]` (`ci.yml:26-27`).
+
+## Open exactly one pull request
+
+Tip only, targeting `dev`:
+
+```sh
+gh pr create --repo lidge-jun/opencodex --base dev \
+ --head codex/260908-d-group-l2-cursor-watchdog \
+ --title "fix(test): preserve lane output after timeouts and stabilize the Cursor stream-health watchdog" \
+ --body-file
+```
+
+The lower layer gets **no** pull request. `ci.yml` triggers on a bare
+`pull_request:` with no base filter (`ci.yml:7`), so a second pull request would
+start a second Cross-platform CI run; draft status does not suppress it either —
+no job in `ci.yml` reads a draft condition.
+
+A stacked child pull request based on the layer-1 branch is also unavailable here:
+`enforce-target` grants the wrong-base exemption only when the parent branch has
+its own **open** pull request (`enforce-pr-target.yml:536-537`), which is exactly
+what this design avoids. The tip therefore targets `dev` directly.
+
+## Description requirements
+
+`.github/PULL_REQUEST_TEMPLATE.md` requires Summary, Verification, and Checklist;
+`enforce-target` rejects thin or malformed descriptions. The description must also:
+
+- name both source pull requests (#3924, #3930) and describe the stack layering;
+- carry `Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>`. The
+ hygiene checker reads that trailer from the description or a commit message
+ (`pr-carry-attribution.cjs:190`), and the carry verbs in the description are what
+ make it demand one at all. The description trailer satisfies the gate; it does
+ **not** by itself put the trailer in the landed commit — see phase 3, where the
+ squash body carries it explicitly;
+- state honestly that local suite, typecheck and build were **NOT RUN** by owner
+ instruction, and that hosted CI on this exact head is the verification gate,
+ naming which job families are skipped by the workflow;
+- be substantive: `pr-quality.cjs` strips template boilerplate and requires real
+ content (two substantial sections, or 120+ characters across two blocks), so
+ placeholder bullets fail the gate.
+
+As a maintainer-authored pull request this needs no readiness checklist and no
+`review-ready` label (`enforce-pr-target.yml:766-768`, `1096-1103`). Do not tick a
+local-CI attestation box that was not earned — the owner forbade the local suite.
+
+No GUI files change, so the screenshot rule does not apply.
+
+## Other workflows that will fire
+
+Expected and unavoidable for any pull request: `enforce-target`, `pr-hygiene`,
+`pr-labeler`, `react-doctor`, plus CodeRabbit. `service-lifecycle` does **not**
+fire — none of the four paths is in its allowlist. These are gate/lint signals, not
+the product suite; only Cross-platform CI is the product gate.
+
+## Outcome
+
+Executed 2026-09-08 against base `942c02873`.
+
+| Ref | SHA | Pull request |
+|---|---|---|
+| `codex/260908-d-group-l1-test-runner-output` | `ab06523e6` | none, by design |
+| `codex/260908-d-group-l2-cursor-watchdog` (tip) | `8b81676ac` | [#3940](https://github.com/lidge-jun/opencodex/pull/3940), base `dev` |
+
+Both pushes used `--no-verify`. Neither started Cross-platform CI, as predicted by
+the `push` branch filter. Opening #3940 started exactly one run on `8b81676ac`; the
+first check-runs to appear were `changes`, `select windows runner`, `hygiene`,
+`label`, `resolve-pr` and `react-doctor`, which matches the expected set.
+
+The layer-1 branch has zero pull requests in any state, which is the property that
+keeps the stack to a single CI run.
+
+## Acceptance
+
+- Both branches exist on `origin` at the expected SHAs.
+- `gh pr list --head codex/260908-d-group-l1-test-runner-output` returns empty.
+- Exactly one open pull request has head `codex/260908-d-group-l2-cursor-watchdog`
+ and base `dev`.
+- Exactly one Cross-platform CI run exists for the tip head SHA. "Exactly one" is
+ scoped to the pre-merge candidate: landing on `dev` starts a separate push run,
+ and a base refresh replaces the candidate with a new head and a new run.
diff --git a/devlog/_plan/260908_d_group_test_infra_stack/030_phase3_merge_and_settle.md b/devlog/_plan/260908_d_group_test_infra_stack/030_phase3_merge_and_settle.md
new file mode 100644
index 0000000000..5e6d3ece96
--- /dev/null
+++ b/devlog/_plan/260908_d_group_test_infra_stack/030_phase3_merge_and_settle.md
@@ -0,0 +1,106 @@
+# Phase 3 — Merge the tip, settle the stack
+
+## Gate
+
+The product gate is the Cross-platform CI run on the tip's **exact** head SHA.
+Record run id, head SHA, and each producer's conclusion. A cancelled or superseded
+run is not evidence, and a run on an earlier head is not evidence for the merged
+head. Read the producers, not only the aggregate `ci` check.
+
+Expected to RUN (`ci: true` via `tests/**` and `scripts/**`): four Linux `test`
+shards, `gates`, `storage policy`, `api usage`, `macos /2`, `keyring` (three OS),
+`docker smoke`.
+
+Expected to be SKIPPED BY WORKFLOW, and recorded as such rather than as passes:
+`windows /6` and `macos control` (both `workflow_dispatch`-only), and
+`npm-global ` (needs `packaging == 'true'`, which these four files do not set).
+
+Merge also requires, on the same head:
+
+- `enforce-target` success and `hygiene` success;
+- every actionable automated review finding resolved;
+- **outstanding maintainer change requests resolved or explicitly withdrawn**
+ (`MAINTAINERS.md:62-64`) — read the human reviews immediately before merging, not
+ only the bot findings;
+- a refreshed read of head, base, merge state, and the integrating actor's
+ repository permission immediately before merging.
+
+## Maintainer integration record
+
+`MAINTAINERS.md:59-63` permits a maintainer with `maintain` or `admin` to integrate
+into `dev` without a second approval, and requires the decision and the exact-head
+verification to be recorded in the pull request. Post that record as a comment
+before merging: the integrating maintainer, the exact head SHA, the CI run link,
+the job matrix including the skipped families, and the statement that local suite,
+typecheck and build were NOT RUN by owner instruction.
+
+The `Protect dev` ruleset still requires an approving review and code-owner review,
+so the merge call itself will be refused without an explicit administrator bypass.
+That bypass is the mechanism this policy exception is exercised through, and it is
+conditional: verified maintainer identity with `admin`, base `dev`, every planned
+check green on the exact head, and the integration record posted. It is never a way
+past failing CI or an unresolved objection.
+
+## Merge order
+
+1. Refresh the tip against `dev` if `dev` moved; a moved base means the green run
+ no longer describes the merge result, so re-run the gate on the new head.
+2. Merge the tip pull request into `dev` with an explicit squash body. The repository
+ sets `squash_merge_commit_message: COMMIT_MESSAGES`, so the landed message is not
+ the pull-request description: supply it directly and make it carry the trailer.
+
+ ```sh
+ gh pr merge --repo lidge-jun/opencodex --squash --admin \
+ --match-head-commit --body-file
+ ```
+
+ `--body-file` supplies the **merge commit body**, which under `--squash` is the
+ squash commit body, replacing the repository's `COMMIT_MESSAGES` default
+ (verified against the installed `gh` 2.91.0 help). `--subject` is optional and
+ only controls the title. `--match-head-commit` refuses the merge if the head
+ moved after the gate was read.
+
+ The squash body must contain, on its own line:
+
+ ```text
+ Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
+ ```
+
+3. Read the landed squash SHA from GitHub, fetch `origin/dev`, and prove:
+ `git merge-base --is-ancestor origin/dev` exits 0, the landed commit
+ message contains the trailer, and the four files on `dev` match the reviewed tip.
+
+Merging is an external state change and stays user-authorized.
+
+## Settling the source pull requests
+
+Both #3924 and #3930 were carried by `cherry-pick -x`, so GitHub will not mark them
+merged automatically. After the tip lands:
+
+- Verify the landed commit's trailer **before** closing either source pull request.
+ A closing comment is prose; only the trailer is contributor-graph data
+ (`CREDITS.md` exists because that distinction was missed 27 times).
+- Then close #3924 and #3930 with a comment naming the landed squash SHA, the tip
+ pull request, and the preserved authorship.
+- Do not delete the contributor branches on the fork; they are not ours.
+
+## Linked issues
+
+Neither #3924 nor #3930 declares a closing issue reference
+(`closingIssuesReferences` is empty for both). If none is discovered during the
+cycle, the "close linked issues" obligation is satisfied vacuously and recorded as
+such. Any issue found to be resolved by this landing is closed at the moment the
+change is on `dev`, with a comment naming the commit.
+
+## Acceptance
+
+- Tip CI: run id + head SHA + per-job conclusions on the merged head, with the three
+ skipped job families named as skipped.
+- `enforce-target` and `hygiene` green on that head; maintainer-integration record
+ posted on the pull request.
+- `git merge-base --is-ancestor origin/dev` exits 0 after fetch, the
+ landed commit carries the `luvs01` trailer, and the four files on `dev` match the
+ reviewed tip.
+- #3924 and #3930 closed after that verification; no lower-layer pull request was
+ ever opened.
+- Linked-issue status stated explicitly (closed, or none exists).
diff --git a/devlog/_plan/260908_sponsor_overview/010_overview.md b/devlog/_plan/260908_sponsor_overview/010_overview.md
new file mode 100644
index 0000000000..92493bf2a9
--- /dev/null
+++ b/devlog/_plan/260908_sponsor_overview/010_overview.md
@@ -0,0 +1,38 @@
+# Sponsor overview presentation
+
+Satisfy-spec, C2, one shared UI slice delivered to existing independent PRs #3914 and #3915. Trigger: the maintainer requested concise marketing copy, hyperlinks, tidy design and PR screenshot mockups. Stop after both remote branches and PR descriptions are updated with truthful verification. No merge, release, deployment, credential changes, outreach or new dependencies. No user-defined resource budget; use existing local tools and remote macmini-cf for heavy validation. This document and the local goalplan hold evidence. Escalate only a conflicting remote edit, inaccessible publication or unrelated baseline failure requiring broader scope; report incomplete evidence honestly.
+
+## Design read
+
+Developer dashboard, existing neutral theme and system font. Keep compact connection facts and quota data; introduce one quiet sponsor strip with product identity, a two-line value proposition, explicit Sponsor disclosure and named outbound actions. No hero, animation, invented discount or performance claim. Variance 3/10, motion 1/10, density D5. Reuse existing ProviderIcon, button/link tokens and locale dictionaries. Desktop strip places copy and actions side by side; narrow containers wrap actions below copy. Screenshot mockups use actual components and synthetic account/usage values, labelled as fixtures in PR prose. Utility dashboard exemption: no generated concept images.
+
+## Existing owners and necessity
+
+- `gui/src/pages/Providers.tsx:289`: existing cached `/api/provider-presets` request; consume its result instead of adding a request/store.
+- `gui/src/components/provider-catalog/provider-presets.ts:17`: CatalogPreset already owns sponsor/sponsorUrl/dashboardUrl/note. No backend field or persistence change.
+- `gui/src/components/provider-workspace/ProviderDetails.tsx:265`: pass the matched preset to Overview.
+- `gui/src/components/provider-workspace/ProviderOverview.tsx:186`: note is duplicated in connection facts and NotesSection. Remove the duplicate and move the existing editable NotesSection into the wider main column. Preserve full note and its editing behavior for every provider.
+- `gui/src/styles/provider-workspace-shell.css:606`: existing responsive grid/tokens.
+- Searched preset matching, sponsor fields, Overview callers and note-save tests; no equivalent overview sponsor presentation exists. Configuration alone cannot add links to the current text-only view.
+
+## Diff map
+
+1. MODIFY Providers cached request typing to CatalogPreset[] and pass matching preset; match canonical id + adapter + normalized endpoint (trailing slash tolerated); mismatched endpoints or absent presets produce no sponsor strip. Do not infer endorsement from name alone. Reuse cache; no new fetch.
+2. MODIFY ProviderDetails and ProviderOverview optional preset prop. NEW small ProviderSponsor component in provider-workspace: render only known sponsor identities with active sponsor metadata; localize concise OrcaRouter adaptive-routing and PackyCode multi-tool API-relay descriptions. Preserve exact existing affiliate URL, expose dashboard link only when distinct, HTTP(S) only, new-tab noopener/noreferrer. No HTML parsing of notes.
+3. MODIFY Overview: render sponsor strip above columns; remove connection note row, put existing NotesSection after auth summary, leaving right column stats/quota only. Full user note remains visible/editable once.
+4. MODIFY existing workspace stylesheet for strip layout, subtle border, readable copy/actions and note wrapping. MODIFY all locale dictionaries for every added key.
+5. NEW focused GUI render tests for sponsor links/disclosure, missing/non-sponsor/custom-endpoint cases; extend existing note test to assert exactly one note and continued editing. No root test-map change for GUI tests.
+6. MODIFY providers guide and GUI SoT for sponsor overview behavior. ADD desktop and narrow actual-render PNGs per sponsor under existing assets/sponsors; update both PR descriptions, preserving prior scope and verification distinctions.
+
+## Acceptance and validation
+
+- Active OrcaRouter API and OAuth presets show the strip only for their configured endpoint; PackyCode only on its sponsor branch. Missing catalog, non-sponsor and changed endpoint remain ordinary provider views. Focused tests activate each branch.
+- Exact sponsorURL survives, duplicate dashboard URL is suppressed, unsafe URLs do not become anchors. Provider limitations and arbitrary user note remain complete and occur once; note-save failure keeps draft/error.
+- Run focused GUI tests (new sponsor tests plus existing notes, catalog sponsor-pinning and locale parity), lint:i18n, lint and GUI build. Existing scripts confirmed in gui/package.json; target files/locale imports prove coverage. Fresh execution recorded in C, not claimed from script existence.
+- For review-ready delivery run root typecheck and full tests plus full GUI tests on isolated macmini-cf checkout; build locally for rendered proof. Existing PR gates already fail before this patch: diagnose separately and do not claim green by inheritance.
+- Browser smoke at 1440px and 390px, light/dark, English/Korean: inspect screenshot, actual hyperlinks and keyboard focus, note editing and overflow. No live account data or upstream inference.
+- Preserve both original histories: build on sponsor remote heads in this bound worktree with separate local branches, carry shared commit to second branch, push fast-forward to each existing remote after refreshing identity. No native stack changes.
+
+## Audit and evidence
+
+Independent audit: GO-WITH-FIXES, one blocking coverage gap. Folded: the browser integration smoke must load the real Providers → Details → Overview chain with delayed catalog resolution, assert sponsor content appears, count the shared preset request, then change the fixture endpoint and verify the strip disappears. Component-only screenshots do not close this row. Branch matrix: Orca API/OAuth positive and Packy absent on Orca head; Packy positive and Orca strip absent on Packy head. Baseline focused tests: 13 pass / 0 fail. Existing CI failure is French modal.badge.sponsor untranslated; correct the sponsor-specific locale value while updating copy.
diff --git a/devlog/_plan/260908_voice_relay/000_plan.md b/devlog/_plan/260908_voice_relay/000_plan.md
new file mode 100644
index 0000000000..2675c20c84
--- /dev/null
+++ b/devlog/_plan/260908_voice_relay/000_plan.md
@@ -0,0 +1,39 @@
+# Codex voice relay follow-up
+
+Satisfy-spec HOTL loop, triggered by the maintainer's September voice source comparison request.
+Goal: carry only verified OpenCodex-owned improvements and document the client/proxy boundary.
+No local product tests, typecheck, build or installs; no release, deployment or user settings changes.
+Verification: read pinned upstream source and Aside findings; independent review; final cumulative
+remote Cross-platform CI dispatch (all lanes), followed by exact-head merge and fetched dev tree proof.
+Local product verification is NOT RUN by explicit user instruction. Git diff/document inspection is
+allowed but does not certify runtime behavior. No latency or live audio improvement is claimed.
+Stop: audited no-change conclusion, or required corrections landed with fresh remote evidence.
+Outcomes: DONE, evidence-backed NOOP, or explicit unmet external gate. No invented time/cost budget;
+existing tools/credentials only, bounded individual probes, no new services or installs.
+Escalation: unresolved maintainer objection, missing external authority, or unavailable required CI.
+
+## Ordered work phases
+
+1. wp1: source research and audited roadmap (documents only).
+2. wp2: scoped relay correction and adjacent regression coverage; depends on wp1.
+3. wp3: publish the documented contract, final cumulative CI, and merge; depends on wp2.
+
+Existing owners: `src/server/live.ts`, `src/server/index.ts`, `tests/server/server-live.test.ts`,
+`docs-site/src/content/docs/guides/codex-integration.md`, `structure/04_transports-and-sidecars.md`.
+No new production abstraction, endpoint or dependency. Preserve preexisting worktree documents.
+Manual two-PR chain: relay implementation/tests, then integration documentation. User explicitly
+requests final-tip-only product CI, overriding per-layer local/full-suite defaults. Automatic
+redundant product CI on these task PRs may be cancelled; it is never counted as passing evidence.
+Use merge commits to preserve stack ancestry, retarget the child only after the parent lands,
+and recheck the current dev tree before final merge. Required checks remain truthful.
+
+Security working material is kept only in ignored scratch per AGENTS.md. The detailed audited
+roadmap resides in `.tmp/voice-0908/010_runtime.md` and `.tmp/voice-0908/020_delivery.md` until
+publication of the fix; it is intentionally not copied into this public planning directory.
+
+## Roadmap audit and lock
+
+Independent plan and security audit: PASS, no blockers. The implementation will preserve view
+bounds and original frame delivery. Diagnostic replacement-character flags are not evidence of
+which peer introduced malformed text. Existing logs are outside this prospective logging change.
+The roadmap is locked for wp2; final runtime evidence remains due in wp3, on the cumulative tree.
diff --git a/devlog/_plan/260908_voice_relay/001_sources.md b/devlog/_plan/260908_voice_relay/001_sources.md
new file mode 100644
index 0000000000..b5a6c2658f
--- /dev/null
+++ b/devlog/_plan/260908_voice_relay/001_sources.md
@@ -0,0 +1,24 @@
+# Source comparison
+
+Pinned upstream: openai/codex b01c3986fd2e79b8a477a08d81430f52f22bc0dc (2026-09-07 UTC).
+The local corpus is `/Users/jun/Developer/codex`; its 120 and 121 upstream checkouts had older
+working heads, so the named commit was fetched without modifying their worktrees.
+
+- https://github.com/openai/codex/commit/1b53f6a44eff890b5169bde8d3bd5b12b8766946:
+ local voice helper offer/answer, ordered oai-events data channel and UDP/TCP transport.
+- https://github.com/openai/codex/commit/b01c3986fd2e79b8a477a08d81430f52f22bc0dc:
+ feature-gated TUI voice commands, captions, handoff answer delivery and lifecycle cleanup.
+- `codex-rs/codex-api/src/endpoint/realtime_call.rs` at the pinned head:
+ backend JSON and API multipart call creation, Frameless `/live`, AVAS `/realtime/calls`.
+- OpenCodex `src/server/live.ts` already implements these call-create and sideband shapes;
+ `src/server/index.ts` transparently relays frames and bounds pending queues and teardown.
+- `tests/server/server-live.test.ts` already covers call creation, protocol headers, pool identity,
+ sideband joins and frame delivery. Existing implementation is reused, not duplicated.
+
+Fast-tier display text and local audio negotiation do not demonstrate a proxy latency gain.
+The TUI merge date does not establish when a desktop binary shipped. Live microphone/audio
+verification is outside the automated evidence gathered here.
+
+The Fast-tier metadata commit is 0e0f55fc4ec9308840e54ceba1f1f1dc9547380f,
+2026-09-04T00:12:18Z; it changes only `codex-rs/models-manager/models.json`.
+It describes the supported service tier, not OpenCodex voice transport performance.
diff --git a/devlog/_plan/260909_config_mutation_lock_windows/000_plan.md b/devlog/_plan/260909_config_mutation_lock_windows/000_plan.md
new file mode 100644
index 0000000000..e5226fa05a
--- /dev/null
+++ b/devlog/_plan/260909_config_mutation_lock_windows/000_plan.md
@@ -0,0 +1,176 @@
+# config-mutation-lock Windows fixture: readiness budget + failure unmasking
+
+## Reader summary
+
+Windows shard 2/6 of run
+[34321628628](https://github.com/lidge-jun/opencodex/actions/runs/34321628628)
+(attempt 1, job 102369384143, head `ddcf8b5f9b13`, branch
+`codex/pr3997-caller-main-cooldown`, a `workflow_dispatch` lane run) failed
+`tests/config/config-mutation-lock.test.ts` at line 111 with `Expected: 0 /
+Received: 143` after 5915.82 ms. The 143 is not a lock defect and not the
+30 s teardown kill: it is the readiness-timeout path's own `child.kill()`,
+and the `finally` block's exit-0 expectation then masks the real error. The
+fix gives spawned-child readiness a measured 30 s budget, stops the masking,
+and corrects a stale comment. No product code, no workflow changes.
+
+## Loop spec
+
+- **Loop archetype:** satisfy-spec repair of a CI test fixture.
+- **Trigger:** delegated follow-up from the managing task after the xAI OAuth
+ unit completed; user-authorized as a small isolated maintainer PR.
+- **Goal:** the Windows flake either passes (child ready within a measured
+ budget) or fails with the real readiness error instead of a bare 143.
+- **Non-goals:** product code, CI workflow files, other tests, skipped tests,
+ accepting 143 as a valid outcome, bare timeout bumps without observability.
+ No local suite/typecheck/build (user restriction).
+- **Verifier:** remote `ci.yml` — PR lane (Linux `test`, macOS
+ `platform-macos`, `gates`) on the PR, then a `workflow_dispatch`
+ `lane=all` run on the exact PR head whose Windows shards execute this file;
+ the previously failing test must pass there.
+- **Stop condition:** PR published, PR lane green, Windows dispatch run green
+ for this file at the exact head, managing task handed the report.
+- **Memory artifact:** this unit directory; goalplan
+ `.codexclaw/goalplans/` entry for this session's second goal.
+- **Expected terminal outcomes:** DONE = both CI evidences green at the exact
+ head. BLOCKED = the Windows run shows the failure is NOT the readiness budget
+ (e.g. child never acquires the lock even in 30 s → real lock defect, which
+ would be out of this task's scope and handed back with evidence).
+- **Escalation condition:** any need to touch `src/` or `.github/`, or a
+ Windows re-failure after the fix.
+
+## Verified cause (log + source, no patch before this was established)
+
+Timeline of the failing attempt (test duration 5915.82 ms):
+
+1. Parent spawns the Bun child and enters `waitForPath(readyPath)` —
+ **500 attempts × 10 ms = 5 s** budget (tests/config/config-mutation-lock.test.ts:27-34).
+2. The child must boot Bun, transpile the `src/config.ts` import chain, and
+ acquire the mutation lock before writing `holder-ready`. On this loaded
+ runner that exceeds 5 s: the sibling child in `an abruptly exited holder
+ releases the OS-backed transaction…` needed **8290.11 ms** end-to-end in the
+ same shard (and passed, because `waitForOwnedChild` allows 30 s). The lock
+ itself is healthy — every other test in the file passed, and attempt 2 of the
+ run was green.
+3. `waitForPath` throws at ~5 s; the catch kills the child — SIGTERM, exit
+ **143** — and rethrows an enriched error with the child's stderr
+ (tests/config/config-mutation-lock.test.ts:85-92).
+4. The `finally` block (line 109-112) runs `writeFileSync(releasePath)` and
+ `expect(await waitForOwnedChild(child)).toBe(0)`. The child is already dead
+ with 143, so this expectation throws and **replaces** the enriched readiness
+ error — the log shows only the 143 mismatch at line 111, and the "child
+ stderr" text never appears.
+5. The stale comment in `waitForOwnedChild` (lines 36-41) attributes a 5858 ms
+ / 143 failure to "this helper's own `kill()`" from the 5 s era — that helper
+ now waits 30 s, so the explanation is wrong; the 143 comes from the
+ readiness-timeout catch.
+
+## File change map
+
+| Path | Action | What |
+|------|--------|------|
+| `tests/config/config-mutation-lock.test.ts` | MODIFY | readiness wait reuses the predeclared platform policy `watchdogMs(5_000)` (5 s local / 30 s CI / 45 s Windows CI) with an elapsed deadline, a final recheck, and fail-fast on an already-exited child; unmask the primary readiness failure in both holder tests' `finally`; correct the stale `waitForOwnedChild` comment |
+
+OUT: `src/**`, `.github/**`, `tests/helpers/ci-watchdog.ts` (imported, not
+modified), every other test file.
+
+Forensics correction (independent verifier Descartes, forwarded by the managing
+task after the first plan draft): the readiness budget must reuse the EXISTING
+`watchdogMs(5_000)` platform policy from `tests/helpers/ci-watchdog.ts`
+(Windows CI floor 45 s) rather than a new hardcoded 30 s constant — that helper
+is the repository's declared answer to "spawned children are slow on loaded
+Windows CI", so this fix expresses policy, not a local bump. It also directed
+the fail-fast on `child.exited` (no 45 s poll on an already-dead child) and
+extending the unmasking to the management-API holder test.
+
+## Diff-level design
+
+### 1. `waitForPath` → `waitForOwnedChildReady` — platform-policy budget, fail-fast
+
+Before (lines 27-34): a fixed 500 × 10 ms (5 s) poll with no knowledge of the
+child.
+
+After: the wait takes the spawned child, budgets `watchdogMs(5_000)` (5 s
+locally, 30 s on CI, 45 s on Windows CI — the predeclared policy in
+`tests/helpers/ci-watchdog.ts`), polls on an elapsed-time deadline with a final
+`existsSync` recheck, and races each 10 ms tick against `child.exited` so a
+child that died before writing the marker fails immediately with its exit code
+and stderr instead of burning the whole budget.
+
+### 2. Unmask the primary failure in both holder tests
+
+Before (lines 84-112):
+
+```ts
+ try {
+ try {
+ await waitForPath(readyPath);
+ } catch (error) {
+ child.kill();
+ await child.exited;
+ const stderr = await new Response(child.stderr).text().catch(() => "");
+ throw new Error(`${(error as Error).message}\nchild stderr: ${stderr}`);
+ }
+ ...
+ } finally {
+ writeFileSync(releasePath, "release");
+ expect(await waitForOwnedChild(child)).toBe(0);
+ }
+```
+
+After:
+
+```ts
+ let childKilled = false;
+ try {
+ try {
+ await waitForOwnedChildReady(child, readyPath);
+ } catch (error) {
+ childKilled = true;
+ child.kill();
+ await child.exited;
+ const stderr = await new Response(child.stderr).text().catch(() => "");
+ throw new Error(`${(error as Error).message}\nchild stderr: ${stderr}`);
+ }
+ ...
+ } finally {
+ writeFileSync(releasePath, "release");
+ // The readiness-timeout path already killed the child; expecting exit 0 here
+ // would mask that primary error with a bare 143.
+ if (!childKilled) {
+ expect(await waitForOwnedChild(child)).toBe(0);
+ }
+ }
+```
+
+The happy path is unchanged: release marker is always written (bounded cleanup),
+the exit-0 core assertion still runs whenever the child was not sacrificed, and
+every lock assertion (not stolen, immediate writer failure, no stale writes) is
+untouched.
+
+### 3. `waitForOwnedChild` comment correction
+
+Replace the stale 5 s-era explanation with the verified provenance:
+
+```ts
+ // The child polls for the release marker on a 10 ms sleep, so its exit is bounded by
+ // the filesystem noticing that write plus one Bun teardown; a loaded Windows runner
+ // needs real room for both. A surfaced exit 143 is never this helper's own kill()
+ // (which fires only after the full budget) — it is the readiness-timeout path's
+ // child.kill(), so read the readiness error, not this wait.
+```
+
+## Regression evidence plan
+
+- The failure mode is exercised by construction: if readiness ever exceeds the
+ budget again, the thrown error is the enriched `waitForOwnedChildReady`
+ message (with child stderr), asserted by reading the code path. A child that
+ *dies* before writing the marker is caught immediately by the `child.exited`
+ race rather than at the deadline; only a child that stays alive and never
+ becomes ready costs the full platform budget, and a dedicated test for that
+ would be a deliberate 45 s negative test on Windows CI — a cost not justified
+ for a CI fixture, where the unmasking is straight-line control flow reviewed
+ in the diff.
+- Positive path: `ci.yml` PR lane plus a `workflow_dispatch` `lane=all` run
+ on the exact PR head; the Windows shard executing
+ `tests\config\config-mutation-lock.test.ts` must pass, and the run must
+ show this file's tests green.
diff --git a/devlog/_plan/260909_usage_custom_range_disclosure/000_plan.md b/devlog/_plan/260909_usage_custom_range_disclosure/000_plan.md
new file mode 100644
index 0000000000..f600a684c3
--- /dev/null
+++ b/devlog/_plan/260909_usage_custom_range_disclosure/000_plan.md
@@ -0,0 +1,55 @@
+# Usage custom date range — manual-query disclosure
+
+Triggered by a maintainer browser comment on `/#usage`: the custom date range block should be a
+dropdown (manual lookup) by default, with the fields below it, and the current layout is visually
+wrong — control heights do not line up. Scope is the usage page filter area only.
+
+## Design read (cxc-dev-uiux-design)
+
+Reading this as: a dense local analytics page for a single operator who reads the presets almost
+every time and reaches for an explicit interval rarely, in the quiet utilitarian language the rest
+of the dashboard already speaks. Tokens come from `gui/src/styles.css`; nothing new is invented.
+
+```text
+DESIGN_VARIANCE: 3
+MOTION_INTENSITY: 1
+Product density profile: D5
+Reasoning: dashboard/admin surface for repeated operator work — the expressive default kit is
+domain-gated off, so the work is restraint, alignment and disclosure rather than decoration.
+```
+
+Do's: one obvious path (presets), expert control demoted behind a labelled disclosure, every
+control on one height, left-aligned so the block reads with the page it belongs to.
+Don'ts: no second full-width flex-end row, no decorative motion, no hidden applied state.
+
+## Problem
+
+`Usage.tsx` renders the custom-range `