Fix localized Inbox pause recovery / 修复收件箱暂停恢复与本地化 - #8270
Merged
SivanCola merged 10 commits intoAug 11, 2026
Conversation
Problem: - Paused Inbox actions surfaced raw English backend errors in localized desktop sessions. - Non-recovered paused queues had no actionable recovery surface and could still attempt guidance admission. Root cause: - Wails transported product-state text instead of stable identifiers, and the Composer rendered Error.message directly. - Pause state was only propagated for recovered Inbox snapshots. Fix: - Encode known Inbox states as stable error codes while preserving Go error unwrapping and unknown diagnostics. - Localize current and legacy error forms in English, Simplified Chinese, and Traditional Chinese. - Propagate pause state, disable guidance admission, and expose resume controls for ordinary paused queues. Verification: - cd desktop && go test ./... -count=1 - Inbox localization tests: 18 passed - Inbox recovery interaction tests: 13 passed - cd desktop/frontend && pnpm build - Verified the zh-CN pause and resume flow in a real browser
Problem: - Inbox cancellation failures exposed English context or stable transport codes in localized sessions. - PR checks were blocked by errorlint and ratcheted source-file budgets. Root cause: - The controller cancellation path bypassed the shared Inbox error formatter. - An intentional error identity assertion lacked a scoped errorlint explanation, while added lines exceeded existing budgets. Fix: - Localize cancellation context and nested Inbox errors while preserving unknown diagnostics. - Add formatter and controller regression coverage. - Keep source budgets unchanged and document the intentional identity assertion. Verification: - go run ./tools/repolint - cd desktop && go test ./... -count=1 - cd desktop && golangci-lint run --timeout=5m ./... - cd desktop/frontend && pnpm build - Inbox localization, cancellation reconciliation, and recovery regression tests
Problem: Durable in-flight guidance could outlive Controller ownership and become an immutable zombie item while the UI kept offering invalid operations. Root cause: Same-process snapshots had no ownership reconciliation, and durable claim/active/ack transitions were not serialized against recovery. The guidance shelf also treated every persisted state like a queued item. Fix: Recover unowned in-flight records to paused, reviewable uncertain state; serialize the full ownership lifecycle; and expose state-aware disabled or retry actions with localized labels. Verification: - go test ./... - go test -race ./internal/control ./internal/sessioninbox - cd desktop && go test . -run Inbox\|Steer - cd desktop/frontend && pnpm test:typecheck && pnpm test && pnpm build - make lint - real Chromium recovery/retry interaction in zh-CN Fixes esengine#8276
Problem: A recovered item could start as a new turn on retry and then reject a stale frontend steer. Completion also held the inbox admission lock across transcript snapshot I/O. Root cause: The steer idempotency path omitted the running state, and completion removed active ownership before persistence, requiring broad serialization. Fix: Treat Controller-owned running items as already admitted. Keep active IDs published while snapshotting and hold admission exclusion only for durable acknowledgement and ownership removal. Verification: - go test ./... - go test -race ./internal/control ./internal/sessioninbox - cd desktop && go test ./... - frontend typecheck, focused Inbox tests, and production build - make lint
Problem: Inbox snapshots and turn completion held admissionMu while waiting on session inbox disk transactions, allowing bounded file-lock waits and per-item acknowledgement loops to block admission. Root cause: Recovery consumed a stale active-ID snapshot, so a broad Controller lock bridged the durable claim-to-ownership and ownership-to-ack windows. Fix: Track admitting and active ownership in lock-free registries that Store recovery consults after refreshing its transaction. Keep ownership published through durable acknowledgement, and remove admission locking from snapshot and completion I/O. Verification: - go test -race -count=1 ./internal/control ./internal/sessioninbox - go test ./... - cd desktop && go test ./... - go vet ./... - make lint - frontend typecheck, Inbox focused tests, and production build
Problem: Queued guidance could remain idle after rotation, a rejected steer, a transient dispatch failure, or the previous durable turn completing. The desktop fallback also disabled the queued action while idle. Root cause: Inbox dispatch used a one-shot edge guard, so kicks that arrived during a scan or a closed admission gate could be lost. Several gate-release paths did not publish a new kick, and the frontend exposed no FIFO-safe recovery action. Fix: Use a level-triggered drain with bounded retry, re-kick after rotation and rejected steering, and expose an idle head-item Send action that reuses the idempotent resume/drain path. Keep later items disabled to preserve FIFO ordering and localize the new states. Verification: - go test -race ./... - go test -race ./internal/control -count=1 - focused inbox race tests with -count=10 - pnpm test:typecheck - pnpm lint:hooks - pnpm build - composer-inbox-recovery.test.tsx
Problem: The Linux and Windows desktop jobs failed the raw initial asset budget after the inbox recovery UI landed, even though every compressed startup and chunk budget remained green. Root cause: The new localized recovery controls add 2.7 KiB to the current main-v2 raw initial bundle beyond its 2246 KiB allowance. Fix: Raise only the raw aggregate allowance to 2249 KiB and document the durable inbox recovery contract. This leaves roughly 0.3 KiB of headroom while preserving all gzip, CSS, locale, and largest-chunk limits. Verification: - wails generate module - pnpm --dir frontend build - pnpm --dir frontend check:bundle - pnpm --dir frontend test - go test -race ./... (root and desktop modules)
Problem: Repository lint rejected the queue liveness patch because it expanded two baselined legacy files and pushed TrySteerInboxItem five lines over the function limit. Root cause: The drain kick and idle recovery details lived inline in already oversized controller and Composer functions. Fix: Move the idle UI kick into composerGuidance, colocate rotation release with inbox dispatch, and extract steer-admission unlock handling. This restores every existing file/function budget without adding lint baselines. Verification: - go run ./tools/repolint - focused inbox race tests with -count=10 - pnpm lint:hooks - pnpm test:typecheck - composer-inbox-recovery.test.tsx
Problem: PR esengine#8270 no longer merged after main-v2 added startup config-warning bundle growth. Root cause: both changes updated the same raw startup bundle ratchet from an older shared baseline. Fix: merge the current main-v2, preserve both feature ownership notes, and set the tight 2251 KiB limit measured from the 2250.4 KiB merged artifact. Verification: go test ./...; go test -race ./internal/control ./internal/sessioninbox; cd desktop && go test -race ./...; frontend pnpm test:all; frontend pnpm build; go vet for both modules; repolint.
SivanCola
added a commit
to SivanCola/DeepSeek-Reasonix
that referenced
this pull request
Aug 11, 2026
Problem: - main-v2 advanced with esengine#8270 and esengine#8340 while the catalog integration was under review. - Both branches changed the controller frontend and startup bundle budgets. Root cause: - The inbox recovery localization and opt-in task-spend defaults overlapped the catalog hydration guards and measured frontend budget ratchets. Fix: - Preserve the history hydration identity/error fences alongside locale-aware inbox recovery. - Keep the latest task-spend defaults and use measured startup bundle budgets without widening the repolint baseline. Verification: - env REASONIX_RELEASE_CACHE_GUARD=1 go test -count=1 ./... - env REASONIX_RELEASE_CACHE_GUARD=1 go test -race -count=1 ./... - cd desktop && go test -count=1 ./... - cd desktop && go test -race -count=1 ./... - cd desktop/frontend && pnpm test:all && pnpm build && pnpm test:motion - go vet ./... and pinned golangci-lint for native and cross-platform build tags - CGO_ENABLED=0 root/Desktop builds for darwin amd64/arm64, windows amd64/arm64, and linux amd64 - Wails binding generation, repolint, release workflow contracts, SDK ordinary/race tests, and go mod tidy -diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
uncertainandblockeditems have an explicit retry pathFixes #8276.
User-visible behavior
Chinese desktop sessions now show
收件箱已暂停instead of the raw backend textinbox is paused. Capacity, invalid-state, read-only, and workspace-startup errors on the same Inbox path are localized as well.If an accepted/running guidance item loses its live Controller owner, the next snapshot safely pauses the Inbox and changes the item to
uncertain. The user can review it, continue, then retry or delete it. Guidance that is still actively owned cannot be sent or deleted again, and the UI explains that it is already being applied.Root cause
Known Inbox states crossed the Wails boundary as English
error.Error()text, and Composer toast paths rendered that text directly. The frontend also propagated pause state only for recovered snapshots, so an ordinary paused queue could still expose the guidance action without a resume surface.For #8276, the normal rejected-steer path already rolls
steer_acceptedback toqueued; the durable failure window was instead same-process ownership loss. Persistedrunning/steer_accepted/steer_consumedrecords were only recovered across process restarts. A live process could therefore retain an in-flight record after its Controller owner disappeared, while the shelf continued presenting queued-item actions. Claim-to-owner and owner-to-ack boundaries also needed serialization against snapshot recovery.Changes
reasonix_error:<code>values while preserving Go error unwrappinguncertain, with a fast no-candidate path that keeps ordinary snapshots lightweightuncertain/blockeditemsVerification
go test ./...go test -race ./internal/control ./internal/sessioninboxcd desktop && go test . -run 'Inbox|Steer' -count=1cd desktop/frontend && pnpm test:typecheck && pnpm testcd desktop/frontend && pnpm build(typecheck, hooks lint, CSS/WAAPI checks, Vite build, bundle budgets)make lintzh-CN: retry is disabled while paused, enabled after继续执行, carries the accessible name重试这条引导, and clicks successfullyTwo unrelated desktop full-suite tests each failed once due existing temporary/global-state flakiness (
TestApplyLinuxVersionedActivatesWithoutPersistingGuardandTestRemoveWorkspaceClearsActivePointerWhenRemovingCurrentWorkspace); each passed 10 consecutive focused reruns. The desktop Inbox/Steer integration set passed.Compatibility and risk
uncertain, paused, retry, and delete contractsuncertainitems; new frontends use the already-existingRetryInboxItembridge methodDocumentation-impact: none - Existing Inbox documentation remains correct; this change localizes runtime errors and makes existing recovery semantics reachable for same-process orphaned items.