[GH-ISSUE #4687] [Bug] Session inventory reports a working trace_call_path as provider_missing #2444

Closed
opened 2026-10-17 21:04:45 +00:00 by bsakaguchi · 4 comments
Owner

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

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Provider or capability discovery

Observed behavior

After opening a target with a bound fake provider that declares available procedure_address, procedure_callees, and procedure_callers operations, MCP binary_session reports trace_call_path as unavailable with reason provider_missing and remediation "No provider composition is declared for this operation." The same session lists trace_call_path in tools/list, and direct forward and backward calls both reach their requested goals without failures or truncation. get_call_graph is reported available in the same inventory.

Reproduction

  1. Use the pinned Node/npm toolchain listed below. In a disposable directory, clone the repository, check out the source revision listed below, run npm ci --ignore-scripts --no-audit --no-fund, then npm run compile. For the release comparison, use a separate directory and run npm install --prefix ./release --ignore-scripts --no-audit --no-fund rea-agents@6.5.0. These preparation commands were run with isolated HOME directories and the pinned runtime on PATH. Set REA_ROOT to the absolute source checkout or to the absolute release/node_modules/rea-agents directory; set PINNED_BIN to the directory containing the pinned node executable. This reproduction uses the production MCP server, registry, session, and tool handlers with an in-memory fake analysis provider; it does not require a real analysis engine.
  2. Save the following as reproduce.mjs in that disposable directory. The fixture declares exactly the three provider operations, maps main to 0x1000 and leaf to 0x1100, and supplies one complete direct edge. It then checks the public inventory and executes both trace directions. It repeats the full-provider case three times and includes controls with only one relationship direction and with unavailable address resolution.
import { createRequire } from 'node:module';
import { pathToFileURL } from 'node:url';
import { writeFile } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import assert from 'node:assert/strict';
const root = resolve(process.env.REA_ROOT);
const local = createRequire(join(root, 'package.json'));
const load = p => import(pathToFileURL(join(root, 'dist', p)).href);
const { Client, InMemoryTransport } = await import(pathToFileURL(local.resolve('@modelcontextprotocol/client')).href);
const { createServer } = await load('server/createServer.js');
const { BinarySession } = await load('application/binary/BinarySession.js');
const { SessionProviderRouter } = await load('application/binary/SessionProviderRouter.js');
const { AnalysisProviderRegistry } = await load('application/binary/AnalysisProviderRegistry.js');
const { createAnalysisProfile } = await load('domain/analysisProfile.js');
const { createAnalysisExecution } = await load('application/AnalysisProvider.js');
const { ok } = await load('domain/result.js');
const { expandProviderCapabilities } = await load('contracts/toolOutputSchemaPrimitives.js');
const { silentLogger } = await load('logger.js');
const target = join(process.env.HOME, 'fixture.hop');
await writeFile(target, 'fixture');
const identity = { id:'fixture', name:'Fixture analysis provider', version:'1' };
const effects = { mutatesArtifact:false, launchesProcess:false, mayShowUi:false, mayAccessNetwork:false, mayWriteFilesystem:false, changesPermissions:false, requiresRoot:false };
const original = ['procedure_address','procedure_callees','procedure_callers'];
const unavailable = { status:'unavailable', code:'not_configured', reason:'Fixture does not probe host tools.', diagnostics:{} };
const port = { inspectAvailability:async()=>unavailable, close:async()=>{}, execute:async()=>{throw Error('Unexpected host probe');} };
function unpack(reply) { return reply.structuredContent ?? JSON.parse(reply.content.find(x=>x.type==='text').text); }
function entry(status, name) { return status.result.tool_availability.groups.find(x=>x.names.includes(name)); }
async function run(label, operations=original, disabled) {
 const calls=[];
 const candidate = {
  identity:()=>identity,
  capabilities:()=>operations.map(operation=>({ provider:identity, operation, available:operation!==disabled, reason:operation===disabled?'Fixture deliberately unsupported.':null, effects, limitations:[], cachePolicy:'live' })),
  inspectAvailability:()=>({status:'available',code:null,reason:null,diagnostics:{}}),
  inspectTargetSupport:()=>({status:'supported',code:null,reason:null,diagnostics:{}}),
  resolveAnalysisProfile:async()=>ok({profile:createAnalysisProfile(identity,{fixture:true})}),
  createClient:()=>({
   execute:async(operation,args)=>{
    calls.push(operation);
    const value=operation==='procedure_address' ? ({main:'0x1000',leaf:'0x1100'}[args.procedure]??args.procedure) : operation==='procedure_callees' ? (args.procedure==='0x1000'?['0x1100']:[]) : operation==='procedure_callers' ? (args.procedure==='0x1100'?['0x1000']:[]) : null;
    return ok(createAnalysisExecution(value,identity,{relationshipCoverage:{status:'complete'}}));
   },
   close:async()=>ok(null),
  }),
 };
 const session=new BinarySession(SessionProviderRouter.selectable(new AnalysisProviderRegistry([candidate]),[]));
 const server=createServer({kind:'session',session},{androidAnalysis:port,adbDeviceAnalysis:port,apktoolAnalysis:port,logger:silentLogger});
 const mcp=new Client({name:'inventory-example',version:'1'});
 const [ct,st]=InMemoryTransport.createLinkedPair();
 try {
  await server.connect(st); await mcp.connect(ct);
  const listed=(await mcp.listTools()).tools.some(x=>x.name==='trace_call_path');
  const before=unpack(await mcp.callTool({name:'binary_session',arguments:{}}));
  const opened=await mcp.callTool({name:'open_binary',arguments:{path:target,provider_id:'fixture'}});
  assert.notEqual(opened.isError,true,JSON.stringify(unpack(opened)));
  const status=unpack(await mcp.callTool({name:'binary_session',arguments:{}}));
  const forward=await mcp.callTool({name:'trace_call_path',arguments:{start:'main',goal:'leaf'}});
  const backward=await mcp.callTool({name:'trace_call_path',arguments:{start:'leaf',goal:'main',direction:'backward'}});
  const trace=entry(status,'trace_call_path');
  const graph=entry(status,'get_call_graph');
  const summary={label,listed,before:entry(before,'trace_call_path').reason,open:status.result.open,binding:status.result.analysis_provider_binding?.provider,capabilities:expandProviderCapabilities(status.result.capabilities).filter(x=>original.includes(x.operation)).map(({operation,available})=>({operation,available})),inventory:{trace_call_path:{available:trace.available,reason:trace.reason,remediation:trace.remediation},get_call_graph:{available:graph.available,reason:graph.reason}},forward:{isError:forward.isError??false,result:unpack(forward).normalized_result??unpack(forward)},backward:{isError:backward.isError??false,result:unpack(backward).normalized_result??unpack(backward)},calls};
  console.log(JSON.stringify(summary));
  if(operations===original&&!disabled){assert.equal(trace.reason,'provider_missing'); assert.equal(summary.forward.result.goal_status,'reached'); assert.equal(summary.backward.result.goal_status,'reached'); assert.equal(graph.available,true);}
 } finally {await mcp.close();await server.close();}
}
for(let n=1;n<=3;n++) await run(`full-${n}`);
await run('forward-only',['procedure_address','procedure_callees']);
await run('backward-only',['procedure_address','procedure_callers']);
await run('address-unsupported',original,'procedure_address');
  1. Run the fixture with a fresh HOME and no client-configuration overrides inherited from the host:
PROBE_ROOT=$(mktemp -d)
mkdir "$PROBE_ROOT/home"
env -i HOME="$PROBE_ROOT/home" PATH="$PINNED_BIN:/usr/bin:/bin" REA_ROOT="$REA_ROOT" node ./reproduce.mjs
  1. Observe that all three full-provider cases list the tool, report its inventory entry as provider_missing, and return successful traces with goal_status reached. The mismatch reproduced 3/3 times on the fresh source build and 3/3 times on the separately installed npm release, for 6/6 full-provider cases. Each build also completed all three controls, using a fresh HOME for its fixture execution.

Expected behavior

The documented binary_session inventory is the surface callers should consult to choose a callable operation. With a supported target open, a bound provider supplying all three operations, and no client feature requirement blocking the tool, trace_call_path should be reported available. The inventory should not say its composition is absent when direct calls in that same session complete successfully.

Actual traversal resolves start and optional goal through procedure_address, then uses procedure_callees for forward expansion or procedure_callers for backward expansion. The opposite relationship direction is not required for a one-direction trace. Availability must still reflect target and provider restrictions; this report does not imply that every provider can trace every direction or resolve every selector.

Impact and scope

The observed result gives callers incorrect operational guidance on every full-provider fixture run. A client following the documented inventory can skip a working call-path analysis. The tool remains listed and direct execution works, so this does not establish that REA blocks tracing itself. The fixture isolates shared inventory behavior; real Hopper, Ghidra, IDA, and doctor CLI behavior were not executed.

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The authoritative discovery result falsely rejects a demonstrated working operation, which can prevent inventory-guided analysis; direct invocation preserves the requested result.
  • Workaround status: available
  • Workaround basis: Calling the listed trace_call_path directly in the same capable session succeeded in both directions in every full-provider case.

REA version

Fresh main source commit 5853089885 (package version 6.5.0); separately installed latest npm release rea-agents 6.5.0.

Runtime and platform

Node.js v24.18.0; npm 11.16.0; Darwin arm64. The source runtime was freshly compiled, and the npm runtime was installed separately; both fixture executions used the repository-pinned toolchain.

Target and artifact context

Synthetic fixture.hop containing the text fixture, admitted by a fake analysis provider with supported target status and a fixed analysis profile. Its two-node graph is main at 0x1000 calling leaf at 0x1100. This fixture verifies inventory and shared composition behavior, not real-provider binary analysis.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

  • Expected source: Identity and discovery; src/contracts/enhancedToolContracts.ts:74
  • Failure source: src/application/CapabilityInventory.ts:682
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Executed the inline fixture against both tested builds through the pinned node runtime with env -i and a separate fresh HOME per build. Both fixture executions exited 0 with empty stderr. The following is the relevant projection of each full-provider output; the script retains the complete trace and operation-call list:

{
  "listed": true,
  "before": "target_required",
  "open": true,
  "binding": {"id":"fixture","name":"Fixture analysis provider","version":"1"},
  "capabilities": [
    {"operation":"procedure_address","available":true},
    {"operation":"procedure_callees","available":true},
    {"operation":"procedure_callers","available":true}
  ],
  "inventory": {
    "trace_call_path": {
      "available": false,
      "reason": "provider_missing",
      "remediation": "No provider composition is declared for this operation."
    },
    "get_call_graph": {"available":true,"reason":"available"}
  },
  "forward": {"isError":false,"result":{"goal_status":"reached","traversal_path":["0x1000","0x1100"],"failures":[],"truncated":false}},
  "backward": {"isError":false,"result":{"goal_status":"reached","traversal_path":["0x1100","0x1000"],"failures":[],"truncated":false}},
  "calls": ["procedure_address","procedure_address","procedure_callees","procedure_address","procedure_address","procedure_callers"]
}

Observed controls: forward-only provider reaches the forward goal; backward-only provider reaches the backward goal. Calling the unsupported relationship direction returns a successful partial trace with goal_status unknown, truncated true, a capability_unavailable failure naming the missing operation, and a residual unknown. Marking procedure_address unavailable makes both directions return isError true with code capability_unavailable, category unsupported_provider, and details.operation procedure_address, without executing the fake client. Before opening a target, inventory correctly reports target_required.

  • Runtime requirement evidence: src/application/CallPathTracing.ts:82 and src/application/ProcedureAddressResolution.ts:19 resolve selectors; src/application/CallPathTracing.ts:140 selects the requested direction; src/application/CallPathTracing.ts:153 preserves unavailable expansions as partial results.
  • Public projection evidence: src/server/registerSessionStatusTool.ts:101 constructs the inventory and src/server/registerSessionStatusTool.ts:155 publishes grouped tool_availability. The reproduction reads this MCP response rather than calling the inventory helper directly.

Typed outcome or recovery expected

With the full-provider fixture and an open supported target, expand binary_session.result.tool_availability.groups and expect the trace_call_path group to have available true, reason available, and null remediation; tools/list should still contain the tool and both direct traces should still reach their goals. The discriminating no-target control should continue to report target_required. Unsupported address resolution must remain a typed error, and unavailable directional relationship reads must preserve their failure and unknown status rather than claim a complete negative trace. A same-start-and-goal request can finish after resolution without expanding relationships.

Analysis or suspected cause

Source-derived reasoning: the enhanced requirements table has no trace_call_path entry. The shared inventory enumerates its registered enhanced contract, passes the open supported target checks, and reaches the undefined-composition fallback, which emits provider_missing. Its implemented runtime composition and server registration exist separately. get_call_graph is a useful available control, but its inventory requirements should not be assumed to define trace_call_path requirements.

Additional context

Searched open and closed issues and pull requests for trace_call_path, provider_missing, the exact composition-remediation text, inventory/trace, and capability/call-path combinations. #4247 and PR #4417 concern multiple goals and roots; #1964 concerns provider-wide limitations causing false truncation; #3988 concerns missing IDA relationship coverage. Availability reports #3947, #3067, #3068, and #3069 cover other operations and provider-readiness paths. None of the inspected reports covers the false composition result for this working call-path tool. No last known good version was established.

Originally created by @coygeek on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4687 ### 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 Provider or capability discovery ### Observed behavior After opening a target with a bound fake provider that declares available procedure_address, procedure_callees, and procedure_callers operations, MCP binary_session reports trace_call_path as unavailable with reason provider_missing and remediation "No provider composition is declared for this operation." The same session lists trace_call_path in tools/list, and direct forward and backward calls both reach their requested goals without failures or truncation. get_call_graph is reported available in the same inventory. ### Reproduction 1. Use the pinned Node/npm toolchain listed below. In a disposable directory, clone the repository, check out the source revision listed below, run `npm ci --ignore-scripts --no-audit --no-fund`, then `npm run compile`. For the release comparison, use a separate directory and run `npm install --prefix ./release --ignore-scripts --no-audit --no-fund rea-agents@6.5.0`. These preparation commands were run with isolated HOME directories and the pinned runtime on PATH. Set REA_ROOT to the absolute source checkout or to the absolute `release/node_modules/rea-agents` directory; set PINNED_BIN to the directory containing the pinned node executable. This reproduction uses the production MCP server, registry, session, and tool handlers with an in-memory fake analysis provider; it does not require a real analysis engine. 2. Save the following as reproduce.mjs in that disposable directory. The fixture declares exactly the three provider operations, maps main to 0x1000 and leaf to 0x1100, and supplies one complete direct edge. It then checks the public inventory and executes both trace directions. It repeats the full-provider case three times and includes controls with only one relationship direction and with unavailable address resolution. ```javascript import { createRequire } from 'node:module'; import { pathToFileURL } from 'node:url'; import { writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import assert from 'node:assert/strict'; const root = resolve(process.env.REA_ROOT); const local = createRequire(join(root, 'package.json')); const load = p => import(pathToFileURL(join(root, 'dist', p)).href); const { Client, InMemoryTransport } = await import(pathToFileURL(local.resolve('@modelcontextprotocol/client')).href); const { createServer } = await load('server/createServer.js'); const { BinarySession } = await load('application/binary/BinarySession.js'); const { SessionProviderRouter } = await load('application/binary/SessionProviderRouter.js'); const { AnalysisProviderRegistry } = await load('application/binary/AnalysisProviderRegistry.js'); const { createAnalysisProfile } = await load('domain/analysisProfile.js'); const { createAnalysisExecution } = await load('application/AnalysisProvider.js'); const { ok } = await load('domain/result.js'); const { expandProviderCapabilities } = await load('contracts/toolOutputSchemaPrimitives.js'); const { silentLogger } = await load('logger.js'); const target = join(process.env.HOME, 'fixture.hop'); await writeFile(target, 'fixture'); const identity = { id:'fixture', name:'Fixture analysis provider', version:'1' }; const effects = { mutatesArtifact:false, launchesProcess:false, mayShowUi:false, mayAccessNetwork:false, mayWriteFilesystem:false, changesPermissions:false, requiresRoot:false }; const original = ['procedure_address','procedure_callees','procedure_callers']; const unavailable = { status:'unavailable', code:'not_configured', reason:'Fixture does not probe host tools.', diagnostics:{} }; const port = { inspectAvailability:async()=>unavailable, close:async()=>{}, execute:async()=>{throw Error('Unexpected host probe');} }; function unpack(reply) { return reply.structuredContent ?? JSON.parse(reply.content.find(x=>x.type==='text').text); } function entry(status, name) { return status.result.tool_availability.groups.find(x=>x.names.includes(name)); } async function run(label, operations=original, disabled) { const calls=[]; const candidate = { identity:()=>identity, capabilities:()=>operations.map(operation=>({ provider:identity, operation, available:operation!==disabled, reason:operation===disabled?'Fixture deliberately unsupported.':null, effects, limitations:[], cachePolicy:'live' })), inspectAvailability:()=>({status:'available',code:null,reason:null,diagnostics:{}}), inspectTargetSupport:()=>({status:'supported',code:null,reason:null,diagnostics:{}}), resolveAnalysisProfile:async()=>ok({profile:createAnalysisProfile(identity,{fixture:true})}), createClient:()=>({ execute:async(operation,args)=>{ calls.push(operation); const value=operation==='procedure_address' ? ({main:'0x1000',leaf:'0x1100'}[args.procedure]??args.procedure) : operation==='procedure_callees' ? (args.procedure==='0x1000'?['0x1100']:[]) : operation==='procedure_callers' ? (args.procedure==='0x1100'?['0x1000']:[]) : null; return ok(createAnalysisExecution(value,identity,{relationshipCoverage:{status:'complete'}})); }, close:async()=>ok(null), }), }; const session=new BinarySession(SessionProviderRouter.selectable(new AnalysisProviderRegistry([candidate]),[])); const server=createServer({kind:'session',session},{androidAnalysis:port,adbDeviceAnalysis:port,apktoolAnalysis:port,logger:silentLogger}); const mcp=new Client({name:'inventory-example',version:'1'}); const [ct,st]=InMemoryTransport.createLinkedPair(); try { await server.connect(st); await mcp.connect(ct); const listed=(await mcp.listTools()).tools.some(x=>x.name==='trace_call_path'); const before=unpack(await mcp.callTool({name:'binary_session',arguments:{}})); const opened=await mcp.callTool({name:'open_binary',arguments:{path:target,provider_id:'fixture'}}); assert.notEqual(opened.isError,true,JSON.stringify(unpack(opened))); const status=unpack(await mcp.callTool({name:'binary_session',arguments:{}})); const forward=await mcp.callTool({name:'trace_call_path',arguments:{start:'main',goal:'leaf'}}); const backward=await mcp.callTool({name:'trace_call_path',arguments:{start:'leaf',goal:'main',direction:'backward'}}); const trace=entry(status,'trace_call_path'); const graph=entry(status,'get_call_graph'); const summary={label,listed,before:entry(before,'trace_call_path').reason,open:status.result.open,binding:status.result.analysis_provider_binding?.provider,capabilities:expandProviderCapabilities(status.result.capabilities).filter(x=>original.includes(x.operation)).map(({operation,available})=>({operation,available})),inventory:{trace_call_path:{available:trace.available,reason:trace.reason,remediation:trace.remediation},get_call_graph:{available:graph.available,reason:graph.reason}},forward:{isError:forward.isError??false,result:unpack(forward).normalized_result??unpack(forward)},backward:{isError:backward.isError??false,result:unpack(backward).normalized_result??unpack(backward)},calls}; console.log(JSON.stringify(summary)); if(operations===original&&!disabled){assert.equal(trace.reason,'provider_missing'); assert.equal(summary.forward.result.goal_status,'reached'); assert.equal(summary.backward.result.goal_status,'reached'); assert.equal(graph.available,true);} } finally {await mcp.close();await server.close();} } for(let n=1;n<=3;n++) await run(`full-${n}`); await run('forward-only',['procedure_address','procedure_callees']); await run('backward-only',['procedure_address','procedure_callers']); await run('address-unsupported',original,'procedure_address'); ``` 3. Run the fixture with a fresh HOME and no client-configuration overrides inherited from the host: ```sh PROBE_ROOT=$(mktemp -d) mkdir "$PROBE_ROOT/home" env -i HOME="$PROBE_ROOT/home" PATH="$PINNED_BIN:/usr/bin:/bin" REA_ROOT="$REA_ROOT" node ./reproduce.mjs ``` 4. Observe that all three full-provider cases list the tool, report its inventory entry as provider_missing, and return successful traces with goal_status reached. The mismatch reproduced 3/3 times on the fresh source build and 3/3 times on the separately installed npm release, for 6/6 full-provider cases. Each build also completed all three controls, using a fresh HOME for its fixture execution. ### Expected behavior The documented binary_session inventory is the surface callers should consult to choose a callable operation. With a supported target open, a bound provider supplying all three operations, and no client feature requirement blocking the tool, trace_call_path should be reported available. The inventory should not say its composition is absent when direct calls in that same session complete successfully. Actual traversal resolves start and optional goal through procedure_address, then uses procedure_callees for forward expansion or procedure_callers for backward expansion. The opposite relationship direction is not required for a one-direction trace. Availability must still reflect target and provider restrictions; this report does not imply that every provider can trace every direction or resolve every selector. ### Impact and scope The observed result gives callers incorrect operational guidance on every full-provider fixture run. A client following the documented inventory can skip a working call-path analysis. The tool remains listed and direct execution works, so this does not establish that REA blocks tracing itself. The fixture isolates shared inventory behavior; real Hopper, Ghidra, IDA, and doctor CLI behavior were not executed. - Impact level: P2 - Assessment status: supported - Impact basis: The authoritative discovery result falsely rejects a demonstrated working operation, which can prevent inventory-guided analysis; direct invocation preserves the requested result. - Workaround status: available - Workaround basis: Calling the listed trace_call_path directly in the same capable session succeeded in both directions in every full-provider case. ### REA version Fresh main source commit 58530898852d3dc5c7415afac1b92d3fec2f8fb5 (package version 6.5.0); separately installed latest npm release rea-agents 6.5.0. ### Runtime and platform Node.js v24.18.0; npm 11.16.0; Darwin arm64. The source runtime was freshly compiled, and the npm runtime was installed separately; both fixture executions used the repository-pinned toolchain. ### Target and artifact context Synthetic fixture.hop containing the text fixture, admitted by a fake analysis provider with supported target status and a fixed analysis profile. Its two-node graph is main at 0x1000 calling leaf at 0x1100. This fixture verifies inventory and shared composition behavior, not real-provider binary analysis. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence - Expected source: [Identity and discovery](https://github.com/morluto/rea/blob/58530898852d3dc5c7415afac1b92d3fec2f8fb5/docs/mcp-contracts.md#L346-L355); src/contracts/enhancedToolContracts.ts:74 - Failure source: src/application/CapabilityInventory.ts:682 - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Executed the inline fixture against both tested builds through the pinned node runtime with env -i and a separate fresh HOME per build. Both fixture executions exited 0 with empty stderr. The following is the relevant projection of each full-provider output; the script retains the complete trace and operation-call list: ```json { "listed": true, "before": "target_required", "open": true, "binding": {"id":"fixture","name":"Fixture analysis provider","version":"1"}, "capabilities": [ {"operation":"procedure_address","available":true}, {"operation":"procedure_callees","available":true}, {"operation":"procedure_callers","available":true} ], "inventory": { "trace_call_path": { "available": false, "reason": "provider_missing", "remediation": "No provider composition is declared for this operation." }, "get_call_graph": {"available":true,"reason":"available"} }, "forward": {"isError":false,"result":{"goal_status":"reached","traversal_path":["0x1000","0x1100"],"failures":[],"truncated":false}}, "backward": {"isError":false,"result":{"goal_status":"reached","traversal_path":["0x1100","0x1000"],"failures":[],"truncated":false}}, "calls": ["procedure_address","procedure_address","procedure_callees","procedure_address","procedure_address","procedure_callers"] } ``` Observed controls: forward-only provider reaches the forward goal; backward-only provider reaches the backward goal. Calling the unsupported relationship direction returns a successful partial trace with goal_status unknown, truncated true, a capability_unavailable failure naming the missing operation, and a residual unknown. Marking procedure_address unavailable makes both directions return isError true with code capability_unavailable, category unsupported_provider, and details.operation procedure_address, without executing the fake client. Before opening a target, inventory correctly reports target_required. - Runtime requirement evidence: src/application/CallPathTracing.ts:82 and src/application/ProcedureAddressResolution.ts:19 resolve selectors; src/application/CallPathTracing.ts:140 selects the requested direction; src/application/CallPathTracing.ts:153 preserves unavailable expansions as partial results. - Public projection evidence: src/server/registerSessionStatusTool.ts:101 constructs the inventory and src/server/registerSessionStatusTool.ts:155 publishes grouped tool_availability. The reproduction reads this MCP response rather than calling the inventory helper directly. ### Typed outcome or recovery expected With the full-provider fixture and an open supported target, expand binary_session.result.tool_availability.groups and expect the trace_call_path group to have available true, reason available, and null remediation; tools/list should still contain the tool and both direct traces should still reach their goals. The discriminating no-target control should continue to report target_required. Unsupported address resolution must remain a typed error, and unavailable directional relationship reads must preserve their failure and unknown status rather than claim a complete negative trace. A same-start-and-goal request can finish after resolution without expanding relationships. ### Analysis or suspected cause Source-derived reasoning: the enhanced requirements table has no trace_call_path entry. The shared inventory enumerates its registered enhanced contract, passes the open supported target checks, and reaches the undefined-composition fallback, which emits provider_missing. Its implemented runtime composition and server registration exist separately. get_call_graph is a useful available control, but its inventory requirements should not be assumed to define trace_call_path requirements. ### Additional context Searched open and closed issues and pull requests for `trace_call_path`, `provider_missing`, the exact composition-remediation text, inventory/trace, and capability/call-path combinations. [#4247](https://github.com/morluto/rea/issues/4247) and [PR #4417](https://github.com/morluto/rea/pull/4417) concern multiple goals and roots; [#1964](https://github.com/morluto/rea/issues/1964) concerns provider-wide limitations causing false truncation; [#3988](https://github.com/morluto/rea/issues/3988) concerns missing IDA relationship coverage. Availability reports [#3947](https://github.com/morluto/rea/issues/3947), [#3067](https://github.com/morluto/rea/issues/3067), [#3068](https://github.com/morluto/rea/issues/3068), and [#3069](https://github.com/morluto/rea/issues/3069) cover other operations and provider-readiness paths. None of the inspected reports covers the false composition result for this working call-path tool. No last known good version was established.
Author
Owner

@xu91102 commented on GitHub (Oct 17, 2026):

Independently reproduced on main 5927937179476c66aa8621658faca42f9578b42a, Node24.18.0 / macOS arm64, through the production MCP server/session/registry and official InMemory SDK with a controlled analysis provider. In 3/3 full-capability sessions, binary_session reported trace_call_path as provider_missing while both actual forward and backward calls reached their goals without failures or truncation. Forward-only and backward-only controls reached their supported goal and retained unknown/partial results in the unsupported direction; an unavailable address-resolution control made no provider execution calls.

The owning capability-composition table has no entry for this existing workflow. A new source regression reproduces the false-unavailable result (1 failed /27 passed); production was unchanged for that RED. I am preparing a small correction using the existing composition owner and its address-plus-direction prerequisites, while preserving target, provider and client gates. This is real MCP composition evidence with a controlled provider, not native-engine qualification; no new upstream PR or CI is claimed.

The correction is now committed and pushed to my fork: 57fd8b4. It adds only the missing address-plus-direction composition and focused source/MCP regressions; target/provider/client gates and unsupported-direction partial Evidence remain intact. Final affected tests:37PASS; deduplicated11file coverage157PASS plus README5PASS, with nine unchanged files reused. Check/docs/discovery passed (1,484 tests discovered exactly once). Independent Standards/Spec review passed after adding awaited session teardown and failure propagation.

This remains a controlled-provider production-MCP investigation, not native-engine, cross-platform or stdio qualification. No upstream PR or upstream CI exists; ordinary upstream creation is still permission-blocked with no specific policy confirmed. Human readiness is not attested.

<!-- gh-comment-id:6230830291 --> @xu91102 commented on GitHub (Oct 17, 2026): Independently reproduced on main `5927937179476c66aa8621658faca42f9578b42a`, Node24.18.0 / macOS arm64, through the production MCP server/session/registry and official InMemory SDK with a controlled analysis provider. In 3/3 full-capability sessions, `binary_session` reported `trace_call_path` as `provider_missing` while both actual forward and backward calls reached their goals without failures or truncation. Forward-only and backward-only controls reached their supported goal and retained unknown/partial results in the unsupported direction; an unavailable address-resolution control made no provider execution calls. The owning capability-composition table has no entry for this existing workflow. A new source regression reproduces the false-unavailable result (1 failed /27 passed); production was unchanged for that RED. I am preparing a small correction using the existing composition owner and its address-plus-direction prerequisites, while preserving target, provider and client gates. This is real MCP composition evidence with a controlled provider, not native-engine qualification; no new upstream PR or CI is claimed. The correction is now committed and pushed to my fork: [57fd8b4](https://github.com/xu91102/rea/commit/57fd8b42f76f4ba07675bac9247af03b9a842bf5). It adds only the missing address-plus-direction composition and focused source/MCP regressions; target/provider/client gates and unsupported-direction partial Evidence remain intact. Final affected tests:37PASS; deduplicated11file coverage157PASS plus README5PASS, with nine unchanged files reused. Check/docs/discovery passed (1,484 tests discovered exactly once). Independent Standards/Spec review passed after adding awaited session teardown and failure propagation. This remains a controlled-provider production-MCP investigation, not native-engine, cross-platform or stdio qualification. No upstream PR or upstream CI exists; ordinary upstream creation is still permission-blocked with no specific policy confirmed. Human readiness is not attested.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Confirmed: the inventory is contradicting the session's actual capability surface — trace_call_path appears in tools/list and both call directions succeed, yet binary_session reports provider_missing. That mismatch is worse than a wrong status alone because callers use inventory to decide whether to attempt the operation at all, so they would skip a working feature. The PR #4729 direction of declaring the provider composition requirements for trace_call_path (procedure_address + procedure_callees + procedure_callers) looks right and should also fix the get_call_graph consistency point mentioned in the report. Suggest adding a regression test that asserts inventory availability matches tools/list for a fake provider declaring exactly that composition, so future operation additions can't drift again.

<!-- gh-comment-id:6248333704 --> @XinwangTao commented on GitHub (Oct 18, 2026): Confirmed: the inventory is contradicting the session's actual capability surface — trace_call_path appears in tools/list and both call directions succeed, yet binary_session reports provider_missing. That mismatch is worse than a wrong status alone because callers use inventory to decide whether to attempt the operation at all, so they would skip a working feature. The PR #4729 direction of declaring the provider composition requirements for trace_call_path (procedure_address + procedure_callees + procedure_callers) looks right and should also fix the get_call_graph consistency point mentioned in the report. Suggest adding a regression test that asserts inventory availability matches tools/list for a fake provider declaring exactly that composition, so future operation additions can't drift again.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Confirmed: the inventory is contradicting the session's actual capability surface — trace_call_path appears in tools/list and both call directions succeed, yet binary_session reports provider_missing. That mismatch is worse than a wrong status alone because callers use inventory to decide whether to attempt the operation at all, so they would skip a working feature. The PR #4729 direction of declaring the provider composition requirements for trace_call_path (procedure_address + procedure_callees + procedure_callers) looks right and should also fix the get_call_graph consistency point mentioned in the report. Suggest adding a regression test that asserts inventory availability matches tools/list for a fake provider declaring exactly that composition, so future operation additions can't drift again.

<!-- gh-comment-id:6248352739 --> @XinwangTao commented on GitHub (Oct 18, 2026): Confirmed: the inventory is contradicting the session's actual capability surface — trace_call_path appears in tools/list and both call directions succeed, yet binary_session reports provider_missing. That mismatch is worse than a wrong status alone because callers use inventory to decide whether to attempt the operation at all, so they would skip a working feature. The PR #4729 direction of declaring the provider composition requirements for trace_call_path (procedure_address + procedure_callees + procedure_callers) looks right and should also fix the get_call_graph consistency point mentioned in the report. Suggest adding a regression test that asserts inventory availability matches tools/list for a fake provider declaring exactly that composition, so future operation additions can't drift again.
Author
Owner

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

Fixed in 1d5bf5ff0, covering #4687 and the independently reproduced sibling #5068.

The root cause was drift between runtime composition and discovery: a missing trace declaration, wrong graph prerequisites, and duplicated direction/default interpretation. Both tools now report forward/backward modes requiring address resolution plus the corresponding relationship operation. Overall availability and default-forward availability are separate; missing operations and owner failure remediation remain inline. Runtime and inventory share one direction mapping, defaults are selected by name, and the enhanced composition table is checked against canonical contract names so new omissions fail typechecking.

The correction adapts PR #4729's proposed missing trace composition, with co-author credit to AHMED. The final change also fixes the graph sibling and completes the directly related ownership/refactor and public-mode checks. This is not a merge or whole-head qualification of that PR.

Validation executed on macOS/Node24.18, official MCP SDK2.3.1 (negotiated protocol2025-11-25):

  • Before production edits, all six capability scenarios reproduced inventory failures after direct MCP execution assertions passed; the no-target control passed. One-direction graph traversal succeeded despite discovery refusing it; missing/unavailable address resolution failed while graph discovery claimed availability.
  • 75 source tests across four files and 76 public MCP/schema tests across eight files passed. The public matrix covers nine cases: both/single directions, missing/unavailable address lookup, unavailable forward relationship with usable backward mode, unsupported host, absent relationships, and no target. It preserves typed errors, graph node failures and unknown/partial traces. Same-endpoint address-only tracing remains callable without relationship reads; discovery is not a handler gate.
  • Full static/architecture checks, docs checks, check:fast and exact test discovery passed (1,589 files). SDK-converted schemas and compact-profile examples were validated. Independent source/design reviews found no blocker.

Completed MCP workflow costs were recorded using listTools → open_binary → binary_session → selected trace → close_binary plus awaited cleanup, three processes per variant/task (first process + two alternating repeated processes). The baseline uses the documented direct-invocation workaround to complete the same answer. Full catalog reply and normalized trace hashes agree across variants. Repeated medians:

Controlled task Estimated complete public-reply cl100k tokens Elapsed seconds CPU seconds Sampled peak process-family RSS, MB
Full provider, forward 820786 → 820953 2.142 → 2.142 2.816 → 2.835 739 → 741
Backward-only provider, backward 820785 → 820993 2.147 → 2.156 2.840 → 2.827 742 → 740

The complete full-profile catalog alone accounts for 805328 estimated tokens in these SDK observations; this is a wire-response estimate, not measured model context. Additional tokens carry mode/prerequisite facts. No true cold-cache or speedup claim; requests/framing, model selection/retries/host context, real providers, large/failure workload costs remain unmeasured.

Research used DeepWiki as navigation and checked the primary 2025-11-25 MCP tools specification, matching the observed negotiated version. Newer session-removal proposals in the current wiki were not applied. The fixed catalog policy and exact availability semantics remain owned by REA's contracts.

No native engine, CLI, Linux/Windows or model tool-selection qualification. Source-only follow-ups remain in native dispatch/UI composition prerequisites; those require separate runtime evidence. The wider codebase audit remains active.

<!-- gh-comment-id:6253960573 --> @morluto commented on GitHub (Oct 18, 2026): Fixed in [1d5bf5ff0](https://github.com/morluto/rea/commit/1d5bf5ff084b49c1c630a312520c59d6b08c6ade), covering #4687 and the independently reproduced sibling #5068. The root cause was drift between runtime composition and discovery: a missing trace declaration, wrong graph prerequisites, and duplicated direction/default interpretation. Both tools now report forward/backward modes requiring address resolution plus the corresponding relationship operation. Overall availability and default-forward availability are separate; missing operations and owner failure remediation remain inline. Runtime and inventory share one direction mapping, defaults are selected by name, and the enhanced composition table is checked against canonical contract names so new omissions fail typechecking. The correction adapts [PR #4729](https://github.com/morluto/rea/pull/4729)'s proposed missing trace composition, with co-author credit to AHMED. The final change also fixes the graph sibling and completes the directly related ownership/refactor and public-mode checks. This is not a merge or whole-head qualification of that PR. Validation executed on macOS/Node24.18, official MCP SDK2.3.1 (negotiated protocol2025-11-25): - Before production edits, all six capability scenarios reproduced inventory failures after direct MCP execution assertions passed; the no-target control passed. One-direction graph traversal succeeded despite discovery refusing it; missing/unavailable address resolution failed while graph discovery claimed availability. - 75 source tests across four files and 76 public MCP/schema tests across eight files passed. The public matrix covers nine cases: both/single directions, missing/unavailable address lookup, unavailable forward relationship with usable backward mode, unsupported host, absent relationships, and no target. It preserves typed errors, graph node failures and unknown/partial traces. Same-endpoint address-only tracing remains callable without relationship reads; discovery is not a handler gate. - Full static/architecture checks, docs checks, check:fast and exact test discovery passed (1,589 files). SDK-converted schemas and compact-profile examples were validated. Independent source/design reviews found no blocker. Completed MCP workflow costs were recorded using listTools → open_binary → binary_session → selected trace → close_binary plus awaited cleanup, three processes per variant/task (first process + two alternating repeated processes). The baseline uses the documented direct-invocation workaround to complete the same answer. Full catalog reply and normalized trace hashes agree across variants. Repeated medians: | Controlled task | Estimated complete public-reply cl100k tokens | Elapsed seconds | CPU seconds | Sampled peak process-family RSS, MB | | --- | --- | --- | --- | --- | | Full provider, forward | 820786 → 820953 | 2.142 → 2.142 | 2.816 → 2.835 | 739 → 741 | | Backward-only provider, backward | 820785 → 820993 | 2.147 → 2.156 | 2.840 → 2.827 | 742 → 740 | The complete full-profile catalog alone accounts for 805328 estimated tokens in these SDK observations; this is a wire-response estimate, not measured model context. Additional tokens carry mode/prerequisite facts. No true cold-cache or speedup claim; requests/framing, model selection/retries/host context, real providers, large/failure workload costs remain unmeasured. Research used DeepWiki as navigation and checked the [primary 2025-11-25 MCP tools specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools), matching the observed negotiated version. Newer session-removal proposals in the current wiki were not applied. The fixed catalog policy and exact availability semantics remain owned by REA's contracts. No native engine, CLI, Linux/Windows or model tool-selection qualification. Source-only follow-ups remain in native dispatch/UI composition prerequisites; those require separate runtime evidence. The wider codebase audit remains active.
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#2444
No description provided.