# fix\(contracts\): older clients connect to servers with idle compaction modes · PR \#23213 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/23213)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: open

Source repository: pingdotgg/t3code

Source branch: fix/issue-23109

Target branch: main

Head commit: de75c79a56bc5cc6b2e8da37e6c7be7ff5e612ee

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/23213)

[Commits](https://git.cafe/pingdotgg/t3code/pull/23213/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/23213/diffs?format=markdown)

## Description

---

## Problem

The desktop nightly's web client at [680152e27b](https://git.cafe/pingdotgg/t3code/commit/680152e27b2a961686389ca69a1557cbb2c55f08) cannot connect to servers with idle compaction modes: it expects a boolean `compactIdleThreads`, receives a string, and repeatedly closes the config subscription. Reproduced with the unchanged historical web client against the real server at [2333f16884](https://git.cafe/pingdotgg/t3code/commit/2333f168845f853f9ef358d1c4e6cf75189f4e8b).

## Change

Keep `compactIdleThreads` boolean on the wire and carry the full mode in an additive `idleCompactionMode` field. Use that codec for config snapshots, config/settings updates and settings RPC responses. Accept legacy boolean settings patches while preserving the existing string storage model and string patches from current clients.

New clients decode boolean-only, string-only and additive server responses. Old clients cannot distinguish `off` from `onReturn`; explicitly writing their legacy `false` selects `onReturn`. New mode-string patches to old boolean-only servers remain unsupported, as before.

## Scope and approval

Fixes #23109
GitCafe: https://git.cafe/pingdotgg/t3code/issues/23109
Triaged bug via the automated issue flow: [#23109](https://git.cafe/pingdotgg/t3code/issues/23109). One protocol compatibility fix; no rendering, transport, authentication, permissions, provider or MCP changes. Label: `via-triage`. Dispatcher owns merging.

## Verification

Post-merge head [de75c79a56](https://git.cafe/pingdotgg/t3code/commit/de75c79a56bc5cc6b2e8da37e6c7be7ff5e612ee), with main merged via a merge commit:

- `packages/contracts`: `vp test run src/settings.test.ts src/server.test.ts src/rpc.test.ts` — 36 passed.
- `apps/server`: `vp test run src/serverSettings.test.ts src/ws.test.ts` — 52 passed.
- `packages/client-runtime`: `vp test run src/state/server.test.ts src/rpc/client.test.ts` — 27 passed.
- Contracts `tsc-rs --noEmit` — passed. Focused lint and formatting — passed; three existing lint warnings outside the changed lines.
- Implementation-step server typecheck passed; an independent review repeat timed out. Earlier web typecheck found two unrelated errors in `useChatShortcuts.browser.test.tsx`; not rerun here.
- Independent GPT-6.1 Sol and Claude Opus 5.5 reviews returned MERGE for the six-file fix.

Evidence: [index and empty visual fixture matrix](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/1f654c34d8ed211e/evidence-index.md). This changes server contracts, so proof is the red test plus the real runtime transcript; visual matrix is empty (0/0 rows). The screenshots below supplement the protocol proof and do not claim pixel or interaction coverage.

| Before: server [2333f16884](https://git.cafe/pingdotgg/t3code/commit/2333f168845f853f9ef358d1c4e6cf75189f4e8b) | After: server [ba8da1f771](https://git.cafe/pingdotgg/t3code/commit/ba8da1f771f4000163f2a026d809b51621bd4265) |
| --- | --- |
| [Runtime transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/579ad3a619e4d817/runtime-before.txt): old decoder rejects `"onReturn"`; WebSocket closes/retries; subscription interrupted. | [Runtime transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/0790c71d395b9562/runtime-after.txt): old decoder accepts `false` plus `"onReturn"`; workspace/composer opens and remains connected. |
| ![Before: old client stuck connecting](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/c423fa27708e70ba/browser-screenshot-localhost-mviodq1l-2fa804e2.png) | ![After: unchanged old client opens workspace](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/bc5bf2da9e46098c/browser-screenshot-localhost-mviop3f7-a4956427.png) |

Both captures use the unchanged historical web client, localhost port 7761 proxying server port 15527, isolated state, light theme, 1280×800. DPR and font scaling were not recorded. Runtime proof predates the clean main merge; the six-file fix diff is unchanged. Incidental differences: provider-update toast and git card appear after connecting. No UI code changes.

[Original red output](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/dc34a7cac8f61125/red.log): four behavior failures. These assertions initially targeted the storage schema and moved to the separate wire codec in the fix; final tests are not unchanged tests runnable against main, which lacks that export. Runtime before/after independently verifies the failure boundary.

Unverified: native desktop/Electron (`cannot-verify desktop`), mobile, real SSH/relay/tunnel connections and historical server binaries. Shared contract coverage does not claim native-client verification.

Models: Claude Opus 5.5 (implementation), GPT-6.1 Sol and Claude Opus 5.5 (reviews); Codex and Claude Code harnesses through T3 Code.


<!-- gc2-pull-create:648d56451ab67c79bd423615a197bc68ac048b3541a353cb6c0b8c8688e402e7 -->
