diff --git a/devlog/_plan/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md b/devlog/_plan/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md new file mode 100644 index 0000000000..b60734cc15 --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/070_wp4b_exactly_once_terminal.md @@ -0,0 +1,68 @@ +# 070 — wp4b: land the exactly-once terminal recorder for PR #2433 + +## Why this is its own work-phase + +wp4 closed with #2433 held, not merged. The blocker was real and the PR was +otherwise complete, so the correct move was to build the missing piece rather +than hand a maintainer's finished work back over a seam they had no reason to +suspect. That build is this work-phase. + +## The change + +Branch `codex/fix-2433-exactly-once-terminal`, based on `origin/dev` at +`ed719b568`. Three commits: the two original #2433 commits cherry-picked +(`56275ac50`, `3cc24816a`), then the fix `abdeaf8cc`. + +The fix moves the once-guard off the exported callback and onto the recorder at +its creation site: + +- `src/server/responses/core.ts` — `handleComboResponses` no longer wraps + `setTerminalOutcomeRecorder` in a local `terminalOutcomeRecorded` closure. + Instead `handleResponsesInner` guards `codexForwardTerminalOutcomeRecorder` + where it is constructed, so the preflight callback and the eager/tee + inspectors all receive the same guarded function. +- `tests/server-combo-failover-e2e.test.ts` — new regression asserting exactly + one account-health failure per streamed attempt. + +21 lines changed in the runtime, 43 added in the test. + +## Evidence + +Red-green, from the implementer: + +- `bun test tests/server-combo-failover-e2e.test.ts --test-name-pattern "records one account-health failure"` +- RED before the source fix: 0 pass, 1 fail, observed `consecutiveFailures: 2`, expected `1`. +- GREEN after: 1 pass, 0 fail. + +Full focused run after rebasing onto current `origin/dev`: +`bun test tests/combos.test.ts tests/combo-stream-preflight.test.ts tests/server-combo-failover-e2e.test.ts tests/core-lab-boundary.test.ts` +-> 127 pass, 0 fail, 697 assertions. `bun run typecheck` exit 0. + +## The question that decides this phase + +Moving a guard to a wider scope trades one bug for a possible worse one. The +guard must be once-per-streamed-attempt, not once-per-request. A combo failing +over across three targets must still record three terminals, one per attempt. +If the recorder is created once per `handleResponsesInner` call and combo retries +happen inside that scope, the new guard would swallow later attempts' terminals — +which would be a quieter and more damaging defect than the one being fixed. + +An independent reviewer was dispatched specifically on that lifetime question. +This phase does not land until that verdict is in. + + +## Landing record + +Merged as PR #2449, squashed onto `dev` as `88b7cc057`, with @Ingwannu's two +original commits preserved in the branch history. + +The independent lifetime audit answered the question this phase turned on: +each combo target calls `handleResponses` afresh at `core.ts:1915`, each call +builds a new `handleResponsesInner` at `:2163`, so each attempt gets its own +guard at `:3579`. Per attempt, not per request — a three-target failover still +records three terminals. The reviewer also confirmed the regression is +load-bearing: remove the guard and the tee inspector plus preflight both record, +putting `consecutiveFailures` back at 2. + +CI 23 pass on the exact head. Issue #2431 closed; PR #2433 closed as superseded +with the reasoning posted for its author. diff --git a/devlog/_plan/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md b/devlog/_plan/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md new file mode 100644 index 0000000000..0c91079f29 --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/080_wp7_issue2392_auth_error_mapping.md @@ -0,0 +1,77 @@ +# 080 — wp7: issue #2392, centralize Codex auth-context error mapping + +## Item + +`Ingwannu` issue #2392, "centralize Codex auth-context error mapping across +Responses and compact". No PR exists; this work-phase builds one. + +## Investigation verdict + +`gpt-5.6-sol` high, read-only, against `origin/dev`: + +- STATUS REPRODUCES (structural), disposition FIX_SMALL, effort small. +- `src/server/responses/core.ts:1537` — regular Responses carries a full local + exception matrix through `:1576`. +- `src/server/responses/compact.ts:397` — compact carries the same common matrix + through `:414`, with its own `ForwardAdmissionCredentialError` at `:337`. +- `d52032ebe` (PR #2390) already fixed the user-visible half of this — the compact + substitution failure — by adding one local 401 branch. What remains is + duplication, not a defect, so the refactor must change no observable behavior. +- `tests/codex-envkey-admission-substitution.test.ts` 4/4 confirms both + substitution paths return before upstream I/O. +- `tests/core-lab-boundary.test.ts` 13/13 confirms the protected-core guard on + `src/server/responses/core.ts`. + +## Why this one is riskier than it looks + +The existing tests check status codes on both paths but not byte-level parity +(`tests/server-auth.test.ts:1889`, `:1900`). A refactor that folds two error +matrices into one can pass those tests while quietly changing a response body or +a `Retry-After`. So the characterization test comes first in the definition of +done, not last: it must assert identical status, serialized body, content type, +cooldown and drain `Retry-After`, thread-affinity 409, zero upstream I/O for +substitution, regular-only safe logging, and rejection of unknown errors. + +The new module also becomes a dependency of a protected core file, so it has to +be a pure leaf — builtins and local types only. + +## Plan + +New `src/server/responses/codex-auth-error.ts` exporting a pure +`mapCodexAuthContextErrorToResponse(error, { accountSelector, now })` returning +`Response | undefined`. Core and compact delegate the common classes and keep +their endpoint-specific logging and admission handling local. Unmapped errors +rethrow rather than being swallowed. `structure/01_runtime.md` records the new +owner. + + +## Execution record + +Built on `codex/fix-2392-auth-error-mapping`, rebased onto `81bf4b9a4`, opened as +PR #2450. + +New pure leaf `src/server/responses/codex-auth-error.ts`. Seven error classes +moved to it; four things deliberately left local, each for a stated reason: + +| Left local | Reason | +|---|---| +| regular-Responses pseudonymous reauth log | compact has no equivalent, folding it in would add a log line | +| `ForwardAdmissionCredentialError` (both paths) | not an auth-context resolution error | +| compact alternate-account `CodexMainProfileDrainingError` | returns `null` to preserve the first account's rejection | +| unmapped errors | rethrown in both handlers, never swallowed | + +Verification: 147 pass / 0 fail on the four focused suites, `typecheck` exit 0, +`privacy:scan` pass, and a full `bun run test` at 14,521 pass / 11 skip / 0 fail +across 906 files. Independently re-run by the main session after rebase: +61 pass / 0 fail on routing, admission-substitution, and core-lab-boundary. + +The full suite was run here despite the session's focused-proof instruction +because this is the authentication surface and `AGENTS.md` requires security +review for it. + +## Landing record + +PR #2450 merged to `dev` as `9cebfc64e`, CI 20 pass / 0 fail. Issue #2392 closed. + +This clears the entire Ingwannu queue: six PRs and five issues, all with a +recorded terminal disposition. diff --git a/devlog/_plan/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md b/devlog/_plan/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md new file mode 100644 index 0000000000..efab490838 --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/090_wp8_issue2443_wait_coercion.md @@ -0,0 +1,43 @@ +# 090 — wp8: issue #2443, Codex Desktop wait integer coercion + +## Item + +`lidge-jun` issue #2443, "Codex Desktop wait.yield_time_ms / max_tokens still +rejected as 120000.0 after #2316". + +## Investigation verdict + +STATUS REPRODUCES, disposition FIX_SMALL. `src/lib/tool-argument-integers.ts:77` +allowlists only `timeout_ms`; commit `a9cb7661b` fixed #2316 alone, so the two +`wait` fields still forward as `120000.0` and `8000.0` through both bridge paths +at `src/bridge.ts:627` and `:1657`. + +## The scoping decision + +The obvious fix — adding both names to the global allowlist — is wrong. +`yield-time_ms` and `max_tokens` are ordinary names: Cursor has its own +`yield_time_ms` at `src/adapters/cursor/tool-definitions.ts:42`, and any +third-party tool may legitimately want a fractional `max_tokens`. The repair is +therefore keyed to the bare `wait` tool, with tool identity threaded through the +coercer and passed only when no namespace is present. + +`tests/tool-argument-integers.test.ts:328` asserted the opposite contract for +`yield-time_ms`. It was written for #2316's narrower scope, and is updated here +deliberately rather than quietly deleted. + +## Evidence + +Red-green: 33 pass / 2 fail before the source change, 35 pass / 0 fail after. +`bun run typecheck` exit 0. + +## Landing record + +PR #2448, squashed onto `dev` as `81bf4b9a4`. Issue #2443 closed. + +One CI wrinkle worth recording: the first macOS run failed on +`Codex autostart shim > Unix install rejects a recursive dynamic launcher`, a +test with nothing to do with integer coercion. Rather than merge past it, the +test was run on clean `dev` (1 pass) and on the PR branch worktree itself +(69 pass / 0 fail), which established the failure as environmental. The rerun +then came back green across all 23 checks. + diff --git a/devlog/_plan/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md b/devlog/_plan/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md new file mode 100644 index 0000000000..687e514495 --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/100_wp9_verdict_only_issues.md @@ -0,0 +1,42 @@ +# 100 — wp9: issues resolved without new code (#2292, #1587) + +Two of the nine owner issues needed a verdict, not a patch. Both claims were +re-verified against `origin/dev` by the main session rather than taken from the +reviewer's report. + +## #2292 — Windows model picker stays stale + +Fixed by PR #2382, merged as `84ee2e284` (`a3bbcdb03 feat(cli): add an opt-in +Windows desktop-app restart for a stale model picker`). Verified present in +`origin/dev` history. + +The fix is opt-in by design. On Windows the desktop UI caches `model/list` and +invalidates only on `codex-app-server-initialized`, so killing the app-server +child does not refresh the picker — a full app restart does. Making that restart +automatic would kill a user's UI without asking, so it stays behind a flag. + +## #1587 — routed first-turn tool catalog 3-5x native Sol + +Already fixed by `fcbef381e`, confirmed an ancestor of `origin/dev` via +`git merge-base --is-ancestor`. That commit restored deferred discovery after +measuring the regression: 258,929 characters down to 96,699, recorded at +`structure/03_catalog-and-subagents.md:231`, with MCP reachability preserved. + +`normalizeRoutedCatalogEntry()` at `src/codex/catalog/parsing.ts:526` now pairs +`tool_mode: "code_mode_only"` with `supports_search_tool: true`, and +`src/codex/catalog/sync.ts:371` gives template-less routed entries the same +contract. `bun test tests/catalog-cursor-search.test.ts` re-run by the main +session: 5 pass / 0 fail. + +One honest caveat: a later comment on the issue describes a Claude Desktop +cache-tail comparison. That is a different client and a different, smaller +question — it is not a reproduction of the original Codex App defect. Closing +#1587 on the original report; the Claude Desktop question earns its own issue if +anyone wants to pursue it, rather than keeping a fixed bug open as a placeholder. + + +## Execution record + +#2292 and #1587 closed 2026-08-23 with the verification evidence posted on each. +The #2152 repair went out as PR #2452 in the same work-phase, since it is the +third issue whose resolution needed no product change. diff --git a/devlog/_plan/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md b/devlog/_plan/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md new file mode 100644 index 0000000000..5332413659 --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/110_wp10_roadmap_issue_dispositions.md @@ -0,0 +1,70 @@ +# 110 — wp10: the four roadmap issues (#1478, #1049, #1048, #820) + +Four of the nine owner issues are accepted architecture work, not defects. The +honest disposition for each is to stay open with a stated reason, not to be +closed for tidiness and not to be half-implemented inside a backlog sweep. + +Closing an accepted roadmap item because a cleanup pass wanted a zero would +destroy the record of a decision the project already made. Each is re-confirmed +against `origin/dev` and annotated so its next reader knows where it stands. + +## #1478 — config rebase provenance for deletion vs unseen keys + +Labelled `roadmap`. The rebase-on-save from #1273 cannot distinguish "this +writer deleted the key" from "this writer never saw the key". That is a data +model gap in the merge's inputs, not a bug in its code: no amount of care in the +merge function recovers information the writer never recorded. + +Fixing it means adding provenance to persisted config — a schema change with a +migration and a compatibility story for every existing install. That is its own +cycle. **Retain.** + +## #1049 — adopt pre-substrate Codex homes into the write coordinator + +Already given a deferral verdict in +`devlog/_plan/260822_backlog_disposition_program/060` and `061` during the prior +program, and nothing since has changed the calculus. Coordination covers clean +first applies and homes that already carry a valid coordinator; a home routed +before the substrate existed keeps its old uncoordinated path — which is every +install predating the substrate. + +The reason it stays deferred is that adoption has to be safe on a home that may +be mid-write by an older binary, and that safety argument is the actual work. +**Retain, deferral standing.** + +## #1048 — WP13 composed acceptance at the production boundary + +Partially implemented: PR #1106 landed the workstation-safe composed acceptance +suite and six production-path scenarios on `dev`. What remains is the Windows +leg, which is exactly what #2152 addresses — so this issue's remaining scope is +now tracked by concrete work rather than being open-ended. **Retain, linked to +#2152.** + +## #820 — 32 concurrent tool-recall sessions, protocol-safe and memory-bounded + +Labelled `roadmap`, `architecture`. Defines a concurrency and memory +architecture for 32 sustained sessions with a 64-session burst, with no +OpenCodex-imposed serialization and no loss of Codex, Responses, Chat +Completions, Anthropic, or MCP compatibility. That is a program, not an issue. +**Retain.** + +## Why this is a real disposition + +Every one of these gets an annotation comment on the issue recording its current +state against `dev` today. "Still open" with a dated reason is a verdict; "still +open" with silence is a backlog. + + +## Execution record + +All four annotated 2026-08-23 with a dated state check. Comments posted, then +rewritten via the API: the first attempt was assembled through a shell argument +and had its backticks and newlines eaten. Worth noting rather than hiding — the +repaired bodies are the ones now live. + +| Issue | Comment | +|---|---| +| #1478 | 5386880900 | +| #1049 | 5386880991 | +| #1048 | 5386881069 | +| #820 | 5386881161 | diff --git a/devlog/_plan/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md b/devlog/_plan/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md new file mode 100644 index 0000000000..e3e5fb06ca --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/120_wp11_issue1702_combo_quota.md @@ -0,0 +1,60 @@ +# 120 — wp11: issue #1702, per-target quota state in the combo workspace + +## Item + +`lidge-jun` issue #1702, "surface per-target quota state in the combo workspace — +disable actions when all targets have 0 credits". + +## Investigation verdict + +STATUS REPRODUCES, disposition FIX_NOW, effort medium. +`gui/src/pages/Combos.tsx:110-117` loads combos, config, and models but never +calls `/api/provider-quotas`. `combo-workspace-detail-panel.tsx:189-190` disables +Save/Create only for clean edits or busy state. + +An earlier attempt exists — `c8c4358a1`, PR #1704, closed unmerged — and is not +an ancestor of `dev`. It added presentation without action gating, so it was not +resurrected. + +The backing endpoint already exists at +`src/server/management/provider-routes.ts:372-378`, so this is GUI-only: no +runtime change. + +## The design rule this hangs on + +Quota state is tri-state: available, exhausted, **unknown**. Missing, stale, +malformed, failed, conflicting, or incomplete aggregate evidence all resolve to +unknown, and unknown must never disable a control. Only "every usable target is +KNOWN exhausted" disables Save and Create, and recovery re-enables automatically. + +The inverse — treating absent evidence as exhausted — would turn a dropped poll +into a locked workspace, which is a worse bug than the one being fixed. Disabled +targets are excluded from the all-exhausted decision, since a disabled target is +not a target the combo can use. + +## Evidence + +- `bun test tests/combo-workspace-data.test.ts` -> 35 pass / 0 fail + (USD, percentage, custom window, unlimited, stale/unknown, trimmed provider, + incomplete aggregation, disabled target, mixed state, all-exhausted, recovery). +- `cd gui && bun test tests/combo-workspace-empty.test.tsx tests/combo-workspace-dirty.test.tsx` -> 5 pass. +- `bun run typecheck`, `bun run lint:gui`, `cd gui && bun run lint:i18n`, + `bun run build:gui` -> all pass. +- `cd docs-site && bun run build` -> 393 pages. +- Browser QA at 1440x813 and 500x757; badges wrap without clipping. + +31 files: GUI components and data derivation, all nine locales +(`gui/AGENTS.md:14-18` requires every one), CSS, three test files, and the combo +guide in English plus its seven translations. + +Re-verified by the main session after rebase onto `6b0f61f64`: 35 pass / 0 fail. + + +## Execution record + +Opened as PR #2454 against `dev`, rebased onto `6b0f61f64`. + +The repository's `enforce-target` gate rejects any PR mentioning `gui` without a +screenshot in the description, so the capture was committed to a throwaway +branch (`codex/asset-1702`, not for merge) purely to give the image a stable raw +URL. That branch gets deleted once the PR lands. diff --git a/devlog/_plan/260823_owner_backlog_closeout/900_closing_reconciliation.md b/devlog/_plan/260823_owner_backlog_closeout/900_closing_reconciliation.md new file mode 100644 index 0000000000..24d3a8e8de --- /dev/null +++ b/devlog/_plan/260823_owner_backlog_closeout/900_closing_reconciliation.md @@ -0,0 +1,68 @@ +# 900 — closing reconciliation + +Opened 2026-08-23 against `origin/dev` at `bf8bcfd3c`. Closed 2026-08-24 at +`c9a202e38`. + +## What went in + +| PR | Item | Landed | +|----|------|--------| +| #2444, #2445 | wp0 roadmap + reviewer evidence | `3023be06d`, `c2b72fa22` | +| #2439 | contract manifest (Ingwannu) | `2a2f6e68f` | +| #2437 | history manifest contract (Ingwannu) | `81474259e` | +| #2435 | fetch helper boundary (Ingwannu) | `4fb0fbe7b` | +| #2446 | wp1-wp5 records | `ed719b568` | +| #2387 | process-state ownership (Ingwannu) | `b6c7c0afe` | +| #2380 | provider validation boundary (Ingwannu) | `aa37c8bea` | +| #2449 | combo zero-output failover, terminal recorded once | `88b7cc057` | +| #2448 | scoped `wait` integer coercion | `81bf4b9a4` | +| #2450 | centralized auth-context error mapping | `9cebfc64e` | +| #2452 | Windows WP13 stabilization | `6b0f61f64` | +| #2454 | combo target quota state | `c9a202e38` | + +Closed: issues #2436, #2434, #2379, #2378, #2392 (Ingwannu); #2443, #2292, +#1587, #1702, #2152 (lidge-jun); #2431. PR #2433 closed as superseded by #2449, +with its author's commits preserved in that branch's history. + +Retained with a dated reason on the issue: #1478, #1049, #1048, #820. + +## The finding that justified the process + +Every one of the six maintainer PRs arrived with green focused tests and green +CI. Five deserved to land on that evidence. One did not. + +#2433's preflight recorded a failed terminal that the native passthrough +inspectors had already recorded, so a single 502 counted twice against account +health and halved the effective failover threshold on a healthy credential. The +existing tests asserted stream behavior, not health-transition counts, so +nothing in the pipeline could have caught it. It took a reviewer reading the +recorder's call graph across 2,000 lines of `core.ts` to see it. + +The correction was then built rather than handed back, because the PR was +otherwise complete and the defect sat in a seam its author had no reason to +suspect. Moving a once-guard to a wider scope is itself risky — a guard that +became per-request instead of per-attempt would silently swallow later failover +terminals, quieter and worse than the bug being fixed — so that lifetime +question was audited on its own before the fix was allowed to land. + +## What the evidence does not cover + +#2152's repair is verified on macOS and by CI, but macOS cannot demonstrate +Windows scheduler relief or exercise the PowerShell identity timeout. Removing a +documented CPU-starvation source from a timeout-shaped failure is a well-founded +bet, not a proof. The issue is closed with that stated plainly, and the manual +Windows leg remains the only thing that can confirm it. + +## Process notes worth keeping + +Protected `dev` refuses direct pushes, so every devlog record travelled as its +own PR. Twice a `git reset --hard origin/dev` after a squash-merge dropped local +devlog commits that had not yet been pushed; both times the work was recovered +verbatim from reflog. The lesson is to branch the record before syncing, not +after. + +The FSM refused several shortcuts that would have produced a tidier-looking +history than the work deserved: a phase skip while wp4 was still active, an +audit attestation whose pasted output ended in FAIL, and three C→D transitions +whose test receipts no longer matched the tree. Each refusal was correct. +