Skip to content

fix(desktop): localize expected errors - #4457

Open
orangeCatDeveloper wants to merge 8 commits into
apache:mainfrom
orangeCatDeveloper:fix/desktop-error-codes
Open

fix(desktop): localize expected errors#4457
orangeCatDeveloper wants to merge 8 commits into
apache:mainfrom
orangeCatDeveloper:fix/desktop-error-codes

Conversation

@orangeCatDeveloper

@orangeCatDeveloperorangeCatDeveloper commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Desktop surfaces rendered raw exception text as user-facing copy: a zh user hitting an expected failure saw an untranslated English error.message, and unexpected exceptions could leak internal details into toasts and error banners. Producers (guest-session mounts, Work Board IPC, WorkHub controller, the composer attachment pipeline) now return machine-readable codes — { code, params } where a message needs data — and the renderer maps codes through the locale catalogs. Expected failures throw a typed ExpectedOperationError; everything else logs a redacted diagnostic and shows a localized fallback. This also deletes WorkHub's English-message-regex classifier and the MAKA_SESSION_READ_MESSAGES_ERROR marker protocol.

Per review, the global error mapper is split: each domain maps its own code union at its presenter; the ExpectedOperationError transport and redacted diagnostics live once in the renderer's application/contracts/operation-diagnostics entry, now delegating to reportUnexpectedOperation/unexpectedOperationFallback in @maka/core/redaction so copy catalogs (bare-import-only) and the renderer share one diagnostics channel. They are Desktop-only, and hosting them in @maka/ui pulled the icon bundle into the main-process test bundles. The 11 attachment validations reject with stable attachment_ingest:<code> tokens that survive the Electron IPC wrapper, mapped at the shared localizedShellErrorMessage entry — both locales previously lost these reasons to a generic fallback. The Runtime's 8 session-control guards emit session_control_blocked:<code> tokens; today no in-repo caller reaches those guards (Desktop changes session settings through session.configuration.update, whose failures already carry protocol codes, and the CLI drives SessionManager only through the Runtime Host protocol), so the tokens stay as a typed, test-pinned contract for the future CLI-local path. A structured {ok, code} envelope for configuration setters and attachment failures is the follow-up.

The WorkHub waiting summary is a complete catalog message in each locale, independent of the separately displayed status and retry paragraphs. This preserves existing output while letting future translations choose their own sentence structure.

Refs #2672

Verification

Before (zh UI, stale Work Board write / import over mount limit — raw English internals):

Work Board item wb-01 revision changed from 1 to 3
At most 12 shared Sessions can be retained

After (same failures; raw detail now only in the redacted console diagnostic):

工作板内容已更新,请刷新后重试。
共享 Session 数量已达上限。
apps/desktop full dist suite: 2228 pass / 0 fail
packages/core tests: 829 pass / 0 fail
packages/runtime tests: 3246 pass (5 sandbox-only filesystem-worker failures, unrelated)
typecheck (4 tsconfigs): 0 errors
renderer architecture check: passes under the #4581 checker
repo format (biome): clean on all touched files

Rebase/review follow-up (2a7c11d6a) re-verified all of the above after moving the redacted unexpected-failure diagnostics into @maka/core/redaction (reportUnexpectedOperation / unexpectedOperationFallback) so the copy catalog and the renderer entry share one channel; operation-diagnostics keeps its public surface for its seven renderer importers and delegates to the core helper. No behavior change.

Review follow-up (575f10b39 + fe1190919): folded the duplicate attachmentIngestBlocked imports; extracted workBoardActionErrorText in work-board-panel.tsx (exported test seam) so the presentation test drives the panel's real code-to-copy branch instead of re-implementing it — a panel mis-map now fails the test. The copy catalog stays free of transport imports (copy catalogs may only hold bare package runtime imports), and the expected-code lookup lives in the catalog as workBoardErrorCodeCopy so the panel adds no dependency-debt edge. Re-verified against the PR base: desktop 2228/0, four typechecks 0 errors, renderer architecture ratchet (--base 411512bd9), biome clean.

Earlier follow-up verification still holds: all 122 WorkHub tests pass, including three-locale summary assertions that remain valid when the separate paragraph copy changes; all 101 architecture-checker tests pass. The branch base is the current main (411512bd9), so no prerequisite PRs remain; the draft blocker (#4493 checker policy) landed on 2026-09-02.

AI use

Select exactly one:

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

Tool(s) and scope: Claude Code — analysis, implementation, tests, and this description, under the contributor's direction; the commit carries a Generated-by: Claude Code trailer.

OpenCode implemented the complete waiting-summary catalog messages and added output tests; its follow-up commit carries Generated-by: OpenCode. Claude Code landed the rebase/review follow-up (2a7c11d6a: single diagnostics channel in @maka/core/redaction, operation-diagnostics delegating), verified the branch against current main, and updated this description.

Checklist

  • Tests cover the change and fail without it

@orangeCatDeveloper

Copy link
Copy Markdown
ContributorAuthor

Converting to draft: blocked on the copy-gate/architecture-ratchet collision described in #2672 (comment)#4493 resolves the checker policy; this branch then rebases (and splits the global error mapper per review). Will mark ready once green.

@orangeCatDeveloper
orangeCatDeveloperforce-pushed the fix/desktop-error-codes branch 2 times, most recently from adf4f4a to 6b28e30CompareSeptember 2, 2026 08:40
Astro-Han pushed a commit that referenced this pull request Sep 2, 2026
…cture ratchet (#4493)
Two repository gates deadlocked. The locale policy (#2672) moves user-visible copy out of business files into src/renderer/locales/*-copy.ts catalogs, which adds an import edge; the renderer architecture ratchet forbids legacy files from growing their dependency count and rejects new AppShell-closure entries. #4457 failed CI on exactly that collision, and no placement of a catalog could satisfy both gates.
Admit one dependency class instead of loosening the ratchet: a validated copy catalog, recognized structurally and re-verified on every run, never grandfathered. It must live under src/renderer/locales/*-copy.ts, carry the UiCatalog marker from @maka/core/ui-locale, have zero tracked capabilities by the checker's own metrics, and import bare package specifiers only, so it can never become a tunnel to renderer implementation. Admitted edges are excluded from the dependency-count ratchets and closure admission, and the ledger drops 26 budget entries that only existed for catalog imports. Root-entry files get no discount, and a catalog that grows a hook or a relative import loses admission immediately.
The environment-capability predicate now counts identifiers only in value-reference positions, so a copy key named history or a parameter named location no longer reads as a browser global, and type-only imports and exports are not counted as runtime dependencies. Adversarial fixtures cover hook smuggling, implementation-import smuggling, a missing marker, dynamic imports and an unrelated dependency added beside a valid catalog.
Part of #2672.
Generated-by: Codex
@orangeCatDeveloper
orangeCatDeveloperforce-pushed the fix/desktop-error-codes branch 4 times, most recently from 13b0d58 to ad06382CompareSeptember 2, 2026 18:13
@github-actionsgithub-actionsBot added effort/XL Under 2500 readable lines and removed effort/L Under 1000 readable lines labels Sep 3, 2026
@orangeCatDeveloper
orangeCatDeveloperforce-pushed the fix/desktop-error-codes branch 12 times, most recently from 9050c08 to 47537fdCompareSeptember 5, 2026 04:24
@orangeCatDeveloper
orangeCatDeveloperforce-pushed the fix/desktop-error-codes branch 3 times, most recently from 6d7be43 to 429a206CompareSeptember 5, 2026 12:16
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
Move the redacted unexpected-failure diagnostics into
@maka/core/redaction as reportUnexpectedOperation /
unexpectedOperationFallback: copy catalogs may only hold bare package
runtime imports, so shell-copy inlined the channel; the core helper
removes the inline copy and lets operation-diagnostics delegate, keeping
its public surface for the seven renderer importers.
No behavior change: the same redacted console.error line, same fallbacks.
Generated-by: Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
@orangeCatDeveloper
orangeCatDeveloper marked this pull request as ready for review September 5, 2026 23:18
Code review follow-ups on the expected-errors PR:
- Fold the duplicate attachmentIngestBlocked imports in
attachment-ingest.ts and attachment-ingest-payload.ts into the
existing @maka/core/attachments import.
- Extract workBoardActionErrorText in work-board-panel.tsx (module-level,
exported as a test seam): runAction and the presentation test now drive
the exact same code-to-copy branch, so a panel mis-map fails the test
instead of the test asserting its own re-implemented ternary. The
expected-code lookup uses lookupCopy, so unknown/inherited keys keep
the caller fallback.
- The copy catalog stays import-free (copy catalogs may only hold bare
package runtime imports), keeping the transport concern at the panel.
Generated-by: Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
CI ratchet flagged the new @maka/core/ui-locale edge on
work-board-panel.tsx as dependency debt (7 -> 8). Move the expected-code
lookup into work-board-error-copy.ts as workBoardErrorCodeCopy: a
validated copy catalog's bare-package runtime imports are exempt from
pricing, so the panel sheds the new edge and the catalog's existing
lookupCopy import becomes live again.
No behavior change; the panel's workBoardActionErrorText keeps the same
branch shape over the catalog helper.
Generated-by: Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>

@hqhq1025hqhq1025 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head fe1190919fdd6ca246c4ca91ac8c423c184bd440.

This change replaces raw Desktop error text with localized copy and structured error handling across attachment ingestion, guest mounts, Work Board, collaboration, WorkHub, and Plan Mode. I found one P2 and one P3, so I do not think this head is ready to merge yet.

Validation: clean install; build:test; Desktop 2228/2228, Core 829/829, Runtime 3238 passed / 13 skipped; full Desktop typecheck; renderer architecture 101/101 including the base-relative gate; lint, format, ASF headers, diff check; Storybook build; and a clean patch-preserving merge onto current main 411512bd9. Full Storybook smoke had one product-sidebar-session-list--project-groups focus failure that reproduced on the exact base, while the base-only loading-catalog failure passed on this head. Hosted test and package were still running at publication. Native macOS/Windows behavior was not run locally.

Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.

await refresh();
} catch (cause) {
setError(message(cause));
reportUnexpectedError('plan-mode:action', cause);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Preserve the Runtime Host plan error code here instead of classifying every rejection as unexpected. plan.control and plan.turn.start legitimately return stable codes such as session_busy and operation_conflict (for an active root Turn or a stale proposal/store version), but the IPC path currently rejects and this catch logs the cause as unexpected and renders only operationFailed. A user who needs to wait or refresh therefore gets an unactionable “try again later” message. Please carry/map the structured code through the Desktop boundary and keep this generic path for genuinely unknown failures; the new test currently pins only the generic copy.

// The reason token survives the Electron IPC wrapper.
const blocked = lookupCopy(
maps.attachmentIngestBlocked,
message.match(/attachment_ingest:([a-z_]+)/u)?.[1],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: This matcher is used by the global shell error presenter, not only attachment ingestion, and it accepts the marker anywhere in arbitrary error text. For example, new Error("Unable to open /tmp/attachment_ingest:count_limit/report.txt") is rendered as “At most 8 attachments per message” and skips unexpected-error diagnostics. Please recognize an exact IPC envelope/token (or use a structured error) and add a negative test for unrelated messages containing the substring.

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.

2 participants

@orangeCatDeveloper@hqhq1025