[GH-ISSUE #6041] [Bug] V8 role mismatch points to an agreeing target_id parameter #3687

Closed
opened 2026-10-31 00:43:04 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Process capture or runtime observation

Observed behavior

reconcile_javascript_runtime reports a mismatch only in runtime_kind at the agreeing target_id field. This reproduced through the registered MCP tool with digest-valid synthetic Evidence: the recorded target ID and result target ID both equal example-v8-target, while the parameter role is node and the result role is electron-main.

The request correctly fails with invalid_request; its issue path is runtime_observations[0].parameters.target_id. A target-only mismatch correctly uses that same path. Matching both values succeeds.

Reproduction

With dependencies installed at this revision, save this as tests/boundary/mcp/issuePathReproduction.test.ts and run:

node node_modules/vitest/vitest.mjs run tests/boundary/mcp/issuePathReproduction.test.ts --maxWorkers 1

The executed test uses the real SDK client, in-memory transport and registered server. The observation and static Evidence are synthetic; no Inspector endpoint is contacted and no target or provider starts. These assertions record current behavior.

import { Client, InMemoryTransport } from '@modelcontextprotocol/client';
import { expect, it } from 'vitest';
import { createServer } from '../../../src/server/createServer.js';
import { createTestBinarySession } from '../../fixtures/binarySession.js';
import { parseMcpToolError } from '../../fixtures/mcpToolError.js';
import { JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE } from '../../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js';
import { createJavaScriptRuntimeObservationEvidence } from '../../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js';
import { V8_INSPECTOR_PROVIDER_IDENTITY } from '../../../src/inspector/providerIdentity.js';
import { javascriptRuntimeObservationSchema } from '../../../src/domain/javascript/javascriptRuntimeObservation.js';

const withMcp = async (run: (client: Client) => Promise<void>) => {
  let providerLaunches = 0;
  const session = createTestBinarySession(() => { providerLaunches++; throw new Error('No provider expected'); });
  const server = createServer({kind:'session', session});
  const client = new Client({name:'issue-path-test', version:'1'});
  const [ct, st] = InMemoryTransport.createLinkedPair();
  try {
    await server.connect(st); await client.connect(ct);
    await run(client);
    expect(providerLaunches).toBe(0);
    await client.ping();
  } finally { await client.close();await server.close();await session.close(); }
};


it('reports a role-only V8 mismatch at target_id through MCP', async () => {
  await withMcp(async (client) => {
    const observation = javascriptRuntimeObservationSchema.parse({
      runtime:{product:'node.js',protocol_version:'1.3',v8_version:null},
      target:{target_id:'example-v8-target',protocol_type:'node',attached:false,
        location:{kind:'file',file_path:'/fixtures/main.js'}, runtime_kind:'electron-main',runtime_kind_authority:'caller-declared-unverified'},
      capture:{observation_ms:100,events_observed:0,events_retained:0,events_dropped:0,metadata_bytes_retained:0,truncated:false,truncation_reasons:[]},
      scripts:{items:[],observed_total:0,excluded:{unsupported_location:0,invalid_protocol_value:0}},
      execution_contexts:[],directly_observed:[],unavailable_without_instrumentation:[],unknowns:[],limitations:[]
    });
    for (const [label,target_id,runtime_kind] of [
      ['role-mismatch','example-v8-target','node'],
      ['target-mismatch','wrong-target','electron-main'],
      ['valid','example-v8-target','electron-main']
    ] as const) {
      const evidence = createJavaScriptRuntimeObservationEvidence('observe_javascript_runtime', {
        inspector_endpoint:'http://127.0.0.1:9229',target_id,runtime_kind,observation_ms:100
      },observation,V8_INSPECTOR_PROVIDER_IDENTITY);
      const response = await client.callTool({name:'reconcile_javascript_runtime',arguments:{
        static_layers:JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE.static_layers,runtime_observations:[evidence]
      }});
      if(label === 'valid') { expect(response.isError).not.toBe(true); console.log(JSON.stringify({case:label,success:true})); }
      else {
        const diagnostic = parseMcpToolError(response);
        console.log(JSON.stringify({case:label,diagnostic}));
        expect(diagnostic.error.details).toMatchObject({issues:[{path:['runtime_observations',0,'parameters','target_id'],reason:'invalid_value'}]});
      }
    }
  });
});

The focused run passed. The role-only and target-only requests both returned the path above; the matching-values control succeeded and the session remained responsive.

Expected behavior

Attribute a role-only mismatch to runtime_observations[0].parameters.runtime_kind, retaining the existing rejection and the target-ID path when the target ID differs. The input issue type defines correction metadata for the rejected argument; documented recovery tells callers to correct the listed fields. Sibling parameter checks attribute each rejected field separately.

Impact and scope

P3: incorrect correction metadata for rejected, caller-assembled Evidence. The message already mentions a target or declared-role disagreement, and validation still rejects the mismatch. Matching values succeed. No normal producer output, actual downstream correction-loop failure, valid-input failure or data loss was observed; production frequency is unknown. Callers can compare both named values themselves and rebuild consistent Evidence.

REA version

rea-agents 6.7.0; source revision 52415975942a4b9c53a817915b313ccc404f280e.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1 arm64; locked Vitest 5.0.3. The repository pins Node 24.18.0, which was not separately tested.

Target and artifact context

Synthetic schema-valid V8 runtime observation with an empty script list, plus the shipped complete static application Evidence example. Evidence creation recomputes the semantic digest. The local fixture path and loopback endpoint in the test are identifiers only; neither is accessed.

Interface

MCP

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Actual MCP diagnostic subset for the role-only mismatch:

{"code":"invalid_request","category":"invalid_input","retryable":false,"recovery":{"kind":"inspect_input_contract","operation":"reconcile_javascript_runtime"},"details":{"operation":"reconcile_javascript_runtime","issues":[{"path":["runtime_observations",0,"parameters","target_id"],"reason":"invalid_value","message":"Runtime Evidence target or declared role disagrees with its result"}]}}

The identical diagnostic occurs for a target-only mismatch. The control with matching target and role returns successful Evidence.

Typed outcome or recovery expected

Keep invalid_request, invalid_input, retryable: false and inspect_input_contract recovery. Use the role parameter path when that comparison fails so callers can correct the rejected value.

Analysis or suspected cause

Source-derived: assertV8RuntimeParameters combines two comparisons with one target_id issue. Splitting their attribution would retain the validation contract. The V8 producer echoes the declared role into its result, so unmodified output from that producer is not shown to trigger the mismatch.

Additional context

Checked #5950, #5971, #5980, #6001 and #6003: their native-matching, Android, Kuna, artifact-view and binary-layout branches require different corrections. PR #4327 and its replacement #4941 concern runtime filesystem-path bytes and Electron ownership. PR #3122 concerns analysis-view parent parsing. None changes the role comparison.

Fetched upstream main 6d356b84344659085f2b912857b5e27fe0160c9b retains the relevant capture parser and reconciliation service unchanged. That later revision was inspected, not executed. CLI shares the service by source inspection but was not separately run.

Originally created by @coygeek on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6041 ### 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 Process capture or runtime observation ### Observed behavior `reconcile_javascript_runtime` reports a mismatch only in `runtime_kind` at the agreeing `target_id` field. This reproduced through the registered MCP tool with digest-valid synthetic Evidence: the recorded target ID and result target ID both equal `example-v8-target`, while the parameter role is `node` and the result role is `electron-main`. The request correctly fails with `invalid_request`; its issue path is `runtime_observations[0].parameters.target_id`. A target-only mismatch correctly uses that same path. Matching both values succeeds. ### Reproduction With dependencies installed at this revision, save this as `tests/boundary/mcp/issuePathReproduction.test.ts` and run: ```sh node node_modules/vitest/vitest.mjs run tests/boundary/mcp/issuePathReproduction.test.ts --maxWorkers 1 ``` The executed test uses the real SDK client, in-memory transport and registered server. The observation and static Evidence are synthetic; no Inspector endpoint is contacted and no target or provider starts. These assertions record current behavior. ```ts import { Client, InMemoryTransport } from '@modelcontextprotocol/client'; import { expect, it } from 'vitest'; import { createServer } from '../../../src/server/createServer.js'; import { createTestBinarySession } from '../../fixtures/binarySession.js'; import { parseMcpToolError } from '../../fixtures/mcpToolError.js'; import { JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE } from '../../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js'; import { createJavaScriptRuntimeObservationEvidence } from '../../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js'; import { V8_INSPECTOR_PROVIDER_IDENTITY } from '../../../src/inspector/providerIdentity.js'; import { javascriptRuntimeObservationSchema } from '../../../src/domain/javascript/javascriptRuntimeObservation.js'; const withMcp = async (run: (client: Client) => Promise<void>) => { let providerLaunches = 0; const session = createTestBinarySession(() => { providerLaunches++; throw new Error('No provider expected'); }); const server = createServer({kind:'session', session}); const client = new Client({name:'issue-path-test', version:'1'}); const [ct, st] = InMemoryTransport.createLinkedPair(); try { await server.connect(st); await client.connect(ct); await run(client); expect(providerLaunches).toBe(0); await client.ping(); } finally { await client.close();await server.close();await session.close(); } }; it('reports a role-only V8 mismatch at target_id through MCP', async () => { await withMcp(async (client) => { const observation = javascriptRuntimeObservationSchema.parse({ runtime:{product:'node.js',protocol_version:'1.3',v8_version:null}, target:{target_id:'example-v8-target',protocol_type:'node',attached:false, location:{kind:'file',file_path:'/fixtures/main.js'}, runtime_kind:'electron-main',runtime_kind_authority:'caller-declared-unverified'}, capture:{observation_ms:100,events_observed:0,events_retained:0,events_dropped:0,metadata_bytes_retained:0,truncated:false,truncation_reasons:[]}, scripts:{items:[],observed_total:0,excluded:{unsupported_location:0,invalid_protocol_value:0}}, execution_contexts:[],directly_observed:[],unavailable_without_instrumentation:[],unknowns:[],limitations:[] }); for (const [label,target_id,runtime_kind] of [ ['role-mismatch','example-v8-target','node'], ['target-mismatch','wrong-target','electron-main'], ['valid','example-v8-target','electron-main'] ] as const) { const evidence = createJavaScriptRuntimeObservationEvidence('observe_javascript_runtime', { inspector_endpoint:'http://127.0.0.1:9229',target_id,runtime_kind,observation_ms:100 },observation,V8_INSPECTOR_PROVIDER_IDENTITY); const response = await client.callTool({name:'reconcile_javascript_runtime',arguments:{ static_layers:JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE.static_layers,runtime_observations:[evidence] }}); if(label === 'valid') { expect(response.isError).not.toBe(true); console.log(JSON.stringify({case:label,success:true})); } else { const diagnostic = parseMcpToolError(response); console.log(JSON.stringify({case:label,diagnostic})); expect(diagnostic.error.details).toMatchObject({issues:[{path:['runtime_observations',0,'parameters','target_id'],reason:'invalid_value'}]}); } } }); }); ``` The focused run passed. The role-only and target-only requests both returned the path above; the matching-values control succeeded and the session remained responsive. ### Expected behavior Attribute a role-only mismatch to `runtime_observations[0].parameters.runtime_kind`, retaining the existing rejection and the target-ID path when the target ID differs. The [input issue type](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/analysisErrorCore.ts#L79-L95) defines correction metadata for the rejected argument; [documented recovery](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/docs/mcp-contracts.md#L92-L100) tells callers to correct the listed fields. [Sibling parameter checks](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts#L466-L501) attribute each rejected field separately. ### Impact and scope P3: incorrect correction metadata for rejected, caller-assembled Evidence. The message already mentions a target or declared-role disagreement, and validation still rejects the mismatch. Matching values succeed. No normal producer output, actual downstream correction-loop failure, valid-input failure or data loss was observed; production frequency is unknown. Callers can compare both named values themselves and rebuild consistent Evidence. ### REA version rea-agents 6.7.0; source revision `52415975942a4b9c53a817915b313ccc404f280e`. ### Runtime and platform Node.js v26.12.0; macOS 27.0.1 arm64; locked Vitest 5.0.3. The repository pins Node 24.18.0, which was not separately tested. ### Target and artifact context Synthetic schema-valid V8 runtime observation with an empty script list, plus the shipped complete static application Evidence example. Evidence creation recomputes the semantic digest. The local fixture path and loopback endpoint in the test are identifiers only; neither is accessed. ### Interface MCP ### Earliest failure stage Request parsing or validation ### Relevant output or evidence Actual MCP diagnostic subset for the role-only mismatch: ```json {"code":"invalid_request","category":"invalid_input","retryable":false,"recovery":{"kind":"inspect_input_contract","operation":"reconcile_javascript_runtime"},"details":{"operation":"reconcile_javascript_runtime","issues":[{"path":["runtime_observations",0,"parameters","target_id"],"reason":"invalid_value","message":"Runtime Evidence target or declared role disagrees with its result"}]}} ``` The identical diagnostic occurs for a target-only mismatch. The control with matching target and role returns successful Evidence. ### Typed outcome or recovery expected Keep `invalid_request`, `invalid_input`, `retryable: false` and `inspect_input_contract` recovery. Use the role parameter path when that comparison fails so callers can correct the rejected value. ### Analysis or suspected cause Source-derived: [assertV8RuntimeParameters](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts#L283-L308) combines two comparisons with one `target_id` issue. Splitting their attribution would retain the validation contract. [The V8 producer](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/inspector/V8InspectorCaptureProjection.ts#L169-L181) echoes the declared role into its result, so unmodified output from that producer is not shown to trigger the mismatch. ### Additional context Checked #5950, #5971, #5980, #6001 and #6003: their native-matching, Android, Kuna, artifact-view and binary-layout branches require different corrections. PR #4327 and its replacement #4941 concern runtime filesystem-path bytes and Electron ownership. PR #3122 concerns analysis-view parent parsing. None changes the role comparison. Fetched upstream main `6d356b84344659085f2b912857b5e27fe0160c9b` retains the relevant capture parser and reconciliation service unchanged. That later revision was inspected, not executed. CLI shares the service by source inspection but was not separately run.
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked the reported fix on main at d87e73f2db.

V8 parameter validation now separately checks target_id and runtime_kind, assigning each mismatch to its actual field. The registered-MCP regression uses agreeing target IDs with node versus electron-main, a target-only mismatch, and a fully agreeing control; it checks the complete runtime_observations[0].parameters field path. Synthetic digest-valid Evidence establishes validation behavior only, not real inspector role discovery.

Implementation: javascriptRuntimeReconciliationCaptureParsing.ts, javascriptRuntimeReconciliationCaptureParsing.ts.

The relevant regression checks in javascriptRuntimeObservationMcp.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.

<!-- gh-comment-id:6380742494 --> @coygeek commented on GitHub (Oct 24, 2026): Checked the reported fix on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. V8 parameter validation now separately checks target_id and runtime_kind, assigning each mismatch to its actual field. The registered-MCP regression uses agreeing target IDs with node versus electron-main, a target-only mismatch, and a fully agreeing control; it checks the complete runtime_observations[0].parameters field path. Synthetic digest-valid Evidence establishes validation behavior only, not real inspector role discovery. Implementation: [javascriptRuntimeReconciliationCaptureParsing.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts#L303), [javascriptRuntimeReconciliationCaptureParsing.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts#L309). The relevant regression checks in [javascriptRuntimeObservationMcp.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/tests/boundary/mcp/javascriptRuntimeObservationMcp.test.ts) passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.
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#3687
No description provided.