[GH-ISSUE #8428] [Bug] Unavailable address navigation hides usable instruction alternatives #6601

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

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

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

CLI or MCP tool behavior and recovery

Observed behavior

When an analyst asks next_address on either Ghidra or Kuna, REA reports capability_unavailable and tells them to choose another analysis or target. On the tested function, useful same-provider instruction observations were available through other REA tools, but the refusal did not suggest them.

Reproduction

  1. Open the same owned static arm64 Mach-O in separate real MCP sessions with Ghidra 12.1.4 and Kuna 1.986.
  2. Call next_address at known function entry 0x100000430. Both return capability_unavailable; message and remediation are “This analysis is unavailable for the current target. Choose another analysis or target.”
  3. On Ghidra, inspect_native_instruction at that entry returns the decoded instruction and length, and read_function_instructions at the known function entry returns its ordered listing, including 0x100000434. On Kuna, both structured instruction operations are unavailable, but procedure_assembly for the entry returns assembly text containing both addresses.

Expected behavior

Help an agent discover relevant same-provider observations when the analyst's question is instruction-oriented, while explaining their actual scope. A function listing is not a replacement for arbitrary next analyzed code/data objects, and ordering or address + length is not proof of executed control flow. The best recovery may depend on provider capability and which tool families are advertised; no particular new primitive is assumed.

Impact and scope

The tested refusal sends the agent away from usable information on the selected provider. One owned binary and two real providers were checked; general frequency, other hosts, addresses outside a known function, data objects and autonomous-agent behavior are unverified.

REA version

Draft #8426 stack, 458674fba8bc5adc7873adb99b5256ed0e16fc30. This is existing provider availability behavior, not claimed to be introduced by that draft.

Runtime and platform

macOS arm64, Node 24.22.1, Ghidra 12.1.4/JDK 21, Kuna 1.986; MCP server and TypeScript SDK in-memory transport, passing advertised tool definitions to the client.

Target and artifact context

Static arm64 Mach-O, SHA-256 ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d; target digest unchanged and the target was not executed.

Interface

MCP. CLI and Hopper not tested.

Earliest failure stage

Provider capability admission.

Relevant output or evidence

Ghidra's 0x100000448 conditional branch reports a direct destination at 0x100000464, while the next listed instruction is 0x10000044c; 0x10000047c is a return. These controls show why a listed next address must not be described as a proven next runtime instruction.

Typed outcome or recovery expected

Keep capability_unavailable and the selected-provider identity, but offer relevant executable follow-up guidance where applicable and preserve the difference between decoded instruction, listing order, and control flow.

Analysis or suspected cause

Source-derived: neither provider declares next_address; shared generic capability presentation has no operation-specific alternative. read_function_instructions and inspect_native_instruction are Ghidra operations; Kuna supports procedure_assembly. Whether and where to surface conditional recovery requires design and catalog-scope checks.

Additional context

Related: #8241 concerns resolving byte hits to containing instructions; it is not the same as moving between analyzed objects. This report does not request unqualified API parity or assume a function-only fallback answers all uses of next_address.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Real-provider control of #8537

On an isolated checkout of #8537 head b71ee066b, real Ghidra 12.1.4 and Kuna 1.990 on macOS arm64 were exercised through public stdio MCP in compact and full input/output profiles. For the owned arm64 Mach-O function at 0x1000003c0, both next_address and prev_address returned capability_unavailable with the same provider-specific alternatives and the warning that instruction order is not runtime control flow. Ghidra advertised inspect_native_instruction, read_function_instructions and procedure_assembly; all three calls succeeded at the selected function. Kuna advertised procedure_assembly, which succeeded. The target was not executed and its SHA-256 remained 496e188170232c15f1ceeebf33165f060c6a31b46be9571b6f49778ef0e8d910.

This verifies an explicitly driven positive handoff on one host and target. It does not test IDA, actual client decisions, unavailable alternative filtering, arbitrary data navigation, or independently validate the returned output schemas. The PR itself was not modified by this control.

Data-address control of #8537

On the same PR head and target, both real provider sessions requested next_address at data slot 0x100004000 in compact and full MCP. The refusal continued to name provider-level instruction alternatives while explicitly saying none navigates arbitrary analyzed objects such as data or addresses outside a procedure. Ghidra inspect_native_instruction identified the slot as data and resolve_containing_procedure reported not_in_procedure; procedure_assembly rejected that address. Kuna procedure_assembly also rejected the slot as not a discovered procedure entry. The target SHA-256 stayed unchanged.

This tests the qualifier on one data address; an advertised alternative is an available capability, not a guarantee that the supplied address is a suitable procedure. It does not test autonomous agent selection or establish a next-data-object capability.

Discovery and refusal agreement

A follow-up on #8537 head b71ee066b used real Ghidra 12.1.4 and Kuna 1.990 in separate compact/full MCP sessions. In each, binary_session grouped next_address and prev_address as unavailable and exposed exactly the same ordered alternatives as the later next_address refusal: the three Ghidra instruction tools or Kuna's assembly tool respectively. The successful session and alternative results validated against fetched advertised output schemas with Ajv 2020. The unexecuted fixture hash remained unchanged. This checks one positive capability state on one host, not dynamic failure filtering, client selection or complete discovery.

Controlled runtime failure and recovery

On #8537 head b71ee066b, a test-only Kuna wrapper forwarded --version to real Kuna 1.990 but deliberately exited 42 on analysis commands. In one public MCP session, next_address initially offered procedure_assembly; the injected procedure_assembly failure returned execution_failure, after which both its navigation refusal and binary_session omitted that alternative. Once the wrapper was allowed to forward real commands, an immediate retry still returned Kuna's explicit project-export-failed refusal instructing the caller to reopen. Closing and reopening the same target allowed real procedure_assembly to succeed, and the navigation refusal offered it again.

This is controlled fault injection plus a real Kuna recovery, not a naturally occurring provider failure or a frequency estimate. It exercises one operation, one output profile and one host; it does not establish all provider-wide failure or concurrent-call behavior. The target was not executed.

Integration probe with #8567

A disposable, uncommitted merge of #8537 b71ee066b and #8567 b282fece7 conflicted in BinarySessionExecution.ts: both own undeclared-operation recovery. A local experimental resolution prioritized available instruction alternatives and used #8567's general provider-discovery guidance when no alternative qualified. Real Ghidra 12.1.4 and Kuna 1.990 compact/full MCP controls returned their instruction alternatives and successfully used them; Kuna's unsupported search_bytes separately returned the general binary_session guidance. A controlled Kuna failure removed the assembly alternative, and a real successful analysis after close/reopen restored it.

This is an integration experiment, not a merged fix or a prescribed final resolution. The explicit choice of precedence, disclosure of provider-switch recovery when alternatives exist, catalog filtering, schema validation and full lifecycle tests still need review. The source target was not executed; the PRs remain independent and their conflict must be resolved before combining them.

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8428 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 CLI or MCP tool behavior and recovery ### Observed behavior When an analyst asks `next_address` on either Ghidra or Kuna, REA reports `capability_unavailable` and tells them to choose another analysis or target. On the tested function, useful same-provider instruction observations were available through other REA tools, but the refusal did not suggest them. ### Reproduction 1. Open the same owned static arm64 Mach-O in separate real MCP sessions with Ghidra 12.1.4 and Kuna 1.986. 2. Call `next_address` at known function entry `0x100000430`. Both return `capability_unavailable`; message and remediation are “This analysis is unavailable for the current target. Choose another analysis or target.” 3. On Ghidra, `inspect_native_instruction` at that entry returns the decoded instruction and length, and `read_function_instructions` at the known function entry returns its ordered listing, including `0x100000434`. On Kuna, both structured instruction operations are unavailable, but `procedure_assembly` for the entry returns assembly text containing both addresses. ### Expected behavior Help an agent discover relevant same-provider observations when the analyst's question is instruction-oriented, while explaining their actual scope. A function listing is not a replacement for arbitrary next analyzed code/data objects, and ordering or `address + length` is not proof of executed control flow. The best recovery may depend on provider capability and which tool families are advertised; no particular new primitive is assumed. ### Impact and scope The tested refusal sends the agent away from usable information on the selected provider. One owned binary and two real providers were checked; general frequency, other hosts, addresses outside a known function, data objects and autonomous-agent behavior are unverified. ### REA version Draft #8426 stack, `458674fba8bc5adc7873adb99b5256ed0e16fc30`. This is existing provider availability behavior, not claimed to be introduced by that draft. ### Runtime and platform macOS arm64, Node 24.22.1, Ghidra 12.1.4/JDK 21, Kuna 1.986; MCP server and TypeScript SDK in-memory transport, passing advertised tool definitions to the client. ### Target and artifact context Static arm64 Mach-O, SHA-256 `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`; target digest unchanged and the target was not executed. ### Interface MCP. CLI and Hopper not tested. ### Earliest failure stage Provider capability admission. ### Relevant output or evidence Ghidra's `0x100000448` conditional branch reports a direct destination at `0x100000464`, while the next listed instruction is `0x10000044c`; `0x10000047c` is a return. These controls show why a listed next address must not be described as a proven next runtime instruction. ### Typed outcome or recovery expected Keep `capability_unavailable` and the selected-provider identity, but offer relevant executable follow-up guidance where applicable and preserve the difference between decoded instruction, listing order, and control flow. ### Analysis or suspected cause Source-derived: neither provider declares `next_address`; shared generic capability presentation has no operation-specific alternative. `read_function_instructions` and `inspect_native_instruction` are Ghidra operations; Kuna supports `procedure_assembly`. Whether and where to surface conditional recovery requires design and catalog-scope checks. ### Additional context Related: #8241 concerns resolving byte hits to containing instructions; it is not the same as moving between analyzed objects. This report does not request unqualified API parity or assume a function-only fallback answers all uses of `next_address`. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 ### Real-provider control of #8537 On an isolated checkout of #8537 head `b71ee066b`, real Ghidra 12.1.4 and Kuna 1.990 on macOS arm64 were exercised through public stdio MCP in compact and full input/output profiles. For the owned arm64 Mach-O function at `0x1000003c0`, both `next_address` and `prev_address` returned `capability_unavailable` with the same provider-specific alternatives and the warning that instruction order is not runtime control flow. Ghidra advertised `inspect_native_instruction`, `read_function_instructions` and `procedure_assembly`; all three calls succeeded at the selected function. Kuna advertised `procedure_assembly`, which succeeded. The target was not executed and its SHA-256 remained `496e188170232c15f1ceeebf33165f060c6a31b46be9571b6f49778ef0e8d910`. This verifies an explicitly driven positive handoff on one host and target. It does not test IDA, actual client decisions, unavailable alternative filtering, arbitrary data navigation, or independently validate the returned output schemas. The PR itself was not modified by this control. ### Data-address control of #8537 On the same PR head and target, both real provider sessions requested `next_address` at data slot `0x100004000` in compact and full MCP. The refusal continued to name provider-level instruction alternatives while explicitly saying none navigates arbitrary analyzed objects such as data or addresses outside a procedure. Ghidra `inspect_native_instruction` identified the slot as data and `resolve_containing_procedure` reported `not_in_procedure`; `procedure_assembly` rejected that address. Kuna `procedure_assembly` also rejected the slot as not a discovered procedure entry. The target SHA-256 stayed unchanged. This tests the qualifier on one data address; an advertised alternative is an available capability, not a guarantee that the supplied address is a suitable procedure. It does not test autonomous agent selection or establish a next-data-object capability. ### Discovery and refusal agreement A follow-up on #8537 head `b71ee066b` used real Ghidra 12.1.4 and Kuna 1.990 in separate compact/full MCP sessions. In each, `binary_session` grouped `next_address` and `prev_address` as unavailable and exposed exactly the same ordered alternatives as the later `next_address` refusal: the three Ghidra instruction tools or Kuna's assembly tool respectively. The successful session and alternative results validated against fetched advertised output schemas with Ajv 2020. The unexecuted fixture hash remained unchanged. This checks one positive capability state on one host, not dynamic failure filtering, client selection or complete discovery. ### Controlled runtime failure and recovery On #8537 head `b71ee066b`, a test-only Kuna wrapper forwarded `--version` to real Kuna 1.990 but deliberately exited 42 on analysis commands. In one public MCP session, `next_address` initially offered `procedure_assembly`; the injected `procedure_assembly` failure returned `execution_failure`, after which both its navigation refusal and `binary_session` omitted that alternative. Once the wrapper was allowed to forward real commands, an immediate retry still returned Kuna's explicit project-export-failed refusal instructing the caller to reopen. Closing and reopening the same target allowed real `procedure_assembly` to succeed, and the navigation refusal offered it again. This is controlled fault injection plus a real Kuna recovery, not a naturally occurring provider failure or a frequency estimate. It exercises one operation, one output profile and one host; it does not establish all provider-wide failure or concurrent-call behavior. The target was not executed. ### Integration probe with #8567 A disposable, uncommitted merge of #8537 `b71ee066b` and #8567 `b282fece7` conflicted in `BinarySessionExecution.ts`: both own undeclared-operation recovery. A local experimental resolution prioritized available instruction alternatives and used #8567's general provider-discovery guidance when no alternative qualified. Real Ghidra 12.1.4 and Kuna 1.990 compact/full MCP controls returned their instruction alternatives and successfully used them; Kuna's unsupported `search_bytes` separately returned the general `binary_session` guidance. A controlled Kuna failure removed the assembly alternative, and a real successful analysis after close/reopen restored it. This is an integration experiment, not a merged fix or a prescribed final resolution. The explicit choice of precedence, disclosure of provider-switch recovery when alternatives exist, catalog filtering, schema validation and full lifecycle tests still need review. The source target was not executed; the PRs remain independent and their conflict must be resolved before combining them.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Scoped-catalog follow-up: repeated the real Ghidra/Kuna checks with only the session,direct MCP families enabled and confirmed the suggested instruction tools and both navigation calls were advertised. prev_address also produced the same generic capability refusal on both providers. binary_session with detail: complete correctly grouped next_address and prev_address as provider_missing; it reported Ghidra's read_function_instructions and procedure_assembly available, and Kuna's procedure_assembly available while its structured instruction read was provider_missing.

This gives an existing discovery path in this particular catalog and argues for building recovery on actual advertised tools and provider availability rather than declaring a substitute universally supported. The direct refusal did not point to that status or a conditional same-provider follow-up. The tested entry was inside a known function; navigation around data and no-containing-function addresses remains untested, as do configurations without the session family.

<!-- gh-comment-id:6552793010 --> @morluto commented on GitHub (Nov 1, 2026): Scoped-catalog follow-up: repeated the real Ghidra/Kuna checks with only the `session,direct` MCP families enabled and confirmed the suggested instruction tools and both navigation calls were advertised. `prev_address` also produced the same generic capability refusal on both providers. `binary_session` with `detail: complete` correctly grouped `next_address` and `prev_address` as `provider_missing`; it reported Ghidra's `read_function_instructions` and `procedure_assembly` available, and Kuna's `procedure_assembly` available while its structured instruction read was `provider_missing`. This gives an existing discovery path in this particular catalog and argues for building recovery on actual advertised tools and provider availability rather than declaring a substitute universally supported. The direct refusal did not point to that status or a conditional same-provider follow-up. The tested entry was inside a known function; navigation around data and no-containing-function addresses remains untested, as do configurations without the `session` family.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Boundary follow-up on the same real MCP/provider/target setup, using the scoped session,direct catalog:

  • At interior byte 0x100000431, Ghidra returned not-instruction-boundary; resolve_containing_procedure found _evaluate at 0x100000430, and read_function_instructions given the interior address returned that function's listing. Kuna's structured inspection and containment are unavailable, and procedure_assembly rejected the interior address as not a discovered procedure entry; the known entry remained a working control.
  • At data symbol 0x100004000, Ghidra reported data and no containing procedure; both its function listing and assembly requests failed as invalid selectors. Kuna's function assembly likewise rejected the data symbol and identified its __DATA,__data section.
  • At unmapped 0x200000000, Ghidra reported outside-memory and outside_segments, while Kuna's function assembly rejected the address as not a discovered entry.

This reinforces that guidance to inspect a known function is conditional and cannot replace general next/previous object navigation. The interior-byte result does not itself identify the containing instruction's start; #8241 covers that separate question. All calls used the real providers and advertised MCP definitions; the owned static target digest remained unchanged and the target was not executed. One Mach-O, no alternative instruction modes or other platforms were tested.

<!-- gh-comment-id:6552803091 --> @morluto commented on GitHub (Nov 1, 2026): Boundary follow-up on the same real MCP/provider/target setup, using the scoped `session,direct` catalog: - At interior byte `0x100000431`, Ghidra returned `not-instruction-boundary`; `resolve_containing_procedure` found `_evaluate` at `0x100000430`, and `read_function_instructions` given the interior address returned that function's listing. Kuna's structured inspection and containment are unavailable, and `procedure_assembly` rejected the interior address as not a discovered procedure entry; the known entry remained a working control. - At data symbol `0x100004000`, Ghidra reported `data` and no containing procedure; both its function listing and assembly requests failed as invalid selectors. Kuna's function assembly likewise rejected the data symbol and identified its `__DATA,__data` section. - At unmapped `0x200000000`, Ghidra reported `outside-memory` and `outside_segments`, while Kuna's function assembly rejected the address as not a discovered entry. This reinforces that guidance to inspect a known function is conditional and cannot replace general next/previous object navigation. The interior-byte result does not itself identify the containing instruction's start; #8241 covers that separate question. All calls used the real providers and advertised MCP definitions; the owned static target digest remained unchanged and the target was not executed. One Mach-O, no alternative instruction modes or other platforms were tested.
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#6601
No description provided.