[GH-ISSUE #8579] fix(ghidra): preserve nested project selection in failure recovery #6656

Open
opened 2026-11-01 21:12:59 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @morluto on GitHub (Nov 1, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8579

Before submitting

  • I searched the open and closed issues for related reports.
  • I removed private data and credentials.

Area

MCP or agent integration.

Observed behavior

In a temporary conflict-resolved integration of proposed nested-project selection, an absent project folder returns generic execution_failure and rea doctor advice. An absent program in an existing nested folder returns configuration_invalid, but its message and remediation incorrectly say to select a root program. This observation is on an unmerged proposal, not current main.

Reproduction

On macOS arm64, Node 24.22.1, Ghidra 12.1.4 and JDK 21, create a disposable local merge of #3817 f8abf28c and main 46c13b998, resolving its launcher and test conflicts. In an owned project with program workflow under /group, set REA_GHIDRA_PROJECT_PATH to its .gpr and:

  1. Set REA_GHIDRA_PROGRAM_FOLDER=/missing and REA_GHIDRA_PROGRAM_NAME=workflow. Open the target through stdio MCP and call list_procedures. It returns execution_failure with generic doctor advice. The captured process diagnostics contain Ghidra's Specified project folder not found message.
  2. Set REA_GHIDRA_PROGRAM_FOLDER=/group and REA_GHIDRA_PROGRAM_NAME=absent-program. The same call returns configuration_invalid saying no root program has that name and directs selection of a root program.

Both cases were run in compact and full MCP schema profiles. open_binary binds lazily; each subsequent query failed and close_binary succeeded. The .gpr, all eight regular .rep files and target bytes were unchanged. The owned target SHA-256 was ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d and it was not executed.

Doctor follow-up

On the same temporary merge and target, rea doctor --provider ghidra --target <target> --format json returned scoped healthy: true with both /group and the nonexistent /missing folder. The returned checks cover Node, target, Ghidra installation and Java, not a check that the folder or program exists. This does not contradict those checks, but shows the generic doctor advice cannot resolve the observed folder-selection failure by itself. It is not a request for doctor to open every project or auto-select a program.

Local guidance prototype

An unmerged experiment on the same temporary integration checkout passes the already-selected programFolder to the existing missing-program guidance owner. With Ghidra 12.1.4, both compact and full real MCP profiles then returned configuration_invalid naming the exact /group folder and absent-program; source project and target hashes remained unchanged. The existing 195-test Ghidra provider behavior suite also passed, including root-selection cases. This is a prototype, not a change to #3817 or main, and it did not address missing-folder attribution. Further verification should cover root and nested explicit/default names, output contracts, CLI and cancellation/cleanup.

Ghidra producer boundary

The failing real control reported exit code 1 and included Specified project folder not found: /missing in the captured, complete failure output. Inspection of Ghidra 12.1.4 HeadlessAnalyzer.processNoImport shows it resolves the selected DomainFolder and throws that IOException before it enumerates programs; the missing-program exception is a separate later branch. This is source-derived for that version, not a structured protocol or a guarantee about future output. Because folder resolution fails before processing a program, the per-program REA bridge cannot supply an authenticated failure for this path using the existing launch sequence.

A potential design could retain a scoped, exact-match log observation with uncertainty, or establish the folder fact through a separate supported project inspection boundary. Compare that with the existing root missing-program matcher and account for truncated output, localized or version-changed messages, configured folder identity, cleanup and producer failure; do not silently interpret an unrelated exception as a confirmed missing folder. The separate guidance prototype above does not solve this producer boundary.

Expected behavior

Preserve the selected folder and program in applicable errors, distinguish a missing folder from a missing program when the producer establishes that distinction, and give a correct selection/restart handoff without guessing from arbitrary log strings. Keep failure, source-project preservation, and no implicit fresh import.

Impact and scope

This is a negative-path UX finding for a local merged prototype. The contributor's PR head is conflicting with main and was not modified or run unmerged. No prevalence, Windows, CLI, or other Ghidra version claim is made.

REA version

Uncommitted temporary conflict resolution combining #3817 f8abf28c and main 46c13b998.

Runtime and platform

macOS arm64, Node 24.22.1, Ghidra 12.1.4 and JDK 21.

Target and artifact context

Self-built static Mach-O and an owned Ghidra project. The project was opened through REA's owned-copy path.

Interface

MCP.

Earliest failure stage

Provider startup / existing-project selection.

Relevant output or evidence

Missing folder: execution_failure with generic doctor advice; Ghidra reports the missing project folder in captured diagnostics. Missing program: configuration_invalid explicitly says no root program named "absent-program" and advises an exact root name, despite selecting /group.

Typed outcome or recovery expected

Report only producer-established folder/program failure facts and preserve explicit unknowns. Validate an existing root selection, an existing nested selection, both negative cases, and source-project integrity.

Analysis or suspected cause

In the local merge, GhidraProviderClient.ts has an existing missing-program formatter that explicitly assumes root selection. The missing-folder case did not reach that formatter. This explains the misleading message but does not establish a safe structured signal for the missing-folder case.

Additional context

Related: #3817 (nested selection), #8344 (candidate discovery), #8169 (project identity refusal).

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8579 ### Before submitting - [x] I searched the open and closed issues for related reports. - [x] I removed private data and credentials. ### Area MCP or agent integration. ### Observed behavior In a temporary conflict-resolved integration of proposed nested-project selection, an absent project folder returns generic `execution_failure` and `rea doctor` advice. An absent program in an existing nested folder returns `configuration_invalid`, but its message and remediation incorrectly say to select a **root** program. This observation is on an unmerged proposal, not current main. ### Reproduction On macOS arm64, Node 24.22.1, Ghidra 12.1.4 and JDK 21, create a disposable local merge of #3817 `f8abf28c` and main `46c13b998`, resolving its launcher and test conflicts. In an owned project with program `workflow` under `/group`, set `REA_GHIDRA_PROJECT_PATH` to its `.gpr` and: 1. Set `REA_GHIDRA_PROGRAM_FOLDER=/missing` and `REA_GHIDRA_PROGRAM_NAME=workflow`. Open the target through stdio MCP and call `list_procedures`. It returns `execution_failure` with generic doctor advice. The captured process diagnostics contain Ghidra's `Specified project folder not found` message. 2. Set `REA_GHIDRA_PROGRAM_FOLDER=/group` and `REA_GHIDRA_PROGRAM_NAME=absent-program`. The same call returns `configuration_invalid` saying no **root** program has that name and directs selection of a root program. Both cases were run in compact and full MCP schema profiles. `open_binary` binds lazily; each subsequent query failed and `close_binary` succeeded. The `.gpr`, all eight regular `.rep` files and target bytes were unchanged. The owned target SHA-256 was `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d` and it was not executed. ### Doctor follow-up On the same temporary merge and target, `rea doctor --provider ghidra --target <target> --format json` returned scoped `healthy: true` with both `/group` and the nonexistent `/missing` folder. The returned checks cover Node, target, Ghidra installation and Java, not a check that the folder or program exists. This does not contradict those checks, but shows the generic doctor advice cannot resolve the observed folder-selection failure by itself. It is not a request for doctor to open every project or auto-select a program. ### Local guidance prototype An unmerged experiment on the same temporary integration checkout passes the already-selected `programFolder` to the existing missing-program guidance owner. With Ghidra 12.1.4, both compact and full real MCP profiles then returned `configuration_invalid` naming the exact `/group` folder and `absent-program`; source project and target hashes remained unchanged. The existing 195-test Ghidra provider behavior suite also passed, including root-selection cases. This is a prototype, not a change to #3817 or main, and it did not address missing-folder attribution. Further verification should cover root and nested explicit/default names, output contracts, CLI and cancellation/cleanup. ### Ghidra producer boundary The failing real control reported exit code 1 and included `Specified project folder not found: /missing` in the captured, complete failure output. Inspection of [Ghidra 12.1.4 `HeadlessAnalyzer.processNoImport`](https://github.com/NationalSecurityAgency/ghidra/blob/Ghidra_12.1.4_build/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java#L1375-L1404) shows it resolves the selected `DomainFolder` and throws that `IOException` before it enumerates programs; the missing-program exception is a separate later branch. This is source-derived for that version, not a structured protocol or a guarantee about future output. Because folder resolution fails before processing a program, the per-program REA bridge cannot supply an authenticated failure for this path using the existing launch sequence. A potential design could retain a scoped, exact-match log observation with uncertainty, or establish the folder fact through a separate supported project inspection boundary. Compare that with the existing root missing-program matcher and account for truncated output, localized or version-changed messages, configured folder identity, cleanup and producer failure; do not silently interpret an unrelated exception as a confirmed missing folder. The separate guidance prototype above does not solve this producer boundary. ### Expected behavior Preserve the selected folder and program in applicable errors, distinguish a missing folder from a missing program when the producer establishes that distinction, and give a correct selection/restart handoff without guessing from arbitrary log strings. Keep failure, source-project preservation, and no implicit fresh import. ### Impact and scope This is a negative-path UX finding for a local merged prototype. The contributor's PR head is conflicting with main and was not modified or run unmerged. No prevalence, Windows, CLI, or other Ghidra version claim is made. ### REA version Uncommitted temporary conflict resolution combining #3817 `f8abf28c` and main `46c13b998`. ### Runtime and platform macOS arm64, Node 24.22.1, Ghidra 12.1.4 and JDK 21. ### Target and artifact context Self-built static Mach-O and an owned Ghidra project. The project was opened through REA's owned-copy path. ### Interface MCP. ### Earliest failure stage Provider startup / existing-project selection. ### Relevant output or evidence Missing folder: `execution_failure` with generic doctor advice; Ghidra reports the missing project folder in captured diagnostics. Missing program: `configuration_invalid` explicitly says `no root program named "absent-program"` and advises an exact root name, despite selecting `/group`. ### Typed outcome or recovery expected Report only producer-established folder/program failure facts and preserve explicit unknowns. Validate an existing root selection, an existing nested selection, both negative cases, and source-project integrity. ### Analysis or suspected cause In the local merge, `GhidraProviderClient.ts` has an existing missing-program formatter that explicitly assumes root selection. The missing-folder case did not reach that formatter. This explains the misleading message but does not establish a safe structured signal for the missing-folder case. ### Additional context Related: #3817 (nested selection), #8344 (candidate discovery), #8169 (project identity refusal). cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
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#6656
No description provided.