Skip to content

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

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

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

Conversation

@orangeCatDeveloper

@orangeCatDeveloper orangeCatDeveloper commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

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.

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 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 }, narrowed to the four codes a user can act on; unexpected failures still throw. Attachment validation raises a typed AttachmentIngestBlockedError, which preload and main turn into the submitMessage / send envelope's new attachment_blocked variant. The renderer 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. In the Runtime, the session-configuration guards throw a typed SessionConfigurationTransitionError instead of Chinese sentences.

AttachmentIngestBlockedError carries its code twice on purpose: as a field for consumers in the same process, and inside its message as the stable attachment_ingest:<code> token for anything on the far side of the IPC boundary, which drops custom Error fields. So the presenter reads the typed code where the throw is local and never parses a string.

Boundaries: the protocol is untouched, so there is no Host version skew. The plan-mode write in app-shell goes through the session-settings port rather than window.maka directly, which keeps the root-file ratchet flat.

Refs #2672

Verification

apps/desktop full dist suite        2485 pass / 0 fail
apps/desktop typecheck (4)          0 errors
renderer architecture ratchet       passes against the base, no token growth
npm run format:check                clean
protocol epoch guard                no protocol changes

Before, a session_busy answer reached the toast as the locale fallback. After:

sessionSettingFailureCopy('zh-CN', 'permission', new ExpectedOperationError('session_busy')).description
当前任务正在运行或有交互待处理,等结束后再改设置。

sessionSettingFailureCopy('en', 'permission', new ExpectedOperationError('session_busy')).description
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 and the main/preload/renderer changes, the catalog copy, the tests, the rebase onto current main after #4457 merged, and this description. The decision to leave the protocol untouched and the copy wording were reviewed by hand.

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-actions github-actions Bot added the effort/XL Under 2500 readable lines label Sep 5, 2026
@orangeCatDeveloper
orangeCatDeveloper force-pushed the fix/ipc-expected-failure-envelope branch 5 times, most recently from 3af86a4 to 8aaadc1 Compare September 6, 2026 21:32
@github-actions github-actions Bot added effort/XXL Over 2500 readable lines and removed effort/XL Under 2500 readable lines labels Sep 7, 2026
@orangeCatDeveloper
orangeCatDeveloper force-pushed the fix/ipc-expected-failure-envelope branch from b473c45 to b98a8d3 Compare September 8, 2026 20:00
Expected failures now cross the process boundary as machine-readable
codes rather than prose the renderer has to parse. Attachment rejections
carry a typed AttachmentIngestBlockedError whose message keeps the
stable token, since Electron drops custom Error fields; the preload and
session-settings surfaces throw ExpectedOperationError; and the
Runtime's session-configuration guards throw typed transition errors
instead of Chinese sentences. The renderer maps the codes through the
updateFailures catalog in each locale.

Generated-by: Claude Code
Generated-by: OpenCode
@orangeCatDeveloper
orangeCatDeveloper force-pushed the fix/ipc-expected-failure-envelope branch from b98a8d3 to ba1495e Compare September 8, 2026 21:08
@github-actions github-actions Bot added effort/L Under 1000 readable lines and removed effort/XXL Over 2500 readable lines labels Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/L Under 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant