[GH-ISSUE #8371] [Bug] Native value traces discard late child cleanup failures #6573

Closed
opened 2026-11-01 21:12:21 +00:00 by bsakaguchi · 1 comment
Owner

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

Originally assigned to: @kaoru0822-kitauji on GitHub.

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

MCP or agent integration

Observed behavior

After a valid seed function dossier, trace_native_values converts an incomplete-cleanup failure from either call-target resolution or a followed callee dossier into a plain-text unknown and returns successful MCP Evidence. The response retains the child error's message, but does not include the cleanup_incomplete code, cleanup reason, or owned-resource details.

Reproduction

  1. On REA d54a4661da20382ad8456564a08569fdd24131c5, obtain a complete _evaluate dossier and the resolve_native_call_targets result for its call at 0x100000458 through real Ghidra 12.1.4 MCP on the owned arm64 Mach-O fixture from #8282. The call result names direct target 0x100000410. The target was not executed or modified.
  2. Feed these captured valid observations through a fixed analysis port behind the production MCP server and linked in-memory SDK transports. In one run, inject AnalysisCapabilityUnavailableError("fixture", "resolve_native_call_targets", "controlled child failure", {cleanup:{reason:"cleanup proof refused", resources:["owned worker"]}}) at the first call-target read. In another, return the captured call-target result and inject that cleanup-bearing error when the trace reads the followed callee dossier.
  3. Call trace_native_values({procedure:"_evaluate", max_depth:1, max_functions:4, max_call_sites:20, max_nodes:100, max_edges:200, limit:100, offset:0}). Both replies have isError: false, contain controlled child failure, and contain none of cleanup_incomplete, cleanup proof refused, or owned worker anywhere in the MCP response.
  4. Control: return the same cleanup-bearing error on the initial analyze_function seed. The MCP call returns isError: true and retains both cleanup_incomplete and owned worker.

Three focused MCP tests passed in the observed-behavior sense above. This is a real-provider observation with injected subsequent failures; no real Ghidra cleanup failure was induced. The isolated worktree had an unrelated Kuna coverage experiment, which the fixed-port test does not use.

Expected behavior

Keep a cleanup-bearing failure typed and preserve its resource owner/recovery through the outer outcome. Stop dispatching further dependent work and retain already completed observations as partial Evidence where supported. Ordinary provider failures without incomplete cleanup can still produce partial value traces. Also test simultaneous cancellation and cleanup failure, cleanup retry and multiple completed sources; those are not established by this probe. See lifecycle guidance.

Impact and scope

The caller can receive a successful trace with no structured indication that a child reported cleanup incomplete or which resource remains unconfirmed. This does not establish a real process leak or an actual engine's retry behavior. Two injected late-failure locations and the seed control were exercised once each on one host; other providers, CLI, cancellation races and natural occurrence are NOT_ENOUGH_INFO.

REA version

d54a4661da20382ad8456564a08569fdd24131c5

Runtime and platform

Node 24.22.1, macOS arm64, Ghidra 12.1.4 / JDK 21 for the captured observations; TypeScript MCP SDK 2.3.1; fixed injected provider for the later failures.

Target and artifact context

Self-owned arm64 Mach-O, SHA-256 ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d; captured target hash unchanged.

Interface

MCP

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

The two successful late-failure replies each include controlled child failure, but lack cleanup classification/reason/resource fields; the seed-failure control is an MCP error carrying the typed cleanup status and resource. Source-derived: NativeValueTrace.ts preserves seed errors and cancellation but stores later dossier failures as error.message; its call-target branch does the same.

Additional context

Related #8369 concerns cleanup-bearing call-graph errors retained inside successful responses; here even the cleanup classification and resource details are dropped. #8282 separately concerns source Evidence retention. Testing a real provider's cleanup owner and the CLI remains proposed.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8371 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area MCP or agent integration ### Observed behavior After a valid seed function dossier, `trace_native_values` converts an incomplete-cleanup failure from either call-target resolution or a followed callee dossier into a plain-text unknown and returns successful MCP Evidence. The response retains the child error's message, but does not include the `cleanup_incomplete` code, cleanup reason, or owned-resource details. ### Reproduction 1. On REA `d54a4661da20382ad8456564a08569fdd24131c5`, obtain a complete `_evaluate` dossier and the `resolve_native_call_targets` result for its call at `0x100000458` through real Ghidra 12.1.4 MCP on the owned arm64 Mach-O fixture from #8282. The call result names direct target `0x100000410`. The target was not executed or modified. 2. Feed these captured valid observations through a fixed analysis port behind the production MCP server and linked in-memory SDK transports. In one run, inject `AnalysisCapabilityUnavailableError("fixture", "resolve_native_call_targets", "controlled child failure", {cleanup:{reason:"cleanup proof refused", resources:["owned worker"]}})` at the first call-target read. In another, return the captured call-target result and inject that cleanup-bearing error when the trace reads the followed callee dossier. 3. Call `trace_native_values({procedure:"_evaluate", max_depth:1, max_functions:4, max_call_sites:20, max_nodes:100, max_edges:200, limit:100, offset:0})`. Both replies have `isError: false`, contain `controlled child failure`, and contain none of `cleanup_incomplete`, `cleanup proof refused`, or `owned worker` anywhere in the MCP response. 4. Control: return the same cleanup-bearing error on the initial `analyze_function` seed. The MCP call returns `isError: true` and retains both `cleanup_incomplete` and `owned worker`. Three focused MCP tests passed in the observed-behavior sense above. This is a real-provider **observation** with injected subsequent failures; no real Ghidra cleanup failure was induced. The isolated worktree had an unrelated Kuna coverage experiment, which the fixed-port test does not use. ### Expected behavior Keep a cleanup-bearing failure typed and preserve its resource owner/recovery through the outer outcome. Stop dispatching further dependent work and retain already completed observations as partial Evidence where supported. Ordinary provider failures without incomplete cleanup can still produce partial value traces. Also test simultaneous cancellation and cleanup failure, cleanup retry and multiple completed sources; those are not established by this probe. See [lifecycle guidance](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/docs/tool-design.md#own-the-lifecycle). ### Impact and scope The caller can receive a successful trace with no structured indication that a child reported cleanup incomplete or which resource remains unconfirmed. This does not establish a real process leak or an actual engine's retry behavior. Two injected late-failure locations and the seed control were exercised once each on one host; other providers, CLI, cancellation races and natural occurrence are `NOT_ENOUGH_INFO`. ### REA version `d54a4661da20382ad8456564a08569fdd24131c5` ### Runtime and platform Node 24.22.1, macOS arm64, Ghidra 12.1.4 / JDK 21 for the captured observations; TypeScript MCP SDK 2.3.1; fixed injected provider for the later failures. ### Target and artifact context Self-owned arm64 Mach-O, SHA-256 `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`; captured target hash unchanged. ### Interface MCP ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence The two successful late-failure replies each include `controlled child failure`, but lack cleanup classification/reason/resource fields; the seed-failure control is an MCP error carrying the typed cleanup status and resource. Source-derived: [`NativeValueTrace.ts`](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/src/application/native/NativeValueTrace.ts#L92-L103) preserves seed errors and cancellation but stores later dossier failures as `error.message`; its [call-target branch](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/src/application/native/NativeValueTrace.ts#L249-L264) does the same. ### Additional context Related #8369 concerns cleanup-bearing call-graph errors retained *inside* successful responses; here even the cleanup classification and resource details are dropped. #8282 separately concerns source Evidence retention. Testing a real provider's cleanup owner and the CLI remains proposed. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

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

One-shot CLI control on d54a4661, through the production trace-native-values command, runDirectAnalysis, and BinarySession, using the captured real Ghidra _evaluate dossier and an injected provider failure at resolve_native_call_targets:

  • When the simulated client's final close() returned a ProviderCleanupError naming owned worker, the JSON CLI result carried top-level code: "cleanup_incomplete" and that resource. details.partial_observation contained the completed trace_native_values Evidence, including the child failure message. This is a useful cleanup boundary control: a failure still reported at final close is not silently presented as CLI success.
  • When the simulated client's final close() instead returned success, the CLI emitted successful trace Evidence with the child message but no cleanup_incomplete or resource fields. The fixture models the two close outcomes independently; it does not establish whether a real provider's successful close correctly resolves the same cleanup owner or clears its retained error.

Both focused CLI boundary cases passed. This supplements, rather than replaces, the MCP finding: the Ghidra dossier was real, but both the child failure and close outcomes were injected; no real-provider cleanup failure, process leak, exit-code behavior, or retry was tested. The earlier unrelated Kuna coverage edit is not used by this fixed-provider test.

<!-- gh-comment-id:6548536826 --> @morluto commented on GitHub (Oct 31, 2026): One-shot CLI control on `d54a4661`, through the production `trace-native-values` command, `runDirectAnalysis`, and `BinarySession`, using the captured real Ghidra `_evaluate` dossier and an injected provider failure at `resolve_native_call_targets`: - When the simulated client's final `close()` returned a `ProviderCleanupError` naming `owned worker`, the JSON CLI result carried top-level `code: "cleanup_incomplete"` and that resource. `details.partial_observation` contained the completed `trace_native_values` Evidence, including the child failure message. This is a useful cleanup boundary control: a failure still reported at final close is not silently presented as CLI success. - When the simulated client's final `close()` instead returned success, the CLI emitted successful trace Evidence with the child message but no `cleanup_incomplete` or resource fields. The fixture models the two close outcomes independently; it does not establish whether a real provider's successful close correctly resolves the same cleanup owner or clears its retained error. Both focused CLI boundary cases passed. This supplements, rather than replaces, the MCP finding: the Ghidra dossier was real, but both the child failure and close outcomes were injected; no real-provider cleanup failure, process leak, exit-code behavior, or retry was tested. The earlier unrelated Kuna coverage edit is not used by this fixed-provider test.
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#6573
No description provided.