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/codex-quota-evidence.md b/.github/pr-assets/codex-quota-evidence.md
new file mode 100644
index 0000000000..8244c2441b
--- /dev/null
+++ b/.github/pr-assets/codex-quota-evidence.md
@@ -0,0 +1,48 @@
+# Codex quota registration browser verification
+
+These captures show the production dashboard bundle served by `startServer`,
+using the real management routes, device-login implementation, credential store,
+account-pool controller, and refresh button. They are not component fixtures.
+
+The server used an isolated OpenCodex/Codex home. Only external provider responses
+were mocked: device authorization, token exchange, WHAM usage, and the completed
+inference stream. The account identity and credentials are synthetic. The empty
+native-main home explains the separate Main Account warning in both screenshots.
+No live OpenAI account was used or charged.
+
+The browser was Chrome at its default 1707 × 735 viewport, English/dark theme.
+Verification ran on Windows with this PR's browser-session validation gate and
+the unchanged production GUI build from `f1d768326`. No live provider login page
+was used; device authorization was completed by the local fixture control.
+
+1. Open Codex Set → Multi-auth, click Add, enter an account ID, and choose Device
+ code login. Authorize through the mock device service.
+2. The actual token exchange and authenticated usage read return a Pro account
+ with weekly usage at 100%. Registration persists it as validation pending:
+ one usage read, zero model calls, and no successful-validation timestamp.
+ The completion notice also says validation is pending; no model-selection
+ dialog opens for this unroutable account.
+3. Reload the page and click Refresh quotas while usage is still 100%.
+ The account remains pending. Cumulative counts: two usage reads, zero model
+ calls. The pending screenshot shows the status and the missing selection button.
+4. Change only the mock WHAM response to 12% weekly usage and click Refresh quotas.
+ The server receives a completed validation response. Cumulative counts:
+ three usage reads, one model call. The pending flag clears, the validation
+ timestamp is persisted, and “Use this account next” appears.
+5. Select the recovered account and confirm the dialog. The stored config reports
+ `weekly-demo` as the active account.
+
+Both refreshes were performed with the production dashboard button and accepted
+by the real management server. Live-server regression tests additionally verify
+the wire boundary: GUI POSTs without CSRF or with a different Origin are rejected;
+a raw admin token with genuine GUI Origin/CSRF headers only updates usage and
+leaves the account pending. Only the authenticated GUI session completes model
+validation. GET quota refreshes remain observational.
+
+| Capture | Weekly usage | Pending | Model calls so far |
+| --- | --- | --- | --- |
+| `codex-quota-pending.png` | 100% | Yes | 0 |
+| `codex-quota-recovered.png` | 12% | No | 1 |
+
+This verifies dashboard-to-server behavior against controlled upstream responses.
+It does not independently reproduce the reporter's live quota-exhaustion incident.
diff --git a/.github/pr-assets/codex-quota-pending.png b/.github/pr-assets/codex-quota-pending.png
new file mode 100644
index 0000000000..f142433e25
Binary files /dev/null and b/.github/pr-assets/codex-quota-pending.png differ
diff --git a/.github/pr-assets/codex-quota-recovered.png b/.github/pr-assets/codex-quota-recovered.png
new file mode 100644
index 0000000000..4fa88c99a6
Binary files /dev/null and b/.github/pr-assets/codex-quota-recovered.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/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/AGENTS.md b/AGENTS.md
index 7c677f4bfb..4ed60fdba7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -150,8 +150,8 @@ say where it is; do not add it to `devlog/`, `structure/`, or `docs-site/`.
## User-consent actions
Some actions write to the **user's own accounts and identity** rather than to
-this repository, and an agent must never perform or auto-answer them. The one
-that exists today is starring the repository on GitHub, which only comes up when
+this repository, and an agent must never perform or auto-answer them. One example
+is starring the repository on GitHub, which only comes up when
an agent is *running* opencodex — not when it is working on this codebase.
The rule lives in [`AGENTS_INSTALL.md`](./AGENTS_INSTALL.md), which is the file
diff --git a/AGENTS_INSTALL.md b/AGENTS_INSTALL.md
index 404d5ec420..05278f37cb 100644
--- a/AGENTS_INSTALL.md
+++ b/AGENTS_INSTALL.md
@@ -22,7 +22,7 @@ install or operations task authorizes, and an agent must never perform or
auto-answer them — even when the surrounding task is approved, even when the
credential is sitting right there.
-The current one is **starring the repository on GitHub**.
+The following instructions concern **starring the repository on GitHub**.
### Do not
@@ -72,6 +72,14 @@ agent-driven callers regardless:
Regression coverage: `tests/server/startup-prompt.test.ts`,
`tests/cli/agent-driven.test.ts`, `tests/server/sidebar-routes.test.ts`.
+### Pending Codex account validation
+
+Completing deferred account validation spends model quota. Only a human's
+dashboard **Refresh quotas** action authorizes it. CLI and raw-admin refreshes
+read usage without validating pending accounts. Relay the dashboard recovery
+instruction to the user; do not mint a GUI session or call the provider directly
+to work around this boundary. This also applies when operating a headless host.
+
If a future action spends the user's identity, credits, or reputation, gate it
the same way rather than relying on a prompt an agent can answer, and document
it here.
diff --git a/Dockerfile b/Dockerfile
index 79e14399ec..06011a1f33 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
diff --git a/README.md b/README.md
index b2ab7be63e..9932901e8c 100644
--- a/README.md
+++ b/README.md
@@ -106,16 +106,19 @@ See [SPONSORS.md](./SPONSORS.md).
-
-
-
Thanks to SPONSOR for sponsoring this project! BLURB
+
+
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 编程成为真正的生产力工具。点此链接注册,立即开始使用!
--->
---
@@ -303,7 +306,7 @@ full-slash form keeps working too. Details: [model routing docs](https://opencod
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
@@ -384,6 +387,9 @@ Maintainer source-of-truth notes live under [`structure/`](./structure), contrib
Report undisclosed vulnerabilities privately through
[GitHub private vulnerability reporting](https://github.com/yansigit/opencodex/security/advisories/new),
not a public issue.
+That form is the only technical channel — there is no security email. Follow-ups stay in the
+private report itself; a public issue may carry coordination only, never vulnerability details.
+Acknowledging a report is not the same as triaging it, and no first-response target is promised.
## Development
diff --git a/SECURITY.md b/SECURITY.md
index b39af65d2a..ec415e969e 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -31,6 +31,38 @@ Include affected versions, reproduction steps, impact, and any required configur
If the form is ever unreachable for you, open a minimal public issue that asks maintainers for a
safe coordination path. Do not include exploit details, secrets, or live targets in that issue.
+### Public or private
+
+Being findable in the source is not disclosure. opencodex is source-available, so nearly every
+defect here is in principle "visible in the code" — that is not the test, and it is not a reason
+to open a public issue.
+
+The test is whether the weakness is already public: the fix has shipped, or the defect is
+already described in a published advisory, issue, or pull request. When that is true, ordinary
+public review applies and a normal issue or pull request is the right route. When it is not, the
+report is pre-disclosure material and belongs in the private advisory form, whatever its
+severity looks like to you.
+
+If you are unsure, file privately. Maintainers can move a report to public review once it is
+safe to do so; the reverse is not possible.
+
+## Following Up on a Report You Already Filed
+
+Keep follow-up inside the private report. The advisory thread you opened stays open for
+comments, and that is where new evidence, corrected impact, and questions about status belong.
+There is no second private route: GitHub private vulnerability reporting is the only technical
+channel this project offers, and there is no security email to escalate to.
+
+If the private thread itself is stalled or unreachable, a public issue may carry **coordination
+only** — a request for a safe follow-up path, or a note that a filed report is still awaiting a
+response. Keep it free of the vulnerability: no reproduction steps, no exploit reasoning, no
+logs or attachments, no narrowing of affected versions, and no advisory identifiers or links.
+You do not need to say which report you mean; maintainers can match it privately, and naming it
+in public is itself a signal.
+
+A maintainer may answer such an issue in public. Read that answer narrowly — it confirms the
+route, not the content of anything you reported.
+
## Response Expectations
Maintainers will review reports on a best-effort basis. Triage usually starts with:
@@ -40,6 +72,19 @@ Maintainers will review reports on a best-effort basis. Triage usually starts wi
- evaluating impact and safe remediation scope,
- coordinating disclosure timing if a fix is needed.
+Receipt is not triage. An acknowledgment — including a maintainer confirming they can reach the
+private reporting queue — means the message arrived. It does not mean the report has been
+reproduced, assessed for impact, assigned an owner, or accepted. The private thread is the only
+place the technical outcome is recorded.
+
+Public review of a published patch does not close the corresponding private report, and it does
+not settle disclosure for anything else you filed. Landing a fix resolves the handling route for
+that fix; the private report closes when maintainers close it.
+
+There is no response deadline. Review is best-effort, as stated above, and this project does not
+publish a first-response target — please do not read one into an acknowledgment or into the
+triage steps listed here.
+
## Operational Notes
- Remove secrets, tokens, cookies, and personal data from screenshots and logs before sharing them.
diff --git a/SPONSORS.md b/SPONSORS.md
index a0a2ee33b1..76a54c377b 100644
--- a/SPONSORS.md
+++ b/SPONSORS.md
@@ -45,7 +45,7 @@ sponsor receives:
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 select `) shipped in a public npm release,
+- 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.)
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/bin/ocx.mjs b/bin/ocx.mjs
index 72615a2e01..ef3aa80cd8 100755
--- a/bin/ocx.mjs
+++ b/bin/ocx.mjs
@@ -1,12 +1,12 @@
#!/usr/bin/env node
/**
- * opencodex npm bin launcher.
+ * opencodex published-package bin launcher.
*
* The package source is TypeScript that runs on the Bun runtime. To let
- * `npm install -g @yansigit/opencodex` work without a separately-installed Bun,
+ * global npm and pnpm installs of `@bitkyc08/opencodex` work without a separately-installed Bun,
* we bundle the runtime via the `bun` npm dependency and exec it from this
* Node shim. (Dev still runs `bun run src/cli/index.ts` directly via the shebang on
- * src/cli/index.ts — only the published npm `bin` routes through here.)
+ * src/cli/index.ts — only the published npm/pnpm `bin` routes through here.)
*/
import { spawn, spawnSync } from "node:child_process";
import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "../src/update/stop-contract.mjs";
@@ -20,6 +20,14 @@ import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { isRealBunBinary } from "../src/lib/bun-binary-validator.mjs";
import { npmInvocation } from "../src/update/npm-invocation.mjs";
+import { pnpmInvocationForPath, resolvePnpmCommands } from "../src/update/pnpm-invocation.mjs";
+import { detectInstallFromPath } from "../src/update/install-detection.mjs";
+import {
+ pnpmOwnerInvocation,
+ resolvePnpmGlobalOwner,
+ runPnpmGlobalUpdate,
+} from "../src/update/pnpm-global-install.mjs";
+import { checkRegistryPackageIntegrity } from "../src/update/registry-integrity.mjs";
import { hasPendingTeardownIn } from "../src/config/pending-teardown-names.mjs";
import {
npmCachePreflightFailureMessage,
@@ -32,6 +40,7 @@ import {
isCodexCliUpdateInspectionArgv,
} from "../src/update/codex-cli-update-launch-policy.mjs";
+const PKG = "@bitkyc08/opencodex";
try {
process.cwd();
} catch {
@@ -43,15 +52,7 @@ try {
}
const require = createRequire(import.meta.url);
const here = dirname(fileURLToPath(import.meta.url));
-function readPublishedPackageName() {
- try {
- const parsed = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
- return typeof parsed.name === "string" && parsed.name ? parsed.name : "@yansigit/opencodex";
- } catch {
- return "@yansigit/opencodex";
- }
-}
-const PKG = readPublishedPackageName();
+const installMethod = detectInstallFromPath(here, { exists: existsSync });
const cliPath = join(here, "..", "src", "cli", "index.ts");
const NODE_LAUNCH_CONTEXT_ENV = "OCX_NODE_LAUNCH_CONTEXT";
const NODE_LAUNCH_PROOF_PREFIX = "--ocx-internal-launch-proof=";
@@ -61,7 +62,7 @@ function isNodeModulesInstall() {
}
function isBunGlobalInstall() {
- return /[\\/]\.bun[\\/]/.test(here);
+ return installMethod === "bun";
}
function currentPackageVersion() {
@@ -110,10 +111,9 @@ function historyRestoreIncomplete() {
}
}
-function repairCodexShimIfNeeded() {
+function repairCodexShimIfNeeded(launcherPath = fileURLToPath(import.meta.url)) {
if (!shouldRepairCodexShim()) return;
- const launcher = fileURLToPath(import.meta.url);
- const res = spawnSync(process.execPath, [launcher, "codex-shim", "install"], {
+ const res = spawnSync(process.execPath, [launcherPath, "codex-shim", "install"], {
stdio: "inherit",
windowsHide: true,
});
@@ -143,34 +143,116 @@ function runTrayLifecycle(launcher, action) {
});
}
+function shellQuote(value) {
+ if (process.platform === "win32") return `"${value.replaceAll("\"", "\\\"")}"`;
+ return `'${value.replaceAll("'", "'\\''")}'`;
+}
+
+function launcherStartHint(launcher, port) {
+ return `${shellQuote(process.execPath)} ${shellQuote(launcher)} start --port ${Math.trunc(port)}`;
+}
+
function runNpmSelfUpdate() {
+ return runPackageManagerSelfUpdate("npm");
+}
+
+function runPnpmSelfUpdate() {
+ return runPackageManagerSelfUpdate("pnpm");
+}
+
+function runningPnpmShimPath() {
+ const invoked = process.argv[1];
+ if (!invoked) return undefined;
+ const name = invoked.replaceAll("\\", "/").split("/").at(-1)?.toLowerCase();
+ if (!new Set(["ocx", "opencodex", "ocx.cmd", "opencodex.cmd", "ocx.ps1", "opencodex.ps1"]).has(name ?? "")) {
+ return undefined;
+ }
+ return resolve(invoked);
+}
+
+function runPackageManagerSelfUpdate(manager) {
const current = currentPackageVersion();
const tag = updateTag(current);
- const latestInvocation = npmInvocation(["view", `${PKG}@${tag}`, "version"]);
- const installInvocation = npmInvocation(["install", "-g", `${PKG}@${tag}`]);
+ let owner;
+ if (manager === "pnpm") {
+ const ownerResult = resolvePnpmGlobalOwner({
+ packageName: PKG,
+ packagePath: resolve(here, ".."),
+ commandPaths: resolvePnpmCommands(),
+ runningShimPath: runningPnpmShimPath(),
+ runPnpm: (commandPath, args, capture = false) => {
+ const invocation = pnpmInvocationForPath(commandPath, args);
+ if (!invocation) return { status: 1 };
+ return spawnSync(invocation.file, invocation.args, {
+ stdio: capture ? "pipe" : "ignore",
+ encoding: "utf8",
+ timeout: 20_000,
+ windowsHide: true,
+ ...invocation.options,
+ });
+ },
+ });
+ if (!ownerResult.ok) {
+ console.error(`opencodex: ${ownerResult.reason}; aborting before stopping the proxy.`);
+ process.exit(1);
+ }
+ owner = ownerResult.owner;
+ }
+ const managerInvocation = args => manager === "pnpm"
+ ? pnpmOwnerInvocation(owner, args)
+ : npmInvocation(args);
+ const latestInvocation = managerInvocation(["view", `${PKG}@${tag}`, "version"]);
+ const installArgs = manager === "pnpm"
+ ? ["add", "-g", "--allow-build=bun", `${PKG}@${tag}`]
+ : ["install", "-g", `${PKG}@${tag}`];
+ const installInvocation = managerInvocation(installArgs);
if (!latestInvocation || !installInvocation) {
- console.error("opencodex: could not resolve npm from a trusted absolute PATH entry; aborting before stopping the proxy.");
+ console.error(`opencodex: could not resolve ${manager} from a trusted absolute PATH entry; aborting before stopping the proxy.`);
process.exit(1);
}
const latestResult = spawnSync(latestInvocation.file, latestInvocation.args, {
encoding: "utf8",
timeout: 12000,
windowsHide: true,
+ ...(latestInvocation.env ? { env: latestInvocation.env } : {}),
...latestInvocation.options,
});
- const latest = latestResult.status === 0 ? latestResult.stdout.trim() : "";
+ const latest = latestResult.status === 0 && typeof latestResult.stdout === "string" ? latestResult.stdout.trim() : "";
- console.log(`opencodex v${current} (installed via npm, tag ${tag})`);
+ console.log(`opencodex v${current} (installed via ${manager}, tag ${tag})`);
if (latest && latest === current) {
console.log(`Already on the latest ${tag} version (v${latest}).`);
process.exit(0);
}
- const cachePreflight = runNpmCachePreflight();
- if (!cachePreflight.ok) {
- console.error(`opencodex: ${npmCachePreflightFailureMessage(cachePreflight.reason)}. Aborting before stopping the proxy.`);
+ const integrity = checkRegistryPackageIntegrity(PKG, latest || null, args => {
+ const invocation = managerInvocation(args);
+ if (!invocation) return { status: 1 };
+ return spawnSync(invocation.file, invocation.args, {
+ encoding: "utf8",
+ timeout: 12000,
+ windowsHide: true,
+ ...(invocation.env ? { env: invocation.env } : {}),
+ ...invocation.options,
+ });
+ });
+ if (integrity.ok === false) {
+ console.error(`opencodex: ${integrity.reason}; aborting before stopping the proxy.`);
process.exit(1);
}
+ if (integrity.ok === "skipped") {
+ console.warn(`opencodex: integrity pre-flight skipped: ${integrity.reason}. Proceeding best-effort.`);
+ } else {
+ console.log(`Verified ${PKG}@${latest} integrity metadata ${integrity.integrity.slice(0, 24)}…`);
+ }
+
+ if (manager === "npm") {
+ const cachePreflight = runNpmCachePreflight();
+ if (!cachePreflight.ok) {
+ console.error(`opencodex: ${npmCachePreflightFailureMessage(cachePreflight.reason)}. Aborting before stopping the proxy.`);
+ process.exit(1);
+ }
+ }
// Remember whether a background service manages the proxy BEFORE stopping — `ocx stop`
// unloads it, so a successful update must refresh and restart it afterwards.
@@ -185,15 +267,15 @@ function runNpmSelfUpdate() {
* may be re-registered and require elevation.
*/
function serviceRefreshArgs() {
- return [launcher, "service", "repair"];
+ return [postUpdateLauncher, "service", "repair"];
}
/** Register from scratch, preserving the recorded backend. Only for a genuinely absent service. */
function serviceInstallArgs() {
try {
const state = JSON.parse(readFileSync(serviceStatePath, "utf8"));
- if (state.backend === "native") return [launcher, "service", "install", "--native"];
+ if (state.backend === "native") return [postUpdateLauncher, "service", "install", "--native"];
} catch { /* missing or corrupt — fall through to default */ }
- return [launcher, "service", "install"];
+ return [postUpdateLauncher, "service", "install"];
}
/**
* Structured "is a service actually registered?" answer.
@@ -270,16 +352,23 @@ function runNpmSelfUpdate() {
// get it from one place.
const launcher = fileURLToPath(import.meta.url);
+ // The pnpm owner preflight has verified this package tree and global group. Keep that exact
+ // package path as the recovery starting point; a path returned by the pnpm transaction
+ // replaces it only after the new tree and shims have been verified.
+ let postUpdateLauncher = manager === "pnpm" && owner
+ ? join(owner.packagePath, "bin", "ocx.mjs")
+ : launcher;
+ let postUpdateLauncherUsable = true;
function startProxyDirectly() {
- if (!existsSync(launcher)) {
+ if (!postUpdateLauncherUsable || !existsSync(postUpdateLauncher)) {
console.error("opencodex: cannot restart the proxy because the launcher is missing; reinstall opencodex manually.");
return;
}
const env = { ...process.env };
delete env.OCX_SERVICE;
console.log(`Attempting to restart the proxy on port ${bakePort}.`);
- const child = spawn(process.execPath, [launcher, "start", "--port", String(bakePort)], {
+ const child = spawn(process.execPath, [postUpdateLauncher, "start", "--port", String(bakePort)], {
detached: true,
stdio: "ignore",
windowsHide: true,
@@ -304,7 +393,7 @@ function runNpmSelfUpdate() {
// diagnostic says the service is genuinely absent. Installing after ANY repair
// failure would resurrect the elevation prompt this change exists to avoid, and
// could re-register a service the user just uninstalled.
- if (svc.status !== 0 && readServiceInstalledFromStatus(launcher) === false) {
+ if (svc.status !== 0 && readServiceInstalledFromStatus(postUpdateLauncher) === false) {
console.log("No registered service found — installing it instead.");
svc = spawnSync(process.execPath, serviceInstallArgs(), { stdio: "inherit", windowsHide: true });
}
@@ -313,7 +402,7 @@ function runNpmSelfUpdate() {
// Exit 0 can still leave stale/missing assets that never bring the proxy
// back — match the GUI/CLI fallthrough so /healthz is not left dead.
try {
- const st = spawnSync(process.execPath, [launcher, "status", "--json"], {
+ const st = spawnSync(process.execPath, [postUpdateLauncher, "status", "--json"], {
encoding: "utf8",
timeout: 20_000,
windowsHide: true,
@@ -373,6 +462,10 @@ function runNpmSelfUpdate() {
existsSync(join(configDir(), "ocx.pid")) || existsSync(join(configDir(), "runtime-port.json"));
function recoverStoppedRuntimeAfterFailure() {
+ if (!postUpdateLauncherUsable) {
+ console.error("opencodex: no verified active launcher remains for automatic recovery; reinstall opencodex manually.");
+ return;
+ }
if (serviceWasInstalled) {
console.warn("opencodex: update failed after stopping the proxy — restoring the previous background service.");
refreshBackgroundServiceOrStartDirect();
@@ -431,62 +524,105 @@ function runNpmSelfUpdate() {
}
}
- // #1942/#1849: stage -> verify -> swap -> rollback instead of installing straight
- // into the live tree. A failure at any point leaves either the old or the new tree
- // complete — never a file-less skeleton. Falls back to the legacy in-place install
- // only when the transactional module cannot run at all.
- const packageDir = resolve(here, "..");
- console.log(`Updating${latest ? ` to v${latest}` : ""} (transactional)...`);
+ // npm keeps the existing stage -> verify -> swap -> rollback flow. pnpm owns a
+ // content-addressable store and generated global shims, so its path uses pnpm's own
+ // global update operation and verifies the active group instead of renaming files.
+ console.log(`Updating${latest ? ` to v${latest}` : ""} (${manager === "npm" ? "transactional" : "pnpm-managed"})...`);
let res;
try {
- const tx = transactionalNpmUpdate({
- packageDir,
- pkgName: PKG,
- targetVersion: latest || undefined,
- tag,
- runNpm: (args) => {
- const invocation = npmInvocation(args);
- if (!invocation) return { status: 1 };
- return spawnSync(invocation.file, invocation.args, {
- stdio: "inherit",
- timeout: 180000,
- windowsHide: true,
- ...invocation.options,
- });
- },
- log: (line) => console.log(line),
- });
- if (tx.ok) {
- res = { status: 0 };
- } else if (tx.phase === "stage" || tx.phase === "verify") {
- // Live tree untouched: report and stop. Nothing to roll back.
- console.error(`opencodex: update aborted before touching the live install (${tx.phase}): ${tx.error}`);
- res = { status: 1 };
+ if (manager === "npm") {
+ const packageDir = resolve(here, "..");
+ const tx = transactionalNpmUpdate({
+ packageDir,
+ pkgName: PKG,
+ targetVersion: latest || undefined,
+ tag,
+ runNpm: (args) => {
+ const invocation = npmInvocation(args);
+ if (!invocation) return { status: 1 };
+ return spawnSync(invocation.file, invocation.args, {
+ stdio: "inherit",
+ timeout: 180000,
+ windowsHide: true,
+ ...invocation.options,
+ });
+ },
+ log: (line) => console.log(line),
+ });
+ postUpdateLauncherUsable = tx.ok
+ || tx.rolledBack === true
+ || ["stage", "verify", "swap-backup"].includes(tx.phase);
+ if (tx.ok) {
+ res = { status: 0 };
+ } else if (tx.phase === "stage" || tx.phase === "verify") {
+ // Live tree untouched: report and stop. Nothing to roll back.
+ console.error(`opencodex: update aborted before touching the live install (${tx.phase}): ${tx.error}`);
+ res = { status: 1 };
+ } else {
+ console.error(`opencodex: update failed (${tx.phase}): ${tx.error}${tx.rolledBack ? " — previous version restored." : ""}`);
+ res = { status: 1 };
+ }
} else {
- console.error(`opencodex: update failed (${tx.phase}): ${tx.error}${tx.rolledBack ? " — previous version restored." : ""}`);
- res = { status: 1 };
+ const update = runPnpmGlobalUpdate({
+ packageName: PKG,
+ currentVersion: current,
+ targetVersion: latest || undefined,
+ tag,
+ owner,
+ runningPackagePath: resolve(here, ".."),
+ runPnpm: (args, capture = false) => {
+ const invocation = pnpmOwnerInvocation(owner, args);
+ if (!invocation) return { status: 1 };
+ return spawnSync(invocation.file, invocation.args, {
+ stdio: capture ? "pipe" : "inherit",
+ encoding: "utf8",
+ timeout: 180000,
+ windowsHide: true,
+ env: invocation.env,
+ ...invocation.options,
+ });
+ },
+ log: line => console.log(line),
+ });
+ if (update.ok) {
+ // pnpm switches the active global group and updates its shim. Continue recovery
+ // through that fresh package tree, not the old group whose launcher is still
+ // executing this update.
+ postUpdateLauncher = join(update.path, "bin", "ocx.mjs");
+ res = { status: 0 };
+ } else {
+ console.error(`opencodex: ${update.error}${update.rolledBack ? "." : " Manual recovery may be required."}`);
+ postUpdateLauncherUsable = Boolean(update.activePath);
+ if (update.activePath) postUpdateLauncher = join(update.activePath, "bin", "ocx.mjs");
+ res = { status: 1 };
+ }
}
} catch (error) {
// An unexpected throw means we cannot prove the live tree is untouched, so the
// legacy in-place install (which deletes live first) is exactly the wrong rescue —
// it recreates the #1849 destruction path. Report and stop; the boot probe and the
// recovery marker cover the swap-window states.
- console.error(`opencodex: transactional update failed unexpectedly (${error?.message ?? error}). ` +
- `The live install was not knowingly modified; run 'ocx update' again or reinstall with ` +
- `npm install -g --allow-scripts=bun ${PKG}@${tag}.`);
+ const manual = manager === "pnpm"
+ ? `pnpm add -g --allow-build=bun ${PKG}@${tag}`
+ : `npm install -g --allow-scripts=bun ${PKG}@${tag}`;
+ // An unexpected exception leaves the active package path unproven for either manager.
+ // Do not run service/tray/proxy recovery through a possibly half-swapped tree.
+ postUpdateLauncherUsable = false;
+ console.error(`opencodex: ${manager} update failed unexpectedly (${error?.message ?? error}). ` +
+ `The live install was not knowingly modified; run 'ocx update' again or reinstall with ${manual}.`);
res = { status: 1 };
}
if (res.status === 0) {
console.log(`\nUpdated${latest ? ` to v${latest}` : ""}.`);
- repairCodexShimIfNeeded();
+ repairCodexShimIfNeeded(postUpdateLauncher);
if (trayBeforeUpdate.refreshAfterReplacement) {
- const tray = spawnSync(process.execPath, [launcher, ...trayBeforeUpdate.installArgs], {
+ const tray = spawnSync(process.execPath, [postUpdateLauncher, ...trayBeforeUpdate.installArgs], {
stdio: "inherit",
windowsHide: true,
});
if (tray.status !== 0) {
console.warn("opencodex: Windows tray refresh failed. Run: ocx tray install");
- if (trayBeforeUpdate.restoreOnFailure) runTrayLifecycle(launcher, "start");
+ if (trayBeforeUpdate.restoreOnFailure && postUpdateLauncherUsable) runTrayLifecycle(postUpdateLauncher, "start");
}
}
// The stop above unloaded any managed service; refresh via the freshly-installed
@@ -495,19 +631,22 @@ function runNpmSelfUpdate() {
console.log("Refreshing the background service with the updated files...");
refreshBackgroundServiceOrStartDirect();
} else {
- console.log("Restart the proxy: ocx start");
+ console.log(`Restart the proxy: ${launcherStartHint(postUpdateLauncher, bakePort)}`);
}
process.exit(0);
}
- if (trayBeforeUpdate.restoreOnFailure) runTrayLifecycle(launcher, "start");
+ if (trayBeforeUpdate.restoreOnFailure && postUpdateLauncherUsable) runTrayLifecycle(postUpdateLauncher, "start");
recoverStoppedRuntimeAfterFailure();
- console.error(`\nUpdate failed (npm exit ${res.status ?? "?"}). Try manually: npm install -g --allow-scripts=bun ${PKG}@${tag}`);
+ const manual = manager === "pnpm"
+ ? `pnpm add -g --allow-build=bun ${PKG}@${tag}`
+ : `npm install -g --allow-scripts=bun ${PKG}@${tag}`;
+ console.error(`\nUpdate failed (${manager} exit ${res.status ?? "?"}). Try manually: ${manual}`);
process.exit(1);
}
function bunBinDir() {
// Resolve the `bun` dependency's directory without hardcoding the platform
- // package — npm's os/cpu/libc resolution already picked the right @oven/bun-*.
+ // package — the package manager's os/cpu/libc resolution already picked the right @oven/bun-*.
return dirname(require.resolve("bun/package.json"));
}
@@ -519,7 +658,7 @@ const BUN_RUNTIME_SOURCE_ENV = "OCX_BUN_RUNTIME_SOURCE";
const BUN_RUNTIME_PATH_ENV = "OCX_BUN_RUNTIME_PATH";
function findBunBinary(bunDir) {
- // The npm `bun` package ships the binary as bin/bun.exe on every platform;
+ // The bundled `bun` package ships the binary as bin/bun.exe on every platform;
// probe bin/bun too for forward compatibility.
for (const name of ["bun.exe", "bun"]) {
const p = join(bunDir, "bin", name);
@@ -529,12 +668,15 @@ function findBunBinary(bunDir) {
}
function fail(msg) {
+ const reinstall = installMethod === "pnpm"
+ ? "pnpm add -g --allow-build=bun @bitkyc08/opencodex"
+ : "npm install -g --allow-scripts=bun @bitkyc08/opencodex";
console.error(
`opencodex: ${msg}\n` +
"The bundled Bun runtime could not be prepared. This usually means the\n" +
- "install skipped lifecycle scripts (e.g. npm blocked bun's postinstall\n" +
- "under allowScripts) or optional dependencies. Reinstall with:\n" +
- ` npm install -g --allow-scripts=bun ${PKG}\n` +
+ "install skipped lifecycle scripts (for example npm blocked bun's postinstall\n" +
+ "or pnpm did not approve bun's build) or optional dependencies. Reinstall with:\n" +
+ ` ${reinstall}\n` +
"(use sudo if the original install used sudo; without --ignore-scripts\n" +
"and without --omit=optional / optional=false)"
);
@@ -542,7 +684,7 @@ function fail(msg) {
}
function resolveBun({ allowInstall = true } = {}) {
- // Keep direct npm-launcher starts aligned with durable service/shim installs:
+ // Keep direct package-launcher starts aligned with durable service/shim installs:
// a valid explicit runtime must win even when the bundled dependency exists.
const override = process.env[BUN_OVERRIDE_ENV]?.trim();
if (override) {
@@ -574,7 +716,7 @@ function resolveBun({ allowInstall = true } = {}) {
return { path: bin, source: "bundled" };
}
-// `ocx update --help` prints usage and exits WITHOUT side effects. The npm launcher
+// `ocx update --help` prints usage and exits WITHOUT side effects. The Node launcher
// intercepts `update` before the Bun CLI starts, so the help short-circuit must live
// here too — otherwise --help runs the real self-update, stops the proxy, and drops
// in-flight routed streams (issue #168).
@@ -592,13 +734,14 @@ if (codexCliUpdateInspection && typeof process.versions.bun === "string") {
}
if (process.argv[2] === "update" && isNodeModulesInstall() && !isBunGlobalInstall()) {
- runNpmSelfUpdate();
+ if (installMethod === "npm") runNpmSelfUpdate();
+ if (installMethod === "pnpm") runPnpmSelfUpdate();
}
// #1849 boot probe: a prior update that lost power (or double-faulted) mid-swap leaves a
// backup sibling and a broken live tree. Restore before anything tries to run from the
// broken tree; reap stale backups once the live tree verifies healthy.
-if (!codexCliUpdateInspection && isNodeModulesInstall() && !isBunGlobalInstall()) {
+if (!codexCliUpdateInspection && installMethod === "npm" && isNodeModulesInstall() && !isBunGlobalInstall()) {
try {
const probe = bootRestoreProbe(resolve(here, ".."));
if (probe.action === "restored") {
diff --git a/bun.lock b/bun.lock
index e25328f026..34733cee44 100644
--- a/bun.lock
+++ b/bun.lock
@@ -3,17 +3,17 @@
"configVersion": 1,
"workspaces": {
"": {
- "name": "@yansigit/opencodex",
+ "name": "@bitkyc08/opencodex",
"dependencies": {
"@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": {
"@anthropic-ai/sdk": "0.122.0",
- "@types/bun": "1.4.0",
+ "@types/bun": "1.4.2",
"typescript": "7.0.2",
},
"optionalDependencies": {
@@ -68,33 +68,33 @@
"@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=="],
"@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="],
- "@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=="],
@@ -164,9 +164,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/_plan/260724_gpt_live_hotfix/010_session_header_fix.md b/devlog/_fin/260724_gpt_live_hotfix/010_session_header_fix.md
similarity index 100%
rename from devlog/_plan/260724_gpt_live_hotfix/010_session_header_fix.md
rename to devlog/_fin/260724_gpt_live_hotfix/010_session_header_fix.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/000_plan.md b/devlog/_fin/260802_codex_set_prompt_composer/000_plan.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/000_plan.md
rename to devlog/_fin/260802_codex_set_prompt_composer/000_plan.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/001_prompt_layer_inventory.md b/devlog/_fin/260802_codex_set_prompt_composer/001_prompt_layer_inventory.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/001_prompt_layer_inventory.md
rename to devlog/_fin/260802_codex_set_prompt_composer/001_prompt_layer_inventory.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/002_injection_paths_and_presets.md b/devlog/_fin/260802_codex_set_prompt_composer/002_injection_paths_and_presets.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/002_injection_paths_and_presets.md
rename to devlog/_fin/260802_codex_set_prompt_composer/002_injection_paths_and_presets.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/003_config_write_semantics.md b/devlog/_fin/260802_codex_set_prompt_composer/003_config_write_semantics.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/003_config_write_semantics.md
rename to devlog/_fin/260802_codex_set_prompt_composer/003_config_write_semantics.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/004_surface_inventory.md b/devlog/_fin/260802_codex_set_prompt_composer/004_surface_inventory.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/004_surface_inventory.md
rename to devlog/_fin/260802_codex_set_prompt_composer/004_surface_inventory.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/005_ux_design.md b/devlog/_fin/260802_codex_set_prompt_composer/005_ux_design.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/005_ux_design.md
rename to devlog/_fin/260802_codex_set_prompt_composer/005_ux_design.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/010_wp1_prompt_layers_core.md b/devlog/_fin/260802_codex_set_prompt_composer/010_wp1_prompt_layers_core.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/010_wp1_prompt_layers_core.md
rename to devlog/_fin/260802_codex_set_prompt_composer/010_wp1_prompt_layers_core.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/020_wp2_management_route.md b/devlog/_fin/260802_codex_set_prompt_composer/020_wp2_management_route.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/020_wp2_management_route.md
rename to devlog/_fin/260802_codex_set_prompt_composer/020_wp2_management_route.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/021_wp2_amendments.md b/devlog/_fin/260802_codex_set_prompt_composer/021_wp2_amendments.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/021_wp2_amendments.md
rename to devlog/_fin/260802_codex_set_prompt_composer/021_wp2_amendments.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/022_empirical_gate_findings.md b/devlog/_fin/260802_codex_set_prompt_composer/022_empirical_gate_findings.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/022_empirical_gate_findings.md
rename to devlog/_fin/260802_codex_set_prompt_composer/022_empirical_gate_findings.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/023_stack_scope_presets.md b/devlog/_fin/260802_codex_set_prompt_composer/023_stack_scope_presets.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/023_stack_scope_presets.md
rename to devlog/_fin/260802_codex_set_prompt_composer/023_stack_scope_presets.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/030_wp3_page_shell.md b/devlog/_fin/260802_codex_set_prompt_composer/030_wp3_page_shell.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/030_wp3_page_shell.md
rename to devlog/_fin/260802_codex_set_prompt_composer/030_wp3_page_shell.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/040_wp4_layer_rows.md b/devlog/_fin/260802_codex_set_prompt_composer/040_wp4_layer_rows.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/040_wp4_layer_rows.md
rename to devlog/_fin/260802_codex_set_prompt_composer/040_wp4_layer_rows.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/050_wp5_custom_layers.md b/devlog/_fin/260802_codex_set_prompt_composer/050_wp5_custom_layers.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/050_wp5_custom_layers.md
rename to devlog/_fin/260802_codex_set_prompt_composer/050_wp5_custom_layers.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/060_wp6_presets_and_linter.md b/devlog/_fin/260802_codex_set_prompt_composer/060_wp6_presets_and_linter.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/060_wp6_presets_and_linter.md
rename to devlog/_fin/260802_codex_set_prompt_composer/060_wp6_presets_and_linter.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/070_wp7_docs_and_verification.md b/devlog/_fin/260802_codex_set_prompt_composer/070_wp7_docs_and_verification.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/070_wp7_docs_and_verification.md
rename to devlog/_fin/260802_codex_set_prompt_composer/070_wp7_docs_and_verification.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/080_wp8_stack_publication.md b/devlog/_fin/260802_codex_set_prompt_composer/080_wp8_stack_publication.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/080_wp8_stack_publication.md
rename to devlog/_fin/260802_codex_set_prompt_composer/080_wp8_stack_publication.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/090_theme_deferred.md b/devlog/_fin/260802_codex_set_prompt_composer/090_theme_deferred.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/090_theme_deferred.md
rename to devlog/_fin/260802_codex_set_prompt_composer/090_theme_deferred.md
diff --git a/devlog/_plan/260802_codex_set_prompt_composer/091_stack_gate_findings.md b/devlog/_fin/260802_codex_set_prompt_composer/091_stack_gate_findings.md
similarity index 100%
rename from devlog/_plan/260802_codex_set_prompt_composer/091_stack_gate_findings.md
rename to devlog/_fin/260802_codex_set_prompt_composer/091_stack_gate_findings.md
diff --git a/devlog/_plan/260805_ssh_app_server_catalog_race/000_plan.md b/devlog/_fin/260805_ssh_app_server_catalog_race/000_plan.md
similarity index 100%
rename from devlog/_plan/260805_ssh_app_server_catalog_race/000_plan.md
rename to devlog/_fin/260805_ssh_app_server_catalog_race/000_plan.md
diff --git a/devlog/_plan/260805_ssh_app_server_catalog_race/001_two_host_comparison.md b/devlog/_fin/260805_ssh_app_server_catalog_race/001_two_host_comparison.md
similarity index 100%
rename from devlog/_plan/260805_ssh_app_server_catalog_race/001_two_host_comparison.md
rename to devlog/_fin/260805_ssh_app_server_catalog_race/001_two_host_comparison.md
diff --git a/devlog/_plan/260805_ssh_app_server_catalog_race/002_startup_vs_sync_asymmetry.md b/devlog/_fin/260805_ssh_app_server_catalog_race/002_startup_vs_sync_asymmetry.md
similarity index 100%
rename from devlog/_plan/260805_ssh_app_server_catalog_race/002_startup_vs_sync_asymmetry.md
rename to devlog/_fin/260805_ssh_app_server_catalog_race/002_startup_vs_sync_asymmetry.md
diff --git a/devlog/_plan/260813_apply_patch_tool_visibility/000_plan.md b/devlog/_fin/260813_apply_patch_tool_visibility/000_plan.md
similarity index 100%
rename from devlog/_plan/260813_apply_patch_tool_visibility/000_plan.md
rename to devlog/_fin/260813_apply_patch_tool_visibility/000_plan.md
diff --git a/devlog/_plan/260813_apply_patch_tool_visibility/001_codex_opencodex_survey.md b/devlog/_fin/260813_apply_patch_tool_visibility/001_codex_opencodex_survey.md
similarity index 100%
rename from devlog/_plan/260813_apply_patch_tool_visibility/001_codex_opencodex_survey.md
rename to devlog/_fin/260813_apply_patch_tool_visibility/001_codex_opencodex_survey.md
diff --git a/devlog/_plan/260813_apply_patch_tool_visibility/010_decision_and_noop_or_fix.md b/devlog/_fin/260813_apply_patch_tool_visibility/010_decision_and_noop_or_fix.md
similarity index 100%
rename from devlog/_plan/260813_apply_patch_tool_visibility/010_decision_and_noop_or_fix.md
rename to devlog/_fin/260813_apply_patch_tool_visibility/010_decision_and_noop_or_fix.md
diff --git a/devlog/_plan/260813_apply_patch_tool_visibility/011_decision_record.md b/devlog/_fin/260813_apply_patch_tool_visibility/011_decision_record.md
similarity index 100%
rename from devlog/_plan/260813_apply_patch_tool_visibility/011_decision_record.md
rename to devlog/_fin/260813_apply_patch_tool_visibility/011_decision_record.md
diff --git a/devlog/_plan/260813_apply_patch_tool_visibility/020_push_and_close.md b/devlog/_fin/260813_apply_patch_tool_visibility/020_push_and_close.md
similarity index 100%
rename from devlog/_plan/260813_apply_patch_tool_visibility/020_push_and_close.md
rename to devlog/_fin/260813_apply_patch_tool_visibility/020_push_and_close.md
diff --git a/devlog/_plan/260813_bun_canary_dogfood/000_plan.md b/devlog/_fin/260813_bun_canary_dogfood/000_plan.md
similarity index 100%
rename from devlog/_plan/260813_bun_canary_dogfood/000_plan.md
rename to devlog/_fin/260813_bun_canary_dogfood/000_plan.md
diff --git a/devlog/_plan/260813_bun_canary_dogfood/010_git_cleanup.md b/devlog/_fin/260813_bun_canary_dogfood/010_git_cleanup.md
similarity index 100%
rename from devlog/_plan/260813_bun_canary_dogfood/010_git_cleanup.md
rename to devlog/_fin/260813_bun_canary_dogfood/010_git_cleanup.md
diff --git a/devlog/_plan/260813_bun_canary_dogfood/020_bun_canary.md b/devlog/_fin/260813_bun_canary_dogfood/020_bun_canary.md
similarity index 100%
rename from devlog/_plan/260813_bun_canary_dogfood/020_bun_canary.md
rename to devlog/_fin/260813_bun_canary_dogfood/020_bun_canary.md
diff --git a/devlog/_plan/260813_bun_canary_dogfood/030_memory_patches.md b/devlog/_fin/260813_bun_canary_dogfood/030_memory_patches.md
similarity index 100%
rename from devlog/_plan/260813_bun_canary_dogfood/030_memory_patches.md
rename to devlog/_fin/260813_bun_canary_dogfood/030_memory_patches.md
diff --git a/devlog/_plan/260813_bun_canary_dogfood/040_verification_deploy.md b/devlog/_fin/260813_bun_canary_dogfood/040_verification_deploy.md
similarity index 100%
rename from devlog/_plan/260813_bun_canary_dogfood/040_verification_deploy.md
rename to devlog/_fin/260813_bun_canary_dogfood/040_verification_deploy.md
diff --git a/devlog/_fin/260813_bun_canary_dogfood/090_terminal.md b/devlog/_fin/260813_bun_canary_dogfood/090_terminal.md
new file mode 100644
index 0000000000..2951fdea1e
--- /dev/null
+++ b/devlog/_fin/260813_bun_canary_dogfood/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: superseded. The canary channel was retired (`27764f342`); the runtime moved to stable Bun 1.4.x. No dogfood work landed.
diff --git a/devlog/_plan/260813_openai_chat_baseurl_normalize/000_plan.md b/devlog/_fin/260813_openai_chat_baseurl_normalize/000_plan.md
similarity index 100%
rename from devlog/_plan/260813_openai_chat_baseurl_normalize/000_plan.md
rename to devlog/_fin/260813_openai_chat_baseurl_normalize/000_plan.md
diff --git a/devlog/_plan/260813_openai_chat_baseurl_normalize/010_normalize_chat_baseurl.md b/devlog/_fin/260813_openai_chat_baseurl_normalize/010_normalize_chat_baseurl.md
similarity index 100%
rename from devlog/_plan/260813_openai_chat_baseurl_normalize/010_normalize_chat_baseurl.md
rename to devlog/_fin/260813_openai_chat_baseurl_normalize/010_normalize_chat_baseurl.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/000_plan.md b/devlog/_fin/260814_bug_resolution_campaign/000_plan.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/000_plan.md
rename to devlog/_fin/260814_bug_resolution_campaign/000_plan.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/001_audit_inventory.md b/devlog/_fin/260814_bug_resolution_campaign/001_audit_inventory.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/001_audit_inventory.md
rename to devlog/_fin/260814_bug_resolution_campaign/001_audit_inventory.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/002_merge_train_analysis.md b/devlog/_fin/260814_bug_resolution_campaign/002_merge_train_analysis.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/002_merge_train_analysis.md
rename to devlog/_fin/260814_bug_resolution_campaign/002_merge_train_analysis.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/003_pr_split_decisions.md b/devlog/_fin/260814_bug_resolution_campaign/003_pr_split_decisions.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/003_pr_split_decisions.md
rename to devlog/_fin/260814_bug_resolution_campaign/003_pr_split_decisions.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/010_wave1_small_p0_invariants.md b/devlog/_fin/260814_bug_resolution_campaign/010_wave1_small_p0_invariants.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/010_wave1_small_p0_invariants.md
rename to devlog/_fin/260814_bug_resolution_campaign/010_wave1_small_p0_invariants.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/020_wave2_windows_service.md b/devlog/_fin/260814_bug_resolution_campaign/020_wave2_windows_service.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/020_wave2_windows_service.md
rename to devlog/_fin/260814_bug_resolution_campaign/020_wave2_windows_service.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/030_wave3_cursor.md b/devlog/_fin/260814_bug_resolution_campaign/030_wave3_cursor.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/030_wave3_cursor.md
rename to devlog/_fin/260814_bug_resolution_campaign/030_wave3_cursor.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/040_wave4_oauth_config_security.md b/devlog/_fin/260814_bug_resolution_campaign/040_wave4_oauth_config_security.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/040_wave4_oauth_config_security.md
rename to devlog/_fin/260814_bug_resolution_campaign/040_wave4_oauth_config_security.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/050_wave5_provider_capability.md b/devlog/_fin/260814_bug_resolution_campaign/050_wave5_provider_capability.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/050_wave5_provider_capability.md
rename to devlog/_fin/260814_bug_resolution_campaign/050_wave5_provider_capability.md
diff --git a/devlog/_plan/260814_bug_resolution_campaign/060_wave6_ci_bun14.md b/devlog/_fin/260814_bug_resolution_campaign/060_wave6_ci_bun14.md
similarity index 100%
rename from devlog/_plan/260814_bug_resolution_campaign/060_wave6_ci_bun14.md
rename to devlog/_fin/260814_bug_resolution_campaign/060_wave6_ci_bun14.md
diff --git a/devlog/_fin/260814_bug_resolution_campaign/090_terminal.md b/devlog/_fin/260814_bug_resolution_campaign/090_terminal.md
new file mode 100644
index 0000000000..de5ec0216c
--- /dev/null
+++ b/devlog/_fin/260814_bug_resolution_campaign/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: superseded. The six-wave campaign was never executed; later 260819/260821 merge trains covered the backlog in a different shape.
diff --git a/devlog/_plan/260814_usage_memory_roadmap/000_plan.md b/devlog/_fin/260814_usage_memory_roadmap/000_plan.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/000_plan.md
rename to devlog/_fin/260814_usage_memory_roadmap/000_plan.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/010_m0_1_input_admission.md b/devlog/_fin/260814_usage_memory_roadmap/010_m0_1_input_admission.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/010_m0_1_input_admission.md
rename to devlog/_fin/260814_usage_memory_roadmap/010_m0_1_input_admission.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/020_m0_2_continuation_dedup.md b/devlog/_fin/260814_usage_memory_roadmap/020_m0_2_continuation_dedup.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/020_m0_2_continuation_dedup.md
rename to devlog/_fin/260814_usage_memory_roadmap/020_m0_2_continuation_dedup.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/030_m0_3_provider_delivery.md b/devlog/_fin/260814_usage_memory_roadmap/030_m0_3_provider_delivery.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/030_m0_3_provider_delivery.md
rename to devlog/_fin/260814_usage_memory_roadmap/030_m0_3_provider_delivery.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/040_m0_4_memory_recovery.md b/devlog/_fin/260814_usage_memory_roadmap/040_m0_4_memory_recovery.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/040_m0_4_memory_recovery.md
rename to devlog/_fin/260814_usage_memory_roadmap/040_m0_4_memory_recovery.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/050_m0_5_nonjson_depth_cap.md b/devlog/_fin/260814_usage_memory_roadmap/050_m0_5_nonjson_depth_cap.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/050_m0_5_nonjson_depth_cap.md
rename to devlog/_fin/260814_usage_memory_roadmap/050_m0_5_nonjson_depth_cap.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/060_u1_segmented_writer.md b/devlog/_fin/260814_usage_memory_roadmap/060_u1_segmented_writer.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/060_u1_segmented_writer.md
rename to devlog/_fin/260814_usage_memory_roadmap/060_u1_segmented_writer.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/070_u2_sqlite_projector.md b/devlog/_fin/260814_usage_memory_roadmap/070_u2_sqlite_projector.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/070_u2_sqlite_projector.md
rename to devlog/_fin/260814_usage_memory_roadmap/070_u2_sqlite_projector.md
diff --git a/devlog/_plan/260814_usage_memory_roadmap/080_u3_projection_api.md b/devlog/_fin/260814_usage_memory_roadmap/080_u3_projection_api.md
similarity index 100%
rename from devlog/_plan/260814_usage_memory_roadmap/080_u3_projection_api.md
rename to devlog/_fin/260814_usage_memory_roadmap/080_u3_projection_api.md
diff --git a/devlog/_fin/260814_usage_memory_roadmap/090_terminal.md b/devlog/_fin/260814_usage_memory_roadmap/090_terminal.md
new file mode 100644
index 0000000000..c87252e40a
--- /dev/null
+++ b/devlog/_fin/260814_usage_memory_roadmap/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: superseded. The M0/U1-U3 stack PRs (#1693/#1696/#1698) closed unmerged; later usage work (#2396, #1864) took a different shape.
diff --git a/devlog/_plan/260816_undeclared_tool_invocation_contract/000_research.md b/devlog/_fin/260816_undeclared_tool_invocation_contract/000_research.md
similarity index 100%
rename from devlog/_plan/260816_undeclared_tool_invocation_contract/000_research.md
rename to devlog/_fin/260816_undeclared_tool_invocation_contract/000_research.md
diff --git a/devlog/_plan/260818_260818-zcode-client/000_plan.md b/devlog/_fin/260818_260818-zcode-client/000_plan.md
similarity index 100%
rename from devlog/_plan/260818_260818-zcode-client/000_plan.md
rename to devlog/_fin/260818_260818-zcode-client/000_plan.md
diff --git a/devlog/_plan/260818_260818-zcode-client/010_phase1.md b/devlog/_fin/260818_260818-zcode-client/010_phase1.md
similarity index 100%
rename from devlog/_plan/260818_260818-zcode-client/010_phase1.md
rename to devlog/_fin/260818_260818-zcode-client/010_phase1.md
diff --git a/devlog/_plan/260818_260818-zcode-client/020_gui_zcode_tab.png b/devlog/_fin/260818_260818-zcode-client/020_gui_zcode_tab.png
similarity index 100%
rename from devlog/_plan/260818_260818-zcode-client/020_gui_zcode_tab.png
rename to devlog/_fin/260818_260818-zcode-client/020_gui_zcode_tab.png
diff --git a/devlog/_plan/260818_260818-zcode-client/021_zcode_e2e_live.png b/devlog/_fin/260818_260818-zcode-client/021_zcode_e2e_live.png
similarity index 100%
rename from devlog/_plan/260818_260818-zcode-client/021_zcode_e2e_live.png
rename to devlog/_fin/260818_260818-zcode-client/021_zcode_e2e_live.png
diff --git a/devlog/_plan/260818_fastwire_b2_openrouter/evidence/010_logs_openrouter_priority_lower_bound.png b/devlog/_fin/260818_fastwire_b2_openrouter/evidence/010_logs_openrouter_priority_lower_bound.png
similarity index 100%
rename from devlog/_plan/260818_fastwire_b2_openrouter/evidence/010_logs_openrouter_priority_lower_bound.png
rename to devlog/_fin/260818_fastwire_b2_openrouter/evidence/010_logs_openrouter_priority_lower_bound.png
diff --git a/devlog/_plan/260818_fastwire_b2_openrouter/evidence/README.md b/devlog/_fin/260818_fastwire_b2_openrouter/evidence/README.md
similarity index 100%
rename from devlog/_plan/260818_fastwire_b2_openrouter/evidence/README.md
rename to devlog/_fin/260818_fastwire_b2_openrouter/evidence/README.md
diff --git a/devlog/_plan/260818_fastwire_b2_xai/evidence/010_logs_priority_lower_bound.png b/devlog/_fin/260818_fastwire_b2_xai/evidence/010_logs_priority_lower_bound.png
similarity index 100%
rename from devlog/_plan/260818_fastwire_b2_xai/evidence/010_logs_priority_lower_bound.png
rename to devlog/_fin/260818_fastwire_b2_xai/evidence/010_logs_priority_lower_bound.png
diff --git a/devlog/_plan/260818_fastwire_b2_xai/evidence/README.md b/devlog/_fin/260818_fastwire_b2_xai/evidence/README.md
similarity index 100%
rename from devlog/_plan/260818_fastwire_b2_xai/evidence/README.md
rename to devlog/_fin/260818_fastwire_b2_xai/evidence/README.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/000_plan.md b/devlog/_fin/260819_response_state_temp_reclaim/000_plan.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/000_plan.md
rename to devlog/_fin/260819_response_state_temp_reclaim/000_plan.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/001_audit_round1.md b/devlog/_fin/260819_response_state_temp_reclaim/001_audit_round1.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/001_audit_round1.md
rename to devlog/_fin/260819_response_state_temp_reclaim/001_audit_round1.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/002_audit_round1_late.md b/devlog/_fin/260819_response_state_temp_reclaim/002_audit_round1_late.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/002_audit_round1_late.md
rename to devlog/_fin/260819_response_state_temp_reclaim/002_audit_round1_late.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/010_phase1_periodic_sweeper.md b/devlog/_fin/260819_response_state_temp_reclaim/010_phase1_periodic_sweeper.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/010_phase1_periodic_sweeper.md
rename to devlog/_fin/260819_response_state_temp_reclaim/010_phase1_periodic_sweeper.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/011_audit_round2.md b/devlog/_fin/260819_response_state_temp_reclaim/011_audit_round2.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/011_audit_round2.md
rename to devlog/_fin/260819_response_state_temp_reclaim/011_audit_round2.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/012_phase1_verification.md b/devlog/_fin/260819_response_state_temp_reclaim/012_phase1_verification.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/012_phase1_verification.md
rename to devlog/_fin/260819_response_state_temp_reclaim/012_phase1_verification.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/020_phase2_doctor_reclaim.md b/devlog/_fin/260819_response_state_temp_reclaim/020_phase2_doctor_reclaim.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/020_phase2_doctor_reclaim.md
rename to devlog/_fin/260819_response_state_temp_reclaim/020_phase2_doctor_reclaim.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/021_audit_round3.md b/devlog/_fin/260819_response_state_temp_reclaim/021_audit_round3.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/021_audit_round3.md
rename to devlog/_fin/260819_response_state_temp_reclaim/021_audit_round3.md
diff --git a/devlog/_plan/260819_response_state_temp_reclaim/022_phase2_verification.md b/devlog/_fin/260819_response_state_temp_reclaim/022_phase2_verification.md
similarity index 100%
rename from devlog/_plan/260819_response_state_temp_reclaim/022_phase2_verification.md
rename to devlog/_fin/260819_response_state_temp_reclaim/022_phase2_verification.md
diff --git a/devlog/_plan/260819_triage_execution/000_plan.md b/devlog/_fin/260819_triage_execution/000_plan.md
similarity index 100%
rename from devlog/_plan/260819_triage_execution/000_plan.md
rename to devlog/_fin/260819_triage_execution/000_plan.md
diff --git a/devlog/_plan/260819_triage_execution/010_env_key_contract.md b/devlog/_fin/260819_triage_execution/010_env_key_contract.md
similarity index 100%
rename from devlog/_plan/260819_triage_execution/010_env_key_contract.md
rename to devlog/_fin/260819_triage_execution/010_env_key_contract.md
diff --git a/devlog/_plan/260819_triage_execution/020_remote_reasoning_leak_rca.md b/devlog/_fin/260819_triage_execution/020_remote_reasoning_leak_rca.md
similarity index 100%
rename from devlog/_plan/260819_triage_execution/020_remote_reasoning_leak_rca.md
rename to devlog/_fin/260819_triage_execution/020_remote_reasoning_leak_rca.md
diff --git a/devlog/_plan/260819_triage_execution/030_outcome.md b/devlog/_fin/260819_triage_execution/030_outcome.md
similarity index 100%
rename from devlog/_plan/260819_triage_execution/030_outcome.md
rename to devlog/_fin/260819_triage_execution/030_outcome.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/000_research_inventory.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/000_research_inventory.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/000_research_inventory.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/000_research_inventory.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/010_layer1_bearer_admission_2132.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/010_layer1_bearer_admission_2132.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/010_layer1_bearer_admission_2132.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/010_layer1_bearer_admission_2132.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/020_layer2_responses_id_backfill_2131.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/020_layer2_responses_id_backfill_2131.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/020_layer2_responses_id_backfill_2131.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/020_layer2_responses_id_backfill_2131.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/030_sibling_prompt_cache_retention.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/030_sibling_prompt_cache_retention.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/030_sibling_prompt_cache_retention.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/030_sibling_prompt_cache_retention.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/040_sibling_routing_capability.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/040_sibling_routing_capability.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/040_sibling_routing_capability.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/040_sibling_routing_capability.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/050_sibling_k12_short_window.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/050_sibling_k12_short_window.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/050_sibling_k12_short_window.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/050_sibling_k12_short_window.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/060_supersede_and_close_operations.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/060_supersede_and_close_operations.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/060_supersede_and_close_operations.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/060_supersede_and_close_operations.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/070_execution_log.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/070_execution_log.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/070_execution_log.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/070_execution_log.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/090_merge_log.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/090_merge_log.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/090_merge_log.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/090_merge_log.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/100_release_audit.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/100_release_audit.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/100_release_audit.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/100_release_audit.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/100_release_safety_audit.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/100_release_safety_audit.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/100_release_safety_audit.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/100_release_safety_audit.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/110_three_bug_issues.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/110_three_bug_issues.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/110_three_bug_issues.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/110_three_bug_issues.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/120_release_2280.md b/devlog/_fin/260820_bug_pr_backlog_consolidation/120_release_2280.md
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/120_release_2280.md
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/120_release_2280.md
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-badge.png b/devlog/_fin/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-badge.png
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-badge.png
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-badge.png
diff --git a/devlog/_plan/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-filtered.png b/devlog/_fin/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-filtered.png
similarity index 100%
rename from devlog/_plan/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-filtered.png
rename to devlog/_fin/260820_bug_pr_backlog_consolidation/assets/2157-logs-intercepted-filtered.png
diff --git a/devlog/_plan/260820_sidecar_selection_unification/000_unit_overview.md b/devlog/_fin/260820_sidecar_selection_unification/000_unit_overview.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/000_unit_overview.md
rename to devlog/_fin/260820_sidecar_selection_unification/000_unit_overview.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/000_wp0_branch_worktree_cleanup.md b/devlog/_fin/260820_sidecar_selection_unification/000_wp0_branch_worktree_cleanup.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/000_wp0_branch_worktree_cleanup.md
rename to devlog/_fin/260820_sidecar_selection_unification/000_wp0_branch_worktree_cleanup.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/001_research_current_state.md b/devlog/_fin/260820_sidecar_selection_unification/001_research_current_state.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/001_research_current_state.md
rename to devlog/_fin/260820_sidecar_selection_unification/001_research_current_state.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/002_protocol_research.md b/devlog/_fin/260820_sidecar_selection_unification/002_protocol_research.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/002_protocol_research.md
rename to devlog/_fin/260820_sidecar_selection_unification/002_protocol_research.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/003_grok_tools_research.md b/devlog/_fin/260820_sidecar_selection_unification/003_grok_tools_research.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/003_grok_tools_research.md
rename to devlog/_fin/260820_sidecar_selection_unification/003_grok_tools_research.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/010_layer1_sidecar_auth.md b/devlog/_fin/260820_sidecar_selection_unification/010_layer1_sidecar_auth.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/010_layer1_sidecar_auth.md
rename to devlog/_fin/260820_sidecar_selection_unification/010_layer1_sidecar_auth.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/020_layer2_picker_candidates.md b/devlog/_fin/260820_sidecar_selection_unification/020_layer2_picker_candidates.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/020_layer2_picker_candidates.md
rename to devlog/_fin/260820_sidecar_selection_unification/020_layer2_picker_candidates.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/030_layer3_websearch_slots.md b/devlog/_fin/260820_sidecar_selection_unification/030_layer3_websearch_slots.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/030_layer3_websearch_slots.md
rename to devlog/_fin/260820_sidecar_selection_unification/030_layer3_websearch_slots.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/031_future_backend_research.md b/devlog/_fin/260820_sidecar_selection_unification/031_future_backend_research.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/031_future_backend_research.md
rename to devlog/_fin/260820_sidecar_selection_unification/031_future_backend_research.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/040_layer4_write_gates_gui.md b/devlog/_fin/260820_sidecar_selection_unification/040_layer4_write_gates_gui.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/040_layer4_write_gates_gui.md
rename to devlog/_fin/260820_sidecar_selection_unification/040_layer4_write_gates_gui.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/050_layer5_cli_and_final.md b/devlog/_fin/260820_sidecar_selection_unification/050_layer5_cli_and_final.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/050_layer5_cli_and_final.md
rename to devlog/_fin/260820_sidecar_selection_unification/050_layer5_cli_and_final.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/060_layer6_backend_union.md b/devlog/_fin/260820_sidecar_selection_unification/060_layer6_backend_union.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/060_layer6_backend_union.md
rename to devlog/_fin/260820_sidecar_selection_unification/060_layer6_backend_union.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/070_layer7_xai_executor.md b/devlog/_fin/260820_sidecar_selection_unification/070_layer7_xai_executor.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/070_layer7_xai_executor.md
rename to devlog/_fin/260820_sidecar_selection_unification/070_layer7_xai_executor.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/080_layer8_gemini_executor.md b/devlog/_fin/260820_sidecar_selection_unification/080_layer8_gemini_executor.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/080_layer8_gemini_executor.md
rename to devlog/_fin/260820_sidecar_selection_unification/080_layer8_gemini_executor.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/090_layer9_exa_executor.md b/devlog/_fin/260820_sidecar_selection_unification/090_layer9_exa_executor.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/090_layer9_exa_executor.md
rename to devlog/_fin/260820_sidecar_selection_unification/090_layer9_exa_executor.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/100_chat_default_regression.md b/devlog/_fin/260820_sidecar_selection_unification/100_chat_default_regression.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/100_chat_default_regression.md
rename to devlog/_fin/260820_sidecar_selection_unification/100_chat_default_regression.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/110_global_merge_order.md b/devlog/_fin/260820_sidecar_selection_unification/110_global_merge_order.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/110_global_merge_order.md
rename to devlog/_fin/260820_sidecar_selection_unification/110_global_merge_order.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/120_sidecar_chain_merge.md b/devlog/_fin/260820_sidecar_selection_unification/120_sidecar_chain_merge.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/120_sidecar_chain_merge.md
rename to devlog/_fin/260820_sidecar_selection_unification/120_sidecar_chain_merge.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/130_xai_responses_optin_switch.md b/devlog/_fin/260820_sidecar_selection_unification/130_xai_responses_optin_switch.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/130_xai_responses_optin_switch.md
rename to devlog/_fin/260820_sidecar_selection_unification/130_xai_responses_optin_switch.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/140_release_prep.md b/devlog/_fin/260820_sidecar_selection_unification/140_release_prep.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/140_release_prep.md
rename to devlog/_fin/260820_sidecar_selection_unification/140_release_prep.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/141_release_prep_artifact.md b/devlog/_fin/260820_sidecar_selection_unification/141_release_prep_artifact.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/141_release_prep_artifact.md
rename to devlog/_fin/260820_sidecar_selection_unification/141_release_prep_artifact.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/150_lidge_final_gate.md b/devlog/_fin/260820_sidecar_selection_unification/150_lidge_final_gate.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/150_lidge_final_gate.md
rename to devlog/_fin/260820_sidecar_selection_unification/150_lidge_final_gate.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/160_vision_external_research.md b/devlog/_fin/260820_sidecar_selection_unification/160_vision_external_research.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/160_vision_external_research.md
rename to devlog/_fin/260820_sidecar_selection_unification/160_vision_external_research.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/170_vision_backend_union.md b/devlog/_fin/260820_sidecar_selection_unification/170_vision_backend_union.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/170_vision_backend_union.md
rename to devlog/_fin/260820_sidecar_selection_unification/170_vision_backend_union.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/180_vision_describe_executors.md b/devlog/_fin/260820_sidecar_selection_unification/180_vision_describe_executors.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/180_vision_describe_executors.md
rename to devlog/_fin/260820_sidecar_selection_unification/180_vision_describe_executors.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/190_vision_surfaces_and_delivery.md b/devlog/_fin/260820_sidecar_selection_unification/190_vision_surfaces_and_delivery.md
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/190_vision_surfaces_and_delivery.md
rename to devlog/_fin/260820_sidecar_selection_unification/190_vision_surfaces_and_delivery.md
diff --git a/devlog/_plan/260820_sidecar_selection_unification/assets/l4-websearch-picker-filtered.png b/devlog/_fin/260820_sidecar_selection_unification/assets/l4-websearch-picker-filtered.png
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/assets/l4-websearch-picker-filtered.png
rename to devlog/_fin/260820_sidecar_selection_unification/assets/l4-websearch-picker-filtered.png
diff --git a/devlog/_plan/260820_sidecar_selection_unification/assets/vision_routed_dropdown.png b/devlog/_fin/260820_sidecar_selection_unification/assets/vision_routed_dropdown.png
similarity index 100%
rename from devlog/_plan/260820_sidecar_selection_unification/assets/vision_routed_dropdown.png
rename to devlog/_fin/260820_sidecar_selection_unification/assets/vision_routed_dropdown.png
diff --git a/devlog/_plan/260821_260821-model-catalog-refresh/000_plan.md b/devlog/_fin/260821_260821-model-catalog-refresh/000_plan.md
similarity index 100%
rename from devlog/_plan/260821_260821-model-catalog-refresh/000_plan.md
rename to devlog/_fin/260821_260821-model-catalog-refresh/000_plan.md
diff --git a/devlog/_plan/260821_260821-model-catalog-refresh/010_phase1.md b/devlog/_fin/260821_260821-model-catalog-refresh/010_phase1.md
similarity index 100%
rename from devlog/_plan/260821_260821-model-catalog-refresh/010_phase1.md
rename to devlog/_fin/260821_260821-model-catalog-refresh/010_phase1.md
diff --git a/devlog/_plan/260821_260821-windows-picker-full-restart/000_plan.md b/devlog/_fin/260821_260821-windows-picker-full-restart/000_plan.md
similarity index 100%
rename from devlog/_plan/260821_260821-windows-picker-full-restart/000_plan.md
rename to devlog/_fin/260821_260821-windows-picker-full-restart/000_plan.md
diff --git a/devlog/_plan/260821_260821-windows-picker-full-restart/010_phase1.md b/devlog/_fin/260821_260821-windows-picker-full-restart/010_phase1.md
similarity index 100%
rename from devlog/_plan/260821_260821-windows-picker-full-restart/010_phase1.md
rename to devlog/_fin/260821_260821-windows-picker-full-restart/010_phase1.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/000_plan.md b/devlog/_fin/260822_260822-bun14-followup-memory/000_plan.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/000_plan.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/000_plan.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/000_research.md b/devlog/_fin/260822_260822-bun14-followup-memory/000_research.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/000_research.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/000_research.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/010_memory_diagnostics.md b/devlog/_fin/260822_260822-bun14-followup-memory/010_memory_diagnostics.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/010_memory_diagnostics.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/010_memory_diagnostics.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md b/devlog/_fin/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/020_watchdog_gc_relief.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/030_smol_workers.md b/devlog/_fin/260822_260822-bun14-followup-memory/030_smol_workers.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/030_smol_workers.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/030_smol_workers.md
diff --git a/devlog/_plan/260822_260822-bun14-followup-memory/040_macmini_measurement.md b/devlog/_fin/260822_260822-bun14-followup-memory/040_macmini_measurement.md
similarity index 100%
rename from devlog/_plan/260822_260822-bun14-followup-memory/040_macmini_measurement.md
rename to devlog/_fin/260822_260822-bun14-followup-memory/040_macmini_measurement.md
diff --git a/devlog/_fin/260822_260822-bun14-followup-memory/090_terminal.md b/devlog/_fin/260822_260822-bun14-followup-memory/090_terminal.md
new file mode 100644
index 0000000000..4b1ee418c1
--- /dev/null
+++ b/devlog/_fin/260822_260822-bun14-followup-memory/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: superseded. Measurement protocol never executed; the runtime moved to stable Bun 1.4.x (`27764f342`) making the GC/smol comparison stale.
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/000_plan.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/000_plan.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/000_plan.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/000_plan.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/010_phase1.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/010_phase1.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/010_phase1.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/010_phase1.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/020_phase2.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/020_phase2.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/020_phase2.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/020_phase2.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/030_phase3.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/030_phase3.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/030_phase3.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/030_phase3.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/040_phase4.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/040_phase4.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/040_phase4.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/040_phase4.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/050_execution.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/050_execution.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/050_execution.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/050_execution.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/060_container_queries.md b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/060_container_queries.md
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/060_container_queries.md
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/060_container_queries.md
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/evidence/after-aligned.jpg b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/evidence/after-aligned.jpg
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/evidence/after-aligned.jpg
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/evidence/after-aligned.jpg
diff --git a/devlog/_plan/260822_260822-gui-sidecar-layout-dvh/evidence/before-collapse.jpg b/devlog/_fin/260822_260822-gui-sidecar-layout-dvh/evidence/before-collapse.jpg
similarity index 100%
rename from devlog/_plan/260822_260822-gui-sidecar-layout-dvh/evidence/before-collapse.jpg
rename to devlog/_fin/260822_260822-gui-sidecar-layout-dvh/evidence/before-collapse.jpg
diff --git a/devlog/_plan/260822_backlog_disposition_program/000_plan.md b/devlog/_fin/260822_backlog_disposition_program/000_plan.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/000_plan.md
rename to devlog/_fin/260822_backlog_disposition_program/000_plan.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/001_baseline_verifier_evidence.md b/devlog/_fin/260822_backlog_disposition_program/001_baseline_verifier_evidence.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/001_baseline_verifier_evidence.md
rename to devlog/_fin/260822_backlog_disposition_program/001_baseline_verifier_evidence.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/002_audit_synthesis.md b/devlog/_fin/260822_backlog_disposition_program/002_audit_synthesis.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/002_audit_synthesis.md
rename to devlog/_fin/260822_backlog_disposition_program/002_audit_synthesis.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/003_live_drift_and_2360.md b/devlog/_fin/260822_backlog_disposition_program/003_live_drift_and_2360.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/003_live_drift_and_2360.md
rename to devlog/_fin/260822_backlog_disposition_program/003_live_drift_and_2360.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/010_wp1_green_ready_merges.md b/devlog/_fin/260822_backlog_disposition_program/010_wp1_green_ready_merges.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/010_wp1_green_ready_merges.md
rename to devlog/_fin/260822_backlog_disposition_program/010_wp1_green_ready_merges.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/011_wp1_execution_record.md b/devlog/_fin/260822_backlog_disposition_program/011_wp1_execution_record.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/011_wp1_execution_record.md
rename to devlog/_fin/260822_backlog_disposition_program/011_wp1_execution_record.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/020_wp2_changes_requested_rebuilds.md b/devlog/_fin/260822_backlog_disposition_program/020_wp2_changes_requested_rebuilds.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/020_wp2_changes_requested_rebuilds.md
rename to devlog/_fin/260822_backlog_disposition_program/020_wp2_changes_requested_rebuilds.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/021_wp2_execution_record.md b/devlog/_fin/260822_backlog_disposition_program/021_wp2_execution_record.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/021_wp2_execution_record.md
rename to devlog/_fin/260822_backlog_disposition_program/021_wp2_execution_record.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/030_wp3_issue_2316_wait_agent_timeout.md b/devlog/_fin/260822_backlog_disposition_program/030_wp3_issue_2316_wait_agent_timeout.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/030_wp3_issue_2316_wait_agent_timeout.md
rename to devlog/_fin/260822_backlog_disposition_program/030_wp3_issue_2316_wait_agent_timeout.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/040_wp4_issue_2292_windows_picker.md b/devlog/_fin/260822_backlog_disposition_program/040_wp4_issue_2292_windows_picker.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/040_wp4_issue_2292_windows_picker.md
rename to devlog/_fin/260822_backlog_disposition_program/040_wp4_issue_2292_windows_picker.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/041_wp4_execution_record.md b/devlog/_fin/260822_backlog_disposition_program/041_wp4_execution_record.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/041_wp4_execution_record.md
rename to devlog/_fin/260822_backlog_disposition_program/041_wp4_execution_record.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/050_wp5_issue_2221_native_main_refresh.md b/devlog/_fin/260822_backlog_disposition_program/050_wp5_issue_2221_native_main_refresh.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/050_wp5_issue_2221_native_main_refresh.md
rename to devlog/_fin/260822_backlog_disposition_program/050_wp5_issue_2221_native_main_refresh.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/060_wp6_issue_1049_presubstrate_home_adoption.md b/devlog/_fin/260822_backlog_disposition_program/060_wp6_issue_1049_presubstrate_home_adoption.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/060_wp6_issue_1049_presubstrate_home_adoption.md
rename to devlog/_fin/260822_backlog_disposition_program/060_wp6_issue_1049_presubstrate_home_adoption.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/061_wp6_deferral_record.md b/devlog/_fin/260822_backlog_disposition_program/061_wp6_deferral_record.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/061_wp6_deferral_record.md
rename to devlog/_fin/260822_backlog_disposition_program/061_wp6_deferral_record.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/070_wp7_bun14_memory_stack_retarget.md b/devlog/_fin/260822_backlog_disposition_program/070_wp7_bun14_memory_stack_retarget.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/070_wp7_bun14_memory_stack_retarget.md
rename to devlog/_fin/260822_backlog_disposition_program/070_wp7_bun14_memory_stack_retarget.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/071_wp7_execution_record.md b/devlog/_fin/260822_backlog_disposition_program/071_wp7_execution_record.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/071_wp7_execution_record.md
rename to devlog/_fin/260822_backlog_disposition_program/071_wp7_execution_record.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/080_wp8_conflicting_and_remaining.md b/devlog/_fin/260822_backlog_disposition_program/080_wp8_conflicting_and_remaining.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/080_wp8_conflicting_and_remaining.md
rename to devlog/_fin/260822_backlog_disposition_program/080_wp8_conflicting_and_remaining.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/081_wp8_execution_and_reconciliation.md b/devlog/_fin/260822_backlog_disposition_program/081_wp8_execution_and_reconciliation.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/081_wp8_execution_and_reconciliation.md
rename to devlog/_fin/260822_backlog_disposition_program/081_wp8_execution_and_reconciliation.md
diff --git a/devlog/_plan/260822_backlog_disposition_program/090_wp9_new_pr_disposition.md b/devlog/_fin/260822_backlog_disposition_program/090_wp9_new_pr_disposition.md
similarity index 100%
rename from devlog/_plan/260822_backlog_disposition_program/090_wp9_new_pr_disposition.md
rename to devlog/_fin/260822_backlog_disposition_program/090_wp9_new_pr_disposition.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/000_unit_overview.md b/devlog/_fin/260822_cli_usage_cost_query/000_unit_overview.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/000_unit_overview.md
rename to devlog/_fin/260822_cli_usage_cost_query/000_unit_overview.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/001_current_state_inventory.md b/devlog/_fin/260822_cli_usage_cost_query/001_current_state_inventory.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/001_current_state_inventory.md
rename to devlog/_fin/260822_cli_usage_cost_query/001_current_state_inventory.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/010_data_layer.md b/devlog/_fin/260822_cli_usage_cost_query/010_data_layer.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/010_data_layer.md
rename to devlog/_fin/260822_cli_usage_cost_query/010_data_layer.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/020_api_layer.md b/devlog/_fin/260822_cli_usage_cost_query/020_api_layer.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/020_api_layer.md
rename to devlog/_fin/260822_cli_usage_cost_query/020_api_layer.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/021_audit_amendments.md b/devlog/_fin/260822_cli_usage_cost_query/021_audit_amendments.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/021_audit_amendments.md
rename to devlog/_fin/260822_cli_usage_cost_query/021_audit_amendments.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/030_cli_layer.md b/devlog/_fin/260822_cli_usage_cost_query/030_cli_layer.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/030_cli_layer.md
rename to devlog/_fin/260822_cli_usage_cost_query/030_cli_layer.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/031_live_evidence.md b/devlog/_fin/260822_cli_usage_cost_query/031_live_evidence.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/031_live_evidence.md
rename to devlog/_fin/260822_cli_usage_cost_query/031_live_evidence.md
diff --git a/devlog/_plan/260822_cli_usage_cost_query/040_verification_and_pr.md b/devlog/_fin/260822_cli_usage_cost_query/040_verification_and_pr.md
similarity index 100%
rename from devlog/_plan/260822_cli_usage_cost_query/040_verification_and_pr.md
rename to devlog/_fin/260822_cli_usage_cost_query/040_verification_and_pr.md
diff --git a/devlog/_plan/260822_dev_release_readiness/000_plan.md b/devlog/_fin/260822_dev_release_readiness/000_plan.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/000_plan.md
rename to devlog/_fin/260822_dev_release_readiness/000_plan.md
diff --git a/devlog/_plan/260822_dev_release_readiness/001_delta_inventory.md b/devlog/_fin/260822_dev_release_readiness/001_delta_inventory.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/001_delta_inventory.md
rename to devlog/_fin/260822_dev_release_readiness/001_delta_inventory.md
diff --git a/devlog/_plan/260822_dev_release_readiness/002_risk_matrix.md b/devlog/_fin/260822_dev_release_readiness/002_risk_matrix.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/002_risk_matrix.md
rename to devlog/_fin/260822_dev_release_readiness/002_risk_matrix.md
diff --git a/devlog/_plan/260822_dev_release_readiness/009_roadmap_lock.md b/devlog/_fin/260822_dev_release_readiness/009_roadmap_lock.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/009_roadmap_lock.md
rename to devlog/_fin/260822_dev_release_readiness/009_roadmap_lock.md
diff --git a/devlog/_plan/260822_dev_release_readiness/010_wp4_findings.md b/devlog/_fin/260822_dev_release_readiness/010_wp4_findings.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/010_wp4_findings.md
rename to devlog/_fin/260822_dev_release_readiness/010_wp4_findings.md
diff --git a/devlog/_plan/260822_dev_release_readiness/090_go_verdict.md b/devlog/_fin/260822_dev_release_readiness/090_go_verdict.md
similarity index 100%
rename from devlog/_plan/260822_dev_release_readiness/090_go_verdict.md
rename to devlog/_fin/260822_dev_release_readiness/090_go_verdict.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/000_inventory_and_roadmap.md b/devlog/_fin/260823_owner_backlog_closeout/000_inventory_and_roadmap.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/000_inventory_and_roadmap.md
rename to devlog/_fin/260823_owner_backlog_closeout/000_inventory_and_roadmap.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/001_reviewer_evidence.md b/devlog/_fin/260823_owner_backlog_closeout/001_reviewer_evidence.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/001_reviewer_evidence.md
rename to devlog/_fin/260823_owner_backlog_closeout/001_reviewer_evidence.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/010_wp1_pr2439_contract_manifest.md b/devlog/_fin/260823_owner_backlog_closeout/010_wp1_pr2439_contract_manifest.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/010_wp1_pr2439_contract_manifest.md
rename to devlog/_fin/260823_owner_backlog_closeout/010_wp1_pr2439_contract_manifest.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/020_wp2_pr2437_history_manifest.md b/devlog/_fin/260823_owner_backlog_closeout/020_wp2_pr2437_history_manifest.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/020_wp2_pr2437_history_manifest.md
rename to devlog/_fin/260823_owner_backlog_closeout/020_wp2_pr2437_history_manifest.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/030_wp3_pr2435_fetch_helper_boundary.md b/devlog/_fin/260823_owner_backlog_closeout/030_wp3_pr2435_fetch_helper_boundary.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/030_wp3_pr2435_fetch_helper_boundary.md
rename to devlog/_fin/260823_owner_backlog_closeout/030_wp3_pr2435_fetch_helper_boundary.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/040_wp4_pr2433_combo_failover.md b/devlog/_fin/260823_owner_backlog_closeout/040_wp4_pr2433_combo_failover.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/040_wp4_pr2433_combo_failover.md
rename to devlog/_fin/260823_owner_backlog_closeout/040_wp4_pr2433_combo_failover.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/050_wp5_pr2387_process_state.md b/devlog/_fin/260823_owner_backlog_closeout/050_wp5_pr2387_process_state.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/050_wp5_pr2387_process_state.md
rename to devlog/_fin/260823_owner_backlog_closeout/050_wp5_pr2387_process_state.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/060_wp6_pr2380_provider_validation.md b/devlog/_fin/260823_owner_backlog_closeout/060_wp6_pr2380_provider_validation.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/060_wp6_pr2380_provider_validation.md
rename to devlog/_fin/260823_owner_backlog_closeout/060_wp6_pr2380_provider_validation.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md b/devlog/_fin/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md
rename to devlog/_fin/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md b/devlog/_fin/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md
rename to devlog/_fin/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md b/devlog/_fin/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md
rename to devlog/_fin/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md b/devlog/_fin/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md
rename to devlog/_fin/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md b/devlog/_fin/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md
rename to devlog/_fin/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md b/devlog/_fin/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md
rename to devlog/_fin/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md
diff --git a/devlog/_plan/260823_owner_backlog_closeout/900_closing_reconciliation.md b/devlog/_fin/260823_owner_backlog_closeout/900_closing_reconciliation.md
similarity index 100%
rename from devlog/_plan/260823_owner_backlog_closeout/900_closing_reconciliation.md
rename to devlog/_fin/260823_owner_backlog_closeout/900_closing_reconciliation.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/000_baseline_scope_and_roadmap.md b/devlog/_fin/260824_v2_32_1_hotfix_train/000_baseline_scope_and_roadmap.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/000_baseline_scope_and_roadmap.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/000_baseline_scope_and_roadmap.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/001_reviewer_lane_evidence.md b/devlog/_fin/260824_v2_32_1_hotfix_train/001_reviewer_lane_evidence.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/001_reviewer_lane_evidence.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/001_reviewer_lane_evidence.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/010_wp1_dev_fastforward_to_release_lineage.md b/devlog/_fin/260824_v2_32_1_hotfix_train/010_wp1_dev_fastforward_to_release_lineage.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/010_wp1_dev_fastforward_to_release_lineage.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/010_wp1_dev_fastforward_to_release_lineage.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/020_wp3_pr2483_anthropic_id_classification.md b/devlog/_fin/260824_v2_32_1_hotfix_train/020_wp3_pr2483_anthropic_id_classification.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/020_wp3_pr2483_anthropic_id_classification.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/020_wp3_pr2483_anthropic_id_classification.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/030_wp4_pr2481_selectedmodels_slug_equivalence.md b/devlog/_fin/260824_v2_32_1_hotfix_train/030_wp4_pr2481_selectedmodels_slug_equivalence.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/030_wp4_pr2481_selectedmodels_slug_equivalence.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/030_wp4_pr2481_selectedmodels_slug_equivalence.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/040_wp5_pr2473_oversized_ws_transport.md b/devlog/_fin/260824_v2_32_1_hotfix_train/040_wp5_pr2473_oversized_ws_transport.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/040_wp5_pr2473_oversized_ws_transport.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/040_wp5_pr2473_oversized_ws_transport.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/050_wp6_pr2477_namespace_alias_authorization.md b/devlog/_fin/260824_v2_32_1_hotfix_train/050_wp6_pr2477_namespace_alias_authorization.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/050_wp6_pr2477_namespace_alias_authorization.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/050_wp6_pr2477_namespace_alias_authorization.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/060_wp7_pr2476_snapshot_write_amplification.md b/devlog/_fin/260824_v2_32_1_hotfix_train/060_wp7_pr2476_snapshot_write_amplification.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/060_wp7_pr2476_snapshot_write_amplification.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/060_wp7_pr2476_snapshot_write_amplification.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/070_wp2_pr2427_parallel_test_runner.md b/devlog/_fin/260824_v2_32_1_hotfix_train/070_wp2_pr2427_parallel_test_runner.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/070_wp2_pr2427_parallel_test_runner.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/070_wp2_pr2427_parallel_test_runner.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/080_wp8_freeze_verification_and_go_nogo.md b/devlog/_fin/260824_v2_32_1_hotfix_train/080_wp8_freeze_verification_and_go_nogo.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/080_wp8_freeze_verification_and_go_nogo.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/080_wp8_freeze_verification_and_go_nogo.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/090_wp9_issue2472_mixed_sequence_regression.md b/devlog/_fin/260824_v2_32_1_hotfix_train/090_wp9_issue2472_mixed_sequence_regression.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/090_wp9_issue2472_mixed_sequence_regression.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/090_wp9_issue2472_mixed_sequence_regression.md
diff --git a/devlog/_plan/260824_v2_32_1_hotfix_train/900_go_nogo_readiness_report.md b/devlog/_fin/260824_v2_32_1_hotfix_train/900_go_nogo_readiness_report.md
similarity index 100%
rename from devlog/_plan/260824_v2_32_1_hotfix_train/900_go_nogo_readiness_report.md
rename to devlog/_fin/260824_v2_32_1_hotfix_train/900_go_nogo_readiness_report.md
diff --git a/devlog/_plan/260825_oauth_login_ux/000_baseline_and_scope.md b/devlog/_fin/260825_oauth_login_ux/000_baseline_and_scope.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/000_baseline_and_scope.md
rename to devlog/_fin/260825_oauth_login_ux/000_baseline_and_scope.md
diff --git a/devlog/_plan/260825_oauth_login_ux/001_current_state_inventory.md b/devlog/_fin/260825_oauth_login_ux/001_current_state_inventory.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/001_current_state_inventory.md
rename to devlog/_fin/260825_oauth_login_ux/001_current_state_inventory.md
diff --git a/devlog/_plan/260825_oauth_login_ux/002_plan_audit.md b/devlog/_fin/260825_oauth_login_ux/002_plan_audit.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/002_plan_audit.md
rename to devlog/_fin/260825_oauth_login_ux/002_plan_audit.md
diff --git a/devlog/_plan/260825_oauth_login_ux/003_delivery_map.md b/devlog/_fin/260825_oauth_login_ux/003_delivery_map.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/003_delivery_map.md
rename to devlog/_fin/260825_oauth_login_ux/003_delivery_map.md
diff --git a/devlog/_plan/260825_oauth_login_ux/010_wp2_shared_login_hint.md b/devlog/_fin/260825_oauth_login_ux/010_wp2_shared_login_hint.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/010_wp2_shared_login_hint.md
rename to devlog/_fin/260825_oauth_login_ux/010_wp2_shared_login_hint.md
diff --git a/devlog/_plan/260825_oauth_login_ux/020_wp3_first_add_parity.md b/devlog/_fin/260825_oauth_login_ux/020_wp3_first_add_parity.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/020_wp3_first_add_parity.md
rename to devlog/_fin/260825_oauth_login_ux/020_wp3_first_add_parity.md
diff --git a/devlog/_plan/260825_oauth_login_ux/030_wp4_browser_open_control.md b/devlog/_fin/260825_oauth_login_ux/030_wp4_browser_open_control.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/030_wp4_browser_open_control.md
rename to devlog/_fin/260825_oauth_login_ux/030_wp4_browser_open_control.md
diff --git a/devlog/_plan/260825_oauth_login_ux/040_wp5_paste_normalization.md b/devlog/_fin/260825_oauth_login_ux/040_wp5_paste_normalization.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/040_wp5_paste_normalization.md
rename to devlog/_fin/260825_oauth_login_ux/040_wp5_paste_normalization.md
diff --git a/devlog/_plan/260825_oauth_login_ux/090_merge_train_closeout.md b/devlog/_fin/260825_oauth_login_ux/090_merge_train_closeout.md
similarity index 100%
rename from devlog/_plan/260825_oauth_login_ux/090_merge_train_closeout.md
rename to devlog/_fin/260825_oauth_login_ux/090_merge_train_closeout.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/000_research_snapshot.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/000_research_snapshot.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/000_research_snapshot.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/000_research_snapshot.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/001_audit_response.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/001_audit_response.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/001_audit_response.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/001_audit_response.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/010_wp2_merge_train_remainder.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/010_wp2_merge_train_remainder.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/010_wp2_merge_train_remainder.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/010_wp2_merge_train_remainder.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/020_wp4_google_lane.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/020_wp4_google_lane.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/020_wp4_google_lane.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/020_wp4_google_lane.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/030_wp5_hygiene_and_drafts.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/030_wp5_hygiene_and_drafts.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/030_wp5_hygiene_and_drafts.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/030_wp5_hygiene_and_drafts.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/040_wp6_cursor_catalog.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/040_wp6_cursor_catalog.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/040_wp6_cursor_catalog.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/040_wp6_cursor_catalog.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/050_wp7_oauth_failover.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/050_wp7_oauth_failover.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/050_wp7_oauth_failover.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/050_wp7_oauth_failover.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/060_wp8_wp9_cli_and_platform.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/060_wp8_wp9_cli_and_platform.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/060_wp8_wp9_cli_and_platform.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/060_wp8_wp9_cli_and_platform.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/070_wp10_wp11_slug_and_exec.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/070_wp10_wp11_slug_and_exec.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/070_wp10_wp11_slug_and_exec.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/070_wp10_wp11_slug_and_exec.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/080_wp12_catalog_ux.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/080_wp12_catalog_ux.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/080_wp12_catalog_ux.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/080_wp12_catalog_ux.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/090_wp13_architecture.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/090_wp13_architecture.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/090_wp13_architecture.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/090_wp13_architecture.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/100_wp6_wp8_execution.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/100_wp6_wp8_execution.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/100_wp6_wp8_execution.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/100_wp6_wp8_execution.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/110_wp7_oauth_failover.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/110_wp7_oauth_failover.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/110_wp7_oauth_failover.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/110_wp7_oauth_failover.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/111_wp7_audit_response.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/111_wp7_audit_response.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/111_wp7_audit_response.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/111_wp7_audit_response.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/120_wp5_2497_security_review.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/120_wp5_2497_security_review.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/120_wp5_2497_security_review.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/120_wp5_2497_security_review.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/130_wp16_late_bug_prs.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/130_wp16_late_bug_prs.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/130_wp16_late_bug_prs.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/130_wp16_late_bug_prs.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/140_closeout.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/140_closeout.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/140_closeout.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/140_closeout.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/150_community_bug_sweep.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/150_community_bug_sweep.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/150_community_bug_sweep.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/150_community_bug_sweep.md
diff --git a/devlog/_plan/260825_owner_backlog_and_bugpr_closeout/160_terminal_record.md b/devlog/_fin/260825_owner_backlog_and_bugpr_closeout/160_terminal_record.md
similarity index 100%
rename from devlog/_plan/260825_owner_backlog_and_bugpr_closeout/160_terminal_record.md
rename to devlog/_fin/260825_owner_backlog_and_bugpr_closeout/160_terminal_record.md
diff --git a/devlog/_plan/260826_backlog_triage/000_snapshot.md b/devlog/_fin/260826_backlog_triage/000_snapshot.md
similarity index 100%
rename from devlog/_plan/260826_backlog_triage/000_snapshot.md
rename to devlog/_fin/260826_backlog_triage/000_snapshot.md
diff --git a/devlog/_plan/260826_backlog_triage/010_stale_prs.md b/devlog/_fin/260826_backlog_triage/010_stale_prs.md
similarity index 100%
rename from devlog/_plan/260826_backlog_triage/010_stale_prs.md
rename to devlog/_fin/260826_backlog_triage/010_stale_prs.md
diff --git a/devlog/_plan/260826_backlog_triage/020_issue_quick_wins.md b/devlog/_fin/260826_backlog_triage/020_issue_quick_wins.md
similarity index 100%
rename from devlog/_plan/260826_backlog_triage/020_issue_quick_wins.md
rename to devlog/_fin/260826_backlog_triage/020_issue_quick_wins.md
diff --git a/devlog/_plan/260826_backlog_triage/030_recommendations.md b/devlog/_fin/260826_backlog_triage/030_recommendations.md
similarity index 100%
rename from devlog/_plan/260826_backlog_triage/030_recommendations.md
rename to devlog/_fin/260826_backlog_triage/030_recommendations.md
diff --git a/devlog/_plan/260826_glm53_flash_preseed/000_plan.md b/devlog/_fin/260826_glm53_flash_preseed/000_plan.md
similarity index 100%
rename from devlog/_plan/260826_glm53_flash_preseed/000_plan.md
rename to devlog/_fin/260826_glm53_flash_preseed/000_plan.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/000_plan.md b/devlog/_fin/260826_quota_window_and_backlog/000_plan.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/000_plan.md
rename to devlog/_fin/260826_quota_window_and_backlog/000_plan.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/001_audit_response.md b/devlog/_fin/260826_quota_window_and_backlog/001_audit_response.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/001_audit_response.md
rename to devlog/_fin/260826_quota_window_and_backlog/001_audit_response.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/010_phase1.md b/devlog/_fin/260826_quota_window_and_backlog/010_phase1.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/010_phase1.md
rename to devlog/_fin/260826_quota_window_and_backlog/010_phase1.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/020_phase2.md b/devlog/_fin/260826_quota_window_and_backlog/020_phase2.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/020_phase2.md
rename to devlog/_fin/260826_quota_window_and_backlog/020_phase2.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/030_phase3.md b/devlog/_fin/260826_quota_window_and_backlog/030_phase3.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/030_phase3.md
rename to devlog/_fin/260826_quota_window_and_backlog/030_phase3.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/040_phase4.md b/devlog/_fin/260826_quota_window_and_backlog/040_phase4.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/040_phase4.md
rename to devlog/_fin/260826_quota_window_and_backlog/040_phase4.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/050_phase5.md b/devlog/_fin/260826_quota_window_and_backlog/050_phase5.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/050_phase5.md
rename to devlog/_fin/260826_quota_window_and_backlog/050_phase5.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/060_phase6.md b/devlog/_fin/260826_quota_window_and_backlog/060_phase6.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/060_phase6.md
rename to devlog/_fin/260826_quota_window_and_backlog/060_phase6.md
diff --git a/devlog/_plan/260826_quota_window_and_backlog/070_phase7.md b/devlog/_fin/260826_quota_window_and_backlog/070_phase7.md
similarity index 100%
rename from devlog/_plan/260826_quota_window_and_backlog/070_phase7.md
rename to devlog/_fin/260826_quota_window_and_backlog/070_phase7.md
diff --git a/devlog/_plan/260826_wp13_disposable_host/010_census.md b/devlog/_fin/260826_wp13_disposable_host/010_census.md
similarity index 100%
rename from devlog/_plan/260826_wp13_disposable_host/010_census.md
rename to devlog/_fin/260826_wp13_disposable_host/010_census.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/000_intake.md b/devlog/_fin/260827_bug_pr_merge_round/000_intake.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/000_intake.md
rename to devlog/_fin/260827_bug_pr_merge_round/000_intake.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/001_pr2694_compile_break.md b/devlog/_fin/260827_bug_pr_merge_round/001_pr2694_compile_break.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/001_pr2694_compile_break.md
rename to devlog/_fin/260827_bug_pr_merge_round/001_pr2694_compile_break.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/002_pr2639_regression.md b/devlog/_fin/260827_bug_pr_merge_round/002_pr2639_regression.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/002_pr2639_regression.md
rename to devlog/_fin/260827_bug_pr_merge_round/002_pr2639_regression.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/003_disposition_matrix.md b/devlog/_fin/260827_bug_pr_merge_round/003_disposition_matrix.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/003_disposition_matrix.md
rename to devlog/_fin/260827_bug_pr_merge_round/003_disposition_matrix.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/004_pr2693_missing_implementation.md b/devlog/_fin/260827_bug_pr_merge_round/004_pr2693_missing_implementation.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/004_pr2693_missing_implementation.md
rename to devlog/_fin/260827_bug_pr_merge_round/004_pr2693_missing_implementation.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/005_audit_corrections.md b/devlog/_fin/260827_bug_pr_merge_round/005_audit_corrections.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/005_audit_corrections.md
rename to devlog/_fin/260827_bug_pr_merge_round/005_audit_corrections.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/006_execution_order.md b/devlog/_fin/260827_bug_pr_merge_round/006_execution_order.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/006_execution_order.md
rename to devlog/_fin/260827_bug_pr_merge_round/006_execution_order.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/007_audit_round2.md b/devlog/_fin/260827_bug_pr_merge_round/007_audit_round2.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/007_audit_round2.md
rename to devlog/_fin/260827_bug_pr_merge_round/007_audit_round2.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/010_lane_l1_commit_then_merge.md b/devlog/_fin/260827_bug_pr_merge_round/010_lane_l1_commit_then_merge.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/010_lane_l1_commit_then_merge.md
rename to devlog/_fin/260827_bug_pr_merge_round/010_lane_l1_commit_then_merge.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/011_wp2_l1_outcome.md b/devlog/_fin/260827_bug_pr_merge_round/011_wp2_l1_outcome.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/011_wp2_l1_outcome.md
rename to devlog/_fin/260827_bug_pr_merge_round/011_wp2_l1_outcome.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/020_lane_l3_cherry_pick.md b/devlog/_fin/260827_bug_pr_merge_round/020_lane_l3_cherry_pick.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/020_lane_l3_cherry_pick.md
rename to devlog/_fin/260827_bug_pr_merge_round/020_lane_l3_cherry_pick.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/021_status_vs_created_at_asymmetry.md b/devlog/_fin/260827_bug_pr_merge_round/021_status_vs_created_at_asymmetry.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/021_status_vs_created_at_asymmetry.md
rename to devlog/_fin/260827_bug_pr_merge_round/021_status_vs_created_at_asymmetry.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/022_l3_audit.md b/devlog/_fin/260827_bug_pr_merge_round/022_l3_audit.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/022_l3_audit.md
rename to devlog/_fin/260827_bug_pr_merge_round/022_l3_audit.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/030_lane_l2_close_squash.md b/devlog/_fin/260827_bug_pr_merge_round/030_lane_l2_close_squash.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/030_lane_l2_close_squash.md
rename to devlog/_fin/260827_bug_pr_merge_round/030_lane_l2_close_squash.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/031_wp4_l2_outcome.md b/devlog/_fin/260827_bug_pr_merge_round/031_wp4_l2_outcome.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/031_wp4_l2_outcome.md
rename to devlog/_fin/260827_bug_pr_merge_round/031_wp4_l2_outcome.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/040_lane_l4_reimplement.md b/devlog/_fin/260827_bug_pr_merge_round/040_lane_l4_reimplement.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/040_lane_l4_reimplement.md
rename to devlog/_fin/260827_bug_pr_merge_round/040_lane_l4_reimplement.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/041_wp5_l4_outcome.md b/devlog/_fin/260827_bug_pr_merge_round/041_wp5_l4_outcome.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/041_wp5_l4_outcome.md
rename to devlog/_fin/260827_bug_pr_merge_round/041_wp5_l4_outcome.md
diff --git a/devlog/_plan/260827_bug_pr_merge_round/050_round_closeout.md b/devlog/_fin/260827_bug_pr_merge_round/050_round_closeout.md
similarity index 100%
rename from devlog/_plan/260827_bug_pr_merge_round/050_round_closeout.md
rename to devlog/_fin/260827_bug_pr_merge_round/050_round_closeout.md
diff --git a/devlog/_plan/260827_dev_hardening/000_inventory.md b/devlog/_fin/260827_dev_hardening/000_inventory.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/000_inventory.md
rename to devlog/_fin/260827_dev_hardening/000_inventory.md
diff --git a/devlog/_plan/260827_dev_hardening/010_wp2_version_line.md b/devlog/_fin/260827_dev_hardening/010_wp2_version_line.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/010_wp2_version_line.md
rename to devlog/_fin/260827_dev_hardening/010_wp2_version_line.md
diff --git a/devlog/_plan/260827_dev_hardening/020_wp3_failover_identity.md b/devlog/_fin/260827_dev_hardening/020_wp3_failover_identity.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/020_wp3_failover_identity.md
rename to devlog/_fin/260827_dev_hardening/020_wp3_failover_identity.md
diff --git a/devlog/_plan/260827_dev_hardening/030_wp4_locale_docs.md b/devlog/_fin/260827_dev_hardening/030_wp4_locale_docs.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/030_wp4_locale_docs.md
rename to devlog/_fin/260827_dev_hardening/030_wp4_locale_docs.md
diff --git a/devlog/_plan/260827_dev_hardening/040_wp5_local_gates.md b/devlog/_fin/260827_dev_hardening/040_wp5_local_gates.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/040_wp5_local_gates.md
rename to devlog/_fin/260827_dev_hardening/040_wp5_local_gates.md
diff --git a/devlog/_plan/260827_dev_hardening/050_wp6_invariant_locks.md b/devlog/_fin/260827_dev_hardening/050_wp6_invariant_locks.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/050_wp6_invariant_locks.md
rename to devlog/_fin/260827_dev_hardening/050_wp6_invariant_locks.md
diff --git a/devlog/_plan/260827_dev_hardening/060_wp8_launcher_flake.md b/devlog/_fin/260827_dev_hardening/060_wp8_launcher_flake.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/060_wp8_launcher_flake.md
rename to devlog/_fin/260827_dev_hardening/060_wp8_launcher_flake.md
diff --git a/devlog/_plan/260827_dev_hardening/070_wp7_promotion_readiness.md b/devlog/_fin/260827_dev_hardening/070_wp7_promotion_readiness.md
similarity index 100%
rename from devlog/_plan/260827_dev_hardening/070_wp7_promotion_readiness.md
rename to devlog/_fin/260827_dev_hardening/070_wp7_promotion_readiness.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/000_plan.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/000_plan.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/000_plan.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/000_plan.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/001_regression_review.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/001_regression_review.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/001_regression_review.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/001_regression_review.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/010_wp2_git_attribution_layer.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/010_wp2_git_attribution_layer.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/010_wp2_git_attribution_layer.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/010_wp2_git_attribution_layer.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/020_wp3_base_variants.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/020_wp3_base_variants.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/020_wp3_base_variants.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/020_wp3_base_variants.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/021_audit_blockers.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/021_audit_blockers.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/021_audit_blockers.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/021_audit_blockers.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/030_wp4_docs_and_stack.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/030_wp4_docs_and_stack.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/030_wp4_docs_and_stack.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/030_wp4_docs_and_stack.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/040_remote_verification_and_wp3_landing.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/040_remote_verification_and_wp3_landing.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/040_remote_verification_and_wp3_landing.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/040_remote_verification_and_wp3_landing.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/041_wp3_audit_direct.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/041_wp3_audit_direct.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/041_wp3_audit_direct.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/041_wp3_audit_direct.md
diff --git a/devlog/_plan/260827_dev_regression_and_prompt_variants/042_wp3_remote_gate_and_landing.md b/devlog/_fin/260827_dev_regression_and_prompt_variants/042_wp3_remote_gate_and_landing.md
similarity index 100%
rename from devlog/_plan/260827_dev_regression_and_prompt_variants/042_wp3_remote_gate_and_landing.md
rename to devlog/_fin/260827_dev_regression_and_prompt_variants/042_wp3_remote_gate_and_landing.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/000_plan.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/000_plan.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/000_plan.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/000_plan.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/010_phase1.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/010_phase1.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/010_phase1.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/010_phase1.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/011_wp1_outcome.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/011_wp1_outcome.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/011_wp1_outcome.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/011_wp1_outcome.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/020_phase2.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/020_phase2.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/020_phase2.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/020_phase2.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/021_wp2_outcome.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/021_wp2_outcome.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/021_wp2_outcome.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/021_wp2_outcome.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/030_phase3.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/030_phase3.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/030_phase3.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/030_phase3.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/040_phase4.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/040_phase4.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/040_phase4.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/040_phase4.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/041_wp2b_2729_supersede.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/041_wp2b_2729_supersede.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/041_wp2b_2729_supersede.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/041_wp2b_2729_supersede.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/050_phase5.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/050_phase5.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/050_phase5.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/050_phase5.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/060_phase6.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/060_phase6.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/060_phase6.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/060_phase6.md
diff --git a/devlog/_plan/260827_igwanu_bug_pr_merge_round/070_outcome.md b/devlog/_fin/260827_igwanu_bug_pr_merge_round/070_outcome.md
similarity index 100%
rename from devlog/_plan/260827_igwanu_bug_pr_merge_round/070_outcome.md
rename to devlog/_fin/260827_igwanu_bug_pr_merge_round/070_outcome.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/000_plan.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/000_plan.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/000_plan.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/000_plan.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/010_exec_discovery_preservation.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/010_exec_discovery_preservation.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/010_exec_discovery_preservation.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/010_exec_discovery_preservation.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/011_root_cause_nudge_gap.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/011_root_cause_nudge_gap.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/011_root_cause_nudge_gap.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/011_root_cause_nudge_gap.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/012_audit_round1_synthesis.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/012_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/012_audit_round1_synthesis.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/012_audit_round1_synthesis.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/013_wp1_check_evidence.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/013_wp1_check_evidence.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/013_wp1_check_evidence.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/013_wp1_check_evidence.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/020_unbounded_kiro_delegation.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/020_unbounded_kiro_delegation.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/020_unbounded_kiro_delegation.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/020_unbounded_kiro_delegation.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/030_verification.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/030_verification.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/030_verification.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/030_verification.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/040_exec_catalog_priority.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/040_exec_catalog_priority.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/040_exec_catalog_priority.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/040_exec_catalog_priority.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/041_wp2_audit_synthesis.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/041_wp2_audit_synthesis.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/041_wp2_audit_synthesis.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/041_wp2_audit_synthesis.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/042_wp2_check_evidence.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/042_wp2_check_evidence.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/042_wp2_check_evidence.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/042_wp2_check_evidence.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/050_ship.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/050_ship.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/050_ship.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/050_ship.md
diff --git a/devlog/_plan/260827_kiro_subagent_delegation_unblock/051_ci_shard4_triage.md b/devlog/_fin/260827_kiro_subagent_delegation_unblock/051_ci_shard4_triage.md
similarity index 100%
rename from devlog/_plan/260827_kiro_subagent_delegation_unblock/051_ci_shard4_triage.md
rename to devlog/_fin/260827_kiro_subagent_delegation_unblock/051_ci_shard4_triage.md
diff --git a/devlog/_plan/260827_release_train/000_state_and_decisions.md b/devlog/_fin/260827_release_train/000_state_and_decisions.md
similarity index 100%
rename from devlog/_plan/260827_release_train/000_state_and_decisions.md
rename to devlog/_fin/260827_release_train/000_state_and_decisions.md
diff --git a/devlog/_plan/260827_release_train/010_preview_promote.md b/devlog/_fin/260827_release_train/010_preview_promote.md
similarity index 100%
rename from devlog/_plan/260827_release_train/010_preview_promote.md
rename to devlog/_fin/260827_release_train/010_preview_promote.md
diff --git a/devlog/_plan/260827_release_train/020_preview_release.md b/devlog/_fin/260827_release_train/020_preview_release.md
similarity index 100%
rename from devlog/_plan/260827_release_train/020_preview_release.md
rename to devlog/_fin/260827_release_train/020_preview_release.md
diff --git a/devlog/_plan/260827_release_train/030_main_promote.md b/devlog/_fin/260827_release_train/030_main_promote.md
similarity index 100%
rename from devlog/_plan/260827_release_train/030_main_promote.md
rename to devlog/_fin/260827_release_train/030_main_promote.md
diff --git a/devlog/_plan/260827_release_train/040_stable_release.md b/devlog/_fin/260827_release_train/040_stable_release.md
similarity index 100%
rename from devlog/_plan/260827_release_train/040_stable_release.md
rename to devlog/_fin/260827_release_train/040_stable_release.md
diff --git a/devlog/_plan/260827_release_train/050_deploy_and_verify.md b/devlog/_fin/260827_release_train/050_deploy_and_verify.md
similarity index 100%
rename from devlog/_plan/260827_release_train/050_deploy_and_verify.md
rename to devlog/_fin/260827_release_train/050_deploy_and_verify.md
diff --git a/devlog/_plan/260827_remote_hub/000_research.md b/devlog/_fin/260827_remote_hub/000_research.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/000_research.md
rename to devlog/_fin/260827_remote_hub/000_research.md
diff --git a/devlog/_plan/260827_remote_hub/001_interview.md b/devlog/_fin/260827_remote_hub/001_interview.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/001_interview.md
rename to devlog/_fin/260827_remote_hub/001_interview.md
diff --git a/devlog/_plan/260827_remote_hub/002_audit_r1_synthesis.md b/devlog/_fin/260827_remote_hub/002_audit_r1_synthesis.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/002_audit_r1_synthesis.md
rename to devlog/_fin/260827_remote_hub/002_audit_r1_synthesis.md
diff --git a/devlog/_plan/260827_remote_hub/003_audit_r2_synthesis.md b/devlog/_fin/260827_remote_hub/003_audit_r2_synthesis.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/003_audit_r2_synthesis.md
rename to devlog/_fin/260827_remote_hub/003_audit_r2_synthesis.md
diff --git a/devlog/_plan/260827_remote_hub/010_design.md b/devlog/_fin/260827_remote_hub/010_design.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/010_design.md
rename to devlog/_fin/260827_remote_hub/010_design.md
diff --git a/devlog/_plan/260827_remote_hub/020_roadmap.md b/devlog/_fin/260827_remote_hub/020_roadmap.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/020_roadmap.md
rename to devlog/_fin/260827_remote_hub/020_roadmap.md
diff --git a/devlog/_plan/260827_remote_hub/030_phase1_protocol_catalog.md b/devlog/_fin/260827_remote_hub/030_phase1_protocol_catalog.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/030_phase1_protocol_catalog.md
rename to devlog/_fin/260827_remote_hub/030_phase1_protocol_catalog.md
diff --git a/devlog/_plan/260827_remote_hub/040_phase2_remote_session.md b/devlog/_fin/260827_remote_hub/040_phase2_remote_session.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/040_phase2_remote_session.md
rename to devlog/_fin/260827_remote_hub/040_phase2_remote_session.md
diff --git a/devlog/_plan/260827_remote_hub/050_phase3_connect.md b/devlog/_fin/260827_remote_hub/050_phase3_connect.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/050_phase3_connect.md
rename to devlog/_fin/260827_remote_hub/050_phase3_connect.md
diff --git a/devlog/_plan/260827_remote_hub/060_phase4_two_plane.md b/devlog/_fin/260827_remote_hub/060_phase4_two_plane.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/060_phase4_two_plane.md
rename to devlog/_fin/260827_remote_hub/060_phase4_two_plane.md
diff --git a/devlog/_plan/260827_remote_hub/070_phase5_deploy.md b/devlog/_fin/260827_remote_hub/070_phase5_deploy.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/070_phase5_deploy.md
rename to devlog/_fin/260827_remote_hub/070_phase5_deploy.md
diff --git a/devlog/_plan/260827_remote_hub/080_phase6_hardening.md b/devlog/_fin/260827_remote_hub/080_phase6_hardening.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/080_phase6_hardening.md
rename to devlog/_fin/260827_remote_hub/080_phase6_hardening.md
diff --git a/devlog/_plan/260827_remote_hub/090_dogfood_record.md b/devlog/_fin/260827_remote_hub/090_dogfood_record.md
similarity index 100%
rename from devlog/_plan/260827_remote_hub/090_dogfood_record.md
rename to devlog/_fin/260827_remote_hub/090_dogfood_record.md
diff --git a/devlog/_fin/260827_remote_hub/090_terminal.md b/devlog/_fin/260827_remote_hub/090_terminal.md
new file mode 100644
index 0000000000..1547db2ff2
--- /dev/null
+++ b/devlog/_fin/260827_remote_hub/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: superseded by 260901_remote_hub_restack, which landed the restacked hub (#2771-#2789, #3147).
diff --git a/devlog/_plan/260827_remote_hub/assets/gui-p4-dashboard.png b/devlog/_fin/260827_remote_hub/assets/gui-p4-dashboard.png
similarity index 100%
rename from devlog/_plan/260827_remote_hub/assets/gui-p4-dashboard.png
rename to devlog/_fin/260827_remote_hub/assets/gui-p4-dashboard.png
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/000_plan.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/000_plan.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/000_plan.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/000_plan.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/010_phase1.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/010_phase1.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/010_phase1.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/010_phase1.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/020_phase2.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/020_phase2.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/020_phase2.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/020_phase2.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/021_wp2_wp3_outcome.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/021_wp2_wp3_outcome.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/021_wp2_wp3_outcome.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/021_wp2_wp3_outcome.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/030_phase3.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/030_phase3.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/030_phase3.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/030_phase3.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/040_phase4.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/040_phase4.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/040_phase4.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/040_phase4.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/050_phase5.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/050_phase5.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/050_phase5.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/050_phase5.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/060_phase6.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/060_phase6.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/060_phase6.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/060_phase6.md
diff --git a/devlog/_plan/260828_bugpr_fix_and_reimplement/070_outcome.md b/devlog/_fin/260828_bugpr_fix_and_reimplement/070_outcome.md
similarity index 100%
rename from devlog/_plan/260828_bugpr_fix_and_reimplement/070_outcome.md
rename to devlog/_fin/260828_bugpr_fix_and_reimplement/070_outcome.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/000_plan.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/000_plan.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/000_plan.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/000_plan.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/001_backlog_abort_rca.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/001_backlog_abort_rca.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/001_backlog_abort_rca.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/001_backlog_abort_rca.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/002_cursor_open_defect_inventory.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/002_cursor_open_defect_inventory.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/002_cursor_open_defect_inventory.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/002_cursor_open_defect_inventory.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/003_roadmap_lock.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/003_roadmap_lock.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/003_roadmap_lock.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/003_roadmap_lock.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/010_backlog_abort_fix.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/010_backlog_abort_fix.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/010_backlog_abort_fix.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/010_backlog_abort_fix.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/020_macmini_probe_round.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/020_macmini_probe_round.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/020_macmini_probe_round.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/020_macmini_probe_round.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/021_probe_results_round1.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/021_probe_results_round1.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/021_probe_results_round1.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/021_probe_results_round1.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/030_cursor_fixes.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/030_cursor_fixes.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/030_cursor_fixes.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/030_cursor_fixes.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/031_midstream_echo_fix.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/031_midstream_echo_fix.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/031_midstream_echo_fix.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/031_midstream_echo_fix.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/040_closure_round.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/040_closure_round.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/040_closure_round.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/040_closure_round.md
diff --git a/devlog/_plan/260828_cursor_ndjson_backlog_train/050_merge_train.md b/devlog/_fin/260828_cursor_ndjson_backlog_train/050_merge_train.md
similarity index 100%
rename from devlog/_plan/260828_cursor_ndjson_backlog_train/050_merge_train.md
rename to devlog/_fin/260828_cursor_ndjson_backlog_train/050_merge_train.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/000_plan.md b/devlog/_fin/260828_cursor_umbrella_catalog/000_plan.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/000_plan.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/000_plan.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/001_reference_analysis.md b/devlog/_fin/260828_cursor_umbrella_catalog/001_reference_analysis.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/001_reference_analysis.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/001_reference_analysis.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/002_current_surface.md b/devlog/_fin/260828_cursor_umbrella_catalog/002_current_surface.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/002_current_surface.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/002_current_surface.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/003_design.md b/devlog/_fin/260828_cursor_umbrella_catalog/003_design.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/003_design.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/003_design.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/004_roadmap_lock.md b/devlog/_fin/260828_cursor_umbrella_catalog/004_roadmap_lock.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/004_roadmap_lock.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/004_roadmap_lock.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/010_capability_core.md b/devlog/_fin/260828_cursor_umbrella_catalog/010_capability_core.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/010_capability_core.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/010_capability_core.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/020_catalog_integration.md b/devlog/_fin/260828_cursor_umbrella_catalog/020_catalog_integration.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/020_catalog_integration.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/020_catalog_integration.md
diff --git a/devlog/_plan/260828_cursor_umbrella_catalog/030_closure.md b/devlog/_fin/260828_cursor_umbrella_catalog/030_closure.md
similarity index 100%
rename from devlog/_plan/260828_cursor_umbrella_catalog/030_closure.md
rename to devlog/_fin/260828_cursor_umbrella_catalog/030_closure.md
diff --git a/devlog/_plan/260828_quota_reset_detection/000_plan.md b/devlog/_fin/260828_quota_reset_detection/000_plan.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/000_plan.md
rename to devlog/_fin/260828_quota_reset_detection/000_plan.md
diff --git a/devlog/_plan/260828_quota_reset_detection/001_audit_response.md b/devlog/_fin/260828_quota_reset_detection/001_audit_response.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/001_audit_response.md
rename to devlog/_fin/260828_quota_reset_detection/001_audit_response.md
diff --git a/devlog/_plan/260828_quota_reset_detection/002_wp2_audit_response.md b/devlog/_fin/260828_quota_reset_detection/002_wp2_audit_response.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/002_wp2_audit_response.md
rename to devlog/_fin/260828_quota_reset_detection/002_wp2_audit_response.md
diff --git a/devlog/_plan/260828_quota_reset_detection/003_wp3_audit_response.md b/devlog/_fin/260828_quota_reset_detection/003_wp3_audit_response.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/003_wp3_audit_response.md
rename to devlog/_fin/260828_quota_reset_detection/003_wp3_audit_response.md
diff --git a/devlog/_plan/260828_quota_reset_detection/004_wp3_review_response.md b/devlog/_fin/260828_quota_reset_detection/004_wp3_review_response.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/004_wp3_review_response.md
rename to devlog/_fin/260828_quota_reset_detection/004_wp3_review_response.md
diff --git a/devlog/_plan/260828_quota_reset_detection/010_phase2_detection_core.md b/devlog/_fin/260828_quota_reset_detection/010_phase2_detection_core.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/010_phase2_detection_core.md
rename to devlog/_fin/260828_quota_reset_detection/010_phase2_detection_core.md
diff --git a/devlog/_plan/260828_quota_reset_detection/020_phase3_observation_wiring.md b/devlog/_fin/260828_quota_reset_detection/020_phase3_observation_wiring.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/020_phase3_observation_wiring.md
rename to devlog/_fin/260828_quota_reset_detection/020_phase3_observation_wiring.md
diff --git a/devlog/_plan/260828_quota_reset_detection/030_phase4_sinks_and_surface.md b/devlog/_fin/260828_quota_reset_detection/030_phase4_sinks_and_surface.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/030_phase4_sinks_and_surface.md
rename to devlog/_fin/260828_quota_reset_detection/030_phase4_sinks_and_surface.md
diff --git a/devlog/_plan/260828_quota_reset_detection/040_phase5_hardening_delivery.md b/devlog/_fin/260828_quota_reset_detection/040_phase5_hardening_delivery.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/040_phase5_hardening_delivery.md
rename to devlog/_fin/260828_quota_reset_detection/040_phase5_hardening_delivery.md
diff --git a/devlog/_plan/260828_quota_reset_detection/050_activation_evidence.md b/devlog/_fin/260828_quota_reset_detection/050_activation_evidence.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/050_activation_evidence.md
rename to devlog/_fin/260828_quota_reset_detection/050_activation_evidence.md
diff --git a/devlog/_plan/260828_quota_reset_detection/060_closeout.md b/devlog/_fin/260828_quota_reset_detection/060_closeout.md
similarity index 100%
rename from devlog/_plan/260828_quota_reset_detection/060_closeout.md
rename to devlog/_fin/260828_quota_reset_detection/060_closeout.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/120_issue_1527_replay_envelope.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/120_issue_1527_replay_envelope.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/120_issue_1527_replay_envelope.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/120_issue_1527_replay_envelope.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/130_pr2872_probe_fingerprint.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/130_pr2872_probe_fingerprint.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/130_pr2872_probe_fingerprint.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/130_pr2872_probe_fingerprint.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/140_pr2884_shim_backup_matcher.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/140_pr2884_shim_backup_matcher.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/140_pr2884_shim_backup_matcher.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/140_pr2884_shim_backup_matcher.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/150_issue_2887_pool_401_refresh.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/150_issue_2887_pool_401_refresh.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/150_issue_2887_pool_401_refresh.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/150_issue_2887_pool_401_refresh.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/160_issue_2886_entitlement_client_version.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/160_issue_2886_entitlement_client_version.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/160_issue_2886_entitlement_client_version.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/160_issue_2886_entitlement_client_version.md
diff --git a/devlog/_plan/260829_bugpr_lane_h_residual_issues/170_pr2895_pool_401_recovery_budget.md b/devlog/_fin/260829_bugpr_lane_h_residual_issues/170_pr2895_pool_401_recovery_budget.md
similarity index 100%
rename from devlog/_plan/260829_bugpr_lane_h_residual_issues/170_pr2895_pool_401_recovery_budget.md
rename to devlog/_fin/260829_bugpr_lane_h_residual_issues/170_pr2895_pool_401_recovery_budget.md
diff --git a/devlog/_plan/260829_green_pr_merge_train/000_plan.md b/devlog/_fin/260829_green_pr_merge_train/000_plan.md
similarity index 100%
rename from devlog/_plan/260829_green_pr_merge_train/000_plan.md
rename to devlog/_fin/260829_green_pr_merge_train/000_plan.md
diff --git a/devlog/_plan/260829_green_pr_merge_train/010_wp1_2429_privacy_scan.md b/devlog/_fin/260829_green_pr_merge_train/010_wp1_2429_privacy_scan.md
similarity index 100%
rename from devlog/_plan/260829_green_pr_merge_train/010_wp1_2429_privacy_scan.md
rename to devlog/_fin/260829_green_pr_merge_train/010_wp1_2429_privacy_scan.md
diff --git a/devlog/_plan/260829_green_pr_merge_train/020_wp2_2827_expose_header.md b/devlog/_fin/260829_green_pr_merge_train/020_wp2_2827_expose_header.md
similarity index 100%
rename from devlog/_plan/260829_green_pr_merge_train/020_wp2_2827_expose_header.md
rename to devlog/_fin/260829_green_pr_merge_train/020_wp2_2827_expose_header.md
diff --git a/devlog/_plan/260829_green_pr_merge_train/090_closeout.md b/devlog/_fin/260829_green_pr_merge_train/090_closeout.md
similarity index 100%
rename from devlog/_plan/260829_green_pr_merge_train/090_closeout.md
rename to devlog/_fin/260829_green_pr_merge_train/090_closeout.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/000_baseline_and_roadmap.md b/devlog/_fin/260829_gui_dashboard_slop/000_baseline_and_roadmap.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/000_baseline_and_roadmap.md
rename to devlog/_fin/260829_gui_dashboard_slop/000_baseline_and_roadmap.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/010_sidecar_pair_alignment.md b/devlog/_fin/260829_gui_dashboard_slop/010_sidecar_pair_alignment.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/010_sidecar_pair_alignment.md
rename to devlog/_fin/260829_gui_dashboard_slop/010_sidecar_pair_alignment.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/011_audit_correction_align_content.md b/devlog/_fin/260829_gui_dashboard_slop/011_audit_correction_align_content.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/011_audit_correction_align_content.md
rename to devlog/_fin/260829_gui_dashboard_slop/011_audit_correction_align_content.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/012_shipped_fix_and_subgrid_postmortem.md b/devlog/_fin/260829_gui_dashboard_slop/012_shipped_fix_and_subgrid_postmortem.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/012_shipped_fix_and_subgrid_postmortem.md
rename to devlog/_fin/260829_gui_dashboard_slop/012_shipped_fix_and_subgrid_postmortem.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/013_final_shipped_and_measurement_lessons.md b/devlog/_fin/260829_gui_dashboard_slop/013_final_shipped_and_measurement_lessons.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/013_final_shipped_and_measurement_lessons.md
rename to devlog/_fin/260829_gui_dashboard_slop/013_final_shipped_and_measurement_lessons.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/020_phantom_grid_track.md b/devlog/_fin/260829_gui_dashboard_slop/020_phantom_grid_track.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/020_phantom_grid_track.md
rename to devlog/_fin/260829_gui_dashboard_slop/020_phantom_grid_track.md
diff --git a/devlog/_plan/260829_gui_dashboard_slop/030_dynamic_viewport_units.md b/devlog/_fin/260829_gui_dashboard_slop/030_dynamic_viewport_units.md
similarity index 100%
rename from devlog/_plan/260829_gui_dashboard_slop/030_dynamic_viewport_units.md
rename to devlog/_fin/260829_gui_dashboard_slop/030_dynamic_viewport_units.md
diff --git a/devlog/_plan/260829_lane_n_effort_ladder_and_locale_probe/000_units.md b/devlog/_fin/260829_lane_n_effort_ladder_and_locale_probe/000_units.md
similarity index 100%
rename from devlog/_plan/260829_lane_n_effort_ladder_and_locale_probe/000_units.md
rename to devlog/_fin/260829_lane_n_effort_ladder_and_locale_probe/000_units.md
diff --git a/devlog/_plan/260830_dev_version_line_bump_pr/000_cause_and_roadmap.md b/devlog/_fin/260830_dev_version_line_bump_pr/000_cause_and_roadmap.md
similarity index 100%
rename from devlog/_plan/260830_dev_version_line_bump_pr/000_cause_and_roadmap.md
rename to devlog/_fin/260830_dev_version_line_bump_pr/000_cause_and_roadmap.md
diff --git a/devlog/_plan/260830_dev_version_line_bump_pr/010_version_repair.md b/devlog/_fin/260830_dev_version_line_bump_pr/010_version_repair.md
similarity index 100%
rename from devlog/_plan/260830_dev_version_line_bump_pr/010_version_repair.md
rename to devlog/_fin/260830_dev_version_line_bump_pr/010_version_repair.md
diff --git a/devlog/_plan/260830_dev_version_line_bump_pr/020_post_release_bump.md b/devlog/_fin/260830_dev_version_line_bump_pr/020_post_release_bump.md
similarity index 100%
rename from devlog/_plan/260830_dev_version_line_bump_pr/020_post_release_bump.md
rename to devlog/_fin/260830_dev_version_line_bump_pr/020_post_release_bump.md
diff --git a/devlog/_plan/260830_dev_version_line_bump_pr/030_ship.md b/devlog/_fin/260830_dev_version_line_bump_pr/030_ship.md
similarity index 100%
rename from devlog/_plan/260830_dev_version_line_bump_pr/030_ship.md
rename to devlog/_fin/260830_dev_version_line_bump_pr/030_ship.md
diff --git a/devlog/_plan/260830_lane_o_reset_recovery_parity/000_units.md b/devlog/_fin/260830_lane_o_reset_recovery_parity/000_units.md
similarity index 100%
rename from devlog/_plan/260830_lane_o_reset_recovery_parity/000_units.md
rename to devlog/_fin/260830_lane_o_reset_recovery_parity/000_units.md
diff --git a/devlog/_plan/260830_lane_q_2892_gaps_3_4/000_units.md b/devlog/_fin/260830_lane_q_2892_gaps_3_4/000_units.md
similarity index 100%
rename from devlog/_plan/260830_lane_q_2892_gaps_3_4/000_units.md
rename to devlog/_fin/260830_lane_q_2892_gaps_3_4/000_units.md
diff --git a/devlog/_plan/260830_lane_r_2941_copilot_vision/000_units.md b/devlog/_fin/260830_lane_r_2941_copilot_vision/000_units.md
similarity index 100%
rename from devlog/_plan/260830_lane_r_2941_copilot_vision/000_units.md
rename to devlog/_fin/260830_lane_r_2941_copilot_vision/000_units.md
diff --git a/devlog/_plan/260830_release_readiness_train/000_plan.md b/devlog/_fin/260830_release_readiness_train/000_plan.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/000_plan.md
rename to devlog/_fin/260830_release_readiness_train/000_plan.md
diff --git a/devlog/_plan/260830_release_readiness_train/010_wp1_runner_and_hygiene.md b/devlog/_fin/260830_release_readiness_train/010_wp1_runner_and_hygiene.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/010_wp1_runner_and_hygiene.md
rename to devlog/_fin/260830_release_readiness_train/010_wp1_runner_and_hygiene.md
diff --git a/devlog/_plan/260830_release_readiness_train/020_wp2_quota_expiry.md b/devlog/_fin/260830_release_readiness_train/020_wp2_quota_expiry.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/020_wp2_quota_expiry.md
rename to devlog/_fin/260830_release_readiness_train/020_wp2_quota_expiry.md
diff --git a/devlog/_plan/260830_release_readiness_train/030_wp3_responses_and_config.md b/devlog/_fin/260830_release_readiness_train/030_wp3_responses_and_config.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/030_wp3_responses_and_config.md
rename to devlog/_fin/260830_release_readiness_train/030_wp3_responses_and_config.md
diff --git a/devlog/_plan/260830_release_readiness_train/040_wp4_issue_2899_antigravity.md b/devlog/_fin/260830_release_readiness_train/040_wp4_issue_2899_antigravity.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/040_wp4_issue_2899_antigravity.md
rename to devlog/_fin/260830_release_readiness_train/040_wp4_issue_2899_antigravity.md
diff --git a/devlog/_plan/260830_release_readiness_train/050_wp5_issue_1298_acl_proof.md b/devlog/_fin/260830_release_readiness_train/050_wp5_issue_1298_acl_proof.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/050_wp5_issue_1298_acl_proof.md
rename to devlog/_fin/260830_release_readiness_train/050_wp5_issue_1298_acl_proof.md
diff --git a/devlog/_plan/260830_release_readiness_train/060_wp6_release_gates.md b/devlog/_fin/260830_release_readiness_train/060_wp6_release_gates.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/060_wp6_release_gates.md
rename to devlog/_fin/260830_release_readiness_train/060_wp6_release_gates.md
diff --git a/devlog/_plan/260830_release_readiness_train/070_outcome.md b/devlog/_fin/260830_release_readiness_train/070_outcome.md
similarity index 100%
rename from devlog/_plan/260830_release_readiness_train/070_outcome.md
rename to devlog/_fin/260830_release_readiness_train/070_outcome.md
diff --git a/devlog/_plan/260830_sidecar_control_band/010_shared_control_band.md b/devlog/_fin/260830_sidecar_control_band/010_shared_control_band.md
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/010_shared_control_band.md
rename to devlog/_fin/260830_sidecar_control_band/010_shared_control_band.md
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/010-after-ko-1024.png b/devlog/_fin/260830_sidecar_control_band/evidence/010-after-ko-1024.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/010-after-ko-1024.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/010-after-ko-1024.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/010-after-ko-1440.png b/devlog/_fin/260830_sidecar_control_band/evidence/010-after-ko-1440.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/010-after-ko-1440.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/010-after-ko-1440.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/010-before-ko-1024.png b/devlog/_fin/260830_sidecar_control_band/evidence/010-before-ko-1024.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/010-before-ko-1024.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/010-before-ko-1024.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/010-before-ko-1440.png b/devlog/_fin/260830_sidecar_control_band/evidence/010-before-ko-1440.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/010-before-ko-1440.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/010-before-ko-1440.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/020-after-en-1600.png b/devlog/_fin/260830_sidecar_control_band/evidence/020-after-en-1600.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/020-after-en-1600.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/020-after-en-1600.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/020-after-ko-1024.png b/devlog/_fin/260830_sidecar_control_band/evidence/020-after-ko-1024.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/020-after-ko-1024.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/020-after-ko-1024.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/020-after-ko-1440.png b/devlog/_fin/260830_sidecar_control_band/evidence/020-after-ko-1440.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/020-after-ko-1440.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/020-after-ko-1440.png
diff --git a/devlog/_plan/260830_sidecar_control_band/evidence/020-after-ru-1440.png b/devlog/_fin/260830_sidecar_control_band/evidence/020-after-ru-1440.png
similarity index 100%
rename from devlog/_plan/260830_sidecar_control_band/evidence/020-after-ru-1440.png
rename to devlog/_fin/260830_sidecar_control_band/evidence/020-after-ru-1440.png
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/000_roadmap.md b/devlog/_fin/260831_bug_triage_nonprio70/000_roadmap.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/000_roadmap.md
rename to devlog/_fin/260831_bug_triage_nonprio70/000_roadmap.md
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/001_scan_verdicts.md b/devlog/_fin/260831_bug_triage_nonprio70/001_scan_verdicts.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/001_scan_verdicts.md
rename to devlog/_fin/260831_bug_triage_nonprio70/001_scan_verdicts.md
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/002_audit_round1_synthesis.md b/devlog/_fin/260831_bug_triage_nonprio70/002_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/002_audit_round1_synthesis.md
rename to devlog/_fin/260831_bug_triage_nonprio70/002_audit_round1_synthesis.md
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/003_audit_round2_synthesis.md b/devlog/_fin/260831_bug_triage_nonprio70/003_audit_round2_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/003_audit_round2_synthesis.md
rename to devlog/_fin/260831_bug_triage_nonprio70/003_audit_round2_synthesis.md
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/004_audit_round3_synthesis.md b/devlog/_fin/260831_bug_triage_nonprio70/004_audit_round3_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/004_audit_round3_synthesis.md
rename to devlog/_fin/260831_bug_triage_nonprio70/004_audit_round3_synthesis.md
diff --git a/devlog/_plan/260831_bug_triage_nonprio70/070_outcome.md b/devlog/_fin/260831_bug_triage_nonprio70/070_outcome.md
similarity index 100%
rename from devlog/_plan/260831_bug_triage_nonprio70/070_outcome.md
rename to devlog/_fin/260831_bug_triage_nonprio70/070_outcome.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/000_plan.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/000_plan.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/000_plan.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/000_plan.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/001_research_3022_entitlement_floor.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/001_research_3022_entitlement_floor.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/001_research_3022_entitlement_floor.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/001_research_3022_entitlement_floor.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/002_research_3023_roster_ttl.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/002_research_3023_roster_ttl.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/002_research_3023_roster_ttl.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/002_research_3023_roster_ttl.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/003_audit_3018_spill_drain.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/003_audit_3018_spill_drain.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/003_audit_3018_spill_drain.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/003_audit_3018_spill_drain.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/004_audit_round1_synthesis.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/004_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/004_audit_round1_synthesis.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/004_audit_round1_synthesis.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/005_audit_round2_synthesis.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/005_audit_round2_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/005_audit_round2_synthesis.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/005_audit_round2_synthesis.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/006_audit_round3_synthesis.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/006_audit_round3_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/006_audit_round3_synthesis.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/006_audit_round3_synthesis.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/007_audit_round4_wp1_plan.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/007_audit_round4_wp1_plan.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/007_audit_round4_wp1_plan.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/007_audit_round4_wp1_plan.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/008_audit_round5_wp2_plan.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/008_audit_round5_wp2_plan.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/008_audit_round5_wp2_plan.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/008_audit_round5_wp2_plan.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/009_audit_rounds6to8_wp2_and_wp3_review.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/009_audit_rounds6to8_wp2_and_wp3_review.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/009_audit_rounds6to8_wp2_and_wp3_review.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/009_audit_rounds6to8_wp2_and_wp3_review.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/010_wp1_entitlement_floor_and_empty_roster.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/010_wp1_entitlement_floor_and_empty_roster.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/010_wp1_entitlement_floor_and_empty_roster.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/010_wp1_entitlement_floor_and_empty_roster.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/020_wp2_roster_ttl_refresh.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/020_wp2_roster_ttl_refresh.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/020_wp2_roster_ttl_refresh.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/020_wp2_roster_ttl_refresh.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/030_wp3_spill_publication_drain.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/030_wp3_spill_publication_drain.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/030_wp3_spill_publication_drain.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/030_wp3_spill_publication_drain.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/040_wp4_entitlement_diagnostic.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/040_wp4_entitlement_diagnostic.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/040_wp4_entitlement_diagnostic.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/040_wp4_entitlement_diagnostic.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/050_wp5_tristate_entitlement_authority.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/050_wp5_tristate_entitlement_authority.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/050_wp5_tristate_entitlement_authority.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/050_wp5_tristate_entitlement_authority.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/060_wp6_ensure_freshness.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/060_wp6_ensure_freshness.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/060_wp6_ensure_freshness.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/060_wp6_ensure_freshness.md
diff --git a/devlog/_plan/260831_prio70_entitlement_and_spill_train/070_outcome.md b/devlog/_fin/260831_prio70_entitlement_and_spill_train/070_outcome.md
similarity index 100%
rename from devlog/_plan/260831_prio70_entitlement_and_spill_train/070_outcome.md
rename to devlog/_fin/260831_prio70_entitlement_and_spill_train/070_outcome.md
diff --git a/devlog/_plan/260831_prio70_train_round2/000_plan.md b/devlog/_fin/260831_prio70_train_round2/000_plan.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/000_plan.md
rename to devlog/_fin/260831_prio70_train_round2/000_plan.md
diff --git a/devlog/_plan/260831_prio70_train_round2/001_research_scan_evidence.md b/devlog/_fin/260831_prio70_train_round2/001_research_scan_evidence.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/001_research_scan_evidence.md
rename to devlog/_fin/260831_prio70_train_round2/001_research_scan_evidence.md
diff --git a/devlog/_plan/260831_prio70_train_round2/002_audit_round1_synthesis.md b/devlog/_fin/260831_prio70_train_round2/002_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/002_audit_round1_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/002_audit_round1_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/003_audit_round2_synthesis.md b/devlog/_fin/260831_prio70_train_round2/003_audit_round2_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/003_audit_round2_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/003_audit_round2_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/004_audit_round3_synthesis.md b/devlog/_fin/260831_prio70_train_round2/004_audit_round3_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/004_audit_round3_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/004_audit_round3_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/005_audit_round4_synthesis.md b/devlog/_fin/260831_prio70_train_round2/005_audit_round4_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/005_audit_round4_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/005_audit_round4_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/006_audit_round5_synthesis.md b/devlog/_fin/260831_prio70_train_round2/006_audit_round5_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/006_audit_round5_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/006_audit_round5_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/007_audit_round6_synthesis.md b/devlog/_fin/260831_prio70_train_round2/007_audit_round6_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/007_audit_round6_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/007_audit_round6_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/008_audit_round7_synthesis.md b/devlog/_fin/260831_prio70_train_round2/008_audit_round7_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/008_audit_round7_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/008_audit_round7_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/009_audit_round8_synthesis.md b/devlog/_fin/260831_prio70_train_round2/009_audit_round8_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/009_audit_round8_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/009_audit_round8_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/010_audit_round9_synthesis.md b/devlog/_fin/260831_prio70_train_round2/010_audit_round9_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/010_audit_round9_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/010_audit_round9_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/010_wp1_web_search_query_field.md b/devlog/_fin/260831_prio70_train_round2/010_wp1_web_search_query_field.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/010_wp1_web_search_query_field.md
rename to devlog/_fin/260831_prio70_train_round2/010_wp1_web_search_query_field.md
diff --git a/devlog/_plan/260831_prio70_train_round2/011_audit_round10_synthesis.md b/devlog/_fin/260831_prio70_train_round2/011_audit_round10_synthesis.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/011_audit_round10_synthesis.md
rename to devlog/_fin/260831_prio70_train_round2/011_audit_round10_synthesis.md
diff --git a/devlog/_plan/260831_prio70_train_round2/020_wp2_spill_disk_budget.md b/devlog/_fin/260831_prio70_train_round2/020_wp2_spill_disk_budget.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/020_wp2_spill_disk_budget.md
rename to devlog/_fin/260831_prio70_train_round2/020_wp2_spill_disk_budget.md
diff --git a/devlog/_plan/260831_prio70_train_round2/030_wp3_forked_rollout_restore.md b/devlog/_fin/260831_prio70_train_round2/030_wp3_forked_rollout_restore.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/030_wp3_forked_rollout_restore.md
rename to devlog/_fin/260831_prio70_train_round2/030_wp3_forked_rollout_restore.md
diff --git a/devlog/_plan/260831_prio70_train_round2/040_wp4_terminal_short_window.md b/devlog/_fin/260831_prio70_train_round2/040_wp4_terminal_short_window.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/040_wp4_terminal_short_window.md
rename to devlog/_fin/260831_prio70_train_round2/040_wp4_terminal_short_window.md
diff --git a/devlog/_plan/260831_prio70_train_round2/050_wp5_stop_failure_taxonomy.md b/devlog/_fin/260831_prio70_train_round2/050_wp5_stop_failure_taxonomy.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/050_wp5_stop_failure_taxonomy.md
rename to devlog/_fin/260831_prio70_train_round2/050_wp5_stop_failure_taxonomy.md
diff --git a/devlog/_plan/260831_prio70_train_round2/051_wp5_outcome.md b/devlog/_fin/260831_prio70_train_round2/051_wp5_outcome.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/051_wp5_outcome.md
rename to devlog/_fin/260831_prio70_train_round2/051_wp5_outcome.md
diff --git a/devlog/_plan/260831_prio70_train_round2/060_wp6_wham_401_refresh.md b/devlog/_fin/260831_prio70_train_round2/060_wp6_wham_401_refresh.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/060_wp6_wham_401_refresh.md
rename to devlog/_fin/260831_prio70_train_round2/060_wp6_wham_401_refresh.md
diff --git a/devlog/_plan/260831_prio70_train_round2/061_wp6_outcome.md b/devlog/_fin/260831_prio70_train_round2/061_wp6_outcome.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/061_wp6_outcome.md
rename to devlog/_fin/260831_prio70_train_round2/061_wp6_outcome.md
diff --git a/devlog/_plan/260831_prio70_train_round2/070_outcome.md b/devlog/_fin/260831_prio70_train_round2/070_outcome.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/070_outcome.md
rename to devlog/_fin/260831_prio70_train_round2/070_outcome.md
diff --git a/devlog/_plan/260831_prio70_train_round2/070_rescan.md b/devlog/_fin/260831_prio70_train_round2/070_rescan.md
similarity index 100%
rename from devlog/_plan/260831_prio70_train_round2/070_rescan.md
rename to devlog/_fin/260831_prio70_train_round2/070_rescan.md
diff --git a/devlog/_plan/260901_release_train_2390/000_plan.md b/devlog/_fin/260901_release_train_2390/000_plan.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/000_plan.md
rename to devlog/_fin/260901_release_train_2390/000_plan.md
diff --git a/devlog/_plan/260901_release_train_2390/010_wp1_regression_audit.md b/devlog/_fin/260901_release_train_2390/010_wp1_regression_audit.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/010_wp1_regression_audit.md
rename to devlog/_fin/260901_release_train_2390/010_wp1_regression_audit.md
diff --git a/devlog/_plan/260901_release_train_2390/020_wp2_preview_promotion.md b/devlog/_fin/260901_release_train_2390/020_wp2_preview_promotion.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/020_wp2_preview_promotion.md
rename to devlog/_fin/260901_release_train_2390/020_wp2_preview_promotion.md
diff --git a/devlog/_plan/260901_release_train_2390/030_wp3_main_promotion.md b/devlog/_fin/260901_release_train_2390/030_wp3_main_promotion.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/030_wp3_main_promotion.md
rename to devlog/_fin/260901_release_train_2390/030_wp3_main_promotion.md
diff --git a/devlog/_plan/260901_release_train_2390/040_wp4_publish.md b/devlog/_fin/260901_release_train_2390/040_wp4_publish.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/040_wp4_publish.md
rename to devlog/_fin/260901_release_train_2390/040_wp4_publish.md
diff --git a/devlog/_plan/260901_release_train_2390/050_audit_verdicts.md b/devlog/_fin/260901_release_train_2390/050_audit_verdicts.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/050_audit_verdicts.md
rename to devlog/_fin/260901_release_train_2390/050_audit_verdicts.md
diff --git a/devlog/_plan/260901_release_train_2390/070_outcome.md b/devlog/_fin/260901_release_train_2390/070_outcome.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/070_outcome.md
rename to devlog/_fin/260901_release_train_2390/070_outcome.md
diff --git a/devlog/_plan/260901_release_train_2390/080_post_release_repairs.md b/devlog/_fin/260901_release_train_2390/080_post_release_repairs.md
similarity index 100%
rename from devlog/_plan/260901_release_train_2390/080_post_release_repairs.md
rename to devlog/_fin/260901_release_train_2390/080_post_release_repairs.md
diff --git a/devlog/_plan/260901_remote_hub_restack/000_research.md b/devlog/_fin/260901_remote_hub_restack/000_research.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/000_research.md
rename to devlog/_fin/260901_remote_hub_restack/000_research.md
diff --git a/devlog/_plan/260901_remote_hub_restack/002_audit_r1_synthesis.md b/devlog/_fin/260901_remote_hub_restack/002_audit_r1_synthesis.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/002_audit_r1_synthesis.md
rename to devlog/_fin/260901_remote_hub_restack/002_audit_r1_synthesis.md
diff --git a/devlog/_plan/260901_remote_hub_restack/003_review_thread_ledger.md b/devlog/_fin/260901_remote_hub_restack/003_review_thread_ledger.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/003_review_thread_ledger.md
rename to devlog/_fin/260901_remote_hub_restack/003_review_thread_ledger.md
diff --git a/devlog/_plan/260901_remote_hub_restack/010_wp1_design_contract.md b/devlog/_fin/260901_remote_hub_restack/010_wp1_design_contract.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/010_wp1_design_contract.md
rename to devlog/_fin/260901_remote_hub_restack/010_wp1_design_contract.md
diff --git a/devlog/_plan/260901_remote_hub_restack/011_wp1_outcome.md b/devlog/_fin/260901_remote_hub_restack/011_wp1_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/011_wp1_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/011_wp1_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/020_wp2_p1_protocol_catalog.md b/devlog/_fin/260901_remote_hub_restack/020_wp2_p1_protocol_catalog.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/020_wp2_p1_protocol_catalog.md
rename to devlog/_fin/260901_remote_hub_restack/020_wp2_p1_protocol_catalog.md
diff --git a/devlog/_plan/260901_remote_hub_restack/021_wp2_outcome.md b/devlog/_fin/260901_remote_hub_restack/021_wp2_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/021_wp2_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/021_wp2_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/030_wp3_p2_remote_session.md b/devlog/_fin/260901_remote_hub_restack/030_wp3_p2_remote_session.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/030_wp3_p2_remote_session.md
rename to devlog/_fin/260901_remote_hub_restack/030_wp3_p2_remote_session.md
diff --git a/devlog/_plan/260901_remote_hub_restack/031_wp3_outcome.md b/devlog/_fin/260901_remote_hub_restack/031_wp3_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/031_wp3_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/031_wp3_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/040_wp4_p3_connect.md b/devlog/_fin/260901_remote_hub_restack/040_wp4_p3_connect.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/040_wp4_p3_connect.md
rename to devlog/_fin/260901_remote_hub_restack/040_wp4_p3_connect.md
diff --git a/devlog/_plan/260901_remote_hub_restack/041_wp4_outcome.md b/devlog/_fin/260901_remote_hub_restack/041_wp4_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/041_wp4_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/041_wp4_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/050_wp5_p4_two_plane.md b/devlog/_fin/260901_remote_hub_restack/050_wp5_p4_two_plane.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/050_wp5_p4_two_plane.md
rename to devlog/_fin/260901_remote_hub_restack/050_wp5_p4_two_plane.md
diff --git a/devlog/_plan/260901_remote_hub_restack/051_wp5_outcome.md b/devlog/_fin/260901_remote_hub_restack/051_wp5_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/051_wp5_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/051_wp5_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/060_wp6_p5_deploy.md b/devlog/_fin/260901_remote_hub_restack/060_wp6_p5_deploy.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/060_wp6_p5_deploy.md
rename to devlog/_fin/260901_remote_hub_restack/060_wp6_p5_deploy.md
diff --git a/devlog/_plan/260901_remote_hub_restack/061_wp6_outcome.md b/devlog/_fin/260901_remote_hub_restack/061_wp6_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/061_wp6_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/061_wp6_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/070_wp7_p6_hardening.md b/devlog/_fin/260901_remote_hub_restack/070_wp7_p6_hardening.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/070_wp7_p6_hardening.md
rename to devlog/_fin/260901_remote_hub_restack/070_wp7_p6_hardening.md
diff --git a/devlog/_plan/260901_remote_hub_restack/071_wp7_outcome.md b/devlog/_fin/260901_remote_hub_restack/071_wp7_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/071_wp7_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/071_wp7_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/072_stack_state.md b/devlog/_fin/260901_remote_hub_restack/072_stack_state.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/072_stack_state.md
rename to devlog/_fin/260901_remote_hub_restack/072_stack_state.md
diff --git a/devlog/_plan/260901_remote_hub_restack/080_wp8_stack_integrity.md b/devlog/_fin/260901_remote_hub_restack/080_wp8_stack_integrity.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/080_wp8_stack_integrity.md
rename to devlog/_fin/260901_remote_hub_restack/080_wp8_stack_integrity.md
diff --git a/devlog/_plan/260901_remote_hub_restack/081_wp8_ci_repairs.md b/devlog/_fin/260901_remote_hub_restack/081_wp8_ci_repairs.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/081_wp8_ci_repairs.md
rename to devlog/_fin/260901_remote_hub_restack/081_wp8_ci_repairs.md
diff --git a/devlog/_plan/260901_remote_hub_restack/090_outcome.md b/devlog/_fin/260901_remote_hub_restack/090_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/090_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/090_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/100_polish_audit.md b/devlog/_fin/260901_remote_hub_restack/100_polish_audit.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/100_polish_audit.md
rename to devlog/_fin/260901_remote_hub_restack/100_polish_audit.md
diff --git a/devlog/_plan/260901_remote_hub_restack/101_polish_outcome.md b/devlog/_fin/260901_remote_hub_restack/101_polish_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/101_polish_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/101_polish_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/102_axis_ledger.md b/devlog/_fin/260901_remote_hub_restack/102_axis_ledger.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/102_axis_ledger.md
rename to devlog/_fin/260901_remote_hub_restack/102_axis_ledger.md
diff --git a/devlog/_plan/260901_remote_hub_restack/110_merge_train_plan.md b/devlog/_fin/260901_remote_hub_restack/110_merge_train_plan.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/110_merge_train_plan.md
rename to devlog/_fin/260901_remote_hub_restack/110_merge_train_plan.md
diff --git a/devlog/_plan/260901_remote_hub_restack/111_wp1_3147_outcome.md b/devlog/_fin/260901_remote_hub_restack/111_wp1_3147_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/111_wp1_3147_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/111_wp1_3147_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/112_wp2_order_reversal.md b/devlog/_fin/260901_remote_hub_restack/112_wp2_order_reversal.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/112_wp2_order_reversal.md
rename to devlog/_fin/260901_remote_hub_restack/112_wp2_order_reversal.md
diff --git a/devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md b/devlog/_fin/260901_remote_hub_restack/120_merge_train_outcome.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/120_merge_train_outcome.md
rename to devlog/_fin/260901_remote_hub_restack/120_merge_train_outcome.md
diff --git a/devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md b/devlog/_fin/260901_remote_hub_restack/121_open_threads_after_merge.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/121_open_threads_after_merge.md
rename to devlog/_fin/260901_remote_hub_restack/121_open_threads_after_merge.md
diff --git a/devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md b/devlog/_fin/260901_remote_hub_restack/122_post_merge_verification.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/122_post_merge_verification.md
rename to devlog/_fin/260901_remote_hub_restack/122_post_merge_verification.md
diff --git a/devlog/_plan/260901_remote_hub_restack/130_final_state.md b/devlog/_fin/260901_remote_hub_restack/130_final_state.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/130_final_state.md
rename to devlog/_fin/260901_remote_hub_restack/130_final_state.md
diff --git a/devlog/_plan/260901_remote_hub_restack/131_worktree_state.md b/devlog/_fin/260901_remote_hub_restack/131_worktree_state.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/131_worktree_state.md
rename to devlog/_fin/260901_remote_hub_restack/131_worktree_state.md
diff --git a/devlog/_plan/260901_remote_hub_restack/140_objective_closeout.md b/devlog/_fin/260901_remote_hub_restack/140_objective_closeout.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/140_objective_closeout.md
rename to devlog/_fin/260901_remote_hub_restack/140_objective_closeout.md
diff --git a/devlog/_plan/260901_remote_hub_restack/141_review_fix_verification.md b/devlog/_fin/260901_remote_hub_restack/141_review_fix_verification.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/141_review_fix_verification.md
rename to devlog/_fin/260901_remote_hub_restack/141_review_fix_verification.md
diff --git a/devlog/_plan/260901_remote_hub_restack/150_unit_closed.md b/devlog/_fin/260901_remote_hub_restack/150_unit_closed.md
similarity index 100%
rename from devlog/_plan/260901_remote_hub_restack/150_unit_closed.md
rename to devlog/_fin/260901_remote_hub_restack/150_unit_closed.md
diff --git a/devlog/_plan/260902_admin_merge_3190/000_plan.md b/devlog/_fin/260902_admin_merge_3190/000_plan.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/000_plan.md
rename to devlog/_fin/260902_admin_merge_3190/000_plan.md
diff --git a/devlog/_plan/260902_admin_merge_3190/002_audit_round1.md b/devlog/_fin/260902_admin_merge_3190/002_audit_round1.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/002_audit_round1.md
rename to devlog/_fin/260902_admin_merge_3190/002_audit_round1.md
diff --git a/devlog/_plan/260902_admin_merge_3190/010_wp1_anonymize_home_paths.md b/devlog/_fin/260902_admin_merge_3190/010_wp1_anonymize_home_paths.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/010_wp1_anonymize_home_paths.md
rename to devlog/_fin/260902_admin_merge_3190/010_wp1_anonymize_home_paths.md
diff --git a/devlog/_plan/260902_admin_merge_3190/011_wp1_stale_check.md b/devlog/_fin/260902_admin_merge_3190/011_wp1_stale_check.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/011_wp1_stale_check.md
rename to devlog/_fin/260902_admin_merge_3190/011_wp1_stale_check.md
diff --git a/devlog/_plan/260902_admin_merge_3190/020_wp2_rebase_merge_3190.md b/devlog/_fin/260902_admin_merge_3190/020_wp2_rebase_merge_3190.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/020_wp2_rebase_merge_3190.md
rename to devlog/_fin/260902_admin_merge_3190/020_wp2_rebase_merge_3190.md
diff --git a/devlog/_plan/260902_admin_merge_3190/021_wp2_cherry_pick.md b/devlog/_fin/260902_admin_merge_3190/021_wp2_cherry_pick.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/021_wp2_cherry_pick.md
rename to devlog/_fin/260902_admin_merge_3190/021_wp2_cherry_pick.md
diff --git a/devlog/_plan/260902_admin_merge_3190/030_wp3_inventory_refresh.md b/devlog/_fin/260902_admin_merge_3190/030_wp3_inventory_refresh.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/030_wp3_inventory_refresh.md
rename to devlog/_fin/260902_admin_merge_3190/030_wp3_inventory_refresh.md
diff --git a/devlog/_plan/260902_admin_merge_3190/031_wp3_live_inventory.md b/devlog/_fin/260902_admin_merge_3190/031_wp3_live_inventory.md
similarity index 100%
rename from devlog/_plan/260902_admin_merge_3190/031_wp3_live_inventory.md
rename to devlog/_fin/260902_admin_merge_3190/031_wp3_live_inventory.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/000_plan.md b/devlog/_fin/260902_bug_pr_closeout_stack/000_plan.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/000_plan.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/000_plan.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/010_phase1.md b/devlog/_fin/260902_bug_pr_closeout_stack/010_phase1.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/010_phase1.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/010_phase1.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/011_wp1_landing.md b/devlog/_fin/260902_bug_pr_closeout_stack/011_wp1_landing.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/011_wp1_landing.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/011_wp1_landing.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/020_phase2.md b/devlog/_fin/260902_bug_pr_closeout_stack/020_phase2.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/020_phase2.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/020_phase2.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/021_wp2_landing.md b/devlog/_fin/260902_bug_pr_closeout_stack/021_wp2_landing.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/021_wp2_landing.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/021_wp2_landing.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/030_phase3.md b/devlog/_fin/260902_bug_pr_closeout_stack/030_phase3.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/030_phase3.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/030_phase3.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/031_wp3_disposition.md b/devlog/_fin/260902_bug_pr_closeout_stack/031_wp3_disposition.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/031_wp3_disposition.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/031_wp3_disposition.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/040_phase4.md b/devlog/_fin/260902_bug_pr_closeout_stack/040_phase4.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/040_phase4.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/040_phase4.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/050_phase5.md b/devlog/_fin/260902_bug_pr_closeout_stack/050_phase5.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/050_phase5.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/050_phase5.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/060_phase6.md b/devlog/_fin/260902_bug_pr_closeout_stack/060_phase6.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/060_phase6.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/060_phase6.md
diff --git a/devlog/_plan/260902_bug_pr_closeout_stack/070_closeout.md b/devlog/_fin/260902_bug_pr_closeout_stack/070_closeout.md
similarity index 100%
rename from devlog/_plan/260902_bug_pr_closeout_stack/070_closeout.md
rename to devlog/_fin/260902_bug_pr_closeout_stack/070_closeout.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/000_research.md b/devlog/_fin/260902_cursor_local_models_schema/000_research.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/000_research.md
rename to devlog/_fin/260902_cursor_local_models_schema/000_research.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/005_audit_round1.md b/devlog/_fin/260902_cursor_local_models_schema/005_audit_round1.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/005_audit_round1.md
rename to devlog/_fin/260902_cursor_local_models_schema/005_audit_round1.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/010_layer1_models_capabilities.md b/devlog/_fin/260902_cursor_local_models_schema/010_layer1_models_capabilities.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/010_layer1_models_capabilities.md
rename to devlog/_fin/260902_cursor_local_models_schema/010_layer1_models_capabilities.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/011_effort_control.png b/devlog/_fin/260902_cursor_local_models_schema/011_effort_control.png
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/011_effort_control.png
rename to devlog/_fin/260902_cursor_local_models_schema/011_effort_control.png
diff --git a/devlog/_plan/260902_cursor_local_models_schema/012_effort_ladder.png b/devlog/_fin/260902_cursor_local_models_schema/012_effort_ladder.png
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/012_effort_ladder.png
rename to devlog/_fin/260902_cursor_local_models_schema/012_effort_ladder.png
diff --git a/devlog/_plan/260902_cursor_local_models_schema/013_high_turn.png b/devlog/_fin/260902_cursor_local_models_schema/013_high_turn.png
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/013_high_turn.png
rename to devlog/_fin/260902_cursor_local_models_schema/013_high_turn.png
diff --git a/devlog/_plan/260902_cursor_local_models_schema/015_layer1_live_evidence.md b/devlog/_fin/260902_cursor_local_models_schema/015_layer1_live_evidence.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/015_layer1_live_evidence.md
rename to devlog/_fin/260902_cursor_local_models_schema/015_layer1_live_evidence.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/016_layer1_check.md b/devlog/_fin/260902_cursor_local_models_schema/016_layer1_check.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/016_layer1_check.md
rename to devlog/_fin/260902_cursor_local_models_schema/016_layer1_check.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/017_impl_review.md b/devlog/_fin/260902_cursor_local_models_schema/017_impl_review.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/017_impl_review.md
rename to devlog/_fin/260902_cursor_local_models_schema/017_impl_review.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/020_layer2_docs_guide.md b/devlog/_fin/260902_cursor_local_models_schema/020_layer2_docs_guide.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/020_layer2_docs_guide.md
rename to devlog/_fin/260902_cursor_local_models_schema/020_layer2_docs_guide.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/021_pr_rollup.json b/devlog/_fin/260902_cursor_local_models_schema/021_pr_rollup.json
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/021_pr_rollup.json
rename to devlog/_fin/260902_cursor_local_models_schema/021_pr_rollup.json
diff --git a/devlog/_plan/260902_cursor_local_models_schema/022_stack_closeout.md b/devlog/_fin/260902_cursor_local_models_schema/022_stack_closeout.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/022_stack_closeout.md
rename to devlog/_fin/260902_cursor_local_models_schema/022_stack_closeout.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/030_max_mode_context_selector.md b/devlog/_fin/260902_cursor_local_models_schema/030_max_mode_context_selector.md
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/030_max_mode_context_selector.md
rename to devlog/_fin/260902_cursor_local_models_schema/030_max_mode_context_selector.md
diff --git a/devlog/_plan/260902_cursor_local_models_schema/031_context_selector.png b/devlog/_fin/260902_cursor_local_models_schema/031_context_selector.png
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/031_context_selector.png
rename to devlog/_fin/260902_cursor_local_models_schema/031_context_selector.png
diff --git a/devlog/_plan/260902_cursor_local_models_schema/032_context_options.png b/devlog/_fin/260902_cursor_local_models_schema/032_context_options.png
similarity index 100%
rename from devlog/_plan/260902_cursor_local_models_schema/032_context_options.png
rename to devlog/_fin/260902_cursor_local_models_schema/032_context_options.png
diff --git a/devlog/_plan/260902_cursor_unified_identity/000_plan.md b/devlog/_fin/260902_cursor_unified_identity/000_plan.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/000_plan.md
rename to devlog/_fin/260902_cursor_unified_identity/000_plan.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/001_current_state.md b/devlog/_fin/260902_cursor_unified_identity/001_current_state.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/001_current_state.md
rename to devlog/_fin/260902_cursor_unified_identity/001_current_state.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/002_audit_round1.md b/devlog/_fin/260902_cursor_unified_identity/002_audit_round1.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/002_audit_round1.md
rename to devlog/_fin/260902_cursor_unified_identity/002_audit_round1.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/010_wp2_umbrella_seed.md b/devlog/_fin/260902_cursor_unified_identity/010_wp2_umbrella_seed.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/010_wp2_umbrella_seed.md
rename to devlog/_fin/260902_cursor_unified_identity/010_wp2_umbrella_seed.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/020_wp3_codex_fast_toggle.md b/devlog/_fin/260902_cursor_unified_identity/020_wp3_codex_fast_toggle.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/020_wp3_codex_fast_toggle.md
rename to devlog/_fin/260902_cursor_unified_identity/020_wp3_codex_fast_toggle.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/030_wp4_global_fast_switch.md b/devlog/_fin/260902_cursor_unified_identity/030_wp4_global_fast_switch.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/030_wp4_global_fast_switch.md
rename to devlog/_fin/260902_cursor_unified_identity/030_wp4_global_fast_switch.md
diff --git a/devlog/_plan/260902_cursor_unified_identity/040_residuals.md b/devlog/_fin/260902_cursor_unified_identity/040_residuals.md
similarity index 100%
rename from devlog/_plan/260902_cursor_unified_identity/040_residuals.md
rename to devlog/_fin/260902_cursor_unified_identity/040_residuals.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/000_host_inventory.md b/devlog/_fin/260902_multiplatform_qa_and_gui/000_host_inventory.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/000_host_inventory.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/000_host_inventory.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/001_qa_evidence_layout.md b/devlog/_fin/260902_multiplatform_qa_and_gui/001_qa_evidence_layout.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/001_qa_evidence_layout.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/001_qa_evidence_layout.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/002_qa_verdicts.md b/devlog/_fin/260902_multiplatform_qa_and_gui/002_qa_verdicts.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/002_qa_verdicts.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/002_qa_verdicts.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/010_wp2_gui_design.md b/devlog/_fin/260902_multiplatform_qa_and_gui/010_wp2_gui_design.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/010_wp2_gui_design.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/010_wp2_gui_design.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/011_wp2_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/011_wp2_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/011_wp2_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/011_wp2_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/020_wp3_wp5_deploy_qa.md b/devlog/_fin/260902_multiplatform_qa_and_gui/020_wp3_wp5_deploy_qa.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/020_wp3_wp5_deploy_qa.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/020_wp3_wp5_deploy_qa.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/021_wp3_macmini_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/021_wp3_macmini_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/021_wp3_macmini_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/021_wp3_macmini_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/022_wp4_linux_macbook_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/022_wp4_linux_macbook_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/022_wp4_linux_macbook_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/022_wp4_linux_macbook_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/023_wp5_windows_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/023_wp5_windows_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/023_wp5_windows_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/023_wp5_windows_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/090_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/090_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/090_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/090_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/091_wp6_merge_outcome.md b/devlog/_fin/260902_multiplatform_qa_and_gui/091_wp6_merge_outcome.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/091_wp6_merge_outcome.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/091_wp6_merge_outcome.md
diff --git a/devlog/_plan/260902_multiplatform_qa_and_gui/092_objective_closeout.md b/devlog/_fin/260902_multiplatform_qa_and_gui/092_objective_closeout.md
similarity index 100%
rename from devlog/_plan/260902_multiplatform_qa_and_gui/092_objective_closeout.md
rename to devlog/_fin/260902_multiplatform_qa_and_gui/092_objective_closeout.md
diff --git a/devlog/_plan/260902_windows_ci_release/000_inventory.md b/devlog/_fin/260902_windows_ci_release/000_inventory.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/000_inventory.md
rename to devlog/_fin/260902_windows_ci_release/000_inventory.md
diff --git a/devlog/_plan/260902_windows_ci_release/010_async_acl_lifecycle.md b/devlog/_fin/260902_windows_ci_release/010_async_acl_lifecycle.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/010_async_acl_lifecycle.md
rename to devlog/_fin/260902_windows_ci_release/010_async_acl_lifecycle.md
diff --git a/devlog/_plan/260902_windows_ci_release/011_wp2_evidence.md b/devlog/_fin/260902_windows_ci_release/011_wp2_evidence.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/011_wp2_evidence.md
rename to devlog/_fin/260902_windows_ci_release/011_wp2_evidence.md
diff --git a/devlog/_plan/260902_windows_ci_release/020_fsync_spill_bump.md b/devlog/_fin/260902_windows_ci_release/020_fsync_spill_bump.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/020_fsync_spill_bump.md
rename to devlog/_fin/260902_windows_ci_release/020_fsync_spill_bump.md
diff --git a/devlog/_plan/260902_windows_ci_release/030_regression_audit.md b/devlog/_fin/260902_windows_ci_release/030_regression_audit.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/030_regression_audit.md
rename to devlog/_fin/260902_windows_ci_release/030_regression_audit.md
diff --git a/devlog/_plan/260902_windows_ci_release/040_promote_and_bump.md b/devlog/_fin/260902_windows_ci_release/040_promote_and_bump.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/040_promote_and_bump.md
rename to devlog/_fin/260902_windows_ci_release/040_promote_and_bump.md
diff --git a/devlog/_plan/260902_windows_ci_release/070_outcome.md b/devlog/_fin/260902_windows_ci_release/070_outcome.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/070_outcome.md
rename to devlog/_fin/260902_windows_ci_release/070_outcome.md
diff --git a/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md b/devlog/_fin/260902_windows_ci_release/080_release_automation_followups.md
similarity index 100%
rename from devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md
rename to devlog/_fin/260902_windows_ci_release/080_release_automation_followups.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/000_plan.md b/devlog/_fin/260903_bug_drawdown_bcda/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/000_plan.md
rename to devlog/_fin/260903_bug_drawdown_bcda/000_plan.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/010_phase1.md b/devlog/_fin/260903_bug_drawdown_bcda/010_phase1.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/010_phase1.md
rename to devlog/_fin/260903_bug_drawdown_bcda/010_phase1.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/020_phase2.md b/devlog/_fin/260903_bug_drawdown_bcda/020_phase2.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/020_phase2.md
rename to devlog/_fin/260903_bug_drawdown_bcda/020_phase2.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/030_phase3.md b/devlog/_fin/260903_bug_drawdown_bcda/030_phase3.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/030_phase3.md
rename to devlog/_fin/260903_bug_drawdown_bcda/030_phase3.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/040_phase4.md b/devlog/_fin/260903_bug_drawdown_bcda/040_phase4.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/040_phase4.md
rename to devlog/_fin/260903_bug_drawdown_bcda/040_phase4.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/050_phase5.md b/devlog/_fin/260903_bug_drawdown_bcda/050_phase5.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/050_phase5.md
rename to devlog/_fin/260903_bug_drawdown_bcda/050_phase5.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/060_phase6.md b/devlog/_fin/260903_bug_drawdown_bcda/060_phase6.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/060_phase6.md
rename to devlog/_fin/260903_bug_drawdown_bcda/060_phase6.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/070_phase7.md b/devlog/_fin/260903_bug_drawdown_bcda/070_phase7.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/070_phase7.md
rename to devlog/_fin/260903_bug_drawdown_bcda/070_phase7.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/080_phase8.md b/devlog/_fin/260903_bug_drawdown_bcda/080_phase8.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/080_phase8.md
rename to devlog/_fin/260903_bug_drawdown_bcda/080_phase8.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/090_phase9.md b/devlog/_fin/260903_bug_drawdown_bcda/090_phase9.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/090_phase9.md
rename to devlog/_fin/260903_bug_drawdown_bcda/090_phase9.md
diff --git a/devlog/_plan/260903_bug_drawdown_bcda/100_closeout.md b/devlog/_fin/260903_bug_drawdown_bcda/100_closeout.md
similarity index 100%
rename from devlog/_plan/260903_bug_drawdown_bcda/100_closeout.md
rename to devlog/_fin/260903_bug_drawdown_bcda/100_closeout.md
diff --git a/devlog/_plan/260903_contributor_credit_restoration/000_plan.md b/devlog/_fin/260903_contributor_credit_restoration/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_contributor_credit_restoration/000_plan.md
rename to devlog/_fin/260903_contributor_credit_restoration/000_plan.md
diff --git a/devlog/_plan/260903_contributor_credit_restoration/010_credits_file.md b/devlog/_fin/260903_contributor_credit_restoration/010_credits_file.md
similarity index 100%
rename from devlog/_plan/260903_contributor_credit_restoration/010_credits_file.md
rename to devlog/_fin/260903_contributor_credit_restoration/010_credits_file.md
diff --git a/devlog/_plan/260903_contributor_credit_restoration/020_hygiene_gate.md b/devlog/_fin/260903_contributor_credit_restoration/020_hygiene_gate.md
similarity index 100%
rename from devlog/_plan/260903_contributor_credit_restoration/020_hygiene_gate.md
rename to devlog/_fin/260903_contributor_credit_restoration/020_hygiene_gate.md
diff --git a/devlog/_plan/260903_contributor_credit_restoration/030_release_notes.md b/devlog/_fin/260903_contributor_credit_restoration/030_release_notes.md
similarity index 100%
rename from devlog/_plan/260903_contributor_credit_restoration/030_release_notes.md
rename to devlog/_fin/260903_contributor_credit_restoration/030_release_notes.md
diff --git a/devlog/_plan/260903_contributor_credit_restoration/100_closeout.md b/devlog/_fin/260903_contributor_credit_restoration/100_closeout.md
similarity index 100%
rename from devlog/_plan/260903_contributor_credit_restoration/100_closeout.md
rename to devlog/_fin/260903_contributor_credit_restoration/100_closeout.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/000_plan.md b/devlog/_fin/260903_gemini_38_rollout/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/000_plan.md
rename to devlog/_fin/260903_gemini_38_rollout/000_plan.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/001_vendor_claim_ledger.md b/devlog/_fin/260903_gemini_38_rollout/001_vendor_claim_ledger.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/001_vendor_claim_ledger.md
rename to devlog/_fin/260903_gemini_38_rollout/001_vendor_claim_ledger.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/002_live_cca_probe.md b/devlog/_fin/260903_gemini_38_rollout/002_live_cca_probe.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/002_live_cca_probe.md
rename to devlog/_fin/260903_gemini_38_rollout/002_live_cca_probe.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/003_audit_round1_synthesis.md b/devlog/_fin/260903_gemini_38_rollout/003_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/003_audit_round1_synthesis.md
rename to devlog/_fin/260903_gemini_38_rollout/003_audit_round1_synthesis.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/004_no_change_inventory.md b/devlog/_fin/260903_gemini_38_rollout/004_no_change_inventory.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/004_no_change_inventory.md
rename to devlog/_fin/260903_gemini_38_rollout/004_no_change_inventory.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/005_audit_round2_synthesis.md b/devlog/_fin/260903_gemini_38_rollout/005_audit_round2_synthesis.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/005_audit_round2_synthesis.md
rename to devlog/_fin/260903_gemini_38_rollout/005_audit_round2_synthesis.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/006_maintainer_review_fold.md b/devlog/_fin/260903_gemini_38_rollout/006_maintainer_review_fold.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/006_maintainer_review_fold.md
rename to devlog/_fin/260903_gemini_38_rollout/006_maintainer_review_fold.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/007_closeout.md b/devlog/_fin/260903_gemini_38_rollout/007_closeout.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/007_closeout.md
rename to devlog/_fin/260903_gemini_38_rollout/007_closeout.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/010_wp1_antigravity_core.md b/devlog/_fin/260903_gemini_38_rollout/010_wp1_antigravity_core.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/010_wp1_antigravity_core.md
rename to devlog/_fin/260903_gemini_38_rollout/010_wp1_antigravity_core.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/020_wp2_metadata_pricing.md b/devlog/_fin/260903_gemini_38_rollout/020_wp2_metadata_pricing.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/020_wp2_metadata_pricing.md
rename to devlog/_fin/260903_gemini_38_rollout/020_wp2_metadata_pricing.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/030_wp3_peripheral_surfaces.md b/devlog/_fin/260903_gemini_38_rollout/030_wp3_peripheral_surfaces.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/030_wp3_peripheral_surfaces.md
rename to devlog/_fin/260903_gemini_38_rollout/030_wp3_peripheral_surfaces.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/040_wp4_delivery.md b/devlog/_fin/260903_gemini_38_rollout/040_wp4_delivery.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/040_wp4_delivery.md
rename to devlog/_fin/260903_gemini_38_rollout/040_wp4_delivery.md
diff --git a/devlog/_plan/260903_gemini_38_rollout/050_followups.md b/devlog/_fin/260903_gemini_38_rollout/050_followups.md
similarity index 100%
rename from devlog/_plan/260903_gemini_38_rollout/050_followups.md
rename to devlog/_fin/260903_gemini_38_rollout/050_followups.md
diff --git a/devlog/_plan/260903_muse_provider_parity/000_plan.md b/devlog/_fin/260903_muse_provider_parity/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/000_plan.md
rename to devlog/_fin/260903_muse_provider_parity/000_plan.md
diff --git a/devlog/_plan/260903_muse_provider_parity/001_parity_inventory.md b/devlog/_fin/260903_muse_provider_parity/001_parity_inventory.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/001_parity_inventory.md
rename to devlog/_fin/260903_muse_provider_parity/001_parity_inventory.md
diff --git a/devlog/_plan/260903_muse_provider_parity/010_wp1_passive_quota_core.md b/devlog/_fin/260903_muse_provider_parity/010_wp1_passive_quota_core.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/010_wp1_passive_quota_core.md
rename to devlog/_fin/260903_muse_provider_parity/010_wp1_passive_quota_core.md
diff --git a/devlog/_plan/260903_muse_provider_parity/020_wp2_observation_age_ui.md b/devlog/_fin/260903_muse_provider_parity/020_wp2_observation_age_ui.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/020_wp2_observation_age_ui.md
rename to devlog/_fin/260903_muse_provider_parity/020_wp2_observation_age_ui.md
diff --git a/devlog/_plan/260903_muse_provider_parity/030_wp3_parity_closeout.md b/devlog/_fin/260903_muse_provider_parity/030_wp3_parity_closeout.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/030_wp3_parity_closeout.md
rename to devlog/_fin/260903_muse_provider_parity/030_wp3_parity_closeout.md
diff --git a/devlog/_plan/260903_muse_provider_parity/031_wp3_disposition_record.md b/devlog/_fin/260903_muse_provider_parity/031_wp3_disposition_record.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/031_wp3_disposition_record.md
rename to devlog/_fin/260903_muse_provider_parity/031_wp3_disposition_record.md
diff --git a/devlog/_plan/260903_muse_provider_parity/040_wp4_provider_level_quota.md b/devlog/_fin/260903_muse_provider_parity/040_wp4_provider_level_quota.md
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/040_wp4_provider_level_quota.md
rename to devlog/_fin/260903_muse_provider_parity/040_wp4_provider_level_quota.md
diff --git a/devlog/_plan/260903_muse_provider_parity/assets/021_observed_age_render.png b/devlog/_fin/260903_muse_provider_parity/assets/021_observed_age_render.png
similarity index 100%
rename from devlog/_plan/260903_muse_provider_parity/assets/021_observed_age_render.png
rename to devlog/_fin/260903_muse_provider_parity/assets/021_observed_age_render.png
diff --git a/devlog/_plan/260903_muse_release_train/000_plan.md b/devlog/_fin/260903_muse_release_train/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/000_plan.md
rename to devlog/_fin/260903_muse_release_train/000_plan.md
diff --git a/devlog/_plan/260903_muse_release_train/005_audit_round1_synthesis.md b/devlog/_fin/260903_muse_release_train/005_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/005_audit_round1_synthesis.md
rename to devlog/_fin/260903_muse_release_train/005_audit_round1_synthesis.md
diff --git a/devlog/_plan/260903_muse_release_train/010_wp1_regression_review.md b/devlog/_fin/260903_muse_release_train/010_wp1_regression_review.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/010_wp1_regression_review.md
rename to devlog/_fin/260903_muse_release_train/010_wp1_regression_review.md
diff --git a/devlog/_plan/260903_muse_release_train/011_review_ledger.md b/devlog/_fin/260903_muse_release_train/011_review_ledger.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/011_review_ledger.md
rename to devlog/_fin/260903_muse_release_train/011_review_ledger.md
diff --git a/devlog/_plan/260903_muse_release_train/020_wp2_muse_mark.md b/devlog/_fin/260903_muse_release_train/020_wp2_muse_mark.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/020_wp2_muse_mark.md
rename to devlog/_fin/260903_muse_release_train/020_wp2_muse_mark.md
diff --git a/devlog/_plan/260903_muse_release_train/021_meta_mark_screenshot.png b/devlog/_fin/260903_muse_release_train/021_meta_mark_screenshot.png
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/021_meta_mark_screenshot.png
rename to devlog/_fin/260903_muse_release_train/021_meta_mark_screenshot.png
diff --git a/devlog/_plan/260903_muse_release_train/030_wp3_preview_release.md b/devlog/_fin/260903_muse_release_train/030_wp3_preview_release.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/030_wp3_preview_release.md
rename to devlog/_fin/260903_muse_release_train/030_wp3_preview_release.md
diff --git a/devlog/_plan/260903_muse_release_train/040_wp4_main_release.md b/devlog/_fin/260903_muse_release_train/040_wp4_main_release.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/040_wp4_main_release.md
rename to devlog/_fin/260903_muse_release_train/040_wp4_main_release.md
diff --git a/devlog/_plan/260903_muse_release_train/050_followups.md b/devlog/_fin/260903_muse_release_train/050_followups.md
similarity index 100%
rename from devlog/_plan/260903_muse_release_train/050_followups.md
rename to devlog/_fin/260903_muse_release_train/050_followups.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/000_plan.md b/devlog/_fin/260903_muse_spark_plan_oauth/000_plan.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/000_plan.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/000_plan.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/001_vendor_claim_ledger.md b/devlog/_fin/260903_muse_spark_plan_oauth/001_vendor_claim_ledger.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/001_vendor_claim_ledger.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/001_vendor_claim_ledger.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/002_plan_credential_feasibility.md b/devlog/_fin/260903_muse_spark_plan_oauth/002_plan_credential_feasibility.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/002_plan_credential_feasibility.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/002_plan_credential_feasibility.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/003_credential_and_quota_measurements.md b/devlog/_fin/260903_muse_spark_plan_oauth/003_credential_and_quota_measurements.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/003_credential_and_quota_measurements.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/003_credential_and_quota_measurements.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/004_muse_quota_emission_questions.md b/devlog/_fin/260903_muse_spark_plan_oauth/004_muse_quota_emission_questions.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/004_muse_quota_emission_questions.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/004_muse_quota_emission_questions.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/010_wp1_direct_provider.md b/devlog/_fin/260903_muse_spark_plan_oauth/010_wp1_direct_provider.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/010_wp1_direct_provider.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/010_wp1_direct_provider.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/020_wp2_device_oauth.md b/devlog/_fin/260903_muse_spark_plan_oauth/020_wp2_device_oauth.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/020_wp2_device_oauth.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/020_wp2_device_oauth.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/030_wp3_delivery.md b/devlog/_fin/260903_muse_spark_plan_oauth/030_wp3_delivery.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/030_wp3_delivery.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/030_wp3_delivery.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/040_wp4_muse_oauth_provider.md b/devlog/_fin/260903_muse_spark_plan_oauth/040_wp4_muse_oauth_provider.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/040_wp4_muse_oauth_provider.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/040_wp4_muse_oauth_provider.md
diff --git a/devlog/_plan/260903_muse_spark_plan_oauth/050_wp5_passive_muse_quota.md b/devlog/_fin/260903_muse_spark_plan_oauth/050_wp5_passive_muse_quota.md
similarity index 100%
rename from devlog/_plan/260903_muse_spark_plan_oauth/050_wp5_passive_muse_quota.md
rename to devlog/_fin/260903_muse_spark_plan_oauth/050_wp5_passive_muse_quota.md
diff --git a/devlog/_plan/260903_responses_passthrough/000_research.md b/devlog/_fin/260903_responses_passthrough/000_research.md
similarity index 100%
rename from devlog/_plan/260903_responses_passthrough/000_research.md
rename to devlog/_fin/260903_responses_passthrough/000_research.md
diff --git a/devlog/_plan/260903_responses_passthrough/010_wp2_raw_usage_bridge.md b/devlog/_fin/260903_responses_passthrough/010_wp2_raw_usage_bridge.md
similarity index 100%
rename from devlog/_plan/260903_responses_passthrough/010_wp2_raw_usage_bridge.md
rename to devlog/_fin/260903_responses_passthrough/010_wp2_raw_usage_bridge.md
diff --git a/devlog/_plan/260903_responses_passthrough/020_wp3_coverage.md b/devlog/_fin/260903_responses_passthrough/020_wp3_coverage.md
similarity index 100%
rename from devlog/_plan/260903_responses_passthrough/020_wp3_coverage.md
rename to devlog/_fin/260903_responses_passthrough/020_wp3_coverage.md
diff --git a/devlog/_plan/260903_responses_passthrough/030_wp4_prs.md b/devlog/_fin/260903_responses_passthrough/030_wp4_prs.md
similarity index 100%
rename from devlog/_plan/260903_responses_passthrough/030_wp4_prs.md
rename to devlog/_fin/260903_responses_passthrough/030_wp4_prs.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/000_research.md b/devlog/_fin/260903_voice_sideband_regression/000_research.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/000_research.md
rename to devlog/_fin/260903_voice_sideband_regression/000_research.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/010_wp2_inject_realtime_ws_override.md b/devlog/_fin/260903_voice_sideband_regression/010_wp2_inject_realtime_ws_override.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/010_wp2_inject_realtime_ws_override.md
rename to devlog/_fin/260903_voice_sideband_regression/010_wp2_inject_realtime_ws_override.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/020_wp3_proxy_affinity_probe.md b/devlog/_fin/260903_voice_sideband_regression/020_wp3_proxy_affinity_probe.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/020_wp3_proxy_affinity_probe.md
rename to devlog/_fin/260903_voice_sideband_regression/020_wp3_proxy_affinity_probe.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/021_wp3_probe_transcript.md b/devlog/_fin/260903_voice_sideband_regression/021_wp3_probe_transcript.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/021_wp3_probe_transcript.md
rename to devlog/_fin/260903_voice_sideband_regression/021_wp3_probe_transcript.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/030_wp4_docs_pr.md b/devlog/_fin/260903_voice_sideband_regression/030_wp4_docs_pr.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/030_wp4_docs_pr.md
rename to devlog/_fin/260903_voice_sideband_regression/030_wp4_docs_pr.md
diff --git a/devlog/_plan/260903_voice_sideband_regression/040_d_record.md b/devlog/_fin/260903_voice_sideband_regression/040_d_record.md
similarity index 100%
rename from devlog/_plan/260903_voice_sideband_regression/040_d_record.md
rename to devlog/_fin/260903_voice_sideband_regression/040_d_record.md
diff --git a/devlog/_plan/260904_anthropic_effort_ladder/000_research.md b/devlog/_fin/260904_anthropic_effort_ladder/000_research.md
similarity index 100%
rename from devlog/_plan/260904_anthropic_effort_ladder/000_research.md
rename to devlog/_fin/260904_anthropic_effort_ladder/000_research.md
diff --git a/devlog/_plan/260904_anthropic_effort_ladder/010_registry_ladder.md b/devlog/_fin/260904_anthropic_effort_ladder/010_registry_ladder.md
similarity index 100%
rename from devlog/_plan/260904_anthropic_effort_ladder/010_registry_ladder.md
rename to devlog/_fin/260904_anthropic_effort_ladder/010_registry_ladder.md
diff --git a/devlog/_plan/260904_anthropic_effort_ladder/020_verification_and_pr.md b/devlog/_fin/260904_anthropic_effort_ladder/020_verification_and_pr.md
similarity index 100%
rename from devlog/_plan/260904_anthropic_effort_ladder/020_verification_and_pr.md
rename to devlog/_fin/260904_anthropic_effort_ladder/020_verification_and_pr.md
diff --git a/devlog/_plan/260904_anthropic_effort_ladder/030_related_empty_ladders.md b/devlog/_fin/260904_anthropic_effort_ladder/030_related_empty_ladders.md
similarity index 100%
rename from devlog/_plan/260904_anthropic_effort_ladder/030_related_empty_ladders.md
rename to devlog/_fin/260904_anthropic_effort_ladder/030_related_empty_ladders.md
diff --git a/devlog/_plan/260904_astra_release_alignment/000_research.md b/devlog/_fin/260904_astra_release_alignment/000_research.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/000_research.md
rename to devlog/_fin/260904_astra_release_alignment/000_research.md
diff --git a/devlog/_plan/260904_astra_release_alignment/010_wp2_catalog_alignment.md b/devlog/_fin/260904_astra_release_alignment/010_wp2_catalog_alignment.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/010_wp2_catalog_alignment.md
rename to devlog/_fin/260904_astra_release_alignment/010_wp2_catalog_alignment.md
diff --git a/devlog/_plan/260904_astra_release_alignment/015_audit_synthesis.md b/devlog/_fin/260904_astra_release_alignment/015_audit_synthesis.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/015_audit_synthesis.md
rename to devlog/_fin/260904_astra_release_alignment/015_audit_synthesis.md
diff --git a/devlog/_plan/260904_astra_release_alignment/020_wp3_adapter_eof.md b/devlog/_fin/260904_astra_release_alignment/020_wp3_adapter_eof.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/020_wp3_adapter_eof.md
rename to devlog/_fin/260904_astra_release_alignment/020_wp3_adapter_eof.md
diff --git a/devlog/_plan/260904_astra_release_alignment/021_wp3_evidence.md b/devlog/_fin/260904_astra_release_alignment/021_wp3_evidence.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/021_wp3_evidence.md
rename to devlog/_fin/260904_astra_release_alignment/021_wp3_evidence.md
diff --git a/devlog/_plan/260904_astra_release_alignment/030_wp4_merge.md b/devlog/_fin/260904_astra_release_alignment/030_wp4_merge.md
similarity index 100%
rename from devlog/_plan/260904_astra_release_alignment/030_wp4_merge.md
rename to devlog/_fin/260904_astra_release_alignment/030_wp4_merge.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/000_research.md b/devlog/_fin/260904_bug_backlog_closeout/000_research.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/000_research.md
rename to devlog/_fin/260904_bug_backlog_closeout/000_research.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/010_wp2_green_merge_train.md b/devlog/_fin/260904_bug_backlog_closeout/010_wp2_green_merge_train.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/010_wp2_green_merge_train.md
rename to devlog/_fin/260904_bug_backlog_closeout/010_wp2_green_merge_train.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/020_wp3_draft_pr_triage.md b/devlog/_fin/260904_bug_backlog_closeout/020_wp3_draft_pr_triage.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/020_wp3_draft_pr_triage.md
rename to devlog/_fin/260904_bug_backlog_closeout/020_wp3_draft_pr_triage.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/030_wp4_account_pool.md b/devlog/_fin/260904_bug_backlog_closeout/030_wp4_account_pool.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/030_wp4_account_pool.md
rename to devlog/_fin/260904_bug_backlog_closeout/030_wp4_account_pool.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/040_wp5_remaining_issues.md b/devlog/_fin/260904_bug_backlog_closeout/040_wp5_remaining_issues.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/040_wp5_remaining_issues.md
rename to devlog/_fin/260904_bug_backlog_closeout/040_wp5_remaining_issues.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/050_wp6_needs_info.md b/devlog/_fin/260904_bug_backlog_closeout/050_wp6_needs_info.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/050_wp6_needs_info.md
rename to devlog/_fin/260904_bug_backlog_closeout/050_wp6_needs_info.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/060_ledger.md b/devlog/_fin/260904_bug_backlog_closeout/060_ledger.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/060_ledger.md
rename to devlog/_fin/260904_bug_backlog_closeout/060_ledger.md
diff --git a/devlog/_plan/260904_bug_backlog_closeout/070_closeout.md b/devlog/_fin/260904_bug_backlog_closeout/070_closeout.md
similarity index 100%
rename from devlog/_plan/260904_bug_backlog_closeout/070_closeout.md
rename to devlog/_fin/260904_bug_backlog_closeout/070_closeout.md
diff --git a/devlog/_plan/260904_bug_stack_train/000_research.md b/devlog/_fin/260904_bug_stack_train/000_research.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/000_research.md
rename to devlog/_fin/260904_bug_stack_train/000_research.md
diff --git a/devlog/_plan/260904_bug_stack_train/010_wp2_deviceauth_core.md b/devlog/_fin/260904_bug_stack_train/010_wp2_deviceauth_core.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/010_wp2_deviceauth_core.md
rename to devlog/_fin/260904_bug_stack_train/010_wp2_deviceauth_core.md
diff --git a/devlog/_plan/260904_bug_stack_train/020_wp3_deviceauth_surface.md b/devlog/_fin/260904_bug_stack_train/020_wp3_deviceauth_surface.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/020_wp3_deviceauth_surface.md
rename to devlog/_fin/260904_bug_stack_train/020_wp3_deviceauth_surface.md
diff --git a/devlog/_plan/260904_bug_stack_train/030_wp4_bug_carry.md b/devlog/_fin/260904_bug_stack_train/030_wp4_bug_carry.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/030_wp4_bug_carry.md
rename to devlog/_fin/260904_bug_stack_train/030_wp4_bug_carry.md
diff --git a/devlog/_plan/260904_bug_stack_train/040_deferrals.md b/devlog/_fin/260904_bug_stack_train/040_deferrals.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/040_deferrals.md
rename to devlog/_fin/260904_bug_stack_train/040_deferrals.md
diff --git a/devlog/_plan/260904_bug_stack_train/050_outcome.md b/devlog/_fin/260904_bug_stack_train/050_outcome.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/050_outcome.md
rename to devlog/_fin/260904_bug_stack_train/050_outcome.md
diff --git a/devlog/_plan/260904_bug_stack_train/060_closeout.md b/devlog/_fin/260904_bug_stack_train/060_closeout.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/060_closeout.md
rename to devlog/_fin/260904_bug_stack_train/060_closeout.md
diff --git a/devlog/_plan/260904_bug_stack_train/070_issue_dispositions.md b/devlog/_fin/260904_bug_stack_train/070_issue_dispositions.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/070_issue_dispositions.md
rename to devlog/_fin/260904_bug_stack_train/070_issue_dispositions.md
diff --git a/devlog/_plan/260904_bug_stack_train/080_merge_ledger.md b/devlog/_fin/260904_bug_stack_train/080_merge_ledger.md
similarity index 100%
rename from devlog/_plan/260904_bug_stack_train/080_merge_ledger.md
rename to devlog/_fin/260904_bug_stack_train/080_merge_ledger.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/000_research.md b/devlog/_fin/260904_codex_set_head_and_logo/000_research.md
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/000_research.md
rename to devlog/_fin/260904_codex_set_head_and_logo/000_research.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/010_wp1_page_head_wrap.md b/devlog/_fin/260904_codex_set_head_and_logo/010_wp1_page_head_wrap.md
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/010_wp1_page_head_wrap.md
rename to devlog/_fin/260904_codex_set_head_and_logo/010_wp1_page_head_wrap.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/020_wp2_codex_nav_mark.md b/devlog/_fin/260904_codex_set_head_and_logo/020_wp2_codex_nav_mark.md
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/020_wp2_codex_nav_mark.md
rename to devlog/_fin/260904_codex_set_head_and_logo/020_wp2_codex_nav_mark.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/030_live_verification_record.md b/devlog/_fin/260904_codex_set_head_and_logo/030_live_verification_record.md
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/030_live_verification_record.md
rename to devlog/_fin/260904_codex_set_head_and_logo/030_live_verification_record.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/040_wp4_regression_coverage.md b/devlog/_fin/260904_codex_set_head_and_logo/040_wp4_regression_coverage.md
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/040_wp4_regression_coverage.md
rename to devlog/_fin/260904_codex_set_head_and_logo/040_wp4_regression_coverage.md
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/assets/010_after_850_wrapped.png b/devlog/_fin/260904_codex_set_head_and_logo/assets/010_after_850_wrapped.png
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/assets/010_after_850_wrapped.png
rename to devlog/_fin/260904_codex_set_head_and_logo/assets/010_after_850_wrapped.png
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/assets/010_before_850_clipped.png b/devlog/_fin/260904_codex_set_head_and_logo/assets/010_before_850_clipped.png
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/assets/010_before_850_clipped.png
rename to devlog/_fin/260904_codex_set_head_and_logo/assets/010_before_850_clipped.png
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_dark.png b/devlog/_fin/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_dark.png
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_dark.png
rename to devlog/_fin/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_dark.png
diff --git a/devlog/_plan/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_light.png b/devlog/_fin/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_light.png
similarity index 100%
rename from devlog/_plan/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_light.png
rename to devlog/_fin/260904_codex_set_head_and_logo/assets/020_nav_codex_mark_light.png
diff --git a/devlog/_plan/260904_cross_platform_parity/000_problem_model.md b/devlog/_fin/260904_cross_platform_parity/000_problem_model.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/000_problem_model.md
rename to devlog/_fin/260904_cross_platform_parity/000_problem_model.md
diff --git a/devlog/_plan/260904_cross_platform_parity/001_darwin_surface_inventory.md b/devlog/_fin/260904_cross_platform_parity/001_darwin_surface_inventory.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/001_darwin_surface_inventory.md
rename to devlog/_fin/260904_cross_platform_parity/001_darwin_surface_inventory.md
diff --git a/devlog/_plan/260904_cross_platform_parity/002_muse_cli_storage_measurement.md b/devlog/_fin/260904_cross_platform_parity/002_muse_cli_storage_measurement.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/002_muse_cli_storage_measurement.md
rename to devlog/_fin/260904_cross_platform_parity/002_muse_cli_storage_measurement.md
diff --git a/devlog/_plan/260904_cross_platform_parity/003_issue_3320_root_cause.md b/devlog/_fin/260904_cross_platform_parity/003_issue_3320_root_cause.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/003_issue_3320_root_cause.md
rename to devlog/_fin/260904_cross_platform_parity/003_issue_3320_root_cause.md
diff --git a/devlog/_plan/260904_cross_platform_parity/004_implementation_outcome.md b/devlog/_fin/260904_cross_platform_parity/004_implementation_outcome.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/004_implementation_outcome.md
rename to devlog/_fin/260904_cross_platform_parity/004_implementation_outcome.md
diff --git a/devlog/_plan/260904_cross_platform_parity/010_wp1_muse_manual_key.md b/devlog/_fin/260904_cross_platform_parity/010_wp1_muse_manual_key.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/010_wp1_muse_manual_key.md
rename to devlog/_fin/260904_cross_platform_parity/010_wp1_muse_manual_key.md
diff --git a/devlog/_plan/260904_cross_platform_parity/020_wp2_platform_support_docs.md b/devlog/_fin/260904_cross_platform_parity/020_wp2_platform_support_docs.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/020_wp2_platform_support_docs.md
rename to devlog/_fin/260904_cross_platform_parity/020_wp2_platform_support_docs.md
diff --git a/devlog/_plan/260904_cross_platform_parity/030_wp3_windows_identity_decode.md b/devlog/_fin/260904_cross_platform_parity/030_wp3_windows_identity_decode.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/030_wp3_windows_identity_decode.md
rename to devlog/_fin/260904_cross_platform_parity/030_wp3_windows_identity_decode.md
diff --git a/devlog/_plan/260904_cross_platform_parity/040_wp4_stack_closeout.md b/devlog/_fin/260904_cross_platform_parity/040_wp4_stack_closeout.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/040_wp4_stack_closeout.md
rename to devlog/_fin/260904_cross_platform_parity/040_wp4_stack_closeout.md
diff --git a/devlog/_plan/260904_cross_platform_parity/041_ci_triage.md b/devlog/_fin/260904_cross_platform_parity/041_ci_triage.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/041_ci_triage.md
rename to devlog/_fin/260904_cross_platform_parity/041_ci_triage.md
diff --git a/devlog/_plan/260904_cross_platform_parity/050_followups.md b/devlog/_fin/260904_cross_platform_parity/050_followups.md
similarity index 100%
rename from devlog/_plan/260904_cross_platform_parity/050_followups.md
rename to devlog/_fin/260904_cross_platform_parity/050_followups.md
diff --git a/devlog/_plan/260904_dashboard_minimal/000_inventory.md b/devlog/_fin/260904_dashboard_minimal/000_inventory.md
similarity index 76%
rename from devlog/_plan/260904_dashboard_minimal/000_inventory.md
rename to devlog/_fin/260904_dashboard_minimal/000_inventory.md
index 2487c1afae..a1a1d0b094 100644
--- a/devlog/_plan/260904_dashboard_minimal/000_inventory.md
+++ b/devlog/_fin/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/_fin/260904_dashboard_minimal/001_subagent_opinions.md
similarity index 99%
rename from devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md
rename to devlog/_fin/260904_dashboard_minimal/001_subagent_opinions.md
index d4ccdedcd9..a4d9723fa8 100644
--- a/devlog/_plan/260904_dashboard_minimal/001_subagent_opinions.md
+++ b/devlog/_fin/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/002_decisions.md b/devlog/_fin/260904_dashboard_minimal/002_decisions.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/002_decisions.md
rename to devlog/_fin/260904_dashboard_minimal/002_decisions.md
diff --git a/devlog/_plan/260904_dashboard_minimal/003_audit_record.md b/devlog/_fin/260904_dashboard_minimal/003_audit_record.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/003_audit_record.md
rename to devlog/_fin/260904_dashboard_minimal/003_audit_record.md
diff --git a/devlog/_plan/260904_dashboard_minimal/010_sidebar_footer.md b/devlog/_fin/260904_dashboard_minimal/010_sidebar_footer.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/010_sidebar_footer.md
rename to devlog/_fin/260904_dashboard_minimal/010_sidebar_footer.md
diff --git a/devlog/_plan/260904_dashboard_minimal/020_dashboard_home.md b/devlog/_fin/260904_dashboard_minimal/020_dashboard_home.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/020_dashboard_home.md
rename to devlog/_fin/260904_dashboard_minimal/020_dashboard_home.md
diff --git a/devlog/_plan/260904_dashboard_minimal/030_models_catalog.md b/devlog/_fin/260904_dashboard_minimal/030_models_catalog.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/030_models_catalog.md
rename to devlog/_fin/260904_dashboard_minimal/030_models_catalog.md
diff --git a/devlog/_plan/260904_dashboard_minimal/040_integrations.md b/devlog/_fin/260904_dashboard_minimal/040_integrations.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/040_integrations.md
rename to devlog/_fin/260904_dashboard_minimal/040_integrations.md
diff --git a/devlog/_plan/260904_dashboard_minimal/050_codex_set.md b/devlog/_fin/260904_dashboard_minimal/050_codex_set.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/050_codex_set.md
rename to devlog/_fin/260904_dashboard_minimal/050_codex_set.md
diff --git a/devlog/_plan/260904_dashboard_minimal/060_usage.md b/devlog/_fin/260904_dashboard_minimal/060_usage.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/060_usage.md
rename to devlog/_fin/260904_dashboard_minimal/060_usage.md
diff --git a/devlog/_plan/260904_dashboard_minimal/070_startup.md b/devlog/_fin/260904_dashboard_minimal/070_startup.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/070_startup.md
rename to devlog/_fin/260904_dashboard_minimal/070_startup.md
diff --git a/devlog/_plan/260904_dashboard_minimal/080_page_polish.md b/devlog/_fin/260904_dashboard_minimal/080_page_polish.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/080_page_polish.md
rename to devlog/_fin/260904_dashboard_minimal/080_page_polish.md
diff --git a/devlog/_plan/260904_dashboard_minimal/090_i18n_prune_docs.md b/devlog/_fin/260904_dashboard_minimal/090_i18n_prune_docs.md
similarity index 100%
rename from devlog/_plan/260904_dashboard_minimal/090_i18n_prune_docs.md
rename to devlog/_fin/260904_dashboard_minimal/090_i18n_prune_docs.md
diff --git a/devlog/_fin/260904_dashboard_minimal/090_terminal.md b/devlog/_fin/260904_dashboard_minimal/090_terminal.md
new file mode 100644
index 0000000000..4101656c12
--- /dev/null
+++ b/devlog/_fin/260904_dashboard_minimal/090_terminal.md
@@ -0,0 +1,3 @@
+# terminal outcome — abandoned
+
+ABANDONED: reverted. The minimal GUI pass (#3381) was reverted on origin/dev by #3415 (`0e76b20bd`).
diff --git a/devlog/_plan/260904_external_fast_wire/000_plan.md b/devlog/_fin/260904_external_fast_wire/000_plan.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/000_plan.md
rename to devlog/_fin/260904_external_fast_wire/000_plan.md
diff --git a/devlog/_plan/260904_external_fast_wire/005_audit_round1.md b/devlog/_fin/260904_external_fast_wire/005_audit_round1.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/005_audit_round1.md
rename to devlog/_fin/260904_external_fast_wire/005_audit_round1.md
diff --git a/devlog/_plan/260904_external_fast_wire/006_wp0_receipt.md b/devlog/_fin/260904_external_fast_wire/006_wp0_receipt.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/006_wp0_receipt.md
rename to devlog/_fin/260904_external_fast_wire/006_wp0_receipt.md
diff --git a/devlog/_plan/260904_external_fast_wire/010_wp1_fast_row_core.md b/devlog/_fin/260904_external_fast_wire/010_wp1_fast_row_core.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/010_wp1_fast_row_core.md
rename to devlog/_fin/260904_external_fast_wire/010_wp1_fast_row_core.md
diff --git a/devlog/_plan/260904_external_fast_wire/020_wp2_listing.md b/devlog/_fin/260904_external_fast_wire/020_wp2_listing.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/020_wp2_listing.md
rename to devlog/_fin/260904_external_fast_wire/020_wp2_listing.md
diff --git a/devlog/_plan/260904_external_fast_wire/030_wp3_ingress.md b/devlog/_fin/260904_external_fast_wire/030_wp3_ingress.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/030_wp3_ingress.md
rename to devlog/_fin/260904_external_fast_wire/030_wp3_ingress.md
diff --git a/devlog/_plan/260904_external_fast_wire/040_wp4_docs_and_landing.md b/devlog/_fin/260904_external_fast_wire/040_wp4_docs_and_landing.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/040_wp4_docs_and_landing.md
rename to devlog/_fin/260904_external_fast_wire/040_wp4_docs_and_landing.md
diff --git a/devlog/_plan/260904_external_fast_wire/050_outcome.md b/devlog/_fin/260904_external_fast_wire/050_outcome.md
similarity index 100%
rename from devlog/_plan/260904_external_fast_wire/050_outcome.md
rename to devlog/_fin/260904_external_fast_wire/050_outcome.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/000_research.md b/devlog/_fin/260904_gated_client_version_floor/000_research.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/000_research.md
rename to devlog/_fin/260904_gated_client_version_floor/000_research.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/005_audit_synthesis.md b/devlog/_fin/260904_gated_client_version_floor/005_audit_synthesis.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/005_audit_synthesis.md
rename to devlog/_fin/260904_gated_client_version_floor/005_audit_synthesis.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/010_wp2_floor_aware_tier2.md b/devlog/_fin/260904_gated_client_version_floor/010_wp2_floor_aware_tier2.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/010_wp2_floor_aware_tier2.md
rename to devlog/_fin/260904_gated_client_version_floor/010_wp2_floor_aware_tier2.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/020_wp3_projection_verification.md b/devlog/_fin/260904_gated_client_version_floor/020_wp3_projection_verification.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/020_wp3_projection_verification.md
rename to devlog/_fin/260904_gated_client_version_floor/020_wp3_projection_verification.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/030_wp4_landing.md b/devlog/_fin/260904_gated_client_version_floor/030_wp4_landing.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/030_wp4_landing.md
rename to devlog/_fin/260904_gated_client_version_floor/030_wp4_landing.md
diff --git a/devlog/_plan/260904_gated_client_version_floor/070_outcome.md b/devlog/_fin/260904_gated_client_version_floor/070_outcome.md
similarity index 100%
rename from devlog/_plan/260904_gated_client_version_floor/070_outcome.md
rename to devlog/_fin/260904_gated_client_version_floor/070_outcome.md
diff --git a/devlog/_plan/260904_gpt6_astra_prereg/000_plan.md b/devlog/_fin/260904_gpt6_astra_prereg/000_plan.md
similarity index 100%
rename from devlog/_plan/260904_gpt6_astra_prereg/000_plan.md
rename to devlog/_fin/260904_gpt6_astra_prereg/000_plan.md
diff --git a/devlog/_plan/260904_logs_cost_effort_polish/000_research.md b/devlog/_fin/260904_logs_cost_effort_polish/000_research.md
similarity index 100%
rename from devlog/_plan/260904_logs_cost_effort_polish/000_research.md
rename to devlog/_fin/260904_logs_cost_effort_polish/000_research.md
diff --git a/devlog/_plan/260904_logs_cost_effort_polish/010_wp1_plan.md b/devlog/_fin/260904_logs_cost_effort_polish/010_wp1_plan.md
similarity index 100%
rename from devlog/_plan/260904_logs_cost_effort_polish/010_wp1_plan.md
rename to devlog/_fin/260904_logs_cost_effort_polish/010_wp1_plan.md
diff --git a/devlog/_plan/260904_logs_cost_effort_polish/assets/020_logs_ko_after.png b/devlog/_fin/260904_logs_cost_effort_polish/assets/020_logs_ko_after.png
similarity index 100%
rename from devlog/_plan/260904_logs_cost_effort_polish/assets/020_logs_ko_after.png
rename to devlog/_fin/260904_logs_cost_effort_polish/assets/020_logs_ko_after.png
diff --git a/devlog/_plan/260904_main_card_badge_parity/000_evidence.md b/devlog/_fin/260904_main_card_badge_parity/000_evidence.md
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/000_evidence.md
rename to devlog/_fin/260904_main_card_badge_parity/000_evidence.md
diff --git a/devlog/_plan/260904_main_card_badge_parity/010_server_dto_parity.md b/devlog/_fin/260904_main_card_badge_parity/010_server_dto_parity.md
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/010_server_dto_parity.md
rename to devlog/_fin/260904_main_card_badge_parity/010_server_dto_parity.md
diff --git a/devlog/_plan/260904_main_card_badge_parity/020_gui_plan_badge.md b/devlog/_fin/260904_main_card_badge_parity/020_gui_plan_badge.md
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/020_gui_plan_badge.md
rename to devlog/_fin/260904_main_card_badge_parity/020_gui_plan_badge.md
diff --git a/devlog/_plan/260904_main_card_badge_parity/030_verification_and_pr.md b/devlog/_fin/260904_main_card_badge_parity/030_verification_and_pr.md
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/030_verification_and_pr.md
rename to devlog/_fin/260904_main_card_badge_parity/030_verification_and_pr.md
diff --git a/devlog/_plan/260904_main_card_badge_parity/040_promotion_and_release.md b/devlog/_fin/260904_main_card_badge_parity/040_promotion_and_release.md
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/040_promotion_and_release.md
rename to devlog/_fin/260904_main_card_badge_parity/040_promotion_and_release.md
diff --git a/devlog/_plan/260904_main_card_badge_parity/evidence/main-card-badges.png b/devlog/_fin/260904_main_card_badge_parity/evidence/main-card-badges.png
similarity index 100%
rename from devlog/_plan/260904_main_card_badge_parity/evidence/main-card-badges.png
rename to devlog/_fin/260904_main_card_badge_parity/evidence/main-card-badges.png
diff --git a/devlog/_plan/260904_priority65_closeout/000_research.md b/devlog/_fin/260904_priority65_closeout/000_research.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/000_research.md
rename to devlog/_fin/260904_priority65_closeout/000_research.md
diff --git a/devlog/_plan/260904_priority65_closeout/010_wp2_responses_boundary.md b/devlog/_fin/260904_priority65_closeout/010_wp2_responses_boundary.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/010_wp2_responses_boundary.md
rename to devlog/_fin/260904_priority65_closeout/010_wp2_responses_boundary.md
diff --git a/devlog/_plan/260904_priority65_closeout/020_wp3_combo_metadata_carry.md b/devlog/_fin/260904_priority65_closeout/020_wp3_combo_metadata_carry.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/020_wp3_combo_metadata_carry.md
rename to devlog/_fin/260904_priority65_closeout/020_wp3_combo_metadata_carry.md
diff --git a/devlog/_plan/260904_priority65_closeout/030_wp4_combo_context_cap.md b/devlog/_fin/260904_priority65_closeout/030_wp4_combo_context_cap.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/030_wp4_combo_context_cap.md
rename to devlog/_fin/260904_priority65_closeout/030_wp4_combo_context_cap.md
diff --git a/devlog/_plan/260904_priority65_closeout/040_wp5_reset_credit_identity.md b/devlog/_fin/260904_priority65_closeout/040_wp5_reset_credit_identity.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/040_wp5_reset_credit_identity.md
rename to devlog/_fin/260904_priority65_closeout/040_wp5_reset_credit_identity.md
diff --git a/devlog/_plan/260904_priority65_closeout/050_wp6_gate_unblock.md b/devlog/_fin/260904_priority65_closeout/050_wp6_gate_unblock.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/050_wp6_gate_unblock.md
rename to devlog/_fin/260904_priority65_closeout/050_wp6_gate_unblock.md
diff --git a/devlog/_plan/260904_priority65_closeout/060_wp7_rollback_journal_crud.md b/devlog/_fin/260904_priority65_closeout/060_wp7_rollback_journal_crud.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/060_wp7_rollback_journal_crud.md
rename to devlog/_fin/260904_priority65_closeout/060_wp7_rollback_journal_crud.md
diff --git a/devlog/_plan/260904_priority65_closeout/070_wp8_dispositions_and_regression.md b/devlog/_fin/260904_priority65_closeout/070_wp8_dispositions_and_regression.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/070_wp8_dispositions_and_regression.md
rename to devlog/_fin/260904_priority65_closeout/070_wp8_dispositions_and_regression.md
diff --git a/devlog/_plan/260904_priority65_closeout/080_outcome.md b/devlog/_fin/260904_priority65_closeout/080_outcome.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/080_outcome.md
rename to devlog/_fin/260904_priority65_closeout/080_outcome.md
diff --git a/devlog/_plan/260904_priority65_closeout/081_outcome_wp4.md b/devlog/_fin/260904_priority65_closeout/081_outcome_wp4.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/081_outcome_wp4.md
rename to devlog/_fin/260904_priority65_closeout/081_outcome_wp4.md
diff --git a/devlog/_plan/260904_priority65_closeout/082_outcome_wp5.md b/devlog/_fin/260904_priority65_closeout/082_outcome_wp5.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/082_outcome_wp5.md
rename to devlog/_fin/260904_priority65_closeout/082_outcome_wp5.md
diff --git a/devlog/_plan/260904_priority65_closeout/083_outcome_wp6.md b/devlog/_fin/260904_priority65_closeout/083_outcome_wp6.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/083_outcome_wp6.md
rename to devlog/_fin/260904_priority65_closeout/083_outcome_wp6.md
diff --git a/devlog/_plan/260904_priority65_closeout/084_outcome_wp7.md b/devlog/_fin/260904_priority65_closeout/084_outcome_wp7.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/084_outcome_wp7.md
rename to devlog/_fin/260904_priority65_closeout/084_outcome_wp7.md
diff --git a/devlog/_plan/260904_priority65_closeout/085_outcome_wp8.md b/devlog/_fin/260904_priority65_closeout/085_outcome_wp8.md
similarity index 100%
rename from devlog/_plan/260904_priority65_closeout/085_outcome_wp8.md
rename to devlog/_fin/260904_priority65_closeout/085_outcome_wp8.md
diff --git a/devlog/_plan/260904_provider_quota_refresh/000_plan.md b/devlog/_fin/260904_provider_quota_refresh/000_plan.md
similarity index 93%
rename from devlog/_plan/260904_provider_quota_refresh/000_plan.md
rename to devlog/_fin/260904_provider_quota_refresh/000_plan.md
index e37cdca4c2..9a378ce965 100644
--- a/devlog/_plan/260904_provider_quota_refresh/000_plan.md
+++ b/devlog/_fin/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/010_wp1_passive_quota_visibility.md b/devlog/_fin/260904_provider_quota_refresh/010_wp1_passive_quota_visibility.md
similarity index 100%
rename from devlog/_plan/260904_provider_quota_refresh/010_wp1_passive_quota_visibility.md
rename to devlog/_fin/260904_provider_quota_refresh/010_wp1_passive_quota_visibility.md
diff --git a/devlog/_plan/260904_provider_quota_refresh/020_wp2_refresh_affordance.md b/devlog/_fin/260904_provider_quota_refresh/020_wp2_refresh_affordance.md
similarity index 100%
rename from devlog/_plan/260904_provider_quota_refresh/020_wp2_refresh_affordance.md
rename to devlog/_fin/260904_provider_quota_refresh/020_wp2_refresh_affordance.md
diff --git a/devlog/_plan/260904_provider_quota_refresh/021_audit_round1_synthesis.md b/devlog/_fin/260904_provider_quota_refresh/021_audit_round1_synthesis.md
similarity index 100%
rename from devlog/_plan/260904_provider_quota_refresh/021_audit_round1_synthesis.md
rename to devlog/_fin/260904_provider_quota_refresh/021_audit_round1_synthesis.md
diff --git a/devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md b/devlog/_fin/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md
similarity index 56%
rename from devlog/_plan/260904_provider_quota_refresh/030_wp3_live_verification_and_pr.md
rename to devlog/_fin/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/_fin/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/_fin/260904_provider_quota_refresh/031_live_verification_record.md
similarity index 64%
rename from devlog/_plan/260904_provider_quota_refresh/031_live_verification_record.md
rename to devlog/_fin/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/_fin/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_providers_home_and_quota_refresh/000_research.md b/devlog/_fin/260904_providers_home_and_quota_refresh/000_research.md
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/000_research.md
rename to devlog/_fin/260904_providers_home_and_quota_refresh/000_research.md
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/010_brand_home_affordance.md b/devlog/_fin/260904_providers_home_and_quota_refresh/010_brand_home_affordance.md
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/010_brand_home_affordance.md
rename to devlog/_fin/260904_providers_home_and_quota_refresh/010_brand_home_affordance.md
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/020_overview_quota_refresh.md b/devlog/_fin/260904_providers_home_and_quota_refresh/020_overview_quota_refresh.md
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/020_overview_quota_refresh.md
rename to devlog/_fin/260904_providers_home_and_quota_refresh/020_overview_quota_refresh.md
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/030_verify_and_land.md b/devlog/_fin/260904_providers_home_and_quota_refresh/030_verify_and_land.md
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/030_verify_and_land.md
rename to devlog/_fin/260904_providers_home_and_quota_refresh/030_verify_and_land.md
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/040_delivery_record.md b/devlog/_fin/260904_providers_home_and_quota_refresh/040_delivery_record.md
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/040_delivery_record.md
rename to devlog/_fin/260904_providers_home_and_quota_refresh/040_delivery_record.md
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/assets/010_overview_refresh_all_quotas.png b/devlog/_fin/260904_providers_home_and_quota_refresh/assets/010_overview_refresh_all_quotas.png
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/assets/010_overview_refresh_all_quotas.png
rename to devlog/_fin/260904_providers_home_and_quota_refresh/assets/010_overview_refresh_all_quotas.png
diff --git a/devlog/_plan/260904_providers_home_and_quota_refresh/assets/020_brand_home_dashboard.png b/devlog/_fin/260904_providers_home_and_quota_refresh/assets/020_brand_home_dashboard.png
similarity index 100%
rename from devlog/_plan/260904_providers_home_and_quota_refresh/assets/020_brand_home_dashboard.png
rename to devlog/_fin/260904_providers_home_and_quota_refresh/assets/020_brand_home_dashboard.png
diff --git a/devlog/_plan/260904_raycast_integration/000_plan.md b/devlog/_fin/260904_raycast_integration/000_plan.md
similarity index 100%
rename from devlog/_plan/260904_raycast_integration/000_plan.md
rename to devlog/_fin/260904_raycast_integration/000_plan.md
diff --git a/devlog/_plan/260904_release_version_line/000_research.md b/devlog/_fin/260904_release_version_line/000_research.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/000_research.md
rename to devlog/_fin/260904_release_version_line/000_research.md
diff --git a/devlog/_plan/260904_release_version_line/001_design.md b/devlog/_fin/260904_release_version_line/001_design.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/001_design.md
rename to devlog/_fin/260904_release_version_line/001_design.md
diff --git a/devlog/_plan/260904_release_version_line/010_phase1_version_algebra.md b/devlog/_fin/260904_release_version_line/010_phase1_version_algebra.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/010_phase1_version_algebra.md
rename to devlog/_fin/260904_release_version_line/010_phase1_version_algebra.md
diff --git a/devlog/_plan/260904_release_version_line/020_phase2_bump_input.md b/devlog/_fin/260904_release_version_line/020_phase2_bump_input.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/020_phase2_bump_input.md
rename to devlog/_fin/260904_release_version_line/020_phase2_bump_input.md
diff --git a/devlog/_plan/260904_release_version_line/030_phase3_premove.md b/devlog/_fin/260904_release_version_line/030_phase3_premove.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/030_phase3_premove.md
rename to devlog/_fin/260904_release_version_line/030_phase3_premove.md
diff --git a/devlog/_plan/260904_release_version_line/040_phase4_invariant_and_docs.md b/devlog/_fin/260904_release_version_line/040_phase4_invariant_and_docs.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/040_phase4_invariant_and_docs.md
rename to devlog/_fin/260904_release_version_line/040_phase4_invariant_and_docs.md
diff --git a/devlog/_plan/260904_release_version_line/050_migration.md b/devlog/_fin/260904_release_version_line/050_migration.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/050_migration.md
rename to devlog/_fin/260904_release_version_line/050_migration.md
diff --git a/devlog/_plan/260904_release_version_line/060_rollback_and_failure_modes.md b/devlog/_fin/260904_release_version_line/060_rollback_and_failure_modes.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/060_rollback_and_failure_modes.md
rename to devlog/_fin/260904_release_version_line/060_rollback_and_failure_modes.md
diff --git a/devlog/_plan/260904_release_version_line/070_final_rebase.md b/devlog/_fin/260904_release_version_line/070_final_rebase.md
similarity index 100%
rename from devlog/_plan/260904_release_version_line/070_final_rebase.md
rename to devlog/_fin/260904_release_version_line/070_final_rebase.md
diff --git a/devlog/_plan/260904_triage_gap_closure/000_research.md b/devlog/_fin/260904_triage_gap_closure/000_research.md
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/000_research.md
rename to devlog/_fin/260904_triage_gap_closure/000_research.md
diff --git a/devlog/_plan/260904_triage_gap_closure/010_fable_metadata.md b/devlog/_fin/260904_triage_gap_closure/010_fable_metadata.md
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/010_fable_metadata.md
rename to devlog/_fin/260904_triage_gap_closure/010_fable_metadata.md
diff --git a/devlog/_plan/260904_triage_gap_closure/020_credits_3284.md b/devlog/_fin/260904_triage_gap_closure/020_credits_3284.md
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/020_credits_3284.md
rename to devlog/_fin/260904_triage_gap_closure/020_credits_3284.md
diff --git a/devlog/_plan/260904_triage_gap_closure/030_ultrafast_optin.md b/devlog/_fin/260904_triage_gap_closure/030_ultrafast_optin.md
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/030_ultrafast_optin.md
rename to devlog/_fin/260904_triage_gap_closure/030_ultrafast_optin.md
diff --git a/devlog/_plan/260904_triage_gap_closure/040_delivery_record.md b/devlog/_fin/260904_triage_gap_closure/040_delivery_record.md
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/040_delivery_record.md
rename to devlog/_fin/260904_triage_gap_closure/040_delivery_record.md
diff --git a/devlog/_plan/260904_triage_gap_closure/assets/010_codex_set_head_relocated.png b/devlog/_fin/260904_triage_gap_closure/assets/010_codex_set_head_relocated.png
similarity index 100%
rename from devlog/_plan/260904_triage_gap_closure/assets/010_codex_set_head_relocated.png
rename to devlog/_fin/260904_triage_gap_closure/assets/010_codex_set_head_relocated.png
diff --git a/devlog/_plan/260905_admin_token_local_ux/000_research.md b/devlog/_fin/260905_admin_token_local_ux/000_research.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/000_research.md
rename to devlog/_fin/260905_admin_token_local_ux/000_research.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/010_suppress_local_prompt.md b/devlog/_fin/260905_admin_token_local_ux/010_suppress_local_prompt.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/010_suppress_local_prompt.md
rename to devlog/_fin/260905_admin_token_local_ux/010_suppress_local_prompt.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/020_dialog_repair.md b/devlog/_fin/260905_admin_token_local_ux/020_dialog_repair.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/020_dialog_repair.md
rename to devlog/_fin/260905_admin_token_local_ux/020_dialog_repair.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/030_windows_baseline.md b/devlog/_fin/260905_admin_token_local_ux/030_windows_baseline.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/030_windows_baseline.md
rename to devlog/_fin/260905_admin_token_local_ux/030_windows_baseline.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/031_preload_guard_ordering.md b/devlog/_fin/260905_admin_token_local_ux/031_preload_guard_ordering.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/031_preload_guard_ordering.md
rename to devlog/_fin/260905_admin_token_local_ux/031_preload_guard_ordering.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/040_delivery_record.md b/devlog/_fin/260905_admin_token_local_ux/040_delivery_record.md
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/040_delivery_record.md
rename to devlog/_fin/260905_admin_token_local_ux/040_delivery_record.md
diff --git a/devlog/_plan/260905_admin_token_local_ux/assets/admin-token-dialog-before-after.png b/devlog/_fin/260905_admin_token_local_ux/assets/admin-token-dialog-before-after.png
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/assets/admin-token-dialog-before-after.png
rename to devlog/_fin/260905_admin_token_local_ux/assets/admin-token-dialog-before-after.png
diff --git a/devlog/_plan/260905_admin_token_local_ux/assets/local-session-notice-before-after.png b/devlog/_fin/260905_admin_token_local_ux/assets/local-session-notice-before-after.png
similarity index 100%
rename from devlog/_plan/260905_admin_token_local_ux/assets/local-session-notice-before-after.png
rename to devlog/_fin/260905_admin_token_local_ux/assets/local-session-notice-before-after.png
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/000_survey.md b/devlog/_fin/260905_apply_patch_envelope_gap/000_survey.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/000_survey.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/000_survey.md
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/010_disposition.md b/devlog/_fin/260905_apply_patch_envelope_gap/010_disposition.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/010_disposition.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/010_disposition.md
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/020_wp2_implementation.md b/devlog/_fin/260905_apply_patch_envelope_gap/020_wp2_implementation.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/020_wp2_implementation.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/020_wp2_implementation.md
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/030_review_round.md b/devlog/_fin/260905_apply_patch_envelope_gap/030_review_round.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/030_review_round.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/030_review_round.md
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/040_wp1b_parser_guidance.md b/devlog/_fin/260905_apply_patch_envelope_gap/040_wp1b_parser_guidance.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/040_wp1b_parser_guidance.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/040_wp1b_parser_guidance.md
diff --git a/devlog/_plan/260905_apply_patch_envelope_gap/050_delivery_record.md b/devlog/_fin/260905_apply_patch_envelope_gap/050_delivery_record.md
similarity index 100%
rename from devlog/_plan/260905_apply_patch_envelope_gap/050_delivery_record.md
rename to devlog/_fin/260905_apply_patch_envelope_gap/050_delivery_record.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/000_plan.md b/devlog/_fin/260905_external_image_roundtrip/000_plan.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/000_plan.md
rename to devlog/_fin/260905_external_image_roundtrip/000_plan.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/003_all_format_audit.md b/devlog/_fin/260905_external_image_roundtrip/003_all_format_audit.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/003_all_format_audit.md
rename to devlog/_fin/260905_external_image_roundtrip/003_all_format_audit.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/010_chat_image_parts.md b/devlog/_fin/260905_external_image_roundtrip/010_chat_image_parts.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/010_chat_image_parts.md
rename to devlog/_fin/260905_external_image_roundtrip/010_chat_image_parts.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/020_wire_contract.md b/devlog/_fin/260905_external_image_roundtrip/020_wire_contract.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/020_wire_contract.md
rename to devlog/_fin/260905_external_image_roundtrip/020_wire_contract.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/030_image_input_forms.md b/devlog/_fin/260905_external_image_roundtrip/030_image_input_forms.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/030_image_input_forms.md
rename to devlog/_fin/260905_external_image_roundtrip/030_image_input_forms.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/040_orphan_image_carriers.md b/devlog/_fin/260905_external_image_roundtrip/040_orphan_image_carriers.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/040_orphan_image_carriers.md
rename to devlog/_fin/260905_external_image_roundtrip/040_orphan_image_carriers.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/050_cursor_tool_images.md b/devlog/_fin/260905_external_image_roundtrip/050_cursor_tool_images.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/050_cursor_tool_images.md
rename to devlog/_fin/260905_external_image_roundtrip/050_cursor_tool_images.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/060_delivery.md b/devlog/_fin/260905_external_image_roundtrip/060_delivery.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/060_delivery.md
rename to devlog/_fin/260905_external_image_roundtrip/060_delivery.md
diff --git a/devlog/_plan/260905_external_image_roundtrip/070_final_head_delivery.md b/devlog/_fin/260905_external_image_roundtrip/070_final_head_delivery.md
similarity index 100%
rename from devlog/_plan/260905_external_image_roundtrip/070_final_head_delivery.md
rename to devlog/_fin/260905_external_image_roundtrip/070_final_head_delivery.md
diff --git a/devlog/_fin/260905_external_image_roundtrip/090_closeout.md b/devlog/_fin/260905_external_image_roundtrip/090_closeout.md
new file mode 100644
index 0000000000..b612a40671
--- /dev/null
+++ b/devlog/_fin/260905_external_image_roundtrip/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3586/#3589/#3591/#3593/#3595/#3596 (all MERGED; `c514a32c` ancestor of origin/dev). Unit never recorded a post-merge terminal outcome; recorded here during the 260909 post-2.49 reconciliation.
diff --git a/devlog/_plan/260905_fast_default_exports/000_plan.md b/devlog/_fin/260905_fast_default_exports/000_plan.md
similarity index 100%
rename from devlog/_plan/260905_fast_default_exports/000_plan.md
rename to devlog/_fin/260905_fast_default_exports/000_plan.md
diff --git a/devlog/_plan/260905_fast_default_exports/010_implementation.md b/devlog/_fin/260905_fast_default_exports/010_implementation.md
similarity index 100%
rename from devlog/_plan/260905_fast_default_exports/010_implementation.md
rename to devlog/_fin/260905_fast_default_exports/010_implementation.md
diff --git a/devlog/_plan/260905_fast_default_exports/011_review.md b/devlog/_fin/260905_fast_default_exports/011_review.md
similarity index 100%
rename from devlog/_plan/260905_fast_default_exports/011_review.md
rename to devlog/_fin/260905_fast_default_exports/011_review.md
diff --git a/devlog/_fin/260905_fast_default_exports/090_closeout.md b/devlog/_fin/260905_fast_default_exports/090_closeout.md
new file mode 100644
index 0000000000..1cede7db07
--- /dev/null
+++ b/devlog/_fin/260905_fast_default_exports/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3674 MERGED (`0b7f60ee2` on origin/dev). Unit docs stopped at pre-merge review; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
diff --git a/devlog/_plan/260905_grok_responses_default/000_plan.md b/devlog/_fin/260905_grok_responses_default/000_plan.md
similarity index 100%
rename from devlog/_plan/260905_grok_responses_default/000_plan.md
rename to devlog/_fin/260905_grok_responses_default/000_plan.md
diff --git a/devlog/_plan/260905_grok_responses_default/002_first_output_rca.md b/devlog/_fin/260905_grok_responses_default/002_first_output_rca.md
similarity index 100%
rename from devlog/_plan/260905_grok_responses_default/002_first_output_rca.md
rename to devlog/_fin/260905_grok_responses_default/002_first_output_rca.md
diff --git a/devlog/_plan/260905_grok_responses_default/010_default_and_controls.md b/devlog/_fin/260905_grok_responses_default/010_default_and_controls.md
similarity index 100%
rename from devlog/_plan/260905_grok_responses_default/010_default_and_controls.md
rename to devlog/_fin/260905_grok_responses_default/010_default_and_controls.md
diff --git a/devlog/_plan/260905_grok_responses_default/011_verification.md b/devlog/_fin/260905_grok_responses_default/011_verification.md
similarity index 100%
rename from devlog/_plan/260905_grok_responses_default/011_verification.md
rename to devlog/_fin/260905_grok_responses_default/011_verification.md
diff --git a/devlog/_fin/260905_grok_responses_default/090_closeout.md b/devlog/_fin/260905_grok_responses_default/090_closeout.md
new file mode 100644
index 0000000000..f1ae8e5c8a
--- /dev/null
+++ b/devlog/_fin/260905_grok_responses_default/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3670 MERGED 2026-09-05. Unit docs stopped at pending-gate verification; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
diff --git a/devlog/_plan/260905_grok_responses_default/assets/001_chat_optin.png b/devlog/_fin/260905_grok_responses_default/assets/001_chat_optin.png
similarity index 100%
rename from devlog/_plan/260905_grok_responses_default/assets/001_chat_optin.png
rename to devlog/_fin/260905_grok_responses_default/assets/001_chat_optin.png
diff --git a/devlog/_plan/260905_unified_quota_activation/010_unified_control.md b/devlog/_fin/260905_unified_quota_activation/010_unified_control.md
similarity index 100%
rename from devlog/_plan/260905_unified_quota_activation/010_unified_control.md
rename to devlog/_fin/260905_unified_quota_activation/010_unified_control.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/000_plan.md b/devlog/_fin/260906_lane_b_catalog_stack/000_plan.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/000_plan.md
rename to devlog/_fin/260906_lane_b_catalog_stack/000_plan.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/009_roadmap_lock.md b/devlog/_fin/260906_lane_b_catalog_stack/009_roadmap_lock.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/009_roadmap_lock.md
rename to devlog/_fin/260906_lane_b_catalog_stack/009_roadmap_lock.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/010_visibility.md b/devlog/_fin/260906_lane_b_catalog_stack/010_visibility.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/010_visibility.md
rename to devlog/_fin/260906_lane_b_catalog_stack/010_visibility.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/011_visibility_build.md b/devlog/_fin/260906_lane_b_catalog_stack/011_visibility_build.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/011_visibility_build.md
rename to devlog/_fin/260906_lane_b_catalog_stack/011_visibility_build.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/020_context.md b/devlog/_fin/260906_lane_b_catalog_stack/020_context.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/020_context.md
rename to devlog/_fin/260906_lane_b_catalog_stack/020_context.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/021_context_build.md b/devlog/_fin/260906_lane_b_catalog_stack/021_context_build.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/021_context_build.md
rename to devlog/_fin/260906_lane_b_catalog_stack/021_context_build.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/030_ordering.md b/devlog/_fin/260906_lane_b_catalog_stack/030_ordering.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/030_ordering.md
rename to devlog/_fin/260906_lane_b_catalog_stack/030_ordering.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/031_ordering_build.md b/devlog/_fin/260906_lane_b_catalog_stack/031_ordering_build.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/031_ordering_build.md
rename to devlog/_fin/260906_lane_b_catalog_stack/031_ordering_build.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/032_ordering_repair.md b/devlog/_fin/260906_lane_b_catalog_stack/032_ordering_repair.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/032_ordering_repair.md
rename to devlog/_fin/260906_lane_b_catalog_stack/032_ordering_repair.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/033_ordering_control.md b/devlog/_fin/260906_lane_b_catalog_stack/033_ordering_control.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/033_ordering_control.md
rename to devlog/_fin/260906_lane_b_catalog_stack/033_ordering_control.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/034_verification_followup.md b/devlog/_fin/260906_lane_b_catalog_stack/034_verification_followup.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/034_verification_followup.md
rename to devlog/_fin/260906_lane_b_catalog_stack/034_verification_followup.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/035_ordering_landing.md b/devlog/_fin/260906_lane_b_catalog_stack/035_ordering_landing.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/035_ordering_landing.md
rename to devlog/_fin/260906_lane_b_catalog_stack/035_ordering_landing.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/040_management.md b/devlog/_fin/260906_lane_b_catalog_stack/040_management.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/040_management.md
rename to devlog/_fin/260906_lane_b_catalog_stack/040_management.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/041_static_verification.md b/devlog/_fin/260906_lane_b_catalog_stack/041_static_verification.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/041_static_verification.md
rename to devlog/_fin/260906_lane_b_catalog_stack/041_static_verification.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/042_management_build.md b/devlog/_fin/260906_lane_b_catalog_stack/042_management_build.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/042_management_build.md
rename to devlog/_fin/260906_lane_b_catalog_stack/042_management_build.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/043_carry_boundary.md b/devlog/_fin/260906_lane_b_catalog_stack/043_carry_boundary.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/043_carry_boundary.md
rename to devlog/_fin/260906_lane_b_catalog_stack/043_carry_boundary.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/044_react_doctor.md b/devlog/_fin/260906_lane_b_catalog_stack/044_react_doctor.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/044_react_doctor.md
rename to devlog/_fin/260906_lane_b_catalog_stack/044_react_doctor.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/050_fable.md b/devlog/_fin/260906_lane_b_catalog_stack/050_fable.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/050_fable.md
rename to devlog/_fin/260906_lane_b_catalog_stack/050_fable.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/060_landing.md b/devlog/_fin/260906_lane_b_catalog_stack/060_landing.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/060_landing.md
rename to devlog/_fin/260906_lane_b_catalog_stack/060_landing.md
diff --git a/devlog/_plan/260906_lane_b_catalog_stack/061_landed.md b/devlog/_fin/260906_lane_b_catalog_stack/061_landed.md
similarity index 100%
rename from devlog/_plan/260906_lane_b_catalog_stack/061_landed.md
rename to devlog/_fin/260906_lane_b_catalog_stack/061_landed.md
diff --git a/devlog/_plan/260906_opaque_transport_finality/000_plan.md b/devlog/_fin/260906_opaque_transport_finality/000_plan.md
similarity index 100%
rename from devlog/_plan/260906_opaque_transport_finality/000_plan.md
rename to devlog/_fin/260906_opaque_transport_finality/000_plan.md
diff --git a/devlog/_plan/260906_opaque_transport_finality/010_failure_boundaries.md b/devlog/_fin/260906_opaque_transport_finality/010_failure_boundaries.md
similarity index 100%
rename from devlog/_plan/260906_opaque_transport_finality/010_failure_boundaries.md
rename to devlog/_fin/260906_opaque_transport_finality/010_failure_boundaries.md
diff --git a/devlog/_fin/260906_opaque_transport_finality/090_closeout.md b/devlog/_fin/260906_opaque_transport_finality/090_closeout.md
new file mode 100644
index 0000000000..14e3301678
--- /dev/null
+++ b/devlog/_fin/260906_opaque_transport_finality/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3753/#3754 (both MERGED 2026-09-06). Unit 000 still listed them as open/draft; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
diff --git a/devlog/_plan/260906_release_244_publish/000_plan.md b/devlog/_fin/260906_release_244_publish/000_plan.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/000_plan.md
rename to devlog/_fin/260906_release_244_publish/000_plan.md
diff --git a/devlog/_plan/260906_release_244_publish/010_roadmap.md b/devlog/_fin/260906_release_244_publish/010_roadmap.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/010_roadmap.md
rename to devlog/_fin/260906_release_244_publish/010_roadmap.md
diff --git a/devlog/_plan/260906_release_244_publish/020_integrate.md b/devlog/_fin/260906_release_244_publish/020_integrate.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/020_integrate.md
rename to devlog/_fin/260906_release_244_publish/020_integrate.md
diff --git a/devlog/_plan/260906_release_244_publish/030_dev_bump.md b/devlog/_fin/260906_release_244_publish/030_dev_bump.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/030_dev_bump.md
rename to devlog/_fin/260906_release_244_publish/030_dev_bump.md
diff --git a/devlog/_plan/260906_release_244_publish/040_preview.md b/devlog/_fin/260906_release_244_publish/040_preview.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/040_preview.md
rename to devlog/_fin/260906_release_244_publish/040_preview.md
diff --git a/devlog/_plan/260906_release_244_publish/050_stable.md b/devlog/_fin/260906_release_244_publish/050_stable.md
similarity index 100%
rename from devlog/_plan/260906_release_244_publish/050_stable.md
rename to devlog/_fin/260906_release_244_publish/050_stable.md
diff --git a/devlog/_fin/260906_release_244_publish/090_closeout.md b/devlog/_fin/260906_release_244_publish/090_closeout.md
new file mode 100644
index 0000000000..c955060918
--- /dev/null
+++ b/devlog/_fin/260906_release_244_publish/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+v2.44.0 published: #3785 MERGED, `07b48da8f` ancestor of origin/main, tag v2.44.0 exists. Unit never recorded the DONE receipt; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_fin/260907_code_mode_host_contract/000_plan.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/000_plan.md
rename to devlog/_fin/260907_code_mode_host_contract/000_plan.md
diff --git a/devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md b/devlog/_fin/260907_code_mode_host_contract/001_host_probe_evidence.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md
rename to devlog/_fin/260907_code_mode_host_contract/001_host_probe_evidence.md
diff --git a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md b/devlog/_fin/260907_code_mode_host_contract/010_pre_call_contract.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md
rename to devlog/_fin/260907_code_mode_host_contract/010_pre_call_contract.md
diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_fin/260907_code_mode_host_contract/020_post_hoc_annotation.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md
rename to devlog/_fin/260907_code_mode_host_contract/020_post_hoc_annotation.md
diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_fin/260907_code_mode_host_contract/030_docs_and_delivery.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md
rename to devlog/_fin/260907_code_mode_host_contract/030_docs_and_delivery.md
diff --git a/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md b/devlog/_fin/260907_code_mode_host_contract/040_delivery_record.md
similarity index 100%
rename from devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md
rename to devlog/_fin/260907_code_mode_host_contract/040_delivery_record.md
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_a_stack_responses_compat/000_plan.md b/devlog/_fin/260908_a_stack_responses_compat/000_plan.md
new file mode 100644
index 0000000000..3a22b2d98f
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/010_phase1.md b/devlog/_fin/260908_a_stack_responses_compat/010_phase1.md
new file mode 100644
index 0000000000..85f9e11d3d
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/020_phase2.md b/devlog/_fin/260908_a_stack_responses_compat/020_phase2.md
new file mode 100644
index 0000000000..13b4cc949c
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/030_phase3.md b/devlog/_fin/260908_a_stack_responses_compat/030_phase3.md
new file mode 100644
index 0000000000..c0e6a00b3f
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/040_phase4.md b/devlog/_fin/260908_a_stack_responses_compat/040_phase4.md
new file mode 100644
index 0000000000..b5a0f94be3
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/050_phase5.md b/devlog/_fin/260908_a_stack_responses_compat/050_phase5.md
new file mode 100644
index 0000000000..97b928d92c
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_a_stack_responses_compat/090_closeout.md b/devlog/_fin/260908_a_stack_responses_compat/090_closeout.md
new file mode 100644
index 0000000000..e4775732e6
--- /dev/null
+++ b/devlog/_fin/260908_a_stack_responses_compat/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3942 MERGED (`a13041740` ancestor of origin/dev and origin/main); issues #3885/#3922/#3911 CLOSED. Unit docs stopped at the publish/merge procedure; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
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_d_group_test_infra_stack/000_plan.md b/devlog/_fin/260908_d_group_test_infra_stack/000_plan.md
new file mode 100644
index 0000000000..35b2a65c67
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_d_group_test_infra_stack/001_audit_record.md b/devlog/_fin/260908_d_group_test_infra_stack/001_audit_record.md
new file mode 100644
index 0000000000..b668981357
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_d_group_test_infra_stack/010_phase1_stack_build.md b/devlog/_fin/260908_d_group_test_infra_stack/010_phase1_stack_build.md
new file mode 100644
index 0000000000..003cd0ad82
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_d_group_test_infra_stack/020_phase2_publish.md b/devlog/_fin/260908_d_group_test_infra_stack/020_phase2_publish.md
new file mode 100644
index 0000000000..2af6acab12
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_d_group_test_infra_stack/030_phase3_merge_and_settle.md b/devlog/_fin/260908_d_group_test_infra_stack/030_phase3_merge_and_settle.md
new file mode 100644
index 0000000000..5e6d3ece96
--- /dev/null
+++ b/devlog/_fin/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/_fin/260908_d_group_test_infra_stack/090_closeout.md b/devlog/_fin/260908_d_group_test_infra_stack/090_closeout.md
new file mode 100644
index 0000000000..12177be6ba
--- /dev/null
+++ b/devlog/_fin/260908_d_group_test_infra_stack/090_closeout.md
@@ -0,0 +1,3 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #3940 MERGED (`221617b80`); #3924/#3930 CLOSED. Unit docs stopped at the merge gate; terminal outcome recorded here during the 260909 post-2.49 reconciliation.
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/_fin/260909_spark_short_quota_attribution/000_plan.md b/devlog/_fin/260909_spark_short_quota_attribution/000_plan.md
new file mode 100644
index 0000000000..7af10b83ce
--- /dev/null
+++ b/devlog/_fin/260909_spark_short_quota_attribution/000_plan.md
@@ -0,0 +1,160 @@
+# Spark short-quota attribution fix (#4122) — plan
+
+## Reader summary
+
+Problem: on a Pro pool account that served a GPT-5.3-Codex-Spark request, the dashboard shows an
+account-level "5h" quota bar that does not exist at the account level; peer Pro accounts with
+identical upstream limits show none. Answer: the response-header quota path learns which model the
+response was for, and when that model belongs to the Spark limit family the 5h primary window is
+filed under the model's custom windows instead of the account-level short slot. What changes: pool
+accounts with identical limits display identically, and the main-account hard lock and five-hour
+auto-refresh scheduling stop reading a model-specific window as account policy.
+
+## Loop spec
+
+- Loop archetype: satisfy-spec (single work-phase wp1, one PABCD cycle; not multi-cycle, so no
+ docs-first roadmap cycle).
+- Trigger: user directive to fix lidge-jun/opencodex#4122 and land it on dev via PR.
+- Goal: header-observed 5h windows on Spark-model responses no longer occupy the account-level
+ short-quota slot; genuine account-level 5h windows (Plus/Team, non-Spark models) unchanged; PR
+ merged to dev with green final-head CI.
+- Non-goals: WHAM parseUsageQuota mapping (already correct); GUI changes; docs-site; migration or
+ cleanup of already-polluted cache entries (on disk they expire via the six-hour hydration TTL;
+ in a long-running process the tuple persists in memory until restart or the next genuine short
+ write — cleanup stays explicitly out of scope); release or promotion; no local
+ test/typecheck/build runs (standing user rule: push with --no-verify, remote CI is the gate —
+ recorded NOT RUN below). Accepted consequence (reviewer finding 2, folded): once Spark responses
+ stop writing the account-level short slot, a Spark-saturated account is no longer preemptively
+ avoided for Spark-routed requests — routing evidence reads only the account slot
+ (src/routing/quota.ts:40-61, src/codex/quota.ts:67-80, src/codex/routing.ts:373-379). Bounded:
+ Spark requests only, the 429 quota-rotation path absorbs it, and WHAM-only accounts already
+ behave this way. Spark-aware exhaustion from customWindows is a tracked follow-up, not this PR.
+- Verifier: remote CI on the PR's exact final head — .github/workflows/ci.yml pull_request trigger
+ (line 7), job test (line 263, gated on the changes filter at line 266 which covers src/** and
+ tests/** at lines 191/193) runs bash scripts/ci/run-bun-test-batches.sh (line 325) whose
+ `find tests -type f` selection (script line 197) includes
+ tests/codex-integration/codex-quota-parser-parity.test.ts; job platform-macos (line 475, gate
+ 478) runs the macOS suite sharded over tests (line 615). (Audit correction: the lines this plan
+ first cited, 706/839, belong to workflow_dispatch-gated jobs and were wrong.)
+ Conditional paths and their activation: the Spark-attribution branch activates when
+ parseUpstreamQuotaHeaders receives modelId in the Spark family plus a sub-day primary window —
+ proven by a regression row asserting customWindows gain and short* absence; the non-Spark branch
+ activates with the same headers and a non-Spark modelId — proven by a row asserting short* is
+ still written; the label-merge branch activates when existing customWindows hold a Spark Weekly
+ entry — proven by a row asserting it survives the header update.
+- Stop condition: PR merged into dev and landing verified via fetched dev ancestry, or a
+ BLOCKED/NEEDS_HUMAN outcome with evidence.
+- Memory artifact: this unit directory plus the session goalplan
+ (.codexclaw/goalplans/hotl-fix-lidge-jun-opencodex-4122-and-land-it-on/).
+- Expected terminal outcomes: DONE = goal criteria c1-c4 met with fresh evidence; BLOCKED =
+ irreducible CI failure or merge-policy denial; NEEDS_HUMAN = authority gap.
+- Escalation: any requirement to run local suites, push without --no-verify, change merge policy,
+ or expand scope beyond the listed files returns to the user. Reviewer-subagent FAIL after one
+ fold/rebut cycle returns to P with a revised plan rather than forcing B.
+- HOTL resource bounds: tools = this worktree shell/git/gh and read-only upstream GETs;
+ credentials = existing gh auth only; write scope = this worktree plus issues/PRs on
+ lidge-jun/opencodex; token/wall-clock budget = none set by user.
+
+## Root cause (evidence)
+
+Two writers share one per-account snapshot in src/codex/quota.ts:
+
+1. WHAM path: parseUsageQuota maps the account primary window by duration and files
+ additional_rate_limits (metered_feature codex_bengalfox) under customWindows only
+ (src/codex/quota.ts:723+). Correct for Pro: weekly-only primary.
+2. Header path: parseUpstreamQuotaHeaders (src/codex/quota.ts:410) files any sub-day primary
+ window as account-level shortPercent/shortResetAt/shortWindowSeconds. It has no model context,
+ so on a Spark-model response — where upstream reports the Spark governing limit as the primary
+ window — the model-specific 5h window lands in the account slot.
+
+Live proof on 2026-09-09: three Pro accounts returned identical wham/usage shapes (primary
+604800s; Spark 5h/weekly in additional_rate_limits), yet only the Spark-serving account's cache
+carried shortPercent 4 / shortWindowSeconds 18000, with shortResetAt exactly equal to the Spark 5h
+reset_at. Downstream consumers that trust the account slot: main-account hard lock
+(src/codex/main-account-hard-lock.ts:30-34 prioritizes short over weekly), five-hour auto-refresh
+scheduling (src/codex/quota-auto-refresh.ts:62,88), pool evidence (src/routing/quota.ts).
+
+## File-change map (diff level)
+
+1. src/codex/quota.ts
+ - Add module-local helper isCodexSparkModel(modelId): modelId.includes("codex-spark").
+ Necessity search: existing inline equivalents at src/adapters/openai-responses.ts:343,492 and
+ src/responses/hosted-tool-policy.ts:6; no shared helper exists. Reusing those call sites is
+ out of scope; the helper is introduced where the new branch needs it.
+ - parseUpstreamQuotaHeaders(headers, options?: { modelId?: string }): in the primaryIsShort
+ branch, when options.modelId is Spark-family, emit
+ customWindows: [{ label: "GPT-5.3-Codex-Spark 5h", percent, resetAt }] instead of account-level
+ short*; weekly continues to come from the secondary window. Label matches the WHAM parser's
+ Spark 5h label so both wires write the same slot.
+ - applyAccountQuotaFromUpstreamHeaders(accountId, headers, writerGeneration?, mainWriter?,
+ options?: { modelId?: string }): forward options to the parser; when the parsed quota carries
+ customWindows, merge label-wise with the account's existing cached customWindows (replace same
+ label, keep others) before setAccountQuotaFromParsed, so a header update never drops the
+ WHAM-recorded Spark Weekly window (#4007 retention preserved; mergeAccountQuota semantics
+ unchanged — an explicit list still replaces). Provenance amendment (reviewer finding 3,
+ folded): call hydrateAccountQuotasFromDisk() before reading the cached entry so the first
+ call in a process does not merge against an empty map; the pre-merged list goes ONLY into the
+ legacy quota argument — the policyQuota argument keeps the UNMERGED parse result so
+ legacy-cache customWindows are never injected into the identity-bound policy snapshot
+ (setAccountQuotaFromParsed's legacy/policy split at src/codex/quota.ts:245-252 stays intact).
+ - Refresh the stale comment ("Pro stays weekly-only") to describe the model-specific case.
+ - Field chain (PLAN-FIELD-CHAIN-01): the options value is created at the three callers below,
+ consumed only inside parseUpstreamQuotaHeaders/applyAccountQuotaFromUpstreamHeaders; no
+ serialization, no persistence, no enum. Consumers of the written slots (hard lock,
+ auto-refresh, routing evidence, CLI/GUI display) are behaviorally affected only by the
+ corrected attribution — no signature changes.
+2. src/server/responses/core.ts — FOUR write paths, all with route in scope:
+ a. line ~1380 (429/402 quota-refresh-before-rejection path): pass { modelId: route.modelId }.
+ b. line ~5660 (post-response capture for forward-pool responses, behind
+ isCodexWsQuotaObservedResponse dedup): pass { modelId: route.modelId }.
+ c. line ~1022 (codexWsQuotaObserver callback for WebSocket quota frames): the FACTORY
+ codexWsQuotaObserver(authCtx, provider) gains a third parameter modelId and forwards it as
+ options; the CodexWsQuotaObserver TYPE (src/server/responses/codex-ws-metadata.ts:8) is
+ unchanged so direct observer constructions in tests/responses/responses-account-label.test.ts
+ keep compiling; all six factory call sites (lines ~1476, 5053, 5131, 5237, 5357, 5457) pass
+ route.modelId.
+ Found during the main agent's own audit pass after plan v1 named only two core.ts sites —
+ folded into the plan before the reviewer round closed (AUDIT-LOOP-01 amendment).
+3. src/server/responses/compact.ts (line ~1013): pass { modelId: route.modelId } (route in scope;
+ selectedModelId = route.modelId at line 582).
+4. src/codex/quota-auto-refresh.ts — NO CHANGE, recorded with reason: warmCodexAccount there sends
+ DEFAULT_MODEL gpt-5.4-mini (src/codex/warmup.ts:284), never a Spark model, so the warmup header
+ path cannot observe a Spark limit; omitting modelId preserves current behavior.
+5. tests/codex-integration/codex-quota-parser-parity.test.ts — add regression rows (existing file
+ already owns #4007 Spark/header interaction and parser parity; no new file, so no layout.json
+ or fixture registration needed):
+ a. Spark model + 5h primary headers → account-level short* absent; customWindows contains
+ "GPT-5.3-Codex-Spark 5h" with the header percent/reset; weekly taken from secondary.
+ b. Same update with a pre-existing "GPT-5.3-Codex-Spark Weekly" customWindow → weekly entry
+ survives (label-merge), Spark 5h replaced.
+ c. Non-Spark model + identical 5h headers → account-level short* still written (Plus/Team
+ behavior preserved).
+ d. No modelId (legacy caller shape) → behavior identical to today.
+ Red evidence: rows a/b fail against the unpatched parser (short* is written today). Local
+ red-green execution is NOT RUN per the standing user rule; the assertion construction is
+ verified by review against the current code path and the remote CI run is the green gate.
+
+## Scope
+
+IN: the five items above. OUT: parseUsageQuota WHAM mapping, mergeAccountQuota global semantics,
+GUI, docs-site, cache migration, warmup model selection, release/promotion.
+
+## SoT sync (C phase)
+
+structure/08_openai-provider-tiers.md documents quota windows (5h/weekly application around lines
+96-99, 132, 140, 177). In C, check whether any statement now contradicts model-attributed short
+windows and patch that file if so; otherwise record "checked, no contradiction".
+
+## Enforcement / bypass (PLAN-BYPASS-NAMED-01)
+
+This plan adds no enforcement layer. Tier: N/A; executing surface: none; known bypass: a future
+caller can omit modelId and reproduce the old misattribution — mitigated only by the regression
+tests and code review; residual risk accepted; final layer: none.
+
+## Verification gate mapping
+
+- Local bun test / typecheck / build: NOT RUN (standing user rule: never run local suites; push
+ with --no-verify).
+- Remote: PR CI (ci.yml, pull_request trigger, sharded bun test over tests/) must be green on the
+ exact final head before merge; merge per MAINTAINERS.md maintainer PR-only path with the decision
+ and exact-head CI evidence recorded in the PR.
diff --git a/devlog/_fin/260909_spark_short_quota_attribution/090_closeout.md b/devlog/_fin/260909_spark_short_quota_attribution/090_closeout.md
new file mode 100644
index 0000000000..061ec107e6
--- /dev/null
+++ b/devlog/_fin/260909_spark_short_quota_attribution/090_closeout.md
@@ -0,0 +1,27 @@
+# closeout (recorded 2026-09-09)
+
+Landed via #4128 MERGED (`b2142586a`, merge commit `91db6c2f2`, both ancestors of origin/dev);
+issue #4122 CLOSED. Remote CI on the exact head `b2142586a` was green: 28 successful check runs,
+0 failures, 2 skipped by their own matrix gates (`macos control`, `windows ${{ matrix.shard }}/6`).
+
+Delivered exactly the `000_plan.md` file-change map: the optional routed-model hint on
+`parseUpstreamQuotaHeaders` / `applyAccountQuotaFromUpstreamHeaders`
+(src/codex/quota.ts:411-538), all four `src/server/responses/core.ts` write paths plus the six
+`codexWsQuotaObserver` factory call sites, the compact path
+(src/server/responses/compact.ts:1018), and the four regression rows in
+tests/codex-integration/codex-quota-parser-parity.test.ts.
+src/codex/quota-auto-refresh.ts stayed unchanged as planned.
+
+Carried forward, not regressions:
+
+- Already-polluted account entries keep the stale account-level `short*` tuple until the six-hour
+ hydration TTL expires them on disk, or until a restart or a genuine non-Spark short write
+ replaces them in memory. Declared out of scope in the `000_plan.md` non-goals and unchanged by
+ the merge.
+- A Spark-saturated account is no longer preemptively avoided for Spark-routed requests, because
+ routing evidence reads only the account-level slot (src/routing/quota.ts:40-61). Bounded to
+ Spark requests and absorbed by the existing 429 pool rotation. Spark-aware exhaustion sourced
+ from `customWindows` remains a follow-up.
+
+The unit was committed into the product PR rather than kept separate; moving it here is that
+correction, made after the merge closed the unit.
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/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/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_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/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_codex_credential_health_chain/000_plan.md b/devlog/_plan/260909_codex_credential_health_chain/000_plan.md
new file mode 100644
index 0000000000..9c764929a8
--- /dev/null
+++ b/devlog/_plan/260909_codex_credential_health_chain/000_plan.md
@@ -0,0 +1,73 @@
+# Codex credential health chain (#4120, #3848, #3777) — plan
+
+## Reader summary
+
+Problem: a Codex pool credential whose OAuth grant was revoked upstream keeps
+`lastCodexValidationStatus: "ok"` in `codex-accounts.json` and is presented as healthy for as long
+as the install lives. Answer: a revoked/expired refresh grant is the strongest terminal evidence
+available, so the guardian now persists that verdict on the account record instead of dropping it
+into an in-memory backoff map, and the health projector reads it. What changes: an account with a
+dead grant reports "Reauthentication required" on the dashboard, in `ocx status` and in
+`ocx doctor`, and keeps reporting it across restarts until a re-login or a successful refresh
+disproves it.
+
+## Loop spec
+
+- Loop archetype: satisfy-spec, three work-phases delivered as a bottom-up manual branch chain
+ (wp1 -> wp2 -> wp3), so this unit opens with the diff-level roadmap below and each decade doc is
+ revalidated at its own P.
+- Trigger: maintainer directive to deliver #4120, shepherd #3848 and build #3777 as one chain.
+- Goal: each layer is a non-draft, mergeable PR whose exact-head remote CI is green.
+- Non-goals: no merging (the dispatching session owns merge order); no rebase of any layer unless
+ that session asks for one; no release or promotion; no default-on background warmup; and no
+ local product suite, typecheck, build, lint or install — the standing maintainer rule is that
+ remote CI on the PR's exact final head is the only gate, and every skipped local check is
+ recorded NOT RUN.
+- Verifier: `.github/workflows/ci.yml` on `pull_request`; the `test` job selects
+ `tests/**` through the changes filter, so the appended regression rows in
+ `tests/codex-integration/` and `tests/oauth/` are in the selected set on Linux, macOS and
+ Windows.
+- Stop condition: all three PRs non-draft with green exact-head CI, or a BLOCKED outcome naming
+ the blocker. wp1 must be able to land alone if wp2 stalls.
+- Escalation: a required rebase, a merge conflict against `dev`, or any need to run a local suite
+ returns to the dispatching session rather than being resolved unilaterally.
+
+## Root cause (#4120, evidence)
+
+`guardianSweep`'s pool branch decides whether to sweep an account at
+`src/oauth/token-guardian.ts:210-215`:
+
+ const needsRefresh = cred.expiresAt <= nowMs + horizonMs;
+ const needsWarmup = opts.codexWarmupEnabled && (...);
+ if (!needsRefresh && !needsWarmup) continue;
+
+and decides what to persist on failure at `src/oauth/token-guardian.ts:238-241`:
+
+ const permanent = err instanceof TokenRefreshError && (err.reason === "revoked" || err.reason === "expired");
+ if (needsWarmup && !(err instanceof TokenRefreshError)) {
+ markCodexAccountValidationFailed(id, codexWarmupFailureReason(err));
+ }
+
+`permanent` is computed and then used only to widen the in-memory backoff delay
+(`recordFailure`, `:100-115`), which does not survive a restart and is not what any health
+surface reads. The persisted-verdict branch requires `needsWarmup`, which is false in the default
+configuration because `codexWarmupEnabled` defaults to `false` (`:86`), and it additionally
+excludes every `TokenRefreshError`. So the one class of failure that proves the credential is dead
+is the one class that never reaches the account record.
+
+The second half of the defect is on the read side: `src/oauth/health.ts` never consults the
+validation metadata at all. `projectCodexAccountHealth` (`:196-210`) reads only the in-memory
+reauth flag and the cooldown snapshot, so a record carrying a stale login-time `"ok"` projects
+`{ status: "healthy" }`.
+
+## Work-phase roadmap
+
+| Phase | Doc | Layer | Base |
+|---|---|---|---|
+| wp1 | `010_wp1_terminal_verdict.md` | persist + project the terminal verdict (#4120) | `origin/dev` |
+| wp2 | `020_wp2_quota_registration.md` | shepherd #3848 onto the chain | wp1 head |
+| wp3 | `030_wp3_anthropic_plan.md` | Anthropic subscription tier (#3777) | wp2 head |
+
+The order is a dependency order, not an effort order: wp3 edits `src/cli/account-api.ts`, which
+wp2 already rewrites, and wp2 touches the same account-store and guardian surfaces wp1 changes.
+Each layer stands alone for review and carries its own tests.
diff --git a/devlog/_plan/260909_codex_credential_health_chain/010_wp1_terminal_verdict.md b/devlog/_plan/260909_codex_credential_health_chain/010_wp1_terminal_verdict.md
new file mode 100644
index 0000000000..20058f2c4d
--- /dev/null
+++ b/devlog/_plan/260909_codex_credential_health_chain/010_wp1_terminal_verdict.md
@@ -0,0 +1,98 @@
+# wp1 — persist and project the terminal validation verdict (#4120)
+
+Class C4: OAuth credential handling, the credential store, and a health surface.
+
+## Decision 1 — an extra optional key, not a new status value
+
+The obvious shape for "this credential is dead" is a third value in the persisted status union
+(`"ok" | "failed" | "revoked"`). It is unsafe here. `isCredentialRecord`
+(`src/codex/account-store.ts:60`) admits only `undefined | "ok" | "failed"`; a record carrying an
+unrecognized value fails that predicate, so `normalizeRecord` (`:74-88`) falls through to
+`isCredential`, which also fails because a record has no top-level `accessToken`, and returns
+`undefined`. `loadCodexAccountRecordStore` (`:96-101`) then silently omits the record. An
+operator who writes a terminal verdict on 2.51 and rolls back to 2.50 would lose the whole
+account entry, credential included.
+
+An additional optional key has the opposite property: `normalizeRecord` returns
+`{ ...value, refreshGrantFingerprint }`, so an unknown key is carried through untouched by a build
+that has never heard of it. So the record gains:
+
+ lastCodexValidationTerminal?: boolean;
+
+## Decision 2 — the marker clears itself
+
+A terminal verdict that can only be set is worse than no verdict: one spurious `invalid_grant`
+from upstream would brand a live account dead forever, since background warmup is off by default
+and nothing else would revisit it. The marker therefore has exactly two ways to disappear, and both
+are structural rather than remembered:
+
+- `markCodexAccountValidated` clears it explicitly, alongside the error string it already clears.
+- Every credential write drops it for free. `saveCodexAccountCredential` (`:145`),
+ `saveCodexAccountCredentialIfGeneration` (`:216`) and
+ `commitRefreshedCodexCredentialWithAliases` (`:275`, `:303`) rebuild the record from an
+ explicit field list plus `preservedValidationMetadata` (`:121-128`) and never spread
+ `...current`. Keeping the new key out of that pick list is what makes a successful refresh or a
+ re-login erase the verdict, which is correct: a refresh that succeeds disproves "grant revoked".
+
+Those five sites plus the tombstone at `:324` are every record writer in the codebase —
+`loadCodexAccountRecordStore` is module-private and no other module writes
+`codex-accounts.json`.
+
+## Decision 3 — the generation fence
+
+`markCodexAccountValidationFailed` gains an options bag with `expectedGeneration` and
+`terminal`, and returns whether it wrote. The guardian passes the generation it actually observed:
+`record.generation` before the refresh, replaced by `token.generation` once a refresh has
+committed, because a successful refresh bumps the generation and a warmup failure after it belongs
+to the new credential.
+
+A failed refresh never follows a commit inside the same call: `resolveCodexToken` returns on the
+freshness shortcut (`:717-721`), on same-grant adoption (`:465-475`) and on the CAS commit
+(`:975-985`), and the `TokenRefreshError` throw (`:948`) is reached only from a `!res.ok`
+token response with no prior write. If a different writer replaced the credential between the
+guardian's read and the locked re-read, the fence declines to write. That is a deliberate false
+negative: the failure cannot be attributed to the credential the sweep observed, and refusing to
+write is always safer than branding a freshly installed credential dead.
+
+## Decision 4 — project onto the existing health member, with no GUI diff
+
+A terminal verdict maps to `{ status: "reauth_required", reason: "refresh_failed" }`, which
+already exists in `OAuthAccountHealth` (`src/oauth/health.ts:14-18`). That is not a shortcut, it
+is the accurate statement: only a re-login fixes a revoked grant, and `actionFor` (`:88-95`)
+already attaches `CODEX_REAUTH_ACTION` — "reauthenticate via the dashboard Codex account pool" —
+for the `codex` provider.
+
+Reusing it also means the dashboard needs no change at all. The GUI does not render the server's
+`healthLabel`; it recomputes the badge from the `health` object through
+`gui/src/oauth-health-display.ts`, so `reauth_required` already turns the row amber
+(`codex-account-pool-cards.tsx:81,88`), prints "Reauthentication required" and shows the action.
+A new warning reason would have required a GUI enum, nine i18n locales and a dashboard screenshot,
+for strictly worse copy.
+
+`collectLocalCodexEntries` (`:265-282`) currently inlines a copy of the projector's body rather
+than calling it, which is how the CLI path would have silently missed this fix. It is folded onto
+`projectCodexAccountHealth` so the two cannot drift again.
+
+Precedence note: `projectOAuthAccountHealth` checks reauth before cooldown, so an account that is
+both revoked and quota-cooled now reports reauth. That is the right order — telling an operator to
+wait out a cooldown on a credential that will never work again is a false promise.
+
+## Out of scope
+
+Issue expectation 3 (revalidate stored pool credentials on a bounded schedule even with warmup
+disabled) is declined here: it means a default-on inference probe, which this change is explicitly
+not allowed to introduce. Showing `lastCodexValidatedAt` as a first-class dashboard column is also
+deferred — it is a GUI change with no server-side defect behind it.
+
+## Verification
+
+Appended to existing test files, because a new test file additionally requires entries in
+`scripts/test-layout/layout.json` and `tests/fixtures/test-layout-expected.json`:
+
+- `tests/codex-integration/token-guardian.test.ts` — a revoked grant persists
+ `failed` + terminal with no warmup enabled; a transient (`unknown`) refresh failure persists
+ nothing; a credential replaced mid-refresh is not clobbered.
+- `tests/codex-integration/codex-account-store.test.ts` — the generation fence declines a stale
+ write, `markCodexAccountValidated` clears the marker, and a credential write drops it.
+- `tests/oauth/oauth-health.test.ts` — a terminal record projects `reauth_required` with the
+ Codex reauth action, and an ordinary record still projects healthy.
diff --git a/devlog/_plan/260909_codex_credential_health_chain/020_wp2_quota_registration.md b/devlog/_plan/260909_codex_credential_health_chain/020_wp2_quota_registration.md
new file mode 100644
index 0000000000..dbd6364117
--- /dev/null
+++ b/devlog/_plan/260909_codex_credential_health_chain/020_wp2_quota_registration.md
@@ -0,0 +1,24 @@
+# wp2 — shepherd #3848 onto the chain (quota-exhausted registration, #3846)
+
+Author: @shaun0927 (Junghwan). This layer is carried, not reimplemented, so the original author's
+`Co-authored-by` trailers are preserved on the branch commits — `missing_coauthor_credit` in
+`.github/scripts/pr-carry-attribution.cjs` reads the trailer, and a sentence in a commit body is
+read by nothing.
+
+Substance (unchanged from the original PR): a Codex account whose weekly allowance is exhausted
+cannot complete the mandatory inference warmup, so registration fails outright. The change persists
+it as validation-pending, keeps it out of routing and manual selection, and requires a human
+dashboard "Refresh quotas" click to finish validation, because finishing it spends model quota.
+
+Work in this phase:
+
+- Retarget the PR base from `dev` onto the wp1 head branch.
+- Resolve the conflict against current `dev`. This is a conflict inside this lane's own chain,
+ which is the one case the no-rebase rule does not cover; a cross-lane rebase still returns to the
+ dispatching session.
+- Preserve the GUI evidence screenshots already in the description — the PR touches `gui/`, so
+ `missing_ui_screenshot` (`.github/scripts/pr-quality.cjs:531`) requires them.
+- Restore repository hygiene: no vendored reference clones, no tracked gitlink, no security triage
+ under `devlog/` (`tests/ci-workflows/repo-hygiene.test.ts`).
+
+Class C4 — authentication, account store, guardian and GUI in one change.
diff --git a/devlog/_plan/260909_codex_credential_health_chain/030_wp3_anthropic_plan.md b/devlog/_plan/260909_codex_credential_health_chain/030_wp3_anthropic_plan.md
new file mode 100644
index 0000000000..56dc7093f0
--- /dev/null
+++ b/devlog/_plan/260909_codex_credential_health_chain/030_wp3_anthropic_plan.md
@@ -0,0 +1,23 @@
+# wp3 — expose the Anthropic subscription tier (#3777)
+
+The OpenAI provider already reports a per-account `plan` string, so a consumer can weight each
+account's remaining quota by its tier. The Anthropic provider reports rich quota and no tier at
+all, so a six-account Claude pool has no meaningful aggregate capacity number.
+
+Surface, bottom to top:
+
+- `src/providers/quota.ts` `fetchAnthropicUsageQuota` — read the subscription tier from a real
+ field in the upstream usage/billing response.
+- `src/oauth/index.ts` — add `plan: string | null` to the OAuth account summary.
+- `src/server/management/oauth-account-routes.ts` — carry it on the management DTO.
+- `src/cli/account-api.ts` — carry it on the CLI DTO. This file is why the layer chains on wp2,
+ which already rewrites it.
+- The Anthropic GUI rows.
+
+Hard constraint from the issue and from the maintainer: if the upstream response carries no tier
+field, land `plan: null` plus documentation saying so. Do not infer a Max x5 / x20 mapping from
+quota percentages — the issue reporter already established that percentages are normalized per
+account and carry no tier information, so a guess would be indistinguishable from data.
+
+The explicit `null` matters: it lets a consumer tell "unknown tier" apart from "OpenCodex too old
+to report one".
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_mid_thread_agent_task_recovery/000_plan.md b/devlog/_plan/260909_mid_thread_agent_task_recovery/000_plan.md
new file mode 100644
index 0000000000..b5ebf51467
--- /dev/null
+++ b/devlog/_plan/260909_mid_thread_agent_task_recovery/000_plan.md
@@ -0,0 +1,148 @@
+# Mid-thread encrypted agent-task recovery (#4089) — plan
+
+## Reader summary
+
+Problem: switching a live Codex Desktop thread from a native ChatGPT model to a routed provider
+model bricks the thread with `unreadable_encrypted_agent_task`. The thread's history already
+contains a backend-minted `encrypted_content` agent message, every later turn replays it, and
+`agentTaskRecovery` — even when explicitly enabled — never runs, because the direct recovery
+block is gated on `isThreadSpawnRequest(req.headers)` and a mid-thread model switch is not a
+thread spawn. Answer: `threadSpawn` was never the trust boundary; `recoveryAdmission()` is.
+What changes: the direct gate drops the `threadSpawn` conjunct, so any routed Responses request
+carrying an unreadable encrypted agent envelope gets one recovery attempt under the same
+unchanged admission checks. The combo gate keeps its spawn requirement.
+
+## Loop spec
+
+- Loop archetype: satisfy-spec (single work-phase wp1, one PABCD cycle; not multi-cycle, so no
+ docs-first roadmap cycle).
+- Trigger: lidge-jun/opencodex#4089, delegated as one lane of the post-2.49 round.
+- Class: C4. This widens a trust boundary — a code path that spends the caller's stored native
+ ChatGPT session becomes reachable from a request shape that previously could not reach it — so
+ it gets a durable evidence record and expects security review before merge.
+- Goal: a mid-thread native-to-routed model switch attempts recovery; the discriminator
+ `recovery_reason` is present on the non-spawn error body; the admission checks are untouched;
+ PR on `dev` with green exact-head CI.
+- Non-goals: #2495 (opt-in plaintext V2 rewrite) and #3661 (spawn-path recovery failures) are
+ explicitly out of this lane and are not grouped in. No widening of `recoveryAdmission()`. No
+ change to the combo path. No change to `canPassThroughEncryptedV2AgentTask()`, so an
+ OAuth-mode routed provider still has no ciphertext passthrough. No early client-side rejection
+ of the model switch (suggested direction 2 in the issue) — that is a product/UX decision for a
+ separate unit.
+- Local verification: NOT RUN by standing maintainer instruction for this round (no product
+ suite, no typecheck, no build, no lint, no `bun install`). Remote CI on the PR's exact final
+ head is the only gate: `.github/workflows/ci.yml` job `test` (line 263), gated on the
+ `changes` filter that covers `src/**` and `tests/**` (lines 191, 193), runs
+ `bash scripts/ci/run-bun-test-batches.sh` (line 325) whose `find tests -type f` selection
+ includes `tests/server/agent-task-recovery.test.ts`.
+- Stop condition: PR non-draft, mergeable, exact-head CI green. Merging is the main session's.
+- Expected terminal outcomes: DONE = PR open with green exact-head CI; BLOCKED = irreducible CI
+ failure or a conflict the main session must sequence.
+
+## Root cause (evidence)
+
+`src/server/responses/core.ts:3616-3624` — the direct (non-combo) recovery block:
+
+```
+ inboundWire === "responses"
+ && threadSpawn
+ && agentTaskRecovery
+ && !isCanonicalOpenAiForwardProvider(route.provider)
+ && !options.comboAttempt
+ && !canPassThroughEncryptedV2AgentTask(route, inboundWire)
+```
+
+`threadSpawn` is `isThreadSpawnRequest(req.headers)` (`core.ts:3503`), which
+`src/server/effort-policy.ts:33` defines as true only for `x-openai-subagent: collab_spawn`
+or turn metadata `subagent_kind === "thread_spawn"`. A mid-thread model switch carries neither,
+so the whole block is skipped: `restoreCachedEncryptedAgentTasks()` never runs, the recovery
+call never runs, and `recoveryFailureReason` stays `undefined`. The request then falls through
+to `core.ts:3762-3769` and returns `unreadable_encrypted_agent_task` with no
+`recovery_reason` field at all (`core.ts:1988-1999` only attaches the field when a reason
+exists). That absence is exactly the discriminator the reporter observed on loopback.
+
+A thread started on the routed model never carries backend-minted ciphertext, which is why it
+never reproduces. Once one native-minted `encrypted_content` agent message is in the history it
+is replayed on every subsequent turn, so the thread is permanently unusable on that provider.
+
+`canPassThroughEncryptedV2AgentTask()` (`core.ts:1990ff` comment block) requires
+`authMode === "key"` plus `allowEncryptedV2AgentTasks` plus an `openai-responses` wire, so
+an OAuth-mode routed provider has no passthrough escape either. Recovery is the only path.
+
+## Change
+
+One conjunct deleted from `src/server/responses/core.ts:3618-3619`, plus a comment recording
+why. The cache restore (`restoreCachedEncryptedAgentTasks`) lives inside the same `if`, so it
+moves with the gate — which also fixes the reporter's third observation, that a proxy restart
+loses any chance of reusing a previously recovered plaintext for the thread.
+
+## Why the trust boundary is unchanged
+
+`recoveryAdmission()` (`src/server/responses/agent-task-recovery.ts:249-283`) is untouched.
+Every one of its checks still runs on the widened path, and each one independently refuses:
+
+1. `isApiAuthRequired(config)` — a proxy with inbound API auth configured is never admitted.
+2. `CODEX_ORIGINATORS` membership on the `originator` header.
+3. No `x-opencodex-api-key` and no `x-api-key` on the inbound request — remote/shared proxy
+ callers are refused outright, because caller-controlled Codex metadata is not strong enough
+ to authorize spending a stored ChatGPT session.
+4. A `Bearer` token that passes `isNativeChatGptAccessToken()`: RS256 + `kid`, an issuer in
+ `OPENAI_TOKEN_ISSUERS`, the `https://api.openai.com/v1` audience, the Codex OAuth
+ `client_id`/`azp`, unexpired, `nbf` honoured, and a present auth claim object.
+5. The account id extracted from that token must equal the explicit `chatgpt-account-id`
+ header.
+6. A proxy admission secret presented as the bearer is rejected before anything else
+ (`isProxyAdmissionSecret`).
+
+The recovery cache is keyed by an HMAC over the token and account id
+(`agent-task-recovery.ts:275-279`), so a widened entry point cannot read another caller's
+recovered plaintext. `restoreCachedEncryptedAgentTasks()` re-runs `admittedRecovery()` per
+item before touching the cache (`agent-task-recovery.ts:559-561`).
+
+The population that gains reachability is therefore: a loopback request from a Codex originator,
+holding a live native ChatGPT bearer for the same account named in `chatgpt-account-id`, with no
+inbound API key, on a proxy that does not require inbound API auth — that is, the same user whose
+session would be spent, on the same machine. `threadSpawn` narrowed *which of that user's own
+requests* could use their own session; it did not keep anyone else out.
+
+## Plaintext-oracle bound
+
+`src/server/responses/encrypted-payload.ts:181-192` records the reason recovery is
+`NEW_TASK`-only: `MESSAGE` is matched for the unreadability CHECK so a reply envelope whose
+whole body is one Fernet token is not forwarded verbatim, but decrypting a `MESSAGE` on the
+parent's behalf would build a plaintext oracle out of a payload the parent's session may not be
+entitled to read. That asymmetry is enforced in
+`src/server/responses/agent-task-recovery.ts:508` and is not touched here. Widening the *entry*
+gate does not widen *what* may be decrypted: an unreadable `MESSAGE` still fails closed with a
+refusal reason, and the only envelope that reaches an actual decrypt attempt is a `NEW_TASK`
+the admitted caller's own session is entitled to read.
+
+## Why the combo gate stays
+
+`core.ts:2691-2694` keeps `!isThreadSpawnRequest(req.headers)`. The combo path has its own
+native-target filtering and per-attempt failover semantics
+(`canDecryptUnreadableAgentTask`, `payloadEligible`, `comboPayloadReadable`), and the
+reported defect is on the direct path. Widening both at once would mean two behavior changes
+under one security review; the combo path can be reconsidered separately with its own evidence.
+
+## Regression
+
+`tests/server/agent-task-recovery.test.ts` gains the reporter's A/B pair: two `post()` calls
+with an identical body — one `agent_message` carrying a routing header plus a structurally valid
+Fernet-shaped `encrypted_content` slot — differing only by the `x-openai-subagent: collab_spawn`
+header, against a routed provider. Both must fail with `unreadable_encrypted_agent_task`, and
+both must now carry `recovery_reason`, because `recovery_reason` is attached only when recovery
+actually ran. Before this change the non-spawn arm has no `recovery_reason` field.
+
+## Docs
+
+`docs-site` framed this feature as spawn-only ("a native ChatGPT parent spawning a routed v2
+child"). The reference page and the sub-agent surface guide now name both qualifying request
+shapes, and the combo paragraph states explicitly that combo recovery is still spawn-only. The
+same one-clause precision is applied to the seven translated locales so they do not contradict
+the English source, matching what #3754 did for the combo-recovery change. The `docs-site` build
+was not run under the same standing instruction; the edits are prose-only inside existing pages.
+
+## Terminal outcome
+
+Tracked on lidge-jun/opencodex#4135. This unit moves to `devlog/_fin/` once the PR is on `dev`.
diff --git a/devlog/_plan/260909_post249_scope_cleanup/000_plan.md b/devlog/_plan/260909_post249_scope_cleanup/000_plan.md
new file mode 100644
index 0000000000..048260e265
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/000_plan.md
@@ -0,0 +1,32 @@
+# 260909 post-2.49 scope cleanup + interview
+
+## Context
+
+v2.49.0 shipped 2026-09-09T12:53Z (main `2f3f73629`, dev reopened at 2.50.0 via #4115).
+Before choosing the next bug/improvement round, the user asked for a full
+reconciliation pass and then an interview to settle scope.
+
+## Work items
+
+1. Reconcile devlog/_plan units (~150) against public git history; move
+ terminal+landed units to _fin. Evidence: parallel read-only recon lanes
+ (dispatched as separate Codex tasks, model xai/grok-4.6).
+2. Reconcile branches (local + origin) and worktrees against live PR state;
+ remove only provably-merged/clean ones; ambiguous ones go to a review list.
+3. Build the open-issue disposition table: CLEAR-FIX / LIVE-PROBE / POLICY /
+ IMPROVEMENT / STALE-FIXED / DUPLICATE.
+4. Interview with the user to pick this round's scope: clear bugs + minor
+ UX improvements in; live-probe items deferred unless measurable via
+ computer-use; policy items decided one by one.
+
+## Known starting state (verified this session)
+
+- CLEAR-FIX, no open PR: #4112 (non-streaming 413 bypasses overflow mapping),
+ #4120 (revoked pool credential stays "ok"), #4089 (agentTaskRecovery gated
+ on threadSpawn).
+- CLEAR-FIX with draft PRs already open: #3926->#4068, #4083->#4084,
+ #4110->#4114.
+- POLICY candidates: #3846 (warmup gate registration), #3761 (passthrough
+ hosted-search bridge).
+- LIVE-PROBE: #3782 (Claude Desktop env), #3781 residual (TUN/Fake-IP),
+ #3775 residual (YYLJ gateway/Desktop).
diff --git a/devlog/_plan/260909_post249_scope_cleanup/010_reconciliation.md b/devlog/_plan/260909_post249_scope_cleanup/010_reconciliation.md
new file mode 100644
index 0000000000..5b0958b1b8
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/010_reconciliation.md
@@ -0,0 +1,32 @@
+# 010 — devlog reconciliation (_plan -> _fin)
+
+Method: five read-only recon lanes (spawned agents, xai/grok-4.6) reconciled all
+158 _plan units against fetched origin/dev 57077ca32 and origin/main 2f3f73629
+(v2.49.0). CLOSEOUT-READY requires a recorded terminal outcome in the unit AND
+landed ancestry evidence. Spot checks by main session: c9a202e38 ancestry,
+PR #3662/#2080/#3966/#3942/#3785 all MERGED — lane claims verified.
+
+## Moved to _fin (101 this round; 260908_provider_runtime_stack was already there)
+
+- 260724-260822: 19 closeout-ready + 4 abandoned (260813_bun_canary_dogfood,
+ 260814_bug_resolution_campaign, 260814_usage_memory_roadmap,
+ 260822_260822-bun14-followup-memory — each with a new 090_terminal.md).
+- 260823-260904: 64 closeout-ready + 2 abandoned (260827_remote_hub superseded
+ by 260901_remote_hub_restack; 260904_dashboard_minimal reverted by #3415).
+- 260905-260909: 6 closeout-ready + 7 landed-but-unrecorded (new 090_closeout.md
+ citing merge evidence: 260905_external_image_roundtrip #3586-#3596,
+ 260905_fast_default_exports #3674, 260905_grok_responses_default #3670,
+ 260906_opaque_transport_finality #3753/#3754, 260906_release_244_publish
+ #3785+v2.44.0, 260908_a_stack_responses_compat #3942,
+ 260908_d_group_test_infra_stack #3940).
+
+Result: _plan 158 -> 57 units, _fin 432 -> 533.
+
+## Still open (57 units)
+
+Genuinely incomplete or design-only units remain in _plan, including:
+260801_monorepo_git_blobless_strategy, 260816_codexrs_multiagent_v2_and_history_perf
+(phase 1 landed, phases 2-5 open), 260817_windows_stability_program,
+260818_megafile_split_program, 260819_next_roadmap, 260821_bug_merge_train,
+260822_senpi_cursor_transfer, and the 260905-260909 working units
+(33 per lane A3, mostly active campaign/merge-train units).
diff --git a/devlog/_plan/260909_post249_scope_cleanup/020_branch_worktree_cleanup.md b/devlog/_plan/260909_post249_scope_cleanup/020_branch_worktree_cleanup.md
new file mode 100644
index 0000000000..268b9bccd8
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/020_branch_worktree_cleanup.md
@@ -0,0 +1,45 @@
+# 020 — branch and worktree cleanup
+
+Evidence standard: local branches deleted only with PR MERGED (gh) or
+ancestor-of-origin/dev proof (recon lane B + main-session spot checks).
+Branches checked out in surviving worktrees were kept.
+
+## Worktrees
+
+- Removed 54 clean /private/tmp worktrees (248-a/248-b lane workers, axis1-5,
+ bug6, track1-3, release-246/247 workers, prs-stack, sponsors, etc.). Clean
+ worktree removal loses nothing: every branch ref was retained unless itself
+ merged (below).
+- Kept: main checkout (dirty local dev, user-owned), this session's ae6a,
+ all ~/.codex/worktrees app-managed slots (app owns their lifecycle),
+ ~/.cursor/worktrees/opencodex/njhf.
+- Dirty merged worktrees left for owner review (uncommitted devlog notes):
+ 8fd91167 (voice-contract-0908), cb55 (pr3997), d974cb89 (bug6-01a07e9d-close),
+ plus 5 detached /var/folders tmp dirs.
+
+## Local branches: 144 deleted
+
+Merged-PR branches (squash, anc=0 but gh MERGED) and ancestor-merged branches:
+248-a/248-b/248-c lanes, 260904-260909 wp/train lanes, 260907 a-e letters,
+axis1/2/3/5, bug6-01a07e9d set, a/b/c-track, prs-l1-l6, rt-m1-m8,
+release-244/246/247/248/249 lines, pr-39xx/40xx/41xx aliases, sponsors/*,
+codex/providers-home-and-quota-refresh, codex/security-pr-lane-20260909
+(same SHA as stale local dev), etc. 208 local branches remain (orphan
+roadmap/diagnostic/rb-*/jrb-*/*-evidence set with no PR and no ancestry —
+kept pending owner review, they hold the only copy of that work).
+
+## Remote branches (origin): 8 deleted
+
+- codex/models-provider-head-uniform-row (#3096 MERGED)
+- codex/providers-home-and-quota-refresh (#3472+#3466 MERGED)
+- codex/release-245-candidate-519b (ancestor of origin/dev)
+- fix/post-layout-guard-regressions (#3532 CLOSED, carried via #3865 MERGED)
+- ingw/fix-chat-json-sse-parity (#3779 CLOSED)
+- ingw/fix-container-codex-volume (#3747 CLOSED)
+- ingw/fix-reasoning-envelope-budget (#3862 CLOSED, superseded by #3879 MERGED)
+- ingw/type-safety-registry-modularization (#2805 CLOSED)
+
+Kept on origin: open-PR heads (improved-remote-control #3458,
+ingw/fix-4110-owned-root-guidance #4114) and ~40 orphan evidence branches
+(assets/*, media/*, *-evidence, diagnose-*, track*) — no PR ref backup exists
+for these, so deletion would be unrecoverable; owner decision required.
diff --git a/devlog/_plan/260909_post249_scope_cleanup/030_issue_disposition.md b/devlog/_plan/260909_post249_scope_cleanup/030_issue_disposition.md
new file mode 100644
index 0000000000..c9f76b24d2
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/030_issue_disposition.md
@@ -0,0 +1,56 @@
+# 030 — open-issue disposition (post-2.49)
+
+Source: recon lane C, verified against gh on 2026-09-09 (57 open issues,
+origin/dev 57077ca32, v2.49.0 = 2f3f73629). No STALE-FIXED, no DUPLICATE.
+
+## CLEAR-FIX (8)
+
+| issue | title | linked PR |
+|---|---|---|
+| #4122 | Spark 5h header window stored as account-level short quota on Pro | — |
+| #4121 | opencode-free Zen rejects without x-opencode-session | — (#3954 related, not closing) |
+| #4120 | revoked-but-time-valid pool credential stays "ok" | — |
+| #4112 | non-streaming 413 never hits context-overflow mapping | #4119 (follow-up, not closing) |
+| #4110 | client-compaction status treats operator-owned URL as non-proxy | #4114 draft (Closes) |
+| #4089 | mid-thread native→routed switch; agentTaskRecovery gated on threadSpawn | — |
+| #4083 | Codex WS 30s response-prelude cuts multi-image slow starts | #4084 draft (Closes) |
+| #3926 | Google AI Studio discovery rejects models[] envelope | #4068 draft (Closes) |
+
+No closing PR yet: #4122, #4121, #4120, #4089, #4112.
+
+## POLICY (8) — interview decisions
+
+| issue | question |
+|---|---|
+| #4076 | remove the ChatGPT quota overlay that blocks picking other models? |
+| #4073 | private follow-up path for pending security reports (process/docs) |
+| #3978 | allow client compaction without disabling V2 routing (Design B) |
+| #3859 | make email masking optional (privacy gate change) |
+| #3846 | persist pool accounts as quota-limited instead of warmup-gating (draft #3848 exists) |
+| #3761 | hosted-search bridge for raw Responses passthrough (contract choice) |
+| #3506 | add a no-progress cutoff after #2600 (product decision) |
+| #2495 | opt-in plaintext V2 rewrite for native→routed subagents (tracking) |
+
+## LIVE-PROBE (9) — deferred unless measurable via computer-use
+
+#3782 (Claude Desktop model switch), #3781 (TUN/Fake-IP), #3775 (gateway/Desktop),
+#3765 (cache plateau attribution), #3719 (Anthropic replay + cache),
+#3661 (V2 subagent encrypted task), #3522 (Windows spill), #3433 (Hermes cache),
+plus #4083's field half already covered by draft #4084.
+
+## IMPROVEMENT (32)
+
+#4079 (quota-reset-first scheduling; draft #4080), #4075 (Gemini setup UX),
+#4057 (account identity in logs), #4055 (persistent WebUI auth on remote binds),
+#4038 (decode tok/s; draft #4040), #4024 (OpenRouter key rotation),
+#3898 (headless hub reauth), #3777 (Anthropic plan exposure), #3774 (DnD picker order),
+#3729 (remote catalog pull), #3705 (Guardrails; draft #4022), #3666 (free-model filter),
+#3630 (catalog auto-refresh), #3573 (configurable body limit), #3494 (VS Code agents),
+#3459 (request transform hook; draft #3463), #3417 (native main login profiles),
+#3379 (dashboard gaps epic), #3377 (per-model capabilities), #3376 (quota history;
+draft #4080), #3375 (OAuth pool lifecycle), #3191 (MSP adapter), #2894 (SOCKS5;
+drafts #3901/#2921), #2834 (relay diagnostics), #2811 (update manager),
+#2730 (alpha search auth), #2511 (image byte budget; #4119 open), #2358 (RFC),
+#2279 (synthetic max; draft #2280), #1711 (zero-credit grey-out),
+#1416 (Orca manifest), #1213 (Claude Desktop catalog mode), #95 (hosted multi-user).
+
diff --git a/devlog/_plan/260909_post249_scope_cleanup/040_dispatch_roadmap.md b/devlog/_plan/260909_post249_scope_cleanup/040_dispatch_roadmap.md
new file mode 100644
index 0000000000..048e6a6099
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/040_dispatch_roadmap.md
@@ -0,0 +1,61 @@
+# 040 — dispatch roadmap (post-2.49 delivery round)
+
+Loop: cxc-loop HOTL under an active host goal. Main session owns phase control,
+merge order, and rebase timing. Eight parallel worktree threads own implementation.
+
+## Delivery contract (identical for every thread)
+
+- Skills: cxc-loop + cxc-dev. Classify each item C0-C5 and scale process to it.
+- NEVER run the local product suite, typecheck, build, or install. Remote CI on the
+ exact PR head is the only gate. Label skipped local checks NOT RUN.
+- Push with `--no-verify`. Branch prefix `codex/` (or keep an existing head branch
+ when shepherding someone else's PR).
+- Every PR bases on `dev` at 57077ca32 unless it is a child inside its own chain,
+ in which case it bases on its parent's head branch.
+- Do NOT rebase. The main session controls rebase timing after watching merge order.
+- Threads may dispatch xai/grok-4.6 subagents (spawn_agent) for parallel bounded work.
+- Carry `Co-authored-by` trailers when landing or shepherding another author's work.
+
+## Thread map
+
+| T | Owns | Kind | Base |
+|---|---|---|---|
+| 1 | #4114, #4084, #4068 | shepherd 3 open PRs to ready | dev (existing heads) |
+| 2 | #4127 (issue #4112) -> #3573 | shepherd + child | dev, then #4127 head |
+| 3 | #4128 (issue #4122) | shepherd | dev (existing head) |
+| 4 | #4120 -> #3848 -> #3777 | new + shepherd + new | dev, then chain |
+| 5 | #4089 | new (C4, security review before merge) | dev |
+| 6 | #4057 | new | dev |
+| 7 | #3761 Design A | new (largest) | dev |
+| 8 | #4073, #4121 | docs only | dev |
+
+## Merge order (main session controls)
+
+Land bottoms as they go green; do not wait for tops.
+#4114 -> #4068/#4084/#4073 -> #4127/#4128 (first green wins, loser rebases on
+instruction) -> #4120 -> #4121-docs/#4057 -> #4089 -> #3573 -> #3777 -> #3848 -> #3761.
+
+Independent of any chain: #4114, #4068, #4084, #4073, #4127, #4128, #4120, #4057, #4121.
+Chain-dependent: #3573 (needs #4127), #3777 (needs #3848 for cli/account-api.ts),
+#3848 (needs #4120 for the account store/guardian fields), #3761 (wants a settled core.ts).
+
+## Shared-file risk
+
+`src/server/responses/core.ts` is the common trunk for #4127, #4128, #4089, #3573,
+#3761, and part of #4057. Parallel implementation is fine; merging is serial and the
+main session issues the rebase instruction to whichever PR loses the race.
+
+`token-guardian.ts` / `account-store.ts` / `types/accounts.ts` are the second trunk,
+shared by #4120 and #3848 — which is why they are one chain rather than two lanes.
+
+## Probes (main session, no PR)
+
+#3782 Claude Desktop in-conversation model switch, #3765 Astra cache plateau,
+#3719 Anthropic thinking replay. Evidence attaches to the issues.
+
+## Out of this round
+
+#4076 closed (transient overlay; registration half covered by #3848).
+#3506 direction comment posted (translation fidelity, not a proxy-side progress cutoff).
+#2495 dropped after a feasibility study: not redundant with #4089, needs its own cycle.
+#3978 deferred until the compaction status contract settles.
diff --git a/devlog/_plan/260909_post249_scope_cleanup/050_delivery_record.md b/devlog/_plan/260909_post249_scope_cleanup/050_delivery_record.md
new file mode 100644
index 0000000000..d806dfd4a3
--- /dev/null
+++ b/devlog/_plan/260909_post249_scope_cleanup/050_delivery_record.md
@@ -0,0 +1,68 @@
+# 050 — delivery record (post-2.49 round)
+
+Every scoped item landed on `dev`. Fifteen pull requests merged; fourteen issues closed.
+
+## Landed
+
+| PR | Issue | Lane | What landed |
+|---|---|---|---|
+| #4128 | #4122 | T3 | Spark 5h header windows attribute to the model limit, not the account short slot |
+| #4132 | — | T3 | moved the closed Spark unit out of the product PR into _fin |
+| #4114 | #4110 | T1 | client-compaction status compares the operator-owned root URL instead of inferring from a missing marker |
+| #4127 | #4112 | T2 | non-streaming provider input overflow reaches the terminal context-overflow mapping |
+| #4138 | #3573 | T2 | configurable inbound body admission limit, default 256 MiB, hard-ceilinged |
+| #4133 | #4073 | T8 | SECURITY.md private follow-up path, no SLA published |
+| #4136 | #4121 | T8 | documents the opencode-free Zen lock-in instead of forging x-opencode-session |
+| #4084 | #4083 | T1 | 90s Codex WebSocket response prelude |
+| #4068 | #3926 | T1 | Google AI Studio native models[] envelope accepted by catalog discovery |
+| #4134 | #4057 | T6 | routed account label surfaced in Logs and an --account CLI filter |
+| #4135 | #4089 | T5 | agentTaskRecovery runs on a mid-thread native-to-routed switch |
+| #4140 | #4120 | T4 | terminal validation verdict persists for a revoked credential |
+| #3848 | #3846 | T4 | quota-exhausted registration saved as validation-pending |
+| #4146 | #3777 | T4 | explicit account plan field; Anthropic lands plan: null with the upstream gap recorded |
+| #4142 | #3761 | T7 | opt-in provider-level webSearchBridge for key-auth passthrough destinations |
+
+Also closed by decision: #4076 (transient overlay; the registration half is #3848).
+#3506 received a direction comment: translation fidelity, not a proxy-side progress cutoff.
+#2495 was dropped after a feasibility study found it needs its own cycle rather than
+riding on #4089.
+
+## What the parallel structure actually bought
+
+Three findings would not have surfaced from a single serial pass.
+
+T4 found that a textually clean git auto-merge of #3848 against `dev` produced two
+`const needsReauth` declarations in one scope — valid text, invalid TypeScript — and a
+collision on positional slot 5 of `fetchPoolAccountQuota` where taking either side alone
+silently passes the wrong value at the other call site. That is the concrete reason the
+account work was a chain and not two lanes.
+
+T1 found that #4084 and #4068 sat 106 commits behind `dev`, which the readiness gate
+unticks past a 10-commit threshold, so neither could stay non-draft without a branch
+update. It brought them current by merge rather than rebase, preserving contributor
+authorship.
+
+T7's own audit of its diff caught four real defects before the final head: tool-call
+leakage on a failed turn, search-cell ordering, abort handling, and the continuation
+body ceiling.
+
+## Evidence standard held
+
+No local product suite, typecheck, build, or install was run in any lane. Every merge
+cites exact-head remote CI. Cancelled runs were never counted as passing: where a
+concurrency group cancelled a gate with no successful counterpart at the same SHA, the
+run was re-triggered and a real conclusion waited for.
+
+#3848's readiness checklist was cleared by the maintainer rather than by author
+attestation, because the local-CI box is an attestation the gate cannot disprove and
+repository CI at the exact head is stronger evidence. The delivering lane declined to
+tick it rather than assert a run it had not made.
+
+T2 disclosed that it did not drive the orchestrate FSM, because the C-to-D edge requires
+a test receipt it could not honestly produce under the no-local-runs rule. It left the
+session at IDLE rather than fabricate one.
+
+## Not done
+
+Probes #3782, #3765 and #3719 remain open; they need live client observation rather than
+a code change. #3978 stays deferred until the compaction status contract settles.
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 `