[GH-ISSUE #5056] [Bug] Native UI owned deadlines are misreported as caller cancellation #3100

Closed
opened 2026-10-31 00:36:39 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Oct 18, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5056

Observed behavior

Native UI's owned 180-second deadline is reported as AnalysisCancelledError, including when it expires during final cleanup. This conflates an operation timeout with explicit caller cancellation.

Reproduction and evidence

On main 9e259f87c8be3d22a0b96f12ed7838830869c987, ran tests/boundary/providers/native/nativeUiFinalization.test.ts with the two deadline expectations corrected to AnalysisTimeoutError. Both deadline cases fail (cleanup succeeds and cleanup fails): expected timeout, received cancellation; the other nine cases pass. Executed under Node 24.18.0 on macOS arm64 with controlled runtime/helper fixtures. No GUI app, OS permission change or real helper execution.

Root cause and expected behavior

NativeUiObservation and NativeMacOSProvider independently compose caller and runtime signals and reconstruct interruption from signal.aborted. The combined signal retains the reason but loses its source. A reason's name or identity cannot identify that source: a caller may supply a TimeoutError or both sources may share one reason object.

Record the first observed source once at the operation owner, share that fact through helper execution, scenario waits and final cleanup, and distinguish AnalysisTimeoutError from caller cancellation. Preserve exact causes, partial reports, independent producer failures and failed cleanup ownership. Dispose listeners even when cleanup fails. Consolidate scenario failures through the existing typed result path.

Validation and limitations

The candidate passes the same 11 finalization cases plus focused source checks covering helper/wait deadlines, identical reason aliases, caller TimeoutError-shaped reasons and physical/schema failure precedence. Native UI plus LLDB selected checks: 68 passed, two existing large allocation cases skipped. DeepWiki and Context7 were consulted for Node signal semantics. Real GUI/provider behavior, platform coverage and whole-agent costs: NOT_ENOUGH_INFO. No performance improvement claimed.

Searched open/closed native UI deadline issues; no matching defect found. Related lifecycle tracker: #4227.

Originally created by @morluto on GitHub (Oct 18, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5056 ### Observed behavior Native UI's owned 180-second deadline is reported as `AnalysisCancelledError`, including when it expires during final cleanup. This conflates an operation timeout with explicit caller cancellation. ### Reproduction and evidence On main `9e259f87c8be3d22a0b96f12ed7838830869c987`, ran `tests/boundary/providers/native/nativeUiFinalization.test.ts` with the two deadline expectations corrected to `AnalysisTimeoutError`. Both deadline cases fail (cleanup succeeds and cleanup fails): expected timeout, received cancellation; the other nine cases pass. Executed under Node 24.18.0 on macOS arm64 with controlled runtime/helper fixtures. No GUI app, OS permission change or real helper execution. ### Root cause and expected behavior `NativeUiObservation` and `NativeMacOSProvider` independently compose caller and runtime signals and reconstruct interruption from `signal.aborted`. The combined signal retains the reason but loses its source. A reason's name or identity cannot identify that source: a caller may supply a TimeoutError or both sources may share one reason object. Record the first observed source once at the operation owner, share that fact through helper execution, scenario waits and final cleanup, and distinguish `AnalysisTimeoutError` from caller cancellation. Preserve exact causes, partial reports, independent producer failures and failed cleanup ownership. Dispose listeners even when cleanup fails. Consolidate scenario failures through the existing typed result path. ### Validation and limitations The candidate passes the same 11 finalization cases plus focused source checks covering helper/wait deadlines, identical reason aliases, caller TimeoutError-shaped reasons and physical/schema failure precedence. Native UI plus LLDB selected checks: 68 passed, two existing large allocation cases skipped. DeepWiki and Context7 were consulted for Node signal semantics. Real GUI/provider behavior, platform coverage and whole-agent costs: NOT_ENOUGH_INFO. No performance improvement claimed. ### Related search Searched open/closed native UI deadline issues; no matching defect found. Related lifecycle tracker: #4227.
Author
Owner

@morluto commented on GitHub (Oct 18, 2026):

Fixed on main in 36d156ff0. Root cause: independently composed signals lost caller-versus-deadline identity, and several downstream branches inferred cancellation from ambient state. A shared operation control records the first source and exact cause through execution, scenario waits and final cleanup. Scenario failure projection is consolidated; independently observed helper/schema failures stay primary. Listener disposal now runs in finally, including failed cleanup, while failed runtime cleanup ownership remains retained for retry.

Validation: the unchanged-main finalization baseline failed both deadline expectations (nine controls passed); the candidate passes all 11 finalization cases and additional source controls for helper/wait deadlines, shared reason aliases, caller TimeoutError-shaped reasons and late-deadline failure precedence. Combined native selection: 68 passed / two existing large allocation cases skipped, five files. Full npm run check, independent review and pre-push checks passed. Controlled runtime/helpers only; real GUI/provider/platform qualification remains unrun. Completed controlled capture warm medians: reply estimate 261 → 261 tokens, elapsed 0.07208 → 0.07206 s, CPU 0.07027 → 0.06958 s, sampled family RSS 77.3 → 79.0 MB. Two warm repeats/build plus separate first processes; no true cold-cache or performance claim. Whole-agent and real helper costs unmeasured. No directly related structural cleanup remains identified by this review.

<!-- gh-comment-id:6253063329 --> @morluto commented on GitHub (Oct 18, 2026): Fixed on main in 36d156ff0. Root cause: independently composed signals lost caller-versus-deadline identity, and several downstream branches inferred cancellation from ambient state. A shared operation control records the first source and exact cause through execution, scenario waits and final cleanup. Scenario failure projection is consolidated; independently observed helper/schema failures stay primary. Listener disposal now runs in `finally`, including failed cleanup, while failed runtime cleanup ownership remains retained for retry. Validation: the unchanged-main finalization baseline failed both deadline expectations (nine controls passed); the candidate passes all 11 finalization cases and additional source controls for helper/wait deadlines, shared reason aliases, caller TimeoutError-shaped reasons and late-deadline failure precedence. Combined native selection: 68 passed / two existing large allocation cases skipped, five files. Full `npm run check`, independent review and pre-push checks passed. Controlled runtime/helpers only; real GUI/provider/platform qualification remains unrun. Completed controlled capture warm medians: reply estimate 261 → 261 tokens, elapsed 0.07208 → 0.07206 s, CPU 0.07027 → 0.06958 s, sampled family RSS 77.3 → 79.0 MB. Two warm repeats/build plus separate first processes; no true cold-cache or performance claim. Whole-agent and real helper costs unmeasured. No directly related structural cleanup remains identified by this review.
Author
Owner

@gensokyo-dev commented on GitHub (Oct 18, 2026):

Clean-main consumer follow-up: tests/boundary/mcp/nativeUiFinalizationMcp.test.ts still expects the previous cancellation semantics after 36d156ff05f48f9f0b4c4abb8f7c899249a49ebf.

Reproduced both failures once in a clean detached worktree at that main revision, Node 24.18.0/Linux x64, with the locked dependency graph and no source/test edits:

npm --prefix <clean-main-worktree> run test:run -- tests/boundary/mcp/nativeUiFinalizationMcp.test.ts

The successful-close case expects cancelled plus cleanup: complete, but receives provider_timeout without that cleanup field. The failed-close case correctly receives cleanup_incomplete, while its diagnostics.primary_error.code is now provider_timeout rather than the expected cancelled. Both retain the partial observation. The provider-boundary deadline expectations were updated in 36d156ff; this MCP consumer was unchanged.

This is also the two-assertion failure blocking unrelated #4954: exact CI job. The baseline reproduces without that PR. These are production-handler/in-memory MCP checks with a simulated native helper, not real macOS UI verification. The observed failure is consumer expectation drift; I have not changed native UI code or CI gates in #4954.

<!-- gh-comment-id:6253321197 --> @gensokyo-dev commented on GitHub (Oct 18, 2026): Clean-main consumer follow-up: `tests/boundary/mcp/nativeUiFinalizationMcp.test.ts` still expects the previous cancellation semantics after `36d156ff05f48f9f0b4c4abb8f7c899249a49ebf`. Reproduced both failures once in a clean detached worktree at that main revision, Node 24.18.0/Linux x64, with the locked dependency graph and no source/test edits: ```sh npm --prefix <clean-main-worktree> run test:run -- tests/boundary/mcp/nativeUiFinalizationMcp.test.ts ``` The successful-close case expects `cancelled` plus `cleanup: complete`, but receives `provider_timeout` without that cleanup field. The failed-close case correctly receives `cleanup_incomplete`, while its `diagnostics.primary_error.code` is now `provider_timeout` rather than the expected `cancelled`. Both retain the partial observation. The provider-boundary deadline expectations were updated in 36d156ff; this MCP consumer was unchanged. This is also the two-assertion failure blocking unrelated #4954: [exact CI job](https://github.com/morluto/rea/actions/runs/39151389956/job/117746235965). The baseline reproduces without that PR. These are production-handler/in-memory MCP checks with a simulated native helper, not real macOS UI verification. The observed failure is consumer expectation drift; I have not changed native UI code or CI gates in #4954.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3100
No description provided.