[GH-ISSUE #8288] [Design] Preserve feature-trace evidence when reference ownership is unavailable #6526

Open
opened 2026-11-01 21:11:56 +00:00 by bsakaguchi · 17 comments
Owner

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

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

How should trace_feature retain a useful match and observed reference when the provider cannot resolve the reference's containing procedure?

Context and evidence

Through real REA MCP calls on macOS arm64, using Kuna 1.986 and a self-built, unexecuted Mach-O (SHA-256 ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d):

  1. search_procedures({pattern:"evaluate"}) returned _evaluate at 0x100000430.
  2. xrefs({address:"0x100000430"}) returned source 0x1000004b0.
  3. trace_feature({query:"evaluate"}) returned only capability_unavailable: Kuna does not declare resolve_containing_procedure. It did not return the match or reference. The remediation said to choose another analysis or target.
  4. trace_feature({query:"definitely_missing"}) succeeded with no matches. With Ghidra 12.1.4 on the same binary, the matching trace succeeded and resolved that reference's owner. This compares provider observations, not complete ground truth.

Source inspection at REA commit b43c329 shows the composed workflow returns immediately on containment failure after searching and obtaining xrefs; the existing containment result distinguishes a found owner from a verified absence but has no unavailable state. This also applies to other providers that cannot resolve a source, subject to their actual behavior. The inspected source was unchanged at current main 23de10b.

Expected interaction with targets

Read existing files or captured data. No target execution or mutation is proposed.

Boundary details (optional)

Keep the observed match, source and target addresses, provenance, and a truthful unknown/unsupported owner distinct from not_in_procedure. Do not turn cancellation, malformed provider output, or arbitrary errors into a successful empty result. Preserve the provider's reference-coverage limitations.

Options and tradeoffs

Consider a partial trace with an explicit per-reference unresolved outcome and reason, or an error carrying partial evidence and an actionable recovery path. Assess schema and compatibility cost, the difference between an unsupported capability and an operational failure, and whether session capability discovery already gives adequate advance notice. Reuse shared observation/evidence contracts where possible.

Verification available so far

I have a prototype or observed results.

Success criteria and open questions

Exercise a real MCP trace with an observed xref and unsupported containment, a no-reference query, and a provider that resolves the owner. Check cancellation and real lookup failures at a production boundary; verify that all returned references and limitations remain attributable. The observed result does not establish how often agents encounter this case.

References

Related reference-coverage discussion: https://github.com/morluto/rea/issues/8184

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8288 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed How should `trace_feature` retain a useful match and observed reference when the provider cannot resolve the reference's containing procedure? ### Context and evidence Through real REA MCP calls on macOS arm64, using Kuna 1.986 and a self-built, unexecuted Mach-O (SHA-256 `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`): 1. `search_procedures({pattern:"evaluate"})` returned `_evaluate` at `0x100000430`. 2. `xrefs({address:"0x100000430"})` returned source `0x1000004b0`. 3. `trace_feature({query:"evaluate"})` returned only `capability_unavailable`: Kuna does not declare `resolve_containing_procedure`. It did not return the match or reference. The remediation said to choose another analysis or target. 4. `trace_feature({query:"definitely_missing"})` succeeded with no matches. With Ghidra 12.1.4 on the same binary, the matching trace succeeded and resolved that reference's owner. This compares provider observations, not complete ground truth. Source inspection at REA commit `b43c329` shows the composed workflow returns immediately on containment failure after searching and obtaining xrefs; the existing containment result distinguishes a found owner from a verified absence but has no unavailable state. This also applies to other providers that cannot resolve a source, subject to their actual behavior. The inspected source was unchanged at current main `23de10b`. ### Expected interaction with targets Read existing files or captured data. No target execution or mutation is proposed. ### Boundary details (optional) Keep the observed match, source and target addresses, provenance, and a truthful unknown/unsupported owner distinct from `not_in_procedure`. Do not turn cancellation, malformed provider output, or arbitrary errors into a successful empty result. Preserve the provider's reference-coverage limitations. ### Options and tradeoffs Consider a partial trace with an explicit per-reference unresolved outcome and reason, or an error carrying partial evidence and an actionable recovery path. Assess schema and compatibility cost, the difference between an unsupported capability and an operational failure, and whether session capability discovery already gives adequate advance notice. Reuse shared observation/evidence contracts where possible. ### Verification available so far I have a prototype or observed results. ### Success criteria and open questions Exercise a real MCP trace with an observed xref and unsupported containment, a no-reference query, and a provider that resolves the owner. Check cancellation and real lookup failures at a production boundary; verify that all returned references and limitations remain attributable. The observed result does not establish how often agents encounter this case. ### References Related reference-coverage discussion: https://github.com/morluto/rea/issues/8184
Author
Owner

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

For maintainer visibility: @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

<!-- gh-comment-id:6541839999 --> @morluto commented on GitHub (Oct 31, 2026): For maintainer visibility: @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

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

Follow-up: a real binary_session({detail:"complete"}) in the same Kuna session reports trace_feature as available:false, reason:"provider_missing", with remediation to configure a provider for resolve_containing_procedure. The direct operation is also marked unavailable. So capability discovery does warn about the missing dependency; this is not an unadvertised availability claim. The data-dependent behavior remains: a no-match trace succeeds, while the matching trace reaches the unsupported dependency after obtaining evidence and returns an error. Any change should keep discovery consistent with the chosen partial-result semantics.

<!-- gh-comment-id:6541842452 --> @morluto commented on GitHub (Oct 31, 2026): Follow-up: a real `binary_session({detail:"complete"})` in the same Kuna session reports `trace_feature` as `available:false`, `reason:"provider_missing"`, with remediation to configure a provider for `resolve_containing_procedure`. The direct operation is also marked unavailable. So capability discovery does warn about the missing dependency; this is not an unadvertised availability claim. The data-dependent behavior remains: a no-match trace succeeds, while the matching trace reaches the unsupported dependency after obtaining evidence and returns an error. Any change should keep discovery consistent with the chosen partial-result semantics.
Author
Owner

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

Further controls using the public CLI on the same unchanged target: rea trace <target> evaluate --provider kuna --format json exited 1 with capability_unavailable and the missing containment operation in details; definitely_missing exited 0 with no matches. The equivalent two Ghidra CLI calls both exited 0, and the matching trace included the reference and resolved owner. Target SHA-256 remained unchanged; it was not executed.

Test-scope inspection at b43c329 (the named files were unchanged at 23de10b): tests/boundary/mcp/enhancedTools.traceFeatureCoverage.test.ts uses an in-process provider port that supports containment; it covers capped xrefs, xref failure, cancellation and malformed containment. CapabilityInventory.test.ts checks mandatory dependencies separately. scripts/verify-real-kuna.mjs exercises Kuna references, but does not call the composed trace_feature; the real IDA verifier does exercise a trace. These checks establish useful separate properties, but the inspected Kuna verifier does not check the real-provider composition where xrefs are present and containment is unsupported. This is source inspection, not a claim that the suite was run or that no other test can cover it.

After a design decision, a real CLI/MCP regression using a source-owned fixture with a known reference, an empty-result control and preserved provenance could check the chosen contract. Keep malformed-output and cancellation checks at the boundary rather than converting those failures into unknown owners.

<!-- gh-comment-id:6541855623 --> @morluto commented on GitHub (Oct 31, 2026): Further controls using the public CLI on the same unchanged target: `rea trace <target> evaluate --provider kuna --format json` exited 1 with `capability_unavailable` and the missing containment operation in `details`; `definitely_missing` exited 0 with no matches. The equivalent two Ghidra CLI calls both exited 0, and the matching trace included the reference and resolved owner. Target SHA-256 remained unchanged; it was not executed. Test-scope inspection at `b43c329` (the named files were unchanged at `23de10b`): `tests/boundary/mcp/enhancedTools.traceFeatureCoverage.test.ts` uses an in-process provider port that supports containment; it covers capped xrefs, xref failure, cancellation and malformed containment. `CapabilityInventory.test.ts` checks mandatory dependencies separately. `scripts/verify-real-kuna.mjs` exercises Kuna references, but does not call the composed `trace_feature`; the real IDA verifier does exercise a trace. These checks establish useful separate properties, but the inspected Kuna verifier does not check the real-provider composition where xrefs are present and containment is unsupported. This is source inspection, not a claim that the suite was run or that no other test can cover it. After a design decision, a real CLI/MCP regression using a source-owned fixture with a known reference, an empty-result control and preserved provenance could check the chosen contract. Keep malformed-output and cancellation checks at the boundary rather than converting those failures into unknown owners.
Author
Owner

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

Recovery control on the same source-owned Mach-O through real Kuna MCP: search_procedures found _evaluate at 0x100000430; xrefs returned 0x1000004b0; procedure_callers returned 0x100000480; and procedure_assembly for that caller included 0x1000004b0: bl 0x100000430. Ghidra's independent selected function-body observation also associated that source with the caller. The exact name differs by provider (_main vs entry). Each operation carries its own provider limitations, including omitted reference edges and call-graph scope; static observations do not prove runtime reachability.

This is a working, manual recovery for this direct-call example, not a general containment solution. Xrefs include non-call references, the caller list has no source-site identity, and there may be multiple callers or omitted edges. procedure_info and typed procedure_references are unavailable for Kuna; analyze_function succeeded and explicitly reported typed references unavailable. A useful error or partial-result design could point to the available search/xref/caller/assembly path without presenting its results as automatically joined or complete. Target and ten original project-file hashes remained unchanged; no target execution occurred.

<!-- gh-comment-id:6541869083 --> @morluto commented on GitHub (Oct 31, 2026): Recovery control on the same source-owned Mach-O through real Kuna MCP: `search_procedures` found `_evaluate` at `0x100000430`; `xrefs` returned `0x1000004b0`; `procedure_callers` returned `0x100000480`; and `procedure_assembly` for that caller included `0x1000004b0: bl 0x100000430`. Ghidra's independent selected function-body observation also associated that source with the caller. The exact name differs by provider (`_main` vs `entry`). Each operation carries its own provider limitations, including omitted reference edges and call-graph scope; static observations do not prove runtime reachability. This is a working, manual recovery for this direct-call example, not a general containment solution. Xrefs include non-call references, the caller list has no source-site identity, and there may be multiple callers or omitted edges. `procedure_info` and typed `procedure_references` are unavailable for Kuna; `analyze_function` succeeded and explicitly reported typed references unavailable. A useful error or partial-result design could point to the available search/xref/caller/assembly path without presenting its results as automatically joined or complete. Target and ten original project-file hashes remained unchanged; no target execution occurred.
Author
Owner

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

The same bounded recovery also works with the public one-shot CLI on this fixture: rea xrefs <target> 0x100000430 --provider kuna returned 0x1000004b0; rea function <target> 0x100000430 --provider kuna returned _main at 0x100000480 among its caller observations; and rea function <target> 0x100000480 --provider kuna included the bl instruction at that xref address. All three exited 0 with individual Evidence records and limitations; the target hash was unchanged. This does not imply that every xref is a call or that a complete join can be inferred for other targets.

<!-- gh-comment-id:6541876525 --> @morluto commented on GitHub (Oct 31, 2026): The same bounded recovery also works with the public one-shot CLI on this fixture: `rea xrefs <target> 0x100000430 --provider kuna` returned `0x1000004b0`; `rea function <target> 0x100000430 --provider kuna` returned `_main` at `0x100000480` among its caller observations; and `rea function <target> 0x100000480 --provider kuna` included the `bl` instruction at that xref address. All three exited 0 with individual Evidence records and limitations; the target hash was unchanged. This does not imply that every xref is a call or that a complete join can be inferred for other targets.
Author
Owner

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

Evidence-retention control with real stdio MCP on REA b43c329, Kuna 1.986 and the same unexecuted Mach-O: in a new session, I called only open_binary, trace_feature({query:"evaluate"}), and export_evidence_bundle. The trace returned capability_unavailable for resolve_containing_procedure; the exported bundle had zero records and zero unknowns. The error exposes the missing operation but neither the search match nor the observed xref as recoverable Evidence.

In that same session I explicitly called search_procedures({pattern:"evaluate"}) and xrefs({address:"0x100000430"}). They returned _evaluate and source 0x1000004b0, respectively; a second export contained two Evidence records for those calls. This is a working explicit recovery, with separate observations and their limitations; it does not make the failed composed trace itself recoverable.

As a positive control, a separate fresh Ghidra 12.1.4 session on the same artifact successfully ran trace_feature and the immediately exported bundle contained one complete trace_feature record with the match, references and containment results. The two providers' observed references differed, so this is a workflow-retention control, not a provider-accuracy comparison. Both sessions closed successfully; the target SHA-256 remained ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d. No target execution occurred. Inspected trace, workflow-Evidence and Kuna source files were unchanged between the tested revision and current main 23de10b.

For a chosen partial-result design, verify both the inline failure/partial response and what a subsequent session export can recover. Preserve the existing distinction between unavailable ownership, a verified not_in_procedure, cancellation and malformed provider output; do not imply that every intermediate call must become a standalone retained record.

<!-- gh-comment-id:6542274844 --> @morluto commented on GitHub (Oct 31, 2026): Evidence-retention control with real stdio MCP on REA `b43c329`, Kuna 1.986 and the same unexecuted Mach-O: in a new session, I called only `open_binary`, `trace_feature({query:"evaluate"})`, and `export_evidence_bundle`. The trace returned `capability_unavailable` for `resolve_containing_procedure`; the exported bundle had **zero records and zero unknowns**. The error exposes the missing operation but neither the search match nor the observed xref as recoverable Evidence. In that same session I explicitly called `search_procedures({pattern:"evaluate"})` and `xrefs({address:"0x100000430"})`. They returned `_evaluate` and source `0x1000004b0`, respectively; a second export contained two Evidence records for those calls. This is a working explicit recovery, with separate observations and their limitations; it does not make the failed composed trace itself recoverable. As a positive control, a separate fresh Ghidra 12.1.4 session on the same artifact successfully ran `trace_feature` and the immediately exported bundle contained one complete `trace_feature` record with the match, references and containment results. The two providers' observed references differed, so this is a workflow-retention control, not a provider-accuracy comparison. Both sessions closed successfully; the target SHA-256 remained `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`. No target execution occurred. Inspected trace, workflow-Evidence and Kuna source files were unchanged between the tested revision and current main `23de10b`. For a chosen partial-result design, verify both the inline failure/partial response **and** what a subsequent session export can recover. Preserve the existing distinction between unavailable ownership, a verified `not_in_procedure`, cancellation and malformed provider output; do not imply that every intermediate call must become a standalone retained record.
Author
Owner

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

The procedure-alias issue #8330 interacts with this partial-result gap. In a temporary exploratory REA main 60149282 build, Kuna procedure search matched both primary and alias names. With real Kuna 1.986 MCP on two source-built ELFs containing direct callers, the previously omitted aliases were then found, but trace_feature failed at unsupported resolve_containing_procedure and returned neither the discovered procedure matches nor their references. An unmodified-main paired run returned successful results without those procedure matches instead.

A no-caller control with the same-entry primary/alias symbols returned no xrefs for the entry; the experimental feature trace succeeded and contained both same-address procedure-name matches. Thus this is specifically a reference/containment handoff in these fixtures, not an inherent failure merely from multiple names at one address. The tested change is isolated and incomplete, not an implemented fix; none of the targets were executed or modified. See https://github.com/morluto/rea/issues/8330 for the alias-search design and provenance.

<!-- gh-comment-id:6546225800 --> @morluto commented on GitHub (Oct 31, 2026): The procedure-alias issue #8330 interacts with this partial-result gap. In a temporary exploratory REA main `60149282` build, Kuna procedure search matched both primary and alias names. With real Kuna 1.986 MCP on two source-built ELFs containing direct callers, the previously omitted aliases were then found, but `trace_feature` failed at unsupported `resolve_containing_procedure` and returned neither the discovered procedure matches nor their references. An unmodified-main paired run returned successful results without those procedure matches instead. A no-caller control with the same-entry primary/alias symbols returned no xrefs for the entry; the experimental feature trace succeeded and contained both same-address procedure-name matches. Thus this is specifically a reference/containment handoff in these fixtures, not an inherent failure merely from multiple names at one address. The tested change is isolated and incomplete, not an implemented fix; none of the targets were executed or modified. See https://github.com/morluto/rea/issues/8330 for the alias-search design and provenance.
Author
Owner

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

An isolated, unmerged design experiment on REA main 60149282 preserves this result for a narrow unsupported-capability case. It extends only the trace's output shape with an explicit owner outcome {query_address, found: null, procedure: null, reason}, leaving the primitive containing-procedure contract's found/verified-absence states alone. It retains source and target addresses, adds a residual unknown, and preserves the reference-coverage limitations. This is one possible shape for discussion, not a finished fix.

On the original unexecuted Mach-O with real Kuna 1.986, trace_feature("evaluate") returned the _evaluate match and 0x1000004b0 → 0x100000430 reference with owner unknown instead of failing. A no-match query remained empty. Real Ghidra 12.1.4 on the same target still reported the direct reference's owner as found and separate metadata sources as not_in_procedure. Full and compact MCP output schemas validated for successful tested calls against the advertised schemas; the experimental trace also survived export and a target-free import with its record structurally unchanged. The target digest was unchanged.

Paired with the separate alias-search experiment in #8330, the same partial-trace experiment returned two distinct procedure matches and both observed caller addresses on the versioned ELF instead of losing everything on unsupported containment. On a no-caller control it returned both same-address names with no references.

I also exercised the workflow's compiled application boundary with injected failures: cancellation, an already-aborted request, malformed containment, a retryable capability error, and a capability error with incomplete cleanup remained errors; only the injected non-retryable unsupported capability produced the partial result. These are simulated boundary controls, not real-provider cancellation or cleanup verification.

Open design points: this introduces a new found: null state to the trace-specific schema and existing clients may assume a boolean; the prototype reports truncated: true for unavailable ownership, which may conflate missing ownership with omitted references; and matching a generic non-retryable capability-error tag alone may not prove every error was an undeclared operation. The trace evidence records provider identity and limitations but does not link a separate per-xref source record in this experiment. A production change needs an explicit error/coverage and Evidence-ownership design plus broader lifecycle and compatibility checks.

<!-- gh-comment-id:6546252422 --> @morluto commented on GitHub (Oct 31, 2026): An isolated, **unmerged design experiment** on REA main `60149282` preserves this result for a narrow unsupported-capability case. It extends only the trace's output shape with an explicit owner outcome `{query_address, found: null, procedure: null, reason}`, leaving the primitive containing-procedure contract's found/verified-absence states alone. It retains source and target addresses, adds a residual unknown, and preserves the reference-coverage limitations. This is one possible shape for discussion, not a finished fix. On the original unexecuted Mach-O with real Kuna 1.986, `trace_feature("evaluate")` returned the `_evaluate` match and `0x1000004b0 → 0x100000430` reference with owner unknown instead of failing. A no-match query remained empty. Real Ghidra 12.1.4 on the same target still reported the direct reference's owner as found and separate metadata sources as `not_in_procedure`. Full and compact MCP output schemas validated for successful tested calls against the advertised schemas; the experimental trace also survived export and a target-free import with its record structurally unchanged. The target digest was unchanged. Paired with the separate alias-search experiment in #8330, the same partial-trace experiment returned two distinct procedure matches and both observed caller addresses on the versioned ELF instead of losing everything on unsupported containment. On a no-caller control it returned both same-address names with no references. I also exercised the workflow's compiled application boundary with **injected** failures: cancellation, an already-aborted request, malformed containment, a retryable capability error, and a capability error with incomplete cleanup remained errors; only the injected non-retryable unsupported capability produced the partial result. These are simulated boundary controls, not real-provider cancellation or cleanup verification. Open design points: this introduces a new `found: null` state to the trace-specific schema and existing clients may assume a boolean; the prototype reports `truncated: true` for unavailable ownership, which may conflate missing ownership with omitted references; and matching a generic non-retryable capability-error tag alone may not prove every error was an undeclared operation. The trace evidence records provider identity and limitations but does not link a separate per-xref source record in this experiment. A production change needs an explicit error/coverage and Evidence-ownership design plus broader lifecycle and compatibility checks.
Author
Owner

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

Follow-up to the partial-result experiment: I exercised cancellation at the actual containment boundary through the TypeScript SDK and real Ghidra 12.1.4. An audit-only bridge modification wrote a marker immediately on entering resolve_containing_procedure and paused; no behavior was changed in the target, and the temporary bridge source was restored afterward. The experimental REA build also contained the earlier alias/partial-trace prototype.

On the source-owned Base64 Mach-O, I first started Ghidra and captured its verified process-lineage snapshot. After trace_feature reached the marker, aborting the SDK request caused the client call to reject with the cancellation reason, rather than return the prototype's partial success. The three recorded launcher/descendant PIDs were no longer present within the bounded poll; binary_session then reported the target open and no cleanup pending. The Evidence summary contained no trace_feature record from the cancelled request. Repeating the trace succeeded, including the observed reference and resolved owner, then close_binary succeeded. The target SHA-256 was unchanged. A separate cold-start run also reached the barrier, cancelled, and recovered; its lineage had not yet been observed, so it did not establish process cleanup.

This is one deliberately paused real-provider path, not a general proof of cancellation, cleanup, or late-handshake behavior. The MCP cancellation is observed as an SDK rejection; no server-side typed cancellation response is claimed. Other failure injection in the earlier comment remains simulated, and the output schema/error-classification questions remain open.

<!-- gh-comment-id:6546292256 --> @morluto commented on GitHub (Oct 31, 2026): Follow-up to the partial-result experiment: I exercised cancellation at the actual containment boundary through the TypeScript SDK and real Ghidra 12.1.4. An **audit-only bridge modification** wrote a marker immediately on entering `resolve_containing_procedure` and paused; no behavior was changed in the target, and the temporary bridge source was restored afterward. The experimental REA build also contained the earlier alias/partial-trace prototype. On the source-owned Base64 Mach-O, I first started Ghidra and captured its verified process-lineage snapshot. After `trace_feature` reached the marker, aborting the SDK request caused the client call to reject with the cancellation reason, rather than return the prototype's partial success. The three recorded launcher/descendant PIDs were no longer present within the bounded poll; `binary_session` then reported the target open and no cleanup pending. The Evidence summary contained no `trace_feature` record from the cancelled request. Repeating the trace succeeded, including the observed reference and resolved owner, then `close_binary` succeeded. The target SHA-256 was unchanged. A separate cold-start run also reached the barrier, cancelled, and recovered; its lineage had not yet been observed, so it did not establish process cleanup. This is one deliberately paused real-provider path, not a general proof of cancellation, cleanup, or late-handshake behavior. The MCP cancellation is observed as an SDK rejection; no server-side typed cancellation response is claimed. Other failure injection in the earlier comment remains simulated, and the output schema/error-classification questions remain open.
Author
Owner

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

A newer Kuna reference producer makes this composition boundary observable on a string query, without changing REA:

  • On the owned unexecuted Mach-O crypto-sample (SHA-256 6d276076713030d87100f3a98e551b88de799193d5f9e1b57c1774d583aa77e9), verified Kuna 1.986 / REA d54a4661da20382ad8456564a08569fdd24131c5 returns the Base64 alphabet from trace_feature, with no references and the documented incomplete-reference limitation.
  • An unverified Kuna source build at 8c74a944d74f8d3349755e05441a9628b4753111 finds a data reference at 0x10000038c to that string. Direct Kuna xrefs --to associates it with _audit_base64_character at 0x100000378. REA's separate search_strings and xrefs calls return the string and that source address, but trace_feature returns only capability_unavailable for resolve_containing_procedure and its generic recovery. get_evidence_bundle(detail: summary) immediately after the failed trace contained no retained records; the subsequent explicit searches produced their own observations.
  • Ghidra 12.1.4 succeeds with the string and a separately observed reference at 0x100000390 with the containing function. The different provider source addresses represent their own observations, not a claim of identical reference semantics. A nonexistent-query control succeeds with no matches for all three sessions. Explicit procedure_address for the owner name, which was independently obtained from direct Kuna output, succeeds; that does not make REA's xref itself provide an owner.

All checks used public MCP with full advertised output schemas; the fixture hash stayed unchanged. This is not a verified-release upgrade recommendation or a claim that every newly discovered reference causes a failure. It demonstrates that improved upstream discovery can turn an otherwise successful high-level workflow into an error unless REA preserves the match/reference and marks the unavailable owner honestly. Related structured coverage question: #8184.

<!-- gh-comment-id:6548261540 --> @morluto commented on GitHub (Oct 31, 2026): A newer Kuna reference producer makes this composition boundary observable on a **string** query, without changing REA: - On the owned unexecuted Mach-O `crypto-sample` (SHA-256 `6d276076713030d87100f3a98e551b88de799193d5f9e1b57c1774d583aa77e9`), verified Kuna 1.986 / REA `d54a4661da20382ad8456564a08569fdd24131c5` returns the Base64 alphabet from `trace_feature`, with no references and the documented incomplete-reference limitation. - An **unverified** Kuna source build at `8c74a944d74f8d3349755e05441a9628b4753111` finds a `data` reference at `0x10000038c` to that string. Direct Kuna `xrefs --to` associates it with `_audit_base64_character` at `0x100000378`. REA's separate `search_strings` and `xrefs` calls return the string and that source address, but `trace_feature` returns only `capability_unavailable` for `resolve_containing_procedure` and its generic recovery. `get_evidence_bundle(detail: summary)` immediately after the failed trace contained no retained records; the subsequent explicit searches produced their own observations. - Ghidra 12.1.4 succeeds with the string and a separately observed reference at `0x100000390` with the containing function. The different provider source addresses represent their own observations, not a claim of identical reference semantics. A nonexistent-query control succeeds with no matches for all three sessions. Explicit `procedure_address` for the owner name, which was independently obtained from direct Kuna output, succeeds; that does not make REA's xref itself provide an owner. All checks used public MCP with full advertised output schemas; the fixture hash stayed unchanged. This is not a verified-release upgrade recommendation or a claim that every newly discovered reference causes a failure. It demonstrates that improved upstream discovery can turn an otherwise successful high-level workflow into an error unless REA preserves the match/reference and marks the unavailable owner honestly. Related structured coverage question: #8184.
Author
Owner

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

Draft PR #8368 carries a revised, isolated implementation for review. For a non-retryable unavailable owner lookup with no incomplete cleanup, it retains the match and reference, records status: "unavailable" with the provider and reason, and leaves reference truncation separate from the unknown owner. Cancellation, retryable errors, malformed output, and incomplete cleanup still fail. This expands the trace output contract, so clients that assume every owner was resolved need to handle the new state.

The new public MCP regression fails against the baseline and passes with verified Kuna 1.986. Focused boundary tests and real Ghidra 12.1.4 controls also passed; the PR documents the exact scope and remaining verification limits. The PR is a draft, and its human ownership and readiness declarations remain open.

<!-- gh-comment-id:6548411177 --> @morluto commented on GitHub (Oct 31, 2026): Draft PR #8368 carries a revised, isolated implementation for review. For a non-retryable unavailable owner lookup with no incomplete cleanup, it retains the match and reference, records `status: "unavailable"` with the provider and reason, and leaves reference truncation separate from the unknown owner. Cancellation, retryable errors, malformed output, and incomplete cleanup still fail. This expands the trace output contract, so clients that assume every owner was resolved need to handle the new state. The new public MCP regression fails against the baseline and passes with verified Kuna 1.986. Focused boundary tests and real Ghidra 12.1.4 controls also passed; the PR documents the exact scope and remaining verification limits. The PR is a draft, and its human ownership and readiness declarations remain open.
Author
Owner

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

Real-provider recovery control on #8368 (de0305d), the owned unexecuted Mach-O from the report, and public MCP full output schemas:

  1. Open the target with verified Kuna 1.986 and trace_feature({query:"evaluate"}). The partial trace preserves reference source 0x1000004b0 with containing_procedure.status: "unavailable" and Kuna's reason.
  2. Reopen the same target with Ghidra 12.1.4 in the same MCP session and call resolve_containing_procedure({address:"0x1000004b0"}). Ghidra reports that address inside function entry, beginning at 0x100000480.
  3. Export the bundle, close, start a fresh target-free server and import it. Both the original Kuna trace and the separately issued Ghidra containing-procedure Evidence are structurally identical to their original records. The original trace still honestly says its Kuna owner was unavailable; it is not automatically rewritten or linked to the later Ghidra observation. The target hash was unchanged.

This is a usable follow-up for this tested target and address, not proof that provider coordinates agree for arbitrary binaries or that switching preserves an existing Ghidra session's annotations. The query supplies an independently recorded Ghidra observation, not a retroactive Kuna observation. A fresh session is appropriate when keeping an existing provider's transient edits matters (#8289). The experiment does not show that an autonomous agent discovers or chooses this sequence.

<!-- gh-comment-id:6548550181 --> @morluto commented on GitHub (Oct 31, 2026): Real-provider recovery control on #8368 (`de0305d`), the owned unexecuted Mach-O from the report, and public MCP full output schemas: 1. Open the target with verified Kuna 1.986 and `trace_feature({query:"evaluate"})`. The partial trace preserves reference source `0x1000004b0` with `containing_procedure.status: "unavailable"` and Kuna's reason. 2. Reopen the **same target** with Ghidra 12.1.4 in the same MCP session and call `resolve_containing_procedure({address:"0x1000004b0"})`. Ghidra reports that address inside function `entry`, beginning at `0x100000480`. 3. Export the bundle, close, start a fresh target-free server and import it. Both the original Kuna trace and the separately issued Ghidra containing-procedure Evidence are structurally identical to their original records. The original trace still honestly says its Kuna owner was unavailable; it is not automatically rewritten or linked to the later Ghidra observation. The target hash was unchanged. This is a usable follow-up for this tested target and address, not proof that provider coordinates agree for arbitrary binaries or that switching preserves an existing Ghidra session's annotations. The query supplies an independently recorded Ghidra observation, not a retroactive Kuna observation. A fresh session is appropriate when keeping an existing provider's transient edits matters (#8289). The experiment does not show that an autonomous agent discovers or chooses this sequence.
Author
Owner

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

Coordinate caveat to the preceding provider-switch control: #8372 now has a real-provider counterexample where reopening the same binary in a rebased Ghidra project and passing the original Kuna source address succeeds but resolves a different function. The correct corresponding Ghidra address required correlating the source-file mappings; Ghidra correctly resolved each address in its own selected project. This does not invalidate the matching-coordinate control above, but it means a general recovery recommendation should not suggest reusing numeric addresses without establishing coordinate correspondence.

<!-- gh-comment-id:6548579387 --> @morluto commented on GitHub (Oct 31, 2026): Coordinate caveat to the preceding provider-switch control: [#8372](https://github.com/morluto/rea/issues/8372) now has a real-provider counterexample where reopening the **same** binary in a rebased Ghidra project and passing the original Kuna source address succeeds but resolves a different function. The correct corresponding Ghidra address required correlating the source-file mappings; Ghidra correctly resolved each address in its own selected project. This does not invalidate the matching-coordinate control above, but it means a general recovery recommendation should not suggest reusing numeric addresses without establishing coordinate correspondence.
Author
Owner

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

While testing #8368, I found and fixed a distinction in the proposed recovery. In an MCP test using REA's IDA adapter and a simulated IDA upstream, the server reported unknown auto-analysis readiness at the containment boundary. The earlier PR branch incorrectly turned that non-retryable server_health refusal into successful unavailable-owner Evidence, losing its readiness diagnostic and recovery instruction.

The PR now only converts refusals attributed to resolve_containing_procedure; the IDA readiness failure remains a typed error. Controlled tests cover readiness becoming unknown both before containment and after its upstream observation, including preservation of the latter's partial Evidence. The new regression failed against the earlier PR branch and passes on 66fa52613. A real Kuna 1.986 verifier and real Ghidra 12.1.4 MCP control still pass, with the same normalized trace results as before this refinement. IDA itself was not run.

<!-- gh-comment-id:6548657816 --> @morluto commented on GitHub (Oct 31, 2026): While testing #8368, I found and fixed a distinction in the proposed recovery. In an MCP test using REA's IDA adapter and a **simulated** IDA upstream, the server reported unknown auto-analysis readiness at the containment boundary. The earlier PR branch incorrectly turned that non-retryable `server_health` refusal into successful unavailable-owner Evidence, losing its readiness diagnostic and recovery instruction. The PR now only converts refusals attributed to `resolve_containing_procedure`; the IDA readiness failure remains a typed error. Controlled tests cover readiness becoming unknown both before containment and after its upstream observation, including preservation of the latter's partial Evidence. The new regression failed against the earlier PR branch and passes on `66fa52613`. A real Kuna 1.986 verifier and real Ghidra 12.1.4 MCP control still pass, with the same normalized trace results as before this refinement. IDA itself was not run.
Author
Owner

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

Partial-result snapshot follow-up on #8368 (66fa52613): I exercised a saved Ghidra workflow with a deliberately instrumented disposable bridge. The bridge returned method_unavailable for resolve_containing_procedure; real Ghidra 12.1.4 produced the match and xrefs. This is an injected capability refusal, not a claim that an unmodified Ghidra bridge naturally failed.

  • Public MCP returned the partial trace with the unavailable owner states. Closing to an explicit snapshot saved one trace_feature workflow entry with revision 4.
  • After saving, I changed the disposable bridge's refusal reason. The CLI rea trace ... --snapshot <saved> returned the original trace and original refusal reason, with the same Evidence ID; a fresh CLI control without the snapshot returned the new refusal reason. This demonstrates the saved workflow replay for this request and controlled setup.
  • An MCP reopen and same query produced the same normalized trace, and export/import into a target-free server retained the trace record. MCP's workflow handler re-executes the workflow, so I am not treating that equality as proof of an MCP workflow-cache hit. The target and saved snapshot hashes were unchanged during the CLI checks; the disposable bridge was restored.

The real verified Kuna partial trace remains a live-cache case: its earlier snapshot retained Evidence but did not produce a replayable workflow entry. Other saved-provider states and real IDA/Hopper remain unverified.

<!-- gh-comment-id:6548678984 --> @morluto commented on GitHub (Oct 31, 2026): Partial-result snapshot follow-up on #8368 (`66fa52613`): I exercised a saved Ghidra workflow with a **deliberately instrumented disposable bridge**. The bridge returned `method_unavailable` for `resolve_containing_procedure`; real Ghidra 12.1.4 produced the match and xrefs. This is an injected capability refusal, not a claim that an unmodified Ghidra bridge naturally failed. - Public MCP returned the partial trace with the unavailable owner states. Closing to an explicit snapshot saved one `trace_feature` workflow entry with revision 4. - After saving, I changed the disposable bridge's refusal reason. The CLI `rea trace ... --snapshot <saved>` returned the original trace and original refusal reason, with the same Evidence ID; a fresh CLI control without the snapshot returned the new refusal reason. This demonstrates the saved workflow replay for this request and controlled setup. - An MCP reopen and same query produced the same normalized trace, and export/import into a target-free server retained the trace record. MCP's workflow handler re-executes the workflow, so I am not treating that equality as proof of an MCP workflow-cache hit. The target and saved snapshot hashes were unchanged during the CLI checks; the disposable bridge was restored. The real verified Kuna partial trace remains a live-cache case: its earlier snapshot retained Evidence but did not produce a replayable workflow entry. Other saved-provider states and real IDA/Hopper remain unverified.
Author
Owner

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

Multi-reference control for #8368: on a new owned, unexecuted arm64 Mach-O with two distinct direct call sites to _goal, verified Kuna 1.986's direct xrefs returned both sites. Baseline REA d54a4661 failed trace_feature("goal") at owner lookup; the PR returned both exact source addresses, each with an unavailable Kuna owner and its own residual unknown, with truncated:false. Real Ghidra 12.1.4 returned both call sites with the same containing function, plus separate non-procedure references; no claim is made that providers have identical reference inventories. The fixture SHA-256 stayed aab4a4b9cc300f7be8e35d2f869ffea8d30d83391510c3fedce4a1237a844344.

The PR's existing real Kuna verifier now compiles a source-owned fixture with two checksum call sites and checks every direct-provider incoming site against the public MCP feature trace, including unavailable owners. It passed with verified Kuna; running the verifier against base failed at the expected owner capability error with cleanup complete. A controlled MCP regression separately covers a shared source across two distinct targets, one capped target, and one unavailable owner; that shared-source case is simulated, not asserted as a real-provider observation.

<!-- gh-comment-id:6548720889 --> @morluto commented on GitHub (Oct 31, 2026): Multi-reference control for #8368: on a new owned, unexecuted arm64 Mach-O with two distinct direct call sites to `_goal`, verified Kuna 1.986's direct `xrefs` returned both sites. Baseline REA `d54a4661` failed `trace_feature("goal")` at owner lookup; the PR returned both exact source addresses, each with an unavailable Kuna owner and its own residual unknown, with `truncated:false`. Real Ghidra 12.1.4 returned both call sites with the same containing function, plus separate non-procedure references; no claim is made that providers have identical reference inventories. The fixture SHA-256 stayed `aab4a4b9cc300f7be8e35d2f869ffea8d30d83391510c3fedce4a1237a844344`. The PR's existing real Kuna verifier now compiles a source-owned fixture with two checksum call sites and checks every direct-provider incoming site against the public MCP feature trace, including unavailable owners. It passed with verified Kuna; running the verifier against base failed at the expected owner capability error with cleanup complete. A controlled MCP regression separately covers a shared source across two distinct targets, one capped target, and one unavailable owner; that shared-source case is simulated, not asserted as a real-provider observation.
Author
Owner

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

Follow-up on merged #8368: on current main 6e9ee97a69cb16c7150d8b550e705cba055ee4f0, real Kuna 1.986 trace_feature({query:"audit_initial"}) returned the observed procedure and call site 0x1000003e8, with containing_procedure.status: "unavailable" and a corresponding residual unknown. Both full and compact advertised schemas were exercised through the TypeScript MCP SDK. A no-match control succeeded with empty matches.

On the same unexecuted Mach-O, real Ghidra 12.1.4 fresh analysis resolved that call site's owner as _audit_dispatch; the selected incomplete-project control reported only the references it observed. Each trace and no-match result, including limitations, matched after export and import to a separate target-free server. Target, selected-project source files, and bundle hashes remained unchanged. One macOS arm64 fixture was tested; this does not independently establish other providers or operational failure/cancellation paths.

The separate question of reference discovery coverage remains in #8184; unavailable owner and missing references are different unknowns.

<!-- gh-comment-id:6550663370 --> @morluto commented on GitHub (Oct 31, 2026): Follow-up on merged #8368: on current main `6e9ee97a69cb16c7150d8b550e705cba055ee4f0`, real Kuna 1.986 `trace_feature({query:"audit_initial"})` returned the observed procedure and call site `0x1000003e8`, with `containing_procedure.status: "unavailable"` and a corresponding residual unknown. Both full and compact advertised schemas were exercised through the TypeScript MCP SDK. A no-match control succeeded with empty matches. On the same unexecuted Mach-O, real Ghidra 12.1.4 fresh analysis resolved that call site's owner as `_audit_dispatch`; the selected incomplete-project control reported only the references it observed. Each trace and no-match result, including limitations, matched after export and import to a separate target-free server. Target, selected-project source files, and bundle hashes remained unchanged. One macOS arm64 fixture was tested; this does not independently establish other providers or operational failure/cancellation paths. The separate question of reference discovery coverage remains in #8184; unavailable owner and missing references are different unknowns.
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#6526
No description provided.