[GH-ISSUE #6822] [Bug] Managed method pages lose coverage and create false removal claims #4170

Closed
opened 2026-10-31 00:47:22 +00:00 by bsakaguchi · 1 comment
Owner

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

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

The exported inspectManagedMembersBytes supports MethodDef paging but returns a one-method page as coverage.state: "complete", metadata.status: "complete", and selection: null, with no retained method-page boundary. Feeding that real result and a full inspection of the identical bytes into exported compareManagedMembers reports the other two existing methods as removed, without page-coverage limitations, and reports complete-within-inputs coverage.

This is an executed source-function reproduction on current main. It does not establish a failure through the packaged CLI or MCP: current production callers found in this pass do not select method pages. The loss occurs in a production exported parser result that has the same comparison input type as the full inventory.

Reproduction

In a source checkout at the revision below, with locked dependencies installed, save this as /tmp/managed-page-probe.mjs and run from the checkout root:

mise exec node@24.22.1 -- node --import tsx /tmp/managed-page-probe.mjs

The code generates a benign PE/CLI byte fixture entirely in memory; it neither writes nor loads an assembly. The domain comparison takes source observations and schema-valid distinct evidence ID placeholders; the probe does not claim these placeholders authenticate persisted Evidence.

import {pathToFileURL} from 'node:url';
import {arch,release,platform} from 'node:os';
const root=process.env.REA_ROOT??process.cwd();
const load=p=>import(pathToFileURL(root+'/'+p).href);
const {buildManagedPeFixture}=await load('scripts/fixtures/managed/pe.mjs');
const {managedPeFixtureTarget}=await load('src/dotnet/ManagedPe.fixture.ts');
const {inspectManagedMembersBytes}=await load('src/dotnet/ManagedMemberInspector.ts');
const {compareManagedMembers}=await load('src/domain/managed/managedMemberComparison.ts');
console.log(JSON.stringify({node:process.version,platform:platform(),release:release(),arch:arch(),source_revision:'567b55947486516b9d35d30b7202ac69c6f40f6d'}));
const image=buildManagedPeFixture({methods:[
 {name:'First',body:Buffer.from([0x2a])},
 {name:'Second',body:Buffer.from([0x2a])},
 {name:'Third',body:Buffer.from([0x2a])}
]});
const target=managedPeFixtureTarget(image,'/fixture.dll');
const observe=(options)=>inspectManagedMembersBytes(image,target,options);
const all=observe({});const page=observe({methodOffset:1,methodLimit:1});
const firstPage=observe({methodOffset:0,methodLimit:1});
const compare=(left,right)=>compareManagedMembers({evidenceId:'ev_'+'1'.repeat(64),result:left},{evidenceId:'ev_'+'2'.repeat(64),result:right});
for(const [label,left,right] of [['full-versus-page',all,page],['full-versus-full',all,all],['same-page',page,page],['disjoint-pages',firstPage,page]]){
 const comparison=compare(left,right);
 console.log(JSON.stringify({label,left_methods:left.methods.map(m=>m.name),right_methods:right.methods.map(m=>m.name),left_metadata:left.metadata,left_coverage:left.coverage,right_metadata:right.metadata,right_coverage:right.coverage,left_selection:left.selection,right_selection:right.selection,comparison_summary:comparison.summary,comparison_coverage:comparison.coverage,methods:comparison.methods.map(m=>({status:m.status,left:m.left?.name,right:m.right?.name,limitations:m.limitations})),limitations:comparison.limitations}));
}

The completed probe was run twice before drafting, after adding the full/full control. No broad test suite ran.

Expected behavior

A deliberately omitted method must remain outside the observed selection or unknown. A page must retain its selection boundary, or consumers must reject it as a complete method inventory. Comparing the same complete bytes with a partial page must not establish that the omitted methods were removed.

The existing paging test explicitly requests only MethodDef row 2 and expects page coverage to be complete. Completeness within a page can be valid; the defect is that the returned result does not identify that page, and the comparison consequently interprets it as complete coverage of every method. The comparison's inventory check claims to determine whether every member of the declaring type was observed.

Impact and scope

Observed: two false removal claims for methods still present in the exact same artifact bytes. The full/full control returns all three methods unchanged and no removals. The summaries also include one unchanged field, explaining totals of four versus two unchanged items.

Reach is bounded to source consumers that request method pages and subsequently use the normal comparison types; no existing public CLI/MCP page-selecting path was found. External source consumers and real compiled assemblies were not tested. This is a non-security static-result integrity defect. Callers can avoid it by inspecting both sides without methodOffset or methodLimit; that full/full control was executed successfully.

REA version

Main source revision 567b55947486516b9d35d30b7202ac69c6f40f6d; the source manifest says 6.7.0. This is not a reproduction of the published release runtime. The published-tag checkout HEAD was 27dc42d10249f0410904a75c0997842eb03b931c; the probe loaded main's separate locked-dependency source tree. The relevant main files were checked with git show main:<file> before drafting.

Runtime and platform

Observed in the probe: Node.js v24.22.1, Linux kernel 7.2.8-9-omarchy, architecture x64. Source loaded with tsx and main's locked dependencies. No CLR or native analysis provider ran.

Target and artifact context

Benign generated PE/CLI fixture from scripts/fixtures/managed/pe.mjs: three methods named First, Second, and Third, each with a ret body. Both observations use the identical Buffer, artifact SHA-256 and MVID. The one-method page requests methodOffset: 1, methodLimit: 1. CLR validity and execution were not tested.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Selected fields from the actual successful run:

full-versus-page:
  left methods: First, Second, Third
  right methods: Second
  both metadata statuses: complete
  both coverage states: complete
  both selections: null
  summary: {unchanged:2, changed:0, added:0, removed:2, unknown:0}
  methods: Second unchanged; First removed; Third removed
  each method limitations: []
  coverage: {status:"complete-within-inputs", left_status:"complete", right_status:"complete"}
full-versus-full:
  summary: {unchanged:4, changed:0, added:0, removed:0, unknown:0}
  coverage: {status:"complete-within-inputs", left_status:"complete", right_status:"complete"}

Both source observations' table_row_counts.MethodDef remain 3, even when the page's methods array contains one entry. The inspection projects complete coverage without page bounds. The comparison sets inventory completeness solely from metadata status; inventoryCovers then treats selection: null as covering every member.

Typed outcome or recovery expected

Retain method-page coverage so omitted methods remain unknown/out of scope, or reject page observations where whole-inventory comparison is required. Preserve complete inspection and comparison for the executed unpaged control.

Analysis or suspected cause

Source-derived cause: methodOffset and methodLimit are applied to method production but do not survive in ManagedMemberInspection. selection records only selected type names, and neither the result schema nor comparison coverage represents method pages. The comparison therefore has no truthful page boundary to use for absence assertions.

Alternatives considered before drafting: treat complete as complete within the requested page; infer completeness from method counts; explicitly retain the method range. The first interpretation explains the unit test but cannot justify removals because the page scope is absent from the artifact. Count-based inference is insufficient for selected type inventories. Explicit method coverage is the strongest representation; this report does not prescribe an implementation.

Additional context

The source paging test was inspected before drafting. It verifies selected rows and complete page coverage but does not compose the result into comparison. Existing comparison tests for differing type selections and incomplete metadata were also inspected; neither represents method-page selection.

The initial complete open-issue snapshot was searched for managed paging, method_offset, and method_limit. No matching primary behavior was found. Related reports about selected user-string ownership (#5909), malformed signature coverage (#3877), and nested catch identity (#6760) have different triggers. Fresh open/closed searches found related closed #2617, which concerned ignored paging options leaving unrequested methods in the verifier. Here paging is applied correctly; the newly observed defect is loss of the page boundary and false method-removal claims in comparison.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Executed production source functions report two still-present methods as removed with complete coverage when a method page is compared with an unpaged inspection of identical bytes. No public CLI/MCP path selecting method pages was established.
  • Workaround status: available
  • Workaround basis: The executed full/full control, omitting both paging options, retains all three methods and reports zero removals.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6822 ## 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 The exported `inspectManagedMembersBytes` supports MethodDef paging but returns a one-method page as `coverage.state: "complete"`, `metadata.status: "complete"`, and `selection: null`, with no retained method-page boundary. Feeding that real result and a full inspection of the identical bytes into exported `compareManagedMembers` reports the other two existing methods as `removed`, without page-coverage limitations, and reports `complete-within-inputs` coverage. This is an executed source-function reproduction on current main. It does not establish a failure through the packaged CLI or MCP: current production callers found in this pass do not select method pages. The loss occurs in a production exported parser result that has the same comparison input type as the full inventory. ## Reproduction In a source checkout at the revision below, with locked dependencies installed, save this as `/tmp/managed-page-probe.mjs` and run from the checkout root: ```sh mise exec node@24.22.1 -- node --import tsx /tmp/managed-page-probe.mjs ``` The code generates a benign PE/CLI byte fixture entirely in memory; it neither writes nor loads an assembly. The domain comparison takes source observations and schema-valid distinct evidence ID placeholders; the probe does not claim these placeholders authenticate persisted Evidence. ```javascript import {pathToFileURL} from 'node:url'; import {arch,release,platform} from 'node:os'; const root=process.env.REA_ROOT??process.cwd(); const load=p=>import(pathToFileURL(root+'/'+p).href); const {buildManagedPeFixture}=await load('scripts/fixtures/managed/pe.mjs'); const {managedPeFixtureTarget}=await load('src/dotnet/ManagedPe.fixture.ts'); const {inspectManagedMembersBytes}=await load('src/dotnet/ManagedMemberInspector.ts'); const {compareManagedMembers}=await load('src/domain/managed/managedMemberComparison.ts'); console.log(JSON.stringify({node:process.version,platform:platform(),release:release(),arch:arch(),source_revision:'567b55947486516b9d35d30b7202ac69c6f40f6d'})); const image=buildManagedPeFixture({methods:[ {name:'First',body:Buffer.from([0x2a])}, {name:'Second',body:Buffer.from([0x2a])}, {name:'Third',body:Buffer.from([0x2a])} ]}); const target=managedPeFixtureTarget(image,'/fixture.dll'); const observe=(options)=>inspectManagedMembersBytes(image,target,options); const all=observe({});const page=observe({methodOffset:1,methodLimit:1}); const firstPage=observe({methodOffset:0,methodLimit:1}); const compare=(left,right)=>compareManagedMembers({evidenceId:'ev_'+'1'.repeat(64),result:left},{evidenceId:'ev_'+'2'.repeat(64),result:right}); for(const [label,left,right] of [['full-versus-page',all,page],['full-versus-full',all,all],['same-page',page,page],['disjoint-pages',firstPage,page]]){ const comparison=compare(left,right); console.log(JSON.stringify({label,left_methods:left.methods.map(m=>m.name),right_methods:right.methods.map(m=>m.name),left_metadata:left.metadata,left_coverage:left.coverage,right_metadata:right.metadata,right_coverage:right.coverage,left_selection:left.selection,right_selection:right.selection,comparison_summary:comparison.summary,comparison_coverage:comparison.coverage,methods:comparison.methods.map(m=>({status:m.status,left:m.left?.name,right:m.right?.name,limitations:m.limitations})),limitations:comparison.limitations})); } ``` The completed probe was run twice before drafting, after adding the full/full control. No broad test suite ran. ## Expected behavior A deliberately omitted method must remain outside the observed selection or unknown. A page must retain its selection boundary, or consumers must reject it as a complete method inventory. Comparing the same complete bytes with a partial page must not establish that the omitted methods were removed. The existing [paging test](https://github.com/morluto/rea/blob/567b55947486516b9d35d30b7202ac69c6f40f6d/src/dotnet/ManagedMemberInspector.test.ts#L2368) explicitly requests only MethodDef row 2 and expects page coverage to be complete. Completeness within a page can be valid; the defect is that the returned result does not identify that page, and the comparison consequently interprets it as complete coverage of every method. The [comparison's inventory check](https://github.com/morluto/rea/blob/567b55947486516b9d35d30b7202ac69c6f40f6d/src/domain/managed/managedMemberComparisonItems.ts#L50) claims to determine whether every member of the declaring type was observed. ## Impact and scope Observed: two false removal claims for methods still present in the exact same artifact bytes. The full/full control returns all three methods unchanged and no removals. The summaries also include one unchanged field, explaining totals of four versus two unchanged items. Reach is bounded to source consumers that request method pages and subsequently use the normal comparison types; no existing public CLI/MCP page-selecting path was found. External source consumers and real compiled assemblies were not tested. This is a non-security static-result integrity defect. Callers can avoid it by inspecting both sides without `methodOffset` or `methodLimit`; that full/full control was executed successfully. ## REA version Main source revision `567b55947486516b9d35d30b7202ac69c6f40f6d`; the source manifest says `6.7.0`. This is not a reproduction of the published release runtime. The published-tag checkout HEAD was `27dc42d10249f0410904a75c0997842eb03b931c`; the probe loaded main's separate locked-dependency source tree. The relevant main files were checked with `git show main:<file>` before drafting. ## Runtime and platform Observed in the probe: Node.js `v24.22.1`, Linux kernel `7.2.8-9-omarchy`, architecture `x64`. Source loaded with tsx and main's locked dependencies. No CLR or native analysis provider ran. ## Target and artifact context Benign generated PE/CLI fixture from `scripts/fixtures/managed/pe.mjs`: three methods named `First`, `Second`, and `Third`, each with a `ret` body. Both observations use the identical Buffer, artifact SHA-256 and MVID. The one-method page requests `methodOffset: 1, methodLimit: 1`. CLR validity and execution were not tested. ## Interface Other ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence Selected fields from the actual successful run: ```text full-versus-page: left methods: First, Second, Third right methods: Second both metadata statuses: complete both coverage states: complete both selections: null summary: {unchanged:2, changed:0, added:0, removed:2, unknown:0} methods: Second unchanged; First removed; Third removed each method limitations: [] coverage: {status:"complete-within-inputs", left_status:"complete", right_status:"complete"} full-versus-full: summary: {unchanged:4, changed:0, added:0, removed:0, unknown:0} coverage: {status:"complete-within-inputs", left_status:"complete", right_status:"complete"} ``` Both source observations' `table_row_counts.MethodDef` remain `3`, even when the page's methods array contains one entry. The inspection [projects complete coverage without page bounds](https://github.com/morluto/rea/blob/567b55947486516b9d35d30b7202ac69c6f40f6d/src/dotnet/ManagedMemberInspector.ts#L369). The comparison [sets inventory completeness solely from metadata status](https://github.com/morluto/rea/blob/567b55947486516b9d35d30b7202ac69c6f40f6d/src/domain/managed/managedMemberComparison.ts#L265); [inventoryCovers](https://github.com/morluto/rea/blob/567b55947486516b9d35d30b7202ac69c6f40f6d/src/domain/managed/managedMemberComparisonItems.ts#L50) then treats `selection: null` as covering every member. ## Typed outcome or recovery expected Retain method-page coverage so omitted methods remain unknown/out of scope, or reject page observations where whole-inventory comparison is required. Preserve complete inspection and comparison for the executed unpaged control. ## Analysis or suspected cause Source-derived cause: `methodOffset` and `methodLimit` are applied to method production but do not survive in `ManagedMemberInspection`. `selection` records only selected type names, and neither the result schema nor comparison coverage represents method pages. The comparison therefore has no truthful page boundary to use for absence assertions. Alternatives considered before drafting: treat `complete` as complete within the requested page; infer completeness from method counts; explicitly retain the method range. The first interpretation explains the unit test but cannot justify removals because the page scope is absent from the artifact. Count-based inference is insufficient for selected type inventories. Explicit method coverage is the strongest representation; this report does not prescribe an implementation. ## Additional context The source paging test was inspected before drafting. It verifies selected rows and complete page coverage but does not compose the result into comparison. Existing comparison tests for differing type selections and incomplete metadata were also inspected; neither represents method-page selection. The initial complete open-issue snapshot was searched for managed paging, `method_offset`, and `method_limit`. No matching primary behavior was found. Related reports about selected user-string ownership (#5909), malformed signature coverage (#3877), and nested catch identity (#6760) have different triggers. Fresh open/closed searches found related closed #2617, which concerned ignored paging options leaving unrequested methods in the verifier. Here paging is applied correctly; the newly observed defect is loss of the page boundary and false method-removal claims in comparison. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Executed production source functions report two still-present methods as removed with complete coverage when a method page is compared with an unpaged inspection of identical bytes. No public CLI/MCP path selecting method pages was established. - Workaround status: available - Workaround basis: The executed full/full control, omitting both paging options, retains all three methods and reports zero removals.
Author
Owner

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

MethodDef page intervals survive inspection and constrain comparison absence claims. Full, equal-page, overlapping, disjoint and historical-page controls passed. Implemented in github.com/morluto/rea@357e354ac7. Validated on 488c21ab2 using the named production-parser/comparison regression (keeps paged omissions unknown while preserving full and equal-page controls; five selected tests passed). Fixtures are synthetic metadata; no CLR execution or real-provider claim.

<!-- gh-comment-id:6376092774 --> @morluto commented on GitHub (Oct 23, 2026): MethodDef page intervals survive inspection and constrain comparison absence claims. Full, equal-page, overlapping, disjoint and historical-page controls passed. Implemented in https://github.com/morluto/rea/commit/357e354ac7f5aed8e90c209dff30327d6bf212dc. Validated on 488c21ab2 using the named production-parser/comparison regression (`keeps paged omissions unknown while preserving full and equal-page controls`; five selected tests passed). Fixtures are synthetic metadata; no CLR execution or real-provider claim.
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#4170
No description provided.