[GH-ISSUE #4376] [Bug] V8 reconciliation classifies invalid script events as target-scope exclusions #1733

Closed
opened 2026-10-16 21:09:36 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

A local production boundary reproduction passed an Inspector capture state containing three invalid script events through the real capture finalizer, Evidence builder, and reconciliation capture parser. The producer preserved invalid_protocol_value: 3 and unsupported_location: 0. The parser converted these facts into a single BrowserCompleteness exclusion with reason out_of_target_scope, count 3, and marked scripts as policy filtered.

Reproduction

Use a source checkout at either revision listed below, with Node v24.18.0 and the locked dependencies installed using npm ci. Save this complete script as repro.mts in that checkout:

import assert from 'node:assert/strict';
import { pathToFileURL } from 'node:url';
import { join } from 'node:path';
const root = process.env.REA_CHECKOUT!;
const load = (p: string) => import(pathToFileURL(join(root,p)).href);
const {finalizeInspectorCapture} = await load('src/inspector/V8InspectorCaptureProjection.ts');
const {createJavaScriptRuntimeObservationEvidence} = await load('src/application/javascript/JavaScriptRuntimeObservationEvidence.ts');
const {parseRuntimeCaptures} = await load('src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts');
const {V8_INSPECTOR_PROVIDER_IDENTITY} = await load('src/inspector/providerIdentity.ts');
const input = {inspector_endpoint:'http://127.0.0.1:9222',target_id:'fixture',observation_ms:0};
async function run(invalidScripts: number) {
 const result = await finalizeInspectorCapture({input,
  runtime:{product:'Node.js fixture',protocol_version:'1.3',v8_version:null},
  target:{id:'fixture',type:'node',attached:false,location:{kind:'builtin',specifier:'node:fixture'},webSocketUrl:'ws://127.0.0.1:9222/fixture',url:'node:fixture'},
  state:{scripts:[],contexts:new Map(),eventsObserved:invalidScripts,eventsRetained:invalidScripts,eventsDropped:0,metadataBytes:0,scriptsObserved:0,invalidScripts,truncated:false,truncationReasons:new Set()},
 });
 const evidence = createJavaScriptRuntimeObservationEvidence('observe_javascript_runtime',input,result,V8_INSPECTOR_PROVIDER_IDENTITY);
 const [parsed] = parseRuntimeCaptures([evidence]);
 assert.equal(parsed.kind,'v8-inspector');
 return {result,completeness:parsed.inspection.completeness};
}
const control=await run(0); assert.deepEqual(control.completeness.excluded,[]);
const bad=await run(3);
assert.deepEqual(bad.result.scripts.excluded,{unsupported_location:0,invalid_protocol_value:3});
assert.deepEqual(bad.completeness.excluded,[{section:'scripts',reason:'out_of_target_scope',count:3}]);
assert.deepEqual(bad.completeness.policy_filtered_sections,['scripts']);
console.log(JSON.stringify({control:control.completeness.excluded,producer:bad.result.scripts.excluded,normalized:bad.completeness.excluded,policy_filtered_sections:bad.completeness.policy_filtered_sections}));
console.log('PASS: local producer/finalizer and parser boundary; no endpoint connections or live targets.');

Run REA_CHECKOUT="$PWD" node_modules/.bin/tsx repro.mts. The script calls the production finalizer, Evidence builder and parser with three invalid events and a zero-event control. It makes no network requests. All assertions passed on both tested revisions; this does not establish live Inspector or CLI/MCP behavior.

Expected behavior

Preserve the producer's exclusion reason when adapting it to BrowserCompleteness. The BrowserCompleteness contract explicitly offers invalid_protocol_value and describes its coverage semantics as non-lossy. Invalid protocol observations should retain that classification rather than acquire an unsupported target-scope explanation.

Impact and scope

This is an inaccurate internal reconciliation classification. Production Inspector ingestion increments invalidScripts for script-failed-to-parse events and script-parsed events without a usable URL, so the count has real producers. The raw input Evidence retains correct counts. Current reconciliation consumers examine completeness status/section availability rather than the excluded reason; this review did not establish lost script matching, incorrect public graph results, or persisted corruption. The verified impact is therefore limited to internal metadata correctness.

REA version

Main 8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd; published 6.5.0 source 3b79af28e80785afce9f5998d8f03289402a1847.

Runtime and platform

Node v24.18.0; macOS arm64. No V8 Inspector endpoint or provider engine was used.

Target and artifact context

Benign in-memory Inspector capture state and deterministically constructed REA Evidence.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Exact observed output on both revisions:

{"control":[],"producer":{"unsupported_location":0,"invalid_protocol_value":3},"normalized":[{"section":"scripts","reason":"out_of_target_scope","count":3}],"policy_filtered_sections":["scripts"]}
PASS: local producer/finalizer and parser boundary; no endpoint connections or live targets.

Source: normalization at main and real producer branches.

Typed outcome or recovery expected

The normalized ledger should preserve an invalid_protocol_value exclusion with the producer's count. Restoration check: for the three-event case require that reason with count 3; retain the zero-event control's empty exclusion ledger. Do not require unrelated attach-window limitations to disappear.

Analysis or suspected cause

The first incorrect classification appears during reconciliation capture normalization after Evidence construction. excludedV8Scripts sums all reason counters. normalizeV8Inspection assigns that sum one hard-coded reason, losing the producing classification. The conversion was executed; complete CLI/MCP reconciliation was not run.

Additional context

Open and closed issues and PRs were searched. The related Inspector vocabulary PR handles location-denial wire buckets, while the Electron child-frame report handles malformed frame admission. Neither covers conversion of the already distinct invalid-script counter during V8 reconciliation.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: The executed conversion mislabels internal metadata; inspected current consumers do not use the excluded reason to change matching or public result data.
  • Workaround status: available
  • Workaround basis: The original runtime Evidence preserves both exclusion counters and remains available through the parsed capture's evidence field.
Originally created by @coygeek on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4376 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior A local production boundary reproduction passed an Inspector capture state containing three invalid script events through the real capture finalizer, Evidence builder, and reconciliation capture parser. The producer preserved `invalid_protocol_value: 3` and `unsupported_location: 0`. The parser converted these facts into a single BrowserCompleteness exclusion with reason `out_of_target_scope`, count 3, and marked scripts as policy filtered. ### Reproduction Use a source checkout at either revision listed below, with Node v24.18.0 and the locked dependencies installed using `npm ci`. Save this complete script as `repro.mts` in that checkout: ```ts import assert from 'node:assert/strict'; import { pathToFileURL } from 'node:url'; import { join } from 'node:path'; const root = process.env.REA_CHECKOUT!; const load = (p: string) => import(pathToFileURL(join(root,p)).href); const {finalizeInspectorCapture} = await load('src/inspector/V8InspectorCaptureProjection.ts'); const {createJavaScriptRuntimeObservationEvidence} = await load('src/application/javascript/JavaScriptRuntimeObservationEvidence.ts'); const {parseRuntimeCaptures} = await load('src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts'); const {V8_INSPECTOR_PROVIDER_IDENTITY} = await load('src/inspector/providerIdentity.ts'); const input = {inspector_endpoint:'http://127.0.0.1:9222',target_id:'fixture',observation_ms:0}; async function run(invalidScripts: number) { const result = await finalizeInspectorCapture({input, runtime:{product:'Node.js fixture',protocol_version:'1.3',v8_version:null}, target:{id:'fixture',type:'node',attached:false,location:{kind:'builtin',specifier:'node:fixture'},webSocketUrl:'ws://127.0.0.1:9222/fixture',url:'node:fixture'}, state:{scripts:[],contexts:new Map(),eventsObserved:invalidScripts,eventsRetained:invalidScripts,eventsDropped:0,metadataBytes:0,scriptsObserved:0,invalidScripts,truncated:false,truncationReasons:new Set()}, }); const evidence = createJavaScriptRuntimeObservationEvidence('observe_javascript_runtime',input,result,V8_INSPECTOR_PROVIDER_IDENTITY); const [parsed] = parseRuntimeCaptures([evidence]); assert.equal(parsed.kind,'v8-inspector'); return {result,completeness:parsed.inspection.completeness}; } const control=await run(0); assert.deepEqual(control.completeness.excluded,[]); const bad=await run(3); assert.deepEqual(bad.result.scripts.excluded,{unsupported_location:0,invalid_protocol_value:3}); assert.deepEqual(bad.completeness.excluded,[{section:'scripts',reason:'out_of_target_scope',count:3}]); assert.deepEqual(bad.completeness.policy_filtered_sections,['scripts']); console.log(JSON.stringify({control:control.completeness.excluded,producer:bad.result.scripts.excluded,normalized:bad.completeness.excluded,policy_filtered_sections:bad.completeness.policy_filtered_sections})); console.log('PASS: local producer/finalizer and parser boundary; no endpoint connections or live targets.'); ``` Run `REA_CHECKOUT="$PWD" node_modules/.bin/tsx repro.mts`. The script calls the production finalizer, Evidence builder and parser with three invalid events and a zero-event control. It makes no network requests. All assertions passed on both tested revisions; this does not establish live Inspector or CLI/MCP behavior. ### Expected behavior Preserve the producer's exclusion reason when adapting it to BrowserCompleteness. The [BrowserCompleteness contract](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/domain/browserCompleteness.ts#L32-L85) explicitly offers `invalid_protocol_value` and describes its coverage semantics as non-lossy. Invalid protocol observations should retain that classification rather than acquire an unsupported target-scope explanation. ### Impact and scope This is an inaccurate internal reconciliation classification. Production Inspector ingestion increments invalidScripts for script-failed-to-parse events and script-parsed events without a usable URL, so the count has real producers. The raw input Evidence retains correct counts. Current reconciliation consumers examine completeness status/section availability rather than the excluded reason; this review did not establish lost script matching, incorrect public graph results, or persisted corruption. The verified impact is therefore limited to internal metadata correctness. ### REA version Main `8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd`; published 6.5.0 source `3b79af28e80785afce9f5998d8f03289402a1847`. ### Runtime and platform Node v24.18.0; macOS arm64. No V8 Inspector endpoint or provider engine was used. ### Target and artifact context Benign in-memory Inspector capture state and deterministically constructed REA Evidence. ### Interface Other ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Exact observed output on both revisions: ```text {"control":[],"producer":{"unsupported_location":0,"invalid_protocol_value":3},"normalized":[{"section":"scripts","reason":"out_of_target_scope","count":3}],"policy_filtered_sections":["scripts"]} PASS: local producer/finalizer and parser boundary; no endpoint connections or live targets. ``` Source: [normalization at main](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.ts#L353) and [real producer branches](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/inspector/V8InspectorProvider.ts#L439). ### Typed outcome or recovery expected The normalized ledger should preserve an `invalid_protocol_value` exclusion with the producer's count. Restoration check: for the three-event case require that reason with count 3; retain the zero-event control's empty exclusion ledger. Do not require unrelated attach-window limitations to disappear. ### Analysis or suspected cause The first incorrect classification appears during reconciliation capture normalization after Evidence construction. `excludedV8Scripts` sums all reason counters. `normalizeV8Inspection` assigns that sum one hard-coded reason, losing the producing classification. The conversion was executed; complete CLI/MCP reconciliation was not run. ### Additional context Open and closed issues and PRs were searched. The related [Inspector vocabulary PR](https://github.com/morluto/rea/pull/834) handles location-denial wire buckets, while the [Electron child-frame report](https://github.com/morluto/rea/issues/2556) handles malformed frame admission. Neither covers conversion of the already distinct invalid-script counter during V8 reconciliation. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: The executed conversion mislabels internal metadata; inspected current consumers do not use the excluded reason to change matching or public result data. - Workaround status: available - Workaround basis: The original runtime Evidence preserves both exclusion counters and remains available through the parsed capture's evidence field.
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#1733
No description provided.