[GH-ISSUE #2550] fix(call-path): caller uncertainty blocks complete forward absence results #867

Closed
opened 2026-10-15 18:29:07 +00:00 by bsakaguchi · 1 comment
Owner

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

Summary

A forward path search cannot establish that a goal is unreachable from modern headless IDA function Evidence, even when the provider has returned every direct callee. In the reproduced case, the start function has a complete empty callee set, but the search returns unknown because the function's unavailable callers make its combined relationship coverage unknown. The failure concerns the interpretation of coverage during forward search; callers must remain unknown for workflows that depend on them.

Steps to reproduce

  1. Use the recorded production-adapter fixture from tests/fixtures/idaMcp.ts to create an x86_64 target, a RecordingIdaMcp in headless mode, and an IdaSessionClient configured with command fixture, empty args/env, mode headless, timeoutMs 1000, and workspaceRoot equal to the fixture root.
  2. Override only the producer's callees tool to return the following valid modern reply. Leave lookup, lifecycle, assembly and pseudocode replies at their fixture defaults.
[{"callees":[],"more":false}]
  1. Execute procedure_callees and analyze_function with {"procedure":"main"}. Confirm the direct read is complete and the dossier's relationship coverage is unknown solely because callers are unavailable.
  2. Create authenticated analyze_function Evidence with createEvidence using the fixture target, IDA_PROVIDER_IDENTITY, parameters {"procedure":"main"}, and the dossier execution's returned result, relationshipCoverage and limitations. Use confidence derived and authority shipped-artifact. Do not mutate an existing Evidence record or its digest.
  3. Pass that record as the sole functions entry to buildCallPath with start {"address":"0x1000"} and goal {"address":"0x3000"}. This is the domain implementation used by build_call_path. The start has no successors, so there is no missing reachable dossier or additional provider read.
  4. For a discriminating control, create a separate authenticated record with the same dossier and limitations but the direct callee read's coverage. The control establishes not_found. Repeat with more true to confirm that incomplete callee coverage still produces unknown. The metadata control isolates the cause; rewriting combined coverage is not a proposed repair.

Expected behavior

A forward direct-callee search over a completely observed empty start closure reports not_found with search_scope.exhaustive true. Unavailable callers remain unknown and visible, but cannot add an outgoing edge to the forward closure. Provider caveats do not reduce the completeness of a direct callee read returned without a known limit. Workflows that compare both caller and callee sets must retain the caller uncertainty.

Actual behavior

The production client returned complete coverage for the empty direct callee read and unknown coverage for the dossier, with reason "Callers: Upstream xrefs do not establish direct caller relationships." The forward search accepted the authenticated dossier Evidence and returned unknown with search_scope.exhaustive false. The control using complete callee coverage returned not_found with exhaustive true despite retaining the original limitations. With more true, the direct read was partial and both searches stayed unknown with exhaustive false.

Evidence

  • Expected source: docs/tool-design.md:60-64 defines completeness of the observed direct relationship set; src/contracts/sessionToolContracts.ts:126-128 defines direct-callee path construction; src/domain/callPath.test.ts:399-413 requires not_found for a completely covered empty start closure; docs/ida-provider.md:129 requires unavailable callers to stay unknown.
  • Failure source: src/ida/IdaOperationRunner.ts:432-443 supplies caller uncertainty and :604-612 combines it with callee coverage; src/domain/callPath.ts:258-263 treats any non-complete combined state as an incomplete forward expansion. A recorded production-client reproduction followed by the actual domain search returned unknown for an empty, complete callee closure.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

One focused test file passed both the complete and truncated callee cases. The x86-only target selected the modern callees branch and no callgraph call occurred. Authentication, artifact binding, and provider admission succeeded. This verifies the recorded adapter and domain consumer; it does not claim live IDA or public MCP transport verification. The native profile shares the same caller and aggregation branches by source inspection, but was not separately exercised.

The same failure is described in another contributor's open issue #2322. Its proposed fix #2371 was still open and unmerged when checked. This report preserves the requirement to keep caller uncertainty instead of restoring globally complete dossier coverage.

Restoration check

With the valid complete empty callee reply and the unmodified returned function Evidence, the forward search reports not_found and exhaustive true while retaining the unknown-caller explanation. A partial or unavailable callee read still yields unknown and exhaustive false; a reachable child lacking Evidence still prevents an exhaustive absence result. Comparing equal caller/callee collections whose caller coverage is unknown must continue to report unknown rather than equality. These checks distinguish restoring forward search from incorrectly declaring the combined dossier complete.

Runtime or environment

Failure was verified at a2d8b94dd5 and is still present at 8b181716ac by source recheck. Node.js v26.10.0, npm 11.19.1, Vitest v5.0.3. Recorded modern headless x86_64 adapter fixture; no real IDA engine.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Complete forward closure cannot establish an absence result for the reproduced modern IDA dossier, and the shared aggregation/consumer path also applies to native dossiers by source inspection. Observed edges remain available and this failure does not cross a security boundary.
  • Workaround status: available
  • Workaround basis: For the demonstrated leaf case, procedure_callees independently returns a complete empty set, which supports a manual absence conclusion. That direct-read Evidence cannot be substituted directly into build_call_path, which requires analyze_function records; larger closures require separate reads and manual reasoning.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2550 ## Summary A forward path search cannot establish that a goal is unreachable from modern headless IDA function Evidence, even when the provider has returned every direct callee. In the reproduced case, the start function has a complete empty callee set, but the search returns unknown because the function's unavailable callers make its combined relationship coverage unknown. The failure concerns the interpretation of coverage during forward search; callers must remain unknown for workflows that depend on them. ## Steps to reproduce 1. Use the recorded production-adapter fixture from tests/fixtures/idaMcp.ts to create an x86_64 target, a RecordingIdaMcp in headless mode, and an IdaSessionClient configured with command fixture, empty args/env, mode headless, timeoutMs 1000, and workspaceRoot equal to the fixture root. 2. Override only the producer's callees tool to return the following valid modern reply. Leave lookup, lifecycle, assembly and pseudocode replies at their fixture defaults. ```json [{"callees":[],"more":false}] ``` 3. Execute procedure_callees and analyze_function with {"procedure":"main"}. Confirm the direct read is complete and the dossier's relationship coverage is unknown solely because callers are unavailable. 4. Create authenticated analyze_function Evidence with createEvidence using the fixture target, IDA_PROVIDER_IDENTITY, parameters {"procedure":"main"}, and the dossier execution's returned result, relationshipCoverage and limitations. Use confidence derived and authority shipped-artifact. Do not mutate an existing Evidence record or its digest. 5. Pass that record as the sole functions entry to buildCallPath with start {"address":"0x1000"} and goal {"address":"0x3000"}. This is the domain implementation used by build_call_path. The start has no successors, so there is no missing reachable dossier or additional provider read. 6. For a discriminating control, create a separate authenticated record with the same dossier and limitations but the direct callee read's coverage. The control establishes not_found. Repeat with more true to confirm that incomplete callee coverage still produces unknown. The metadata control isolates the cause; rewriting combined coverage is not a proposed repair. ## Expected behavior A forward direct-callee search over a completely observed empty start closure reports not_found with search_scope.exhaustive true. Unavailable callers remain unknown and visible, but cannot add an outgoing edge to the forward closure. Provider caveats do not reduce the completeness of a direct callee read returned without a known limit. Workflows that compare both caller and callee sets must retain the caller uncertainty. ## Actual behavior The production client returned complete coverage for the empty direct callee read and unknown coverage for the dossier, with reason "Callers: Upstream xrefs do not establish direct caller relationships." The forward search accepted the authenticated dossier Evidence and returned unknown with search_scope.exhaustive false. The control using complete callee coverage returned not_found with exhaustive true despite retaining the original limitations. With more true, the direct read was partial and both searches stayed unknown with exhaustive false. ## Evidence - Expected source: docs/tool-design.md:60-64 defines completeness of the observed direct relationship set; src/contracts/sessionToolContracts.ts:126-128 defines direct-callee path construction; src/domain/callPath.test.ts:399-413 requires not_found for a completely covered empty start closure; docs/ida-provider.md:129 requires unavailable callers to stay unknown. - Failure source: src/ida/IdaOperationRunner.ts:432-443 supplies caller uncertainty and :604-612 combines it with callee coverage; src/domain/callPath.ts:258-263 treats any non-complete combined state as an incomplete forward expansion. A recorded production-client reproduction followed by the actual domain search returned unknown for an empty, complete callee closure. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete One focused test file passed both the complete and truncated callee cases. The x86-only target selected the modern callees branch and no callgraph call occurred. Authentication, artifact binding, and provider admission succeeded. This verifies the recorded adapter and domain consumer; it does not claim live IDA or public MCP transport verification. The native profile shares the same caller and aggregation branches by source inspection, but was not separately exercised. The same failure is described in another contributor's open [issue #2322](https://github.com/morluto/rea/issues/2322). Its proposed [fix #2371](https://github.com/morluto/rea/pull/2371) was still open and unmerged when checked. This report preserves the requirement to keep caller uncertainty instead of restoring globally complete dossier coverage. ## Restoration check With the valid complete empty callee reply and the unmodified returned function Evidence, the forward search reports not_found and exhaustive true while retaining the unknown-caller explanation. A partial or unavailable callee read still yields unknown and exhaustive false; a reachable child lacking Evidence still prevents an exhaustive absence result. Comparing equal caller/callee collections whose caller coverage is unknown must continue to report unknown rather than equality. These checks distinguish restoring forward search from incorrectly declaring the combined dossier complete. ## Runtime or environment Failure was verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and is still present at 8b181716aca2cb467be499cba226abfb5ae19141 by source recheck. Node.js v26.10.0, npm 11.19.1, Vitest v5.0.3. Recorded modern headless x86_64 adapter fixture; no real IDA engine. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Complete forward closure cannot establish an absence result for the reproduced modern IDA dossier, and the shared aggregation/consumer path also applies to native dossiers by source inspection. Observed edges remain available and this failure does not cross a security boundary. - Workaround status: available - Workaround basis: For the demonstrated leaf case, procedure_callees independently returns a complete empty set, which supports a manual absence conclusion. That direct-read Evidence cannot be substituted directly into build_call_path, which requires analyze_function records; larger closures require separate reads and manual reasoning.
bsakaguchi 2026-10-15 18:29:07 +00:00
Author
Owner

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

Fixed on published main by the call-path coverage change in this release. Forward search now bases exhaustion on the direct callee closure; unavailable caller coverage remains visible as a limitation and still blocks workflows that need caller data. Validation: src/domain/callPath.test.ts, “establishes not_found when only caller coverage is unknown,” and the controls for unknown callees / both unknown passed in the phase-five source log. This pins domain search semantics; it does not establish behavior of a real IDA engine.

<!-- gh-comment-id:6163978841 --> @morluto commented on GitHub (Oct 14, 2026): Fixed on published main by the call-path coverage change in this release. Forward search now bases exhaustion on the direct callee closure; unavailable caller coverage remains visible as a limitation and still blocks workflows that need caller data. Validation: `src/domain/callPath.test.ts`, “establishes not_found when only caller coverage is unknown,” and the controls for unknown callees / both unknown passed in the phase-five source log. This pins domain search semantics; it does not establish behavior of a real IDA engine.
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#867
No description provided.