[GH-ISSUE #2558] fix(mcp): feature tracing loses a provider-reported reference cap #874

Closed
opened 2026-10-15 18:29:12 +00:00 by bsakaguchi · 0 comments
Owner

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

Summary

When a provider reports that a literal match's reference page is incomplete, trace_feature can return a successful trace that labels the references untruncated and contains no residual unknown. A producer-boundary test with an admitted empty reference page and more: true reproduces this through the production IDA session adapter and shared tracing workflow. The primitive reference read preserves the cap notice, but the composed trace loses it. This can make an incomplete reference inventory look like a complete empty result.

Steps to reproduce

  1. Use the tested checkout and installed lockfile dependencies described under Runtime or environment.
  2. Save the following fixture as src/application/literalTraceCoverage.test.ts. It uses the repository's recording upstream connection, not an installed IDA engine. The empty page with an explicit cap is admitted by the production response parser; this does not assert that a real engine emitted that combination.
import { rm } from "node:fs/promises";
import { expect, it } from "vitest";
import { createIdaTarget, RecordingIdaMcp } from "../../tests/fixtures/idaMcp.js";
import { EnhancedTools } from "./EnhancedTools.js";
import { IdaSessionClient } from "../ida/IdaSessionClient.js";

it("preserves an explicit reference cap in feature tracing", async () => {
  const { root, target } = await createIdaTarget();
  const producer = new RecordingIdaMcp(target, "headless");
  const client = new IdaSessionClient({
    command: "fixture",
    args: [],
    env: {},
    mode: "headless",
    timeoutMs: 1000,
    workspaceRoot: root,
  }, target, producer);
  try {
    producer.overrideCall = (operation) => operation === "xrefs_to"
      ? [{ xrefs: [], more: false }]
      : undefined;
    const control = await new EnhancedTools(client).execute("trace_feature", { query: "a.b" });
    if (!control.ok) throw control.error;
    expect(control.value).toMatchObject({
      references: [], truncated: false, residual_unknowns: [],
    });
    producer.overrideCall = (operation) => operation === "xrefs_to"
      ? [{ xrefs: [], more: true }]
      : undefined;
    const primitive = await client.execute("xrefs", { address: "0x3000" });
    if (!primitive.ok) throw primitive.error;
    expect(primitive.value.limitations).toContain(
      "Upstream xrefs_to capped results at 1000 references; additional references remain unknown.",
    );
    const capped = await new EnhancedTools(client).execute("trace_feature", { query: "a.b" });
    if (!capped.ok) throw capped.error;
    console.log(JSON.stringify(capped.value));
    expect(capped.value).toMatchObject({ references: [], truncated: true });
  } finally {
    await client.close();
    await rm(root, { recursive: true, force: true });
  }
});
  1. Run the focused test command. The uncapped control and primitive cap assertion succeed; the final completeness assertion fails.
npm run test:focused -- src/application/literalTraceCoverage.test.ts

Expected behavior

A successful trace must not describe a reference read that the provider explicitly reports as capped as untruncated. It should retain the received references and report the unresolved reference coverage for the matched address. For the admitted empty page, the trace should distinguish unknown remaining references from a complete empty inventory. The otherwise identical page with more: false should remain untruncated. The representation of the cap across the provider and workflow boundaries is an implementation choice; no interpretation of arbitrary diagnostic prose is required by this report.

Actual behavior

The producer-boundary reproduction succeeds through both searches and the reference read, then returns this result despite the primitive execution's explicit cap notice:

{"query":"a.b","search_mode":"literal","matches":[{"type":"string","address":"0x3000","value":"a.b\nC"}],"references":[],"truncated":false,"residual_unknowns":[]}

The independent focused run contains four tests: two pass and two fail at the completeness assertions. A separate typed-provider test with one returned reference also preserves the reference but returns false completeness metadata. Testing a nonempty capped page through the actual baseline IDA adapter instead produces AnalysisCapabilityUnavailableError for resolve_containing_procedure; it does not produce the successful trace shown here. The empty admitted page avoids that distinct guard because there is no received source address to resolve. No real IDA engine or live target was used, and no particular omitted reference was observed.

Evidence

  • Expected source: AGENTS.md:19 requires preserving omission and uncertainty across boundaries; docs/tool-design.md:68 requires reporting truncation; src/contracts/enhancedToolContracts.ts:70 advertises tracing literal matches and their references with residual unknowns; src/contracts/toolOutputSchemaGroups.ts:217-218 defines the trace's completeness fields.
  • Failure source: The focused producer-boundary execution shown under Actual behavior. src/ida/IdaOperationRunner.ts:393-396 records the admitted page's more: true as a cap limitation, and src/ida/IdaSessionClient.ts:268 retains it on the primitive execution. src/application/EnhancedTools.ts:583 extracts only the primitive result, and src/application/EnhancedLiteralTracing.ts:62 unconditionally labels the composed trace untruncated with no residual unknowns.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The reproduction uses the existing execution contract without adding a nonexistent truncation field or casting away its type checks. The production parser accepts an empty array with more: true; the trace then succeeds without needing the unsupported IDA containment operation. Real-engine frequency and the existence of real empty capped pages remain unmeasured. The completeness failure is independently reproduced at the shared application boundary with a nonempty reference list over a typed synthetic provider.

Existing upstream context is reference-only: another author's open issue 2335 includes cap visibility alongside IDA containment support, and their open PR 2348 proposes carrying a typed cap fact into tracing. Neither is merged into the tested baseline. The standalone xrefs operation preserves the diagnostic cap notice and can reveal incomplete primitive data; complete reference recovery through a practical alternative was not verified.

Restoration check

Replay the admitted upstream response through the producer boundary. The primitive read must still identify the cap, and the successful composed trace must report truncated reference coverage for the matched address without losing received references. The identical uncapped page must still return an untruncated empty trace. Also check a nonempty capped read through a provider that supports containment: preserve its received references and expose its remaining coverage as unknown. This must not turn unsupported containment into success or mark unrelated provider caveats as a reference cap. Keep the producer input and the known cap invariant while allowing the implementation to choose the internal metadata representation and residual wording.

Runtime or environment

Failure verified at a2d8b94dd5 and still present at 8b181716ac. Node.js v26.10.0, npm 11.19.1, package version 6.4.0, Vitest 5.0.3, with already-installed lockfile dependencies. The final focused run completes in 3.47 seconds with exit status 1. Verification uses the production session adapter over the repository's recording connection fixture; it does not run an IDA engine or exercise the MCP wire transport.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A successful composed trace incorrectly labels explicitly incomplete reference coverage as untruncated and can present unknown remaining references as a complete empty result. The reproduced failure is bounded to cap-reporting provider input; no severe harm or universally broken core workflow was observed.
  • Workaround status: unverified
  • Workaround basis: Reading xrefs directly retains the cap notice in the tested session and provides a diagnostic alternative, but it does not recover omitted references. A safe practical way to obtain the complete original trace without a code change has not been established.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2558 ## Summary When a provider reports that a literal match's reference page is incomplete, `trace_feature` can return a successful trace that labels the references untruncated and contains no residual unknown. A producer-boundary test with an admitted empty reference page and `more: true` reproduces this through the production IDA session adapter and shared tracing workflow. The primitive reference read preserves the cap notice, but the composed trace loses it. This can make an incomplete reference inventory look like a complete empty result. ## Steps to reproduce 1. Use the tested checkout and installed lockfile dependencies described under Runtime or environment. 2. Save the following fixture as `src/application/literalTraceCoverage.test.ts`. It uses the repository's recording upstream connection, not an installed IDA engine. The empty page with an explicit cap is admitted by the production response parser; this does not assert that a real engine emitted that combination. ```ts import { rm } from "node:fs/promises"; import { expect, it } from "vitest"; import { createIdaTarget, RecordingIdaMcp } from "../../tests/fixtures/idaMcp.js"; import { EnhancedTools } from "./EnhancedTools.js"; import { IdaSessionClient } from "../ida/IdaSessionClient.js"; it("preserves an explicit reference cap in feature tracing", async () => { const { root, target } = await createIdaTarget(); const producer = new RecordingIdaMcp(target, "headless"); const client = new IdaSessionClient({ command: "fixture", args: [], env: {}, mode: "headless", timeoutMs: 1000, workspaceRoot: root, }, target, producer); try { producer.overrideCall = (operation) => operation === "xrefs_to" ? [{ xrefs: [], more: false }] : undefined; const control = await new EnhancedTools(client).execute("trace_feature", { query: "a.b" }); if (!control.ok) throw control.error; expect(control.value).toMatchObject({ references: [], truncated: false, residual_unknowns: [], }); producer.overrideCall = (operation) => operation === "xrefs_to" ? [{ xrefs: [], more: true }] : undefined; const primitive = await client.execute("xrefs", { address: "0x3000" }); if (!primitive.ok) throw primitive.error; expect(primitive.value.limitations).toContain( "Upstream xrefs_to capped results at 1000 references; additional references remain unknown.", ); const capped = await new EnhancedTools(client).execute("trace_feature", { query: "a.b" }); if (!capped.ok) throw capped.error; console.log(JSON.stringify(capped.value)); expect(capped.value).toMatchObject({ references: [], truncated: true }); } finally { await client.close(); await rm(root, { recursive: true, force: true }); } }); ``` 3. Run the focused test command. The uncapped control and primitive cap assertion succeed; the final completeness assertion fails. ```sh npm run test:focused -- src/application/literalTraceCoverage.test.ts ``` ## Expected behavior A successful trace must not describe a reference read that the provider explicitly reports as capped as untruncated. It should retain the received references and report the unresolved reference coverage for the matched address. For the admitted empty page, the trace should distinguish unknown remaining references from a complete empty inventory. The otherwise identical page with `more: false` should remain untruncated. The representation of the cap across the provider and workflow boundaries is an implementation choice; no interpretation of arbitrary diagnostic prose is required by this report. ## Actual behavior The producer-boundary reproduction succeeds through both searches and the reference read, then returns this result despite the primitive execution's explicit cap notice: ```json {"query":"a.b","search_mode":"literal","matches":[{"type":"string","address":"0x3000","value":"a.b\nC"}],"references":[],"truncated":false,"residual_unknowns":[]} ``` The independent focused run contains four tests: two pass and two fail at the completeness assertions. A separate typed-provider test with one returned reference also preserves the reference but returns false completeness metadata. Testing a nonempty capped page through the actual baseline IDA adapter instead produces `AnalysisCapabilityUnavailableError` for `resolve_containing_procedure`; it does not produce the successful trace shown here. The empty admitted page avoids that distinct guard because there is no received source address to resolve. No real IDA engine or live target was used, and no particular omitted reference was observed. ## Evidence - Expected source: `AGENTS.md:19` requires preserving omission and uncertainty across boundaries; `docs/tool-design.md:68` requires reporting truncation; `src/contracts/enhancedToolContracts.ts:70` advertises tracing literal matches and their references with residual unknowns; `src/contracts/toolOutputSchemaGroups.ts:217-218` defines the trace's completeness fields. - Failure source: The focused producer-boundary execution shown under Actual behavior. `src/ida/IdaOperationRunner.ts:393-396` records the admitted page's `more: true` as a cap limitation, and `src/ida/IdaSessionClient.ts:268` retains it on the primitive execution. `src/application/EnhancedTools.ts:583` extracts only the primitive result, and `src/application/EnhancedLiteralTracing.ts:62` unconditionally labels the composed trace untruncated with no residual unknowns. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The reproduction uses the existing execution contract without adding a nonexistent truncation field or casting away its type checks. The production parser accepts an empty array with `more: true`; the trace then succeeds without needing the unsupported IDA containment operation. Real-engine frequency and the existence of real empty capped pages remain unmeasured. The completeness failure is independently reproduced at the shared application boundary with a nonempty reference list over a typed synthetic provider. Existing upstream context is reference-only: another author's open [issue 2335](https://github.com/morluto/rea/issues/2335) includes cap visibility alongside IDA containment support, and their open [PR 2348](https://github.com/morluto/rea/pull/2348) proposes carrying a typed cap fact into tracing. Neither is merged into the tested baseline. The standalone `xrefs` operation preserves the diagnostic cap notice and can reveal incomplete primitive data; complete reference recovery through a practical alternative was not verified. ## Restoration check Replay the admitted upstream response through the producer boundary. The primitive read must still identify the cap, and the successful composed trace must report truncated reference coverage for the matched address without losing received references. The identical uncapped page must still return an untruncated empty trace. Also check a nonempty capped read through a provider that supports containment: preserve its received references and expose its remaining coverage as unknown. This must not turn unsupported containment into success or mark unrelated provider caveats as a reference cap. Keep the producer input and the known cap invariant while allowing the implementation to choose the internal metadata representation and residual wording. ## Runtime or environment Failure verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and still present at 8b181716aca2cb467be499cba226abfb5ae19141. Node.js v26.10.0, npm 11.19.1, package version 6.4.0, Vitest 5.0.3, with already-installed lockfile dependencies. The final focused run completes in 3.47 seconds with exit status 1. Verification uses the production session adapter over the repository's recording connection fixture; it does not run an IDA engine or exercise the MCP wire transport. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A successful composed trace incorrectly labels explicitly incomplete reference coverage as untruncated and can present unknown remaining references as a complete empty result. The reproduced failure is bounded to cap-reporting provider input; no severe harm or universally broken core workflow was observed. - Workaround status: unverified - Workaround basis: Reading `xrefs` directly retains the cap notice in the tested session and provides a diagnostic alternative, but it does not recover omitted references. A safe practical way to obtain the complete original trace without a code change has not been established.
bsakaguchi 2026-10-15 18:29:12 +00:00
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#874
No description provided.