[GH-ISSUE #4700] [Bug] Kuna shared query waits discard caller cancellation reasons #2453

Closed
opened 2026-10-17 21:04:52 +00:00 by bsakaguchi · 4 comments
Owner

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

Before submitting

  • Searched open and closed issues for Kuna cancellation reasons. #4698 is installation acquisition; #4689 is operation attribution; #4693 is cleanup projection.
  • No credentials or sensitive target data included.

Area

Native analysis or decompilation

Observed behavior

A compiled KunaQueryWork boundary probe loses exact caller abort reasons for both a departing peer and the final waiter. Both return AnalysisCancelledError with cause undefined. The final wait also calls the producer controller's abort without forwarding the final caller's reason.

Reproduction

Ran against compiled source corresponding to 988494abd (Darwin arm64, Node 24.18.0):

  1. Construct KunaQueryWork with a session AbortController, identity ownership callback, and inert command/run-slot arguments (not invoked).
  2. Start a pending load that records its producer signal and returns a typed cancellation when that signal aborts.
  3. Attach two waits; abort the first with a selected object. Its result has an undefined cause; the producer remains active for the peer.
  4. Abort the final waiter with a selected string. Its result also has an undefined cause; producer signal.reason differs from that string.

One reduced probe performed; no native process/resource, target, CLI or MCP request. Retained local probe output records exactReason=false/causeOmitted=true for both waiters, producerReceivedLastReason=false, and cleanupIncomplete=false.

Expected behavior

Preserve the caller's exact AbortSignal.reason as the typed cancellation cause, including null/object/error values, without interpreting it as cleanup authority. Forward the final departing caller's reason to its owned producer while joining cleanup; preserve authored physical failures and any retained cleanup capability. This follows docs/tool-design.md#own-the-lifecycle.

Impact and scope

Confirmed at the compiled shared-wait boundary only. Source consumers include string and reference query workflows. End-to-end CLI/MCP projection, actual command shutdown and real Kuna/Windows effects are unverified. Similar reasonless cancellation constructors/controller.abort calls exist in the single-function waiter path; that is source evidence, not a runtime reproduction.

REA version

988494abd (package 6.5.0).

Runtime and platform

Darwin arm64 / Node 24.18.0; real Kuna not invoked.

Target and artifact context

Not applicable: typed shared-wait boundary probe, no target artifact.

Interface

Other — shared provider workflow boundary.

Earliest failure stage

Cleanup, cancellation, or lifecycle.

Relevant output or evidence

{"first":{"type":"AnalysisCancelledError","exactReason":false,"causeOmitted":true,"cleanupIncomplete":false},"last":{"type":"AnalysisCancelledError","exactReason":false,"causeOmitted":true,"cleanupIncomplete":false},"producerReceivedLastReason":false}

Analysis or suspected cause

Confirmed constructor/forwarding omissions. Repair the shared command owner's representation and affected consumers together; downstream error remapping cannot recover a discarded reason. The existing SharedStartupAttempt demonstrates explicit independent waits and final-departure cleanup, but query cache semantics must be reviewed before reuse.

Additional context

Heavy profiling and stress remain stopped. Proposed checks: exact null/string/foreign-error reasons, peer retention, final departure, mixed physical/cleanup failures, cleanup retry, and cancellation during finalization. None of those broader runtime checks are claimed by this minimal probe.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4700 ### Before submitting - [x] Searched open and closed issues for Kuna cancellation reasons. #4698 is installation acquisition; #4689 is operation attribution; #4693 is cleanup projection. - [x] No credentials or sensitive target data included. ### Area Native analysis or decompilation ### Observed behavior A compiled KunaQueryWork boundary probe loses exact caller abort reasons for both a departing peer and the final waiter. Both return AnalysisCancelledError with cause undefined. The final wait also calls the producer controller's abort without forwarding the final caller's reason. ### Reproduction Ran against compiled source corresponding to 988494abd (Darwin arm64, Node 24.18.0): 1. Construct KunaQueryWork with a session AbortController, identity ownership callback, and inert command/run-slot arguments (not invoked). 2. Start a pending load that records its producer signal and returns a typed cancellation when that signal aborts. 3. Attach two waits; abort the first with a selected object. Its result has an undefined cause; the producer remains active for the peer. 4. Abort the final waiter with a selected string. Its result also has an undefined cause; producer signal.reason differs from that string. One reduced probe performed; no native process/resource, target, CLI or MCP request. Retained local probe output records exactReason=false/causeOmitted=true for both waiters, producerReceivedLastReason=false, and cleanupIncomplete=false. ### Expected behavior Preserve the caller's exact AbortSignal.reason as the typed cancellation cause, including null/object/error values, without interpreting it as cleanup authority. Forward the final departing caller's reason to its owned producer while joining cleanup; preserve authored physical failures and any retained cleanup capability. This follows docs/tool-design.md#own-the-lifecycle. ### Impact and scope Confirmed at the compiled shared-wait boundary only. Source consumers include string and reference query workflows. End-to-end CLI/MCP projection, actual command shutdown and real Kuna/Windows effects are unverified. Similar reasonless cancellation constructors/controller.abort calls exist in the single-function waiter path; that is source evidence, not a runtime reproduction. ### REA version 988494abd (package 6.5.0). ### Runtime and platform Darwin arm64 / Node 24.18.0; real Kuna not invoked. ### Target and artifact context Not applicable: typed shared-wait boundary probe, no target artifact. ### Interface Other — shared provider workflow boundary. ### Earliest failure stage Cleanup, cancellation, or lifecycle. ### Relevant output or evidence ```json {"first":{"type":"AnalysisCancelledError","exactReason":false,"causeOmitted":true,"cleanupIncomplete":false},"last":{"type":"AnalysisCancelledError","exactReason":false,"causeOmitted":true,"cleanupIncomplete":false},"producerReceivedLastReason":false} ``` - [KunaQueryWork.wait](https://github.com/morluto/rea/blob/988494abd/src/kuna/KunaQueryWork.ts#L163): reasonless producer abort and typed cancellation construction. - [Single-function waits](https://github.com/morluto/rea/blob/988494abd/src/kuna/KunaSessionClient.ts#L995): analogous source-only loss in pre-admission/peer cancellation and last-waiter abort. ### Analysis or suspected cause Confirmed constructor/forwarding omissions. Repair the shared command owner's representation and affected consumers together; downstream error remapping cannot recover a discarded reason. The existing SharedStartupAttempt demonstrates explicit independent waits and final-departure cleanup, but query cache semantics must be reviewed before reuse. ### Additional context Heavy profiling and stress remain stopped. Proposed checks: exact null/string/foreign-error reasons, peer retention, final departure, mixed physical/cleanup failures, cleanup retry, and cancellation during finalization. None of those broader runtime checks are claimed by this minimal probe.
Author
Owner

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

Fixed in 592793717, pushed to main, together with the producing cleanup-owner repair in #4702.

Query waits now reuse SharedStartupAttempt instead of copying controller/waiter/settlement state. Peer departure preserves the exact caller reason; final departure forwards it and joins the producer, retaining typed failures, captured facts and unresolved cleanup. Kuna command mapping uses OwnedCommandFailure.cancellation.reason rather than treating its wrapper as the reason; unknown physical failures are no longer classified from a later signal at that boundary. Admission/consumer and single-function checkpoints also preserve exact reasons.

Validation: six shared-wait controls and six tiny fake-process controls cover null/string/foreign-error reasons, peer retention, final departure, successful completion after departure, mixed timeout/cancellation outcomes, captured output, conjunctive process/workspace cleanup and retry. A five-file focused run passed 41 checks; the final overlapping three-file run passed 15 after concurrent close coverage. Nine selected existing string/reference sharing/cleanup checks passed (25 unrelated cases skipped); large scan/capacity cases were not run. Typecheck/lint, docs checks (five README controls), build and hooks passed.

Public CLI SIGINT check with the same tiny ELF and fake Kuna: both builds returned cancelled search_strings, complete cleanup and no surviving fake process. The final build retains producer_operation=kuna:strings and the actual captured command outcome, which the old final-wait wrapper discarded. Cancellation-to-exit was about 83 ms in both final comparison samples; no latency claim. Exact opaque reasons are proved by typed boundary controls, not the JSON CLI envelope.

Equivalent completed malformed-string CLI costs, baseline/candidate: first-process elapsed 1.602/1.534 s, CPU 1.526/1.514 s, sampled process-family RSS 528.5/527.6 MB; two alternating warm repeats gave medians elapsed 1.451/1.418 s, CPU 1.528/1.444 s, sampled family RSS 530.5/528.4 MB. Both replies were 96 raw cl100k tokens. No performance improvement claim. CPU includes reaped children; sampled RSS may miss transients/reparenting. True cold, whole-agent/MCP/catalog/retry, native-engine and larger-output costs remain unmeasured. An initial harness expected the wrong malformed-output code; corrected to the observed unreadable_output before the valid six-task comparison. The earlier pre-final-serialization sample is retained separately.

No real Kuna/Windows/MCP-specific failure qualification or heavy profiling/stress. Remaining pre-command rollback diagnostics, raw exception precedence and completed-fact retention paths remain separate audit work; this does not establish complete Kuna lifecycle coverage.

<!-- gh-comment-id:6230785841 --> @morluto commented on GitHub (Oct 17, 2026): Fixed in 592793717, pushed to main, together with the producing cleanup-owner repair in #4702. Query waits now reuse SharedStartupAttempt instead of copying controller/waiter/settlement state. Peer departure preserves the exact caller reason; final departure forwards it and joins the producer, retaining typed failures, captured facts and unresolved cleanup. Kuna command mapping uses OwnedCommandFailure.cancellation.reason rather than treating its wrapper as the reason; unknown physical failures are no longer classified from a later signal at that boundary. Admission/consumer and single-function checkpoints also preserve exact reasons. Validation: six shared-wait controls and six tiny fake-process controls cover null/string/foreign-error reasons, peer retention, final departure, successful completion after departure, mixed timeout/cancellation outcomes, captured output, conjunctive process/workspace cleanup and retry. A five-file focused run passed 41 checks; the final overlapping three-file run passed 15 after concurrent close coverage. Nine selected existing string/reference sharing/cleanup checks passed (25 unrelated cases skipped); large scan/capacity cases were not run. Typecheck/lint, docs checks (five README controls), build and hooks passed. Public CLI SIGINT check with the same tiny ELF and fake Kuna: both builds returned cancelled search_strings, complete cleanup and no surviving fake process. The final build retains producer_operation=kuna:strings and the actual captured command outcome, which the old final-wait wrapper discarded. Cancellation-to-exit was about 83 ms in both final comparison samples; no latency claim. Exact opaque reasons are proved by typed boundary controls, not the JSON CLI envelope. Equivalent completed malformed-string CLI costs, baseline/candidate: first-process elapsed 1.602/1.534 s, CPU 1.526/1.514 s, sampled process-family RSS 528.5/527.6 MB; two alternating warm repeats gave medians elapsed 1.451/1.418 s, CPU 1.528/1.444 s, sampled family RSS 530.5/528.4 MB. Both replies were 96 raw cl100k tokens. No performance improvement claim. CPU includes reaped children; sampled RSS may miss transients/reparenting. True cold, whole-agent/MCP/catalog/retry, native-engine and larger-output costs remain unmeasured. An initial harness expected the wrong malformed-output code; corrected to the observed unreadable_output before the valid six-task comparison. The earlier pre-final-serialization sample is retained separately. No real Kuna/Windows/MCP-specific failure qualification or heavy profiling/stress. Remaining pre-command rollback diagnostics, raw exception precedence and completed-fact retention paths remain separate audit work; this does not establish complete Kuna lifecycle coverage.
Author
Owner

@XinwangTao commented on GitHub (Oct 17, 2026):

Nice fix — reusing SharedStartupAttempt instead of hand-copying controller/waiter/settlement state removes a whole class of drift bugs, and routing cancellation through OwnedCommandFailure.cancellation.reason is the right level of indirection. Two questions on the shared-wait path: when multiple waiters each abort with different reasons before the final departure, which reason wins for the joined producer (first canceller, last canceller, or a composite)? And since cause: undefined was the reported symptom, it would help to add a serialized cause/log trace on AnalysisCancelledError so multi-waiter cancellation chains are diagnosable in production logs.

<!-- gh-comment-id:6231766941 --> @XinwangTao commented on GitHub (Oct 17, 2026): Nice fix — reusing SharedStartupAttempt instead of hand-copying controller/waiter/settlement state removes a whole class of drift bugs, and routing cancellation through OwnedCommandFailure.cancellation.reason is the right level of indirection. Two questions on the shared-wait path: when multiple waiters each abort with different reasons before the final departure, which reason wins for the joined producer (first canceller, last canceller, or a composite)? And since `cause: undefined` was the reported symptom, it would help to add a serialized cause/log trace on AnalysisCancelledError so multi-waiter cancellation chains are diagnosable in production logs.
Author
Owner

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

Verified on current main (7c458f04b) that this no longer reproduces.

npm run test:focused -- tests/boundary/providers/kuna/kunaQueryCancellation.test.ts passes (6 tests); the caller cancellation reasons survive the shared wait.

Fixed by 592793717 (fix(kuna): preserve cancellation and cleanup ownership), in the rea-agents-6.6.0 release. Verification only; no action requested.

<!-- gh-comment-id:6247506702 --> @skyzhao1223 commented on GitHub (Oct 18, 2026): Verified on current `main` (`7c458f04b`) that this no longer reproduces. `npm run test:focused -- tests/boundary/providers/kuna/kunaQueryCancellation.test.ts` passes (6 tests); the caller cancellation reasons survive the shared wait. Fixed by `592793717` (`fix(kuna): preserve cancellation and cleanup ownership`), in the `rea-agents-6.6.0` release. Verification only; no action requested.
Author
Owner

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

Closing as fixed on main after reconciling this report with the landed owner/consumer changes.

  • 592793717: fix(kuna): preserve cancellation and cleanup ownership.

Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.

<!-- gh-comment-id:6255990730 --> @morluto commented on GitHub (Oct 18, 2026): <!-- rea-backlog-reconciliation-2026-10-19-4700 --> Closing as fixed on `main` after reconciling this report with the landed owner/consumer changes. - [592793717](https://github.com/morluto/rea/commit/5927937179476c66aa8621658faca42f9578b42a): fix(kuna): preserve cancellation and cleanup ownership. Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.
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#2453
No description provided.