[GH-ISSUE #8733] [Design] Make retained graph results reusable across MCP snapshot handoffs #7529

Open
opened 2026-11-03 07:17:04 +00:00 by bsakaguchi · 0 comments
Owner

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

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

A Ghidra get_call_graph result and its source Evidence survive a snapshot handoff, but repeating the exact workflow through a new MCP session starts Ghidra again, even though the snapshot contains a matching get_call_graph workflow entry. The result is correct in the tested case and retains its original source link. The question is whether an agent should be able to select the retained workflow result without paying for another provider analysis.

Reproduction

On REA main 9ebbe67e05af08b567e215340da993c08dae378f, Ghidra 12.1.4, Node 24.22.1 and macOS arm64:

  1. Open a self-built thin Mach-O with Ghidra, call get_call_graph with {address: "_audit_value", direction: "forward"}, and close to a new absolute snapshot_path.
  2. The resulting snapshot has one get_call_graph workflow entry, no primitive replay entries, and the graph and its linked procedure_callees Evidence in its bundle.
  3. Start a fresh stdio MCP process, open the same target with that snapshot, and call binary_session with complete detail. Its analysis_run.process_lineage.status is not_observed.
  4. Repeat the graph request, then inspect binary_session again. Process lineage now reports a verified Ghidra process family. The call took about 3.4 seconds in this one run. The target hash remained unchanged and it was not executed.

The returned graph Evidence ID and its callee Evidence link match the original. This control establishes provider startup during the request, not the exact internal operations executed or typical timings. Compact-profile stdio MCP was tested; other graph shapes, platforms and providers are unverified.

Existing retained-record handoff

A separate fresh compact MCP session opened the same snapshot and called get_evidence_bundle with detail: "records" and filters: {evidence_id: <original graph ID>}. It returned the complete graph record, the original callee link, no missing links, and a limitation saying the record is historical and does not establish current live state. binary_session process lineage remained not_observed before and after. This is an existing way to reuse the historical result without starting Ghidra when the agent knows its Evidence ID; it is not a new analysis or a portable bundle. Evaluate whether discovery and guidance are sufficient before adding another mechanism.

Discovery without a known Evidence ID

A real-Ghidra compact MCP control saved forward and backward get_call_graph results for the same procedure, target and profile, then opened the snapshot in a fresh session. get_evidence_bundle with detail: "summary" and filters: {operation: "get_call_graph"} found both records without launching Ghidra, but the returned summaries had identical operation, subject and profile metadata and did not include the address or direction parameters. A subsequent detail: "records" query returned both complete records in one page, including their respective forward and backward parameters and graph payloads; Ghidra remained unstarted. A further real MCP control selected one candidate with inspect_analysis_view using source: {kind: "retained-evidence", evidence_id: ...} and view: {kind: "summary"}. Its source_parameters included the original address and direction, alongside a bounded graph page, and process lineage stayed not_observed. Thus an agent can inspect candidates without fetching complete graph bodies, but this route takes one view request per candidate. These controls establish available choices and their tradeoffs, not an observed autonomous-agent failure. Consider a bounded, format-aware query identity projection or filtering if it improves discovery; preserve arbitrary caller input, unknowns, and the existing size/retention contracts.

Source-bearing primitive control

A separate real-Ghidra existing-project control used an owned project created with REA's ReaGhidraAnalysisOptions pre-script. Its pseudocode Evidence linked to a historical analyzer-report record. The exported snapshot retained both records but had no primitive replay entries; opening that snapshot and requesting the same explicit-document pseudocode started Ghidra again and preserved the original source link. Source inspection shows this exclusion is deliberate: AnalysisSnapshotCache.record declines source-bearing executions because the entry alone does not contain their source closure. This is a distinct primitive-read case, not evidence that skipping this safeguard is safe. Project and executable hashes were unchanged during REA use.

Expected behavior

Clarify and, if appropriate, offer an agent a way to reuse an exact retained workflow observation with its original source links and an explicit indication that it was not refreshed. Preserve a way to request a fresh analysis and reject incompatible or ambiguous bindings. Distinguish an existing Evidence lookup from re-executing a workflow; do not imply a historical result is live.

Impact and scope

On larger targets this may repeat provider startup and analysis for an answer the investigation already retains. That impact is an inference; no large-target benchmark or autonomous-agent trace was run. The existing snapshot documentation says only eligible exact queries can reuse observations, so this report does not assert a guarantee that get_call_graph is currently eligible.

REA version

9ebbe67e05af08b567e215340da993c08dae378f

Runtime and platform

macOS arm64, Node 24.22.1, Ghidra 12.1.4, JDK 21, stdio MCP compact profile.

Target and artifact context

Self-built, unexecuted arm64 Mach-O, SHA-256 0e0ecf82c96e4918ee2ca1287dc25513d8fd13d5ab7fa5b98db00ad342f03930; temporary caller-owned snapshot.

Interface

MCP

Earliest failure stage

Analysis or provider dispatch

Relevant output or evidence

Snapshot: one get_call_graph workflow entry; zero primitive replay entries. Session process lineage: not_observed before the call, snapshots with a verified Ghidra process family afterward. The returned workflow record linked to the retained original callee Evidence.

Analysis or suspected cause

Source-derived: the CLI's snapshotEvidenceForQuery can find matching workflow entries; the session's provider lookup uses primitive entries, and composed workflow execution records source Evidence separately. Verify the complete MCP admission and delivery paths, target/profile commitments, currentness, source-link closure and cancellation semantics before choosing whether to add reuse or provide a clearer retained-record handoff. Related #8085 concerns repeated CLI decompilation; #8732 concerns direct replay Evidence identity.

Typed outcome or recovery expected

A clear distinction between historical retained results and fresh provider work, with source provenance and exact coverage intact. Exercise provider startup, exact and changed inputs, both MCP profiles, ambiguous/missing sources, and target/profile changes.

Additional context

@gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Nov 3, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8733 ### 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 A Ghidra `get_call_graph` result and its source Evidence survive a snapshot handoff, but repeating the exact workflow through a new MCP session starts Ghidra again, even though the snapshot contains a matching `get_call_graph` workflow entry. The result is correct in the tested case and retains its original source link. The question is whether an agent should be able to select the retained workflow result without paying for another provider analysis. ### Reproduction On REA main `9ebbe67e05af08b567e215340da993c08dae378f`, Ghidra 12.1.4, Node 24.22.1 and macOS arm64: 1. Open a self-built thin Mach-O with Ghidra, call `get_call_graph` with `{address: "_audit_value", direction: "forward"}`, and close to a new absolute `snapshot_path`. 2. The resulting snapshot has one `get_call_graph` workflow entry, no primitive replay entries, and the graph and its linked `procedure_callees` Evidence in its bundle. 3. Start a fresh stdio MCP process, open the same target with that snapshot, and call `binary_session` with complete detail. Its `analysis_run.process_lineage.status` is `not_observed`. 4. Repeat the graph request, then inspect `binary_session` again. Process lineage now reports a verified Ghidra process family. The call took about 3.4 seconds in this one run. The target hash remained unchanged and it was not executed. The returned graph Evidence ID and its callee Evidence link match the original. This control establishes provider startup during the request, not the exact internal operations executed or typical timings. Compact-profile stdio MCP was tested; other graph shapes, platforms and providers are unverified. ### Existing retained-record handoff A separate fresh compact MCP session opened the same snapshot and called `get_evidence_bundle` with `detail: "records"` and `filters: {evidence_id: <original graph ID>}`. It returned the complete graph record, the original callee link, no missing links, and a limitation saying the record is historical and does not establish current live state. `binary_session` process lineage remained `not_observed` before and after. This is an existing way to reuse the historical result without starting Ghidra when the agent knows its Evidence ID; it is not a new analysis or a portable bundle. Evaluate whether discovery and guidance are sufficient before adding another mechanism. ### Discovery without a known Evidence ID A real-Ghidra compact MCP control saved forward and backward `get_call_graph` results for the same procedure, target and profile, then opened the snapshot in a fresh session. `get_evidence_bundle` with `detail: "summary"` and `filters: {operation: "get_call_graph"}` found both records without launching Ghidra, but the returned summaries had identical operation, subject and profile metadata and did not include the address or direction parameters. A subsequent `detail: "records"` query returned both complete records in one page, including their respective `forward` and `backward` parameters and graph payloads; Ghidra remained unstarted. A further real MCP control selected one candidate with `inspect_analysis_view` using `source: {kind: "retained-evidence", evidence_id: ...}` and `view: {kind: "summary"}`. Its `source_parameters` included the original address and direction, alongside a bounded graph page, and process lineage stayed `not_observed`. Thus an agent can inspect candidates without fetching complete graph bodies, but this route takes one view request per candidate. These controls establish available choices and their tradeoffs, not an observed autonomous-agent failure. Consider a bounded, format-aware query identity projection or filtering if it improves discovery; preserve arbitrary caller input, unknowns, and the existing size/retention contracts. ### Source-bearing primitive control A separate real-Ghidra existing-project control used an owned project created with REA's `ReaGhidraAnalysisOptions` pre-script. Its pseudocode Evidence linked to a historical analyzer-report record. The exported snapshot retained both records but had no primitive replay entries; opening that snapshot and requesting the same explicit-document pseudocode started Ghidra again and preserved the original source link. Source inspection shows this exclusion is deliberate: `AnalysisSnapshotCache.record` declines source-bearing executions because the entry alone does not contain their source closure. This is a distinct primitive-read case, not evidence that skipping this safeguard is safe. Project and executable hashes were unchanged during REA use. ### Expected behavior Clarify and, if appropriate, offer an agent a way to reuse an exact retained workflow observation with its original source links and an explicit indication that it was not refreshed. Preserve a way to request a fresh analysis and reject incompatible or ambiguous bindings. Distinguish an existing Evidence lookup from re-executing a workflow; do not imply a historical result is live. ### Impact and scope On larger targets this may repeat provider startup and analysis for an answer the investigation already retains. That impact is an inference; no large-target benchmark or autonomous-agent trace was run. The existing snapshot documentation says only eligible exact queries can reuse observations, so this report does not assert a guarantee that `get_call_graph` is currently eligible. ### REA version `9ebbe67e05af08b567e215340da993c08dae378f` ### Runtime and platform macOS arm64, Node 24.22.1, Ghidra 12.1.4, JDK 21, stdio MCP compact profile. ### Target and artifact context Self-built, unexecuted arm64 Mach-O, SHA-256 `0e0ecf82c96e4918ee2ca1287dc25513d8fd13d5ab7fa5b98db00ad342f03930`; temporary caller-owned snapshot. ### Interface MCP ### Earliest failure stage Analysis or provider dispatch ### Relevant output or evidence Snapshot: one `get_call_graph` workflow entry; zero primitive replay entries. Session process lineage: `not_observed` before the call, `snapshots` with a verified Ghidra process family afterward. The returned workflow record linked to the retained original callee Evidence. ### Analysis or suspected cause Source-derived: the CLI's `snapshotEvidenceForQuery` can find matching workflow entries; the session's provider lookup uses primitive entries, and composed workflow execution records source Evidence separately. Verify the complete MCP admission and delivery paths, target/profile commitments, currentness, source-link closure and cancellation semantics before choosing whether to add reuse or provide a clearer retained-record handoff. Related #8085 concerns repeated CLI decompilation; #8732 concerns direct replay Evidence identity. ### Typed outcome or recovery expected A clear distinction between historical retained results and fresh provider work, with source provenance and exact coverage intact. Exercise provider startup, exact and changed inputs, both MCP profiles, ambiguous/missing sources, and target/profile changes. ### Additional context @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#7529
No description provided.