From 5448c5a2fa2f9a5f7de6b28675eea160094c1269 Mon Sep 17 00:00:00 2001 From: JUN Date: Tue, 15 Sep 2026 14:55:04 +0900 Subject: [PATCH] docs(devlog): open the 2.56.0 release-train plan unit Records the roadmap, the #4683 landing, the seven-slice regression audit and its findings, and the release sequence the workflow gates actually force. --- .../260915_2560_release_train/000_roadmap.md | 38 ++++++++++ .../010_land_4683.md | 27 +++++++ .../020_regression_audit.md | 75 +++++++++++++++++++ .../260915_2560_release_train/030_release.md | 37 +++++++++ 4 files changed, 177 insertions(+) create mode 100644 devlog/_plan/260915_2560_release_train/000_roadmap.md create mode 100644 devlog/_plan/260915_2560_release_train/010_land_4683.md create mode 100644 devlog/_plan/260915_2560_release_train/020_regression_audit.md create mode 100644 devlog/_plan/260915_2560_release_train/030_release.md diff --git a/devlog/_plan/260915_2560_release_train/000_roadmap.md b/devlog/_plan/260915_2560_release_train/000_roadmap.md new file mode 100644 index 0000000000..bae9b980e6 --- /dev/null +++ b/devlog/_plan/260915_2560_release_train/000_roadmap.md @@ -0,0 +1,38 @@ +# 2.56.0 release train — roadmap + +Status: open. Opened 2026-09-15. + +## What this unit covers + +Everything between the `v2.55.0` tip on `main` (`1cc89cf88c`) and the `dev` tip that becomes +2.56.0, plus the release promotion itself. The range is small in commit count and large in blast +radius: three of the seven commits are facade splits of the hottest files in the project +(`bridge.ts` #4672, `server/index.ts` #4675, `server/responses/core.ts` #4677), each landed as a +behaviour-preserving refactor. A refactor that claims to change nothing is exactly the change a +release audit should not take on faith. + +## Constraint that shapes the whole unit + +No local full suite, typecheck or build. Hosted CI at an exact head SHA is the only accepted +evidence for "this tree passes". Source reading and single focused test files are the local +instruments. Every claim below therefore names either a CI run at a SHA or a specific file read. + +## Work phases + +| Phase | Doc | Outcome | +| --- | --- | --- | +| wp1 | this file | Roadmap locked; implementation starts in wp2. | +| wp2 | `10_land_4683.md` | #4683 rebased onto the dev tip, CI green at its exact head, squash-merged. | +| wp3 | `20_regression_audit.md` | Every commit in the range audited by a dispatched subagent; findings triaged. | +| wp4 | `30_release.md` | 2.56.0 promoted to `main`, release workflow green, publish verified. | + +wp2 and wp3 are independent and run concurrently: the audit reads committed objects, the landing +work touches the working tree. wp4 depends on both. + +## Completion criteria + +1. #4683 squash-merged into `dev` with Cross-platform CI success at its exact head SHA. +2. Every commit in `v2.55.0..` the post-merge `dev` tip audited, with each REGRESSION or RISK + finding fixed or explicitly accepted with a stated reason. +3. 2.56.0 on `main` with hosted CI green at the promotion head and a successful publish. +4. No local full suite, typecheck or build was run anywhere in this unit. diff --git a/devlog/_plan/260915_2560_release_train/010_land_4683.md b/devlog/_plan/260915_2560_release_train/010_land_4683.md new file mode 100644 index 0000000000..9567f8f12c --- /dev/null +++ b/devlog/_plan/260915_2560_release_train/010_land_4683.md @@ -0,0 +1,27 @@ +# wp2 — land #4683 + +## The change + +A Codex client chained by `previous_response_id` sends only the newest turn. When local replay +state was gone, a destination on a translated wire received that delta alone under a normal 200: +the conversation was replaced by the one line the user had just typed. Only the canonical ChatGPT +forward route and stateless Responses destinations failed closed. The fix refuses with +`previous_response_not_found` for every destination that cannot see the omitted prefix, and raises +`RESPONSE_TTL_MS` from 1 hour to 24 hours so an ordinary idle gap resumes by expansion instead. + +## Rebase note + +The branch was opened against `49dcdbf535`, before #4677 split `core.ts`. The gate had moved to +`src/server/responses/request-prepare.ts`, so the branch was rebuilt on the current `dev` tip and +the gate ported there rather than rebased through a conflicting delete/split. One rebase, then CI, +then squash merge. + +## Evidence + +- `bun test tests/codex-integration/issue-702-expired-replay-state.test.ts` — 16 pass / 0 fail on + the rebased base. The new case was driven red first: with the gate stashed, the expired + continuation returned 200 carrying the delta only. +- `bun test tests/responses/responses-core-modules.test.ts` — 9 pass, so the owner-module + inventory and line ceiling still hold after the port. +- `bun run structure:check` — passed. +- Cross-platform CI at the exact head SHA — recorded in the PR. diff --git a/devlog/_plan/260915_2560_release_train/020_regression_audit.md b/devlog/_plan/260915_2560_release_train/020_regression_audit.md new file mode 100644 index 0000000000..009d90c408 --- /dev/null +++ b/devlog/_plan/260915_2560_release_train/020_regression_audit.md @@ -0,0 +1,75 @@ +# wp3 — regression audit of v2.55.0..dev + +## Method + +Seven `gpt-5.6-sol` subagents at medium reasoning effort, dispatched in parallel, one per slice. +Each reads committed objects (`git show :`, `git diff ^ `) rather than the +working tree, because the tree was being rebased concurrently for wp2. None runs tests: the local +suite is forbidden for this unit, so the instrument is source reading and the verdict is stated as +CLEAN / RISK / REGRESSION with file and line. + +## Slices + +| Slice | Target | +| --- | --- | +| core.ts facade split | `485a525aa9` — export surface, moved guards, duplicated module state, import cycles, the synchronous activation window. | +| server/index.ts facade split | `a63a47363f` — `labActivationRequired` gate, synchronous `startServer`, slot registration order. | +| bridge.ts facade split | `11f1119718` — export surface, SSE assembly, usage accounting, shared watchdog state. | +| reasoning summary fix | `369be813c4` — in-place mutation of stored/replayed items, scope, coverage. | +| test-side changes | `3ea88f3db8`, `89bc67353c` — is the new guard vacuous; is the destructive-home path fully closed. | +| #4683 itself | the gate allowlist and the 24h retention, attacked rather than confirmed. | +| release readiness | version agreement, stale doc references, `scripts/release.ts` and `release.yml` expectations, unowned `src/` areas. | + +## Findings + +Recorded as they return; a REGRESSION blocks wp4, a RISK is either fixed or accepted with a reason +written here. + +- bridge.ts facade split (`11f1119718`): **CLEAN**. Facade re-exports all six symbols; SSE, JSON + builders and the error formatter are byte-identical; the watchdog state remains a single live + module binding consumed by `src/bridge/sse.ts`; error, incomplete, EOF, stall and cancellation + paths unchanged. + +- core.ts facade split (`485a525aa9`): **CLEAN**. All prior exports present; 23 runtime helpers and + two interfaces AST-identical; combo execution differs only by injected dispatcher wiring; replay + gates intact in `request-prepare.ts`; mutable adapter/retry/continuation state still shared + through accessors; no reverse cycle, no duplicated module state. +- server/index.ts facade split (`a63a47363f`): **CLEAN**. `startServer` still synchronous, Lab + still behind `labActivationRequired` and activated before return, slot registration synchronous, + startup side-effect order and facade exports preserved. +- reasoning summary fix (`369be813c4`): **CLEAN**. Builds a new input array and clones changed + items before adding `summary`, so cached and replayed objects are not mutated; existing + summaries and opaque blobs untouched; scope limited to Responses serialization and native + compact forwarding; regression coverage exists. +- test-side changes (`3ea88f3db8`, `89bc67353c`): **RISK, accepted**. The #4681 fix itself is + sound — the quota test now pins and deletes only its own temporary home. Two guards have + false-negative gaps: the lab synchrony scan stops at direct `startServer` callees, so an async + `installLabAutomationRuntime` would pass, and the destructive-home guard matches only same-line + `rmSync(getConfigDir())` forms. Neither is a runtime regression and neither is new in this + range, so they do not block 2.56.0; they are follow-up hardening. +- #4683 (`4e548b693c`): **RISK, fixed**. The original allowlist let kiro, cursor and devin accept + a delta after a replay miss. Verified in source that all three rebuild the conversation from the + request they are handed — devin sends `mapOcxMessagesToDevin(parsed)` every turn, cursor's + `checkpointRef` is read from the store that just expired and otherwise falls back to + `full-replay`, kiro rebuilds `conversationState.history` from the parsed turns. The allowlist is + now empty and the four-wire refusal is pinned by test. The 24h retention adds no unbounded path: + the 1000-entry, 64 MiB resident and 1 GiB spill ceilings still bind, oldest-first. +- release readiness: **RISK, folded into the plan**. `release.yml` refuses to publish while + `dev` does not outrank the release version, so the `dev-version-bump` pre-move is a required + step and is now written into `030_release.md`. Separately, `docs-site` architecture pages and + `structure/runtime.md` still describe the pre-split ownership; that is documentation drift + across locales, not a runtime regression, and is tracked as follow-up rather than a release + blocker. + +## WebSocket idle timeout — why the TTL does the work + +A codex-rs client caches its `WebsocketSession` across turns and chains `previous_response_id` +onto it, clearing that chain only when it finds the socket closed. This proxy sets +`WEBSOCKET_IDLE_TIMEOUT_SECONDS = 0`, so the socket never closes on its own and the client's own +recovery never fires. Closing the socket instead of refusing the turn was considered and rejected: +Bun refuses a websocket `idleTimeout` above 960 seconds (measured, not inferred), so "close after +an hour" is not expressible as a serve option; one value covers every socket kind including the +live sideband relay; and it would not help HTTP clients, a restarted proxy, or an entry evicted +early by the byte caps. The refusal path covers all of those uniformly, so the timeout stays 0 and +the coupling is recorded where the constant lives, with +`tests/responses/ws-endpoint.test.ts` holding the pair together. diff --git a/devlog/_plan/260915_2560_release_train/030_release.md b/devlog/_plan/260915_2560_release_train/030_release.md new file mode 100644 index 0000000000..44062b9b40 --- /dev/null +++ b/devlog/_plan/260915_2560_release_train/030_release.md @@ -0,0 +1,37 @@ +# wp4 — 2.56.0 release + +## Preconditions + +- wp2 closed: #4683 on `dev` with Cross-platform CI green at its exact head. +- wp3 closed: no open REGRESSION finding. +- `dev` carries 2.56.0 (`dev-version-bump` owns that line). + +## Sequence + +The order is forced by two gates in `.github/workflows/release.yml`, not by preference. + +1. Record the `dev` tip and its Cross-platform CI conclusion at that exact SHA. +2. Cut the promotion branch from that `dev` commit — it still reads 2.56.0 — and open its PR to + `main`. Merge it. That merge commit is the release SHA `M1`. +3. Confirm Cross-platform CI succeeded for `M1` on `main`. `release.yml` requires a successful + run for the dispatched commit (`Require successful Cross-platform CI for this commit`), and + `Service lifecycle` too when service files changed in the range. +4. Dispatch `dev-version-bump.yml` with `intended-version: 2.56.0`, mode `pre-move`. It opens a + PR moving `dev` to the next line; merge it. This is not optional: `release.yml` ends with + `Require dev to be ready for this release`, which runs + `version-line.ts assert-ahead ` and refuses to publish while + `dev` still equals 2.56.0. +5. Dispatch `release.yml` with `version: 2.56.0` and `expected-sha: M1`. The workflow refuses any + dispatch whose `GITHUB_SHA` differs from `expected-sha`, so the branch must not move between + step 3 and here. +6. Verify the publish from the workflow's own conclusion. Registry metadata can lag a successful + publish; a lagging read is not a reason to publish again. + +## Evidence + +Recorded as each step completes: SHA, run id, conclusion. + +- wp2 head under CI: `4e548b693c` (previous heads `27c61e2dfb`, `9dffc3f06f`, `35ad194ec2` + superseded; `35ad194ec2` failed the file-size ratchet on + `tests/responses/responses-state.test.ts` and was fixed by removing the three added lines rather + than raising the cap).