[GH-ISSUE #5434] [Bug] Missing working directory leaves native observation cleanup stuck until MCP restart #3293

Closed
opened 2026-10-31 00:38:52 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Process capture or runtime observation

Observed behavior

When LLDB rejects a nonexistent working_directory, observe-native-calls returns cleanup_incomplete, retains native-target:unknown, and leaves its private runtime directory behind. In a production stdio MCP session, the same failure makes the next valid observe_native_calls and close_binary fail with that retained owner. Restarting the server restores observation and clean close.

The launch diagnostic is preserved in error details. The defect is the unresolved cleanup classification and session recovery, rather than rejection of the invalid directory itself. This report was prepared with AI assistance and independently reproduced through the public CLI and production stdio MCP entry point.

Reproduction

From a prepared baseline checkout on macOS with Xcode LLDB available, compile the repository fixture and run the following CLI reproduction. The verifier ran these operations with isolated HOME, XDG directories, and runtime storage; the command below expresses that environment per invocation.

work_dir="$(mktemp -d)"
mkdir -p "$work_dir/home" "$work_dir/config" "$work_dir/data" "$work_dir/cache" "$work_dir/state" "$work_dir/runtime"
xcrun clang -g -O0 tests/fixtures/native-macos/native-macho-header/fixture.c -o "$work_dir/fixture"
input="$(printf '{"breakpoints":[{"kind":"function","name":"owned_value"}],"duration_ms":2000,"working_directory":"%s/absent"}' "$work_dir")"
env HOME="$work_dir/home" XDG_CONFIG_HOME="$work_dir/config" \
  XDG_DATA_HOME="$work_dir/data" XDG_CACHE_HOME="$work_dir/cache" \
  XDG_STATE_HOME="$work_dir/state" TMPDIR="$work_dir/runtime" \
  node scripts/rea.mjs observe-native-calls "$work_dir/fixture" "$input" --json

The missing-directory call exits 1 with the cleanup error below and leaves a rea-lldb-* runtime directory. Repeating with working_directory set to the existing work_dir exits 0 and records owned_value.

For the independently executed MCP sequence, start node scripts/rea.mjs mcp with the same isolated environment, initialize the client, and use tools/call:

  1. open_binary with {"path":"<absolute fixture path>"}.
  2. observe_native_calls with {"breakpoints":[{"kind":"function","name":"owned_value"}],"duration_ms":2000,"working_directory":"<existing work_dir>"}. This succeeds.
  3. Repeat that request with working_directory set to the missing child directory. It returns cleanup_incomplete.
  4. Repeat the valid request from step 2, then call close_binary with {}. Both return cleanup_incomplete and the same unknown target owner. Closing stdin makes the server report unsuccessful cleanup and exit 1.
  5. Start a fresh server, open the same fixture, repeat the valid observation, and close it. All succeed; stdin EOF exits the server with status 0.

Inspect the retained runtime before removing the disposable files. No target PID file was produced for the failed launch.

Expected behavior

docs/native-investigation.md:500-529 requires separate process-creation and process-exit facts on launch errors, retaining cleanup for unresolved ownership. docs/tool-design.md:71-83 requires available lifecycle facts even when launch fails. When LLDB returns no valid process, preserve that no-process fact and the launch diagnostic, release the runtime, and allow the next valid observation and target close. Genuinely unresolved ownership must remain retained.

Impact and scope

P2: the demonstrated failure blocks subsequent native observations and clean close in the affected MCP session and retains private runtime artifacts after CLI exit. Restarting the MCP server and using an existing directory is a verified workaround; fresh CLI invocations also work. Restarting does not remove already retained directories.

The missing-directory failure and valid control reproduced with the repository fixture through both interfaces. Other launch-failure causes were not exercised. No security boundary crossing, unrelated-process interference, or data loss was established.

REA version

6.7.0; source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1 arm64; Xcode LLDB lldb-2103.0.34.103.

Target and artifact context

Locally compiled Mach-O executable from tests/fixtures/native-macos/native-macho-header/fixture.c, function breakpoint owned_value, duration 2000 ms. No private target or external API was used.

Interface

MCP

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

Reduced observed CLI error fields, with the directory path replaced by a placeholder:

code: cleanup_incomplete
reason: launch-failed: No such file or directory: <missing directory>
cleanup_reason: target process start identity was unavailable; survivor was left untouched
resources include: native-target:unknown, <private runtime directory>

The retained bridge result.json contained status: launch-error and the missing-directory error, with no process-creation or exit fact and no target PID file. The later valid MCP request and close returned the same cleanup failure. The successful restart control traced the same fixture and closed normally.

Typed outcome or recovery expected

Return the launch failure with its diagnostic and completed cleanup when no process was created. In the same MCP connection, the next valid observation should record the selected function and close_binary should succeed. Preserve unresolved cleanup only where ownership actually remains uncertain.

Analysis or suspected cause

Source-derived reasoning at the baseline: bridge/native/rea_lldb_tracer.py:558-563,663-680 omits target_process_created: false for an invalid process. src/native/LldbCallTracer.ts:508-530 requires that explicit fact to resolve the no-PID case. Cleanup retry at :381-430 rereads the absent PID, which still yields identity-unavailable at :1195-1196. This explains the observed retained owner without requiring a claim about other launch failures.

Additional context

Related reports were checked: #3185 concerns pre-target integrity rejection, #4232 concerns a valid but already exited process after launch denial, #5385 concerns cancellation replacing observed exit and no-target proof, and #5297 concerns stale cleanup markers after a successful owner retry. This reproduction instead has an invalid LLDB process after missing-directory rejection, no PID, and no cancellation.

Upstream freshness check: fetched main at 052956af3416fa01d93837e54fdec3ad2739f6d1; none of the cited bridge, tracer, or contract files changed after the reproduced baseline. This was a source comparison, not a fresh execution of that later revision.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5434 ### 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 Process capture or runtime observation ### Observed behavior When LLDB rejects a nonexistent `working_directory`, `observe-native-calls` returns `cleanup_incomplete`, retains `native-target:unknown`, and leaves its private runtime directory behind. In a production stdio MCP session, the same failure makes the next valid `observe_native_calls` and `close_binary` fail with that retained owner. Restarting the server restores observation and clean close. The launch diagnostic is preserved in error details. The defect is the unresolved cleanup classification and session recovery, rather than rejection of the invalid directory itself. This report was prepared with AI assistance and independently reproduced through the public CLI and production stdio MCP entry point. ### Reproduction From a prepared baseline checkout on macOS with Xcode LLDB available, compile the repository fixture and run the following CLI reproduction. The verifier ran these operations with isolated HOME, XDG directories, and runtime storage; the command below expresses that environment per invocation. ```sh work_dir="$(mktemp -d)" mkdir -p "$work_dir/home" "$work_dir/config" "$work_dir/data" "$work_dir/cache" "$work_dir/state" "$work_dir/runtime" xcrun clang -g -O0 tests/fixtures/native-macos/native-macho-header/fixture.c -o "$work_dir/fixture" input="$(printf '{"breakpoints":[{"kind":"function","name":"owned_value"}],"duration_ms":2000,"working_directory":"%s/absent"}' "$work_dir")" env HOME="$work_dir/home" XDG_CONFIG_HOME="$work_dir/config" \ XDG_DATA_HOME="$work_dir/data" XDG_CACHE_HOME="$work_dir/cache" \ XDG_STATE_HOME="$work_dir/state" TMPDIR="$work_dir/runtime" \ node scripts/rea.mjs observe-native-calls "$work_dir/fixture" "$input" --json ``` The missing-directory call exits 1 with the cleanup error below and leaves a `rea-lldb-*` runtime directory. Repeating with `working_directory` set to the existing `work_dir` exits 0 and records `owned_value`. For the independently executed MCP sequence, start `node scripts/rea.mjs mcp` with the same isolated environment, initialize the client, and use `tools/call`: 1. `open_binary` with `{"path":"<absolute fixture path>"}`. 2. `observe_native_calls` with `{"breakpoints":[{"kind":"function","name":"owned_value"}],"duration_ms":2000,"working_directory":"<existing work_dir>"}`. This succeeds. 3. Repeat that request with `working_directory` set to the missing child directory. It returns `cleanup_incomplete`. 4. Repeat the valid request from step 2, then call `close_binary` with `{}`. Both return `cleanup_incomplete` and the same unknown target owner. Closing stdin makes the server report unsuccessful cleanup and exit 1. 5. Start a fresh server, open the same fixture, repeat the valid observation, and close it. All succeed; stdin EOF exits the server with status 0. Inspect the retained runtime before removing the disposable files. No target PID file was produced for the failed launch. ### Expected behavior `docs/native-investigation.md:500-529` requires separate process-creation and process-exit facts on launch errors, retaining cleanup for unresolved ownership. `docs/tool-design.md:71-83` requires available lifecycle facts even when launch fails. When LLDB returns no valid process, preserve that no-process fact and the launch diagnostic, release the runtime, and allow the next valid observation and target close. Genuinely unresolved ownership must remain retained. ### Impact and scope P2: the demonstrated failure blocks subsequent native observations and clean close in the affected MCP session and retains private runtime artifacts after CLI exit. Restarting the MCP server and using an existing directory is a verified workaround; fresh CLI invocations also work. Restarting does not remove already retained directories. The missing-directory failure and valid control reproduced with the repository fixture through both interfaces. Other launch-failure causes were not exercised. No security boundary crossing, unrelated-process interference, or data loss was established. ### REA version 6.7.0; source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node.js v26.12.0; macOS 27.0.1 arm64; Xcode LLDB `lldb-2103.0.34.103`. ### Target and artifact context Locally compiled Mach-O executable from `tests/fixtures/native-macos/native-macho-header/fixture.c`, function breakpoint `owned_value`, duration 2000 ms. No private target or external API was used. ### Interface MCP ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence Reduced observed CLI error fields, with the directory path replaced by a placeholder: ```text code: cleanup_incomplete reason: launch-failed: No such file or directory: <missing directory> cleanup_reason: target process start identity was unavailable; survivor was left untouched resources include: native-target:unknown, <private runtime directory> ``` The retained bridge `result.json` contained `status: launch-error` and the missing-directory error, with no process-creation or exit fact and no target PID file. The later valid MCP request and close returned the same cleanup failure. The successful restart control traced the same fixture and closed normally. ### Typed outcome or recovery expected Return the launch failure with its diagnostic and completed cleanup when no process was created. In the same MCP connection, the next valid observation should record the selected function and `close_binary` should succeed. Preserve unresolved cleanup only where ownership actually remains uncertain. ### Analysis or suspected cause Source-derived reasoning at the baseline: `bridge/native/rea_lldb_tracer.py:558-563,663-680` omits `target_process_created: false` for an invalid process. `src/native/LldbCallTracer.ts:508-530` requires that explicit fact to resolve the no-PID case. Cleanup retry at `:381-430` rereads the absent PID, which still yields identity-unavailable at `:1195-1196`. This explains the observed retained owner without requiring a claim about other launch failures. ### Additional context Related reports were checked: #3185 concerns pre-target integrity rejection, #4232 concerns a valid but already exited process after launch denial, #5385 concerns cancellation replacing observed exit and no-target proof, and #5297 concerns stale cleanup markers after a successful owner retry. This reproduction instead has an invalid LLDB process after missing-directory rejection, no PID, and no cancellation. Upstream freshness check: fetched `main` at `052956af3416fa01d93837e54fdec3ad2739f6d1`; none of the cited bridge, tracer, or contract files changed after the reproduced baseline. This was a source comparison, not a fresh execution of that later revision.
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked the reported fix on main at d87e73f2db.

The LLDB bridge now includes target_process_created: process.IsValid() even on launch-error, so an invalid SBProcess produces explicit false. The tracer consumes false as no-target proof. A regression supplies the invalid-process/no-PID reply, requires launch failure with no cleanup owner and removed runtime, then a successful next observation.

Implementation: rea_lldb_tracer.py, LldbCallTracer.ts.

The relevant regression checks in lldbCallTracerFailures.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.

<!-- gh-comment-id:6380730282 --> @coygeek commented on GitHub (Oct 24, 2026): Checked the reported fix on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. The LLDB bridge now includes target_process_created: process.IsValid() even on launch-error, so an invalid SBProcess produces explicit false. The tracer consumes false as no-target proof. A regression supplies the invalid-process/no-PID reply, requires launch failure with no cleanup owner and removed runtime, then a successful next observation. Implementation: [rea_lldb_tracer.py](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/bridge/native/rea_lldb_tracer.py#L664), [LldbCallTracer.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/native/LldbCallTracer.ts#L666). The relevant regression checks in [lldbCallTracerFailures.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/tests/boundary/providers/native/lldbCallTracerFailures.test.ts) passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.
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#3293
No description provided.