Skip to content

fix(desktop): return expected failures as codes across IPC - #4878

Draft
orangeCatDeveloper wants to merge 6 commits into
apache:mainfrom
orangeCatDeveloper:fix/ipc-expected-failure-envelope
Draft

fix(desktop): return expected failures as codes across IPC#4878
orangeCatDeveloper wants to merge 6 commits into
apache:mainfrom
orangeCatDeveloper:fix/ipc-expected-failure-envelope

Conversation

@orangeCatDeveloper

Copy link
Copy Markdown
Contributor

Summary

Stacked on #4457; review the last commit.

Changing a task's permission mode, plan mode, orchestration, or model while it is busy shows the generic "cannot change right now" toast in every locale, and an attachment that fails validation is reported by parsing an attachment_ingest:<code> token out of the error text.

Root cause: both Desktop serialization boundaries keep only Error.message. The Runtime Host already answers session.configuration.update with a structured code (session_busy, operation_conflict, …) and the Desktop client surfaces it as RuntimeHostOperationError.code, but the main-process IPC handler rethrows, so Electron hands the renderer Error invoking remote method 'sessions:setPermissionMode': Error: Session has a pending Interaction and the presenter can only fall back.

The fix moves expected failures into return values. The five session-setting handlers answer { ok: true, session } | { ok: false, code }, where code is the Host's own code narrowed to the four a user can act on; unexpected failures still throw. Attachment validation raises a typed AttachmentIngestBlockedError that preload and main turn into the submitMessage / send envelope's new attachment_blocked variant. On the renderer side the platform adapters unwrap a failed envelope into ExpectedOperationError(code), so the existing intent hook and sessionSettingFailureCopy keep their shape and map the code through a new updateFailures catalog. localizedShellErrorMessage no longer parses any token.

Boundaries: the protocol is untouched, so there is no Host version skew. The Runtime's session_control_blocked tokens stay for the CLI's local runtime, which is their only consumer. The plan-mode write in app-shell now goes through the session-settings port rather than window.maka directly, which is what keeps the root-file ratchet flat.

Refs #2672

Verification

apps/desktop typecheck (4 tsconfigs) 0 errors
renderer architecture check passed against 411512bd9 (app-shell tokens 15584 -> 15580, chat-actions 4086 -> 4080)
desktop main tests (dist) 2164 pass / 6 fail (the 6 are browser-message-box + runtime-host-client-uds, red on the base commit too)
format:check / biome lint clean

Rendered-output assertions in expected-error-presentation.test.ts:

✔ session setting failures map expected update codes per locale
✔ unexpected setting failures keep the caller fallback

Before, a session_busy answer reached the toast as the locale fallback; after, sessionSettingFailureCopy('zh-CN', 'permission', new ExpectedOperationError('session_busy')).description renders 当前任务正在运行或有交互待处理,等结束后再改设置。 and the en catalog renders A task is running or waiting on you. Change this setting after it settles.

Not run: Electron e2e, packaged build.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code traced the failure path, wrote the envelope types, the main/preload/renderer changes, the catalog copy, and the tests; the design decision to keep the protocol untouched and the copy wording were reviewed by hand. The commit carries Generated-by: Claude Code.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@github-actionsgithub-actionsBot added the effort/XL Under 2500 readable lines label Sep 5, 2026
Raw exception text no longer reaches the UI: expected failures carry
machine-readable codes (with params where needed) that the renderer maps
through locale catalogs, and unexpected failures show a localized
fallback while redacted diagnostics go to the console. WorkHub waiting
summaries are full per-locale templates so they translate independently
of the status and retry paragraphs.
Generated-by: Claude Code
Claude-Session: https://claude.ai/code/session_01AqdSkg56F2x55wEGRWvzcB
Keep message-free WebSearch failures valid at the canonical result boundary so settlement cannot mark them successful. Retain redacted Work Board corruption details without exposing them in product copy.
Generated-by: OpenCode
The session-control and attachment-ingest code unions lived in the
renderer catalog while the Runtime and preload threw string literals,
so a new producer code could miss the catalog without a type error.
Generated-by: Claude Code
Desktop changes session settings through the Runtime Host's
session.configuration.update, whose failures already carry protocol
codes; the SessionManager guards that emit session_control_blocked
tokens run only on the CLI's local runtime.
Generated-by: Claude Code
Session-setting writes and attachment ingest reported expected failures
by throwing, and Electron keeps only the message across both IPC
boundaries, so the renderer either parsed a token out of the text or
fell back to generic copy. The setters now answer with an update
envelope carrying the Runtime Host's own error code, attachment
validation failures ride the existing submit envelope, and the renderer
adapters turn a failed envelope into ExpectedOperationError for the
presenters.
Generated-by: Claude Code
@orangeCatDeveloper
orangeCatDeveloperforce-pushed the fix/ipc-expected-failure-envelope branch from 3e17d5b to 5ac47d9CompareSeptember 6, 2026 02:46
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/XLUnder 2500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@orangeCatDeveloper