[GH-ISSUE #5543] [Bug] Dispatch metadata marks method lists decoded when the record budget omits their methods #3376

Closed
opened 2026-10-31 00:39:42 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Native analysis or decompilation

Observed behavior

inspect-native-dispatch-metadata PATH --max-records N --json can return an Objective-C protocol or class with methods: [] and decode: {"status":"decoded","reason":null} even though the record budget prevented reading an encoded method. Increasing only the budget returns the method from the same binary. Aggregate coverage reports truncation, but the affected declaration does not identify its omitted method facts.

Reproduction

The independent verifier ran this fixture and these five inspection budgets from a built source checkout on macOS with Apple clang and Foundation. The binary was inspected statically and never executed.

WORK=$(mktemp -d)
mkdir -p "$WORK/home" "$WORK/config" "$WORK/data" "$WORK/cache" "$WORK/state" "$WORK/output"
cat > "$WORK/tiny.m" <<'OBJC'
#import <Foundation/Foundation.h>
@protocol TinyProtocol
- (void)tinyMethod;
@end
@interface TinyClass : NSObject <TinyProtocol>
@end
@implementation TinyClass
- (void)tinyMethod {}
@end
int main(void) { return 0; }
OBJC
clang -framework Foundation -o "$WORK/tiny-objc" "$WORK/tiny.m"
rea_probe() {
  env HOME="$WORK/home" \
    XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" \
    XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" \
    TMPDIR="$WORK" REA_LOG_LEVEL=silent \
    node scripts/rea.mjs "$@"
}
for N in 1 2 3 4 5000; do
  rea_probe inspect-native-dispatch-metadata "$WORK/tiny-objc" \
    --max-records "$N" --json > "$WORK/output/n$N.json"
done

Compare normalized_result.result.objc_protocol_records and normalized_result.result.objc_classes. For the class, select name: "TinyClass" and is_meta_class: false. All five calls exited 0. Repeating the five budgets with Node 24 reproduced the same results as Node 26.

Expected behavior

A returned declaration should distinguish a method list cut by the budget from a genuinely empty method list, through partial record/list coverage or another explicit omission fact. Keep the aggregate truncation warnings and retain the methods when the budget admits them.

Source-derived contract: docs/tool-design.md:51-68 requires unknown coverage to remain distinguishable from absence and truncation/partial failures to be reported. docs/native-investigation.md:419-447 documents Objective-C declaration decoding and required/optional method facts. src/domain/native/objcSwiftMetadata.ts:155-164 models protocol methods and record-local decode status; src/native/AppleObjcProtocols.ts:115-118 already marks a declaration partial for a skipped empty selector.

Impact and scope

Supported low budgets produce misleading record-local method inventories. Consumers honoring aggregate partial coverage can avoid treating the entire result as complete, but the returned record's decoded state does not distinguish an omitted method list from a genuinely empty one. This reproduced on the reduced fixture with both tested Node runtimes. Rerunning this fixture at budget 5000 restored both methods and the class's adopted protocol with complete supported Objective-C metadata coverage. Larger production binaries, adequacy of higher budgets there, MCP, and other platforms were not tested. No security boundary crossing was observed.

REA version

rea-agents 6.7.0, source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node.js v26.12.0 and v24.22.0; macOS 27.0.1 arm64, Darwin 27.0.0; Apple clang 21.0.0, clang-2100.3.34.2. The repository's exact pinned Node 24.18.0 was not tested. No deep-analysis provider, snapshot, or persistent provider database was used.

Target and artifact context

Locally compiled Mach-O executable containing one required Objective-C protocol method and its implementing NSObject subclass. The CLI reads the bytes without executing the target.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The verifier observed these results through the built CLI. Selector lists below are projections of structured method objects, not literal method-array values.

Budget TinyProtocol selectors Protocol decode Non-metaclass TinyClass selectors Class decode
1 [] decoded, reason null Class not returned Not applicable
2 ["tinyMethod"] decoded, reason null Class not returned Not applicable
3 ["tinyMethod"] decoded, reason null [] decoded, reason null
4 ["tinyMethod"] decoded, reason null ["tinyMethod"] decoded, reason null
5000 ["tinyMethod"] decoded, reason null ["tinyMethod"] decoded, reason null

The protocol method has method_type: "instance", is_required: true, and is_optional: false. At budgets 1 through 4, multiple aggregate facets report status: "partial" and reason: "max_records_reached", including objc_class_method_ivar_metadata. Those warnings do not identify the affected returned declaration or its omitted list.

Budget 4 restores the class method but still omits its adopted protocol. Budget 5000 also returns protocols: ["TinyProtocol"] and complete supported Objective-C metadata coverage. A separately compiled genuinely methodless EmptyProtocol and EmptyClass control returned empty method lists with decoded status at budget 5000.

Typed outcome or recovery expected

At budgets 1 and 3, explicitly identify the affected record/list's omitted method coverage. Preserve method admission at budgets 2 and 4, complete facts at budget 5000, and valid decoded emptiness for genuinely methodless declarations. These are proposed restoration checks, not results against a fix.

Analysis or suspected cause

Source-derived reasoning at the tested commit: src/native/AppleObjcProtocols.ts:51-52 stops method enumeration on budget exhaustion without adding that omission to the skipped-selector state used for decode status at lines 115-118. src/native/AppleObjcDispatchFacets.ts:115-116 similarly stops class method enumeration; lines 329-368 construct a class from admitted implementations and select decode status from superclass resolution rather than method-list truncation.

The upstream check fetched main at 1195929fa5f039922bc899c5d536e42129ee38f1 and found no later commits touching the cited expected/failure source files. This is a source-history check, not a runtime reproduction of that newer revision.

Additional context

Prepared with AI assistance and independently reproduced by a separate verifier through the public CLI. Related #5529 concerns optional snapshot persistence; this report concerns record-local method coverage without a snapshot. No known-good version or regression boundary was established.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5543 ### 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 Native analysis or decompilation ### Observed behavior `inspect-native-dispatch-metadata PATH --max-records N --json` can return an Objective-C protocol or class with `methods: []` and `decode: {"status":"decoded","reason":null}` even though the record budget prevented reading an encoded method. Increasing only the budget returns the method from the same binary. Aggregate coverage reports truncation, but the affected declaration does not identify its omitted method facts. ### Reproduction The independent verifier ran this fixture and these five inspection budgets from a built source checkout on macOS with Apple clang and Foundation. The binary was inspected statically and never executed. ```sh WORK=$(mktemp -d) mkdir -p "$WORK/home" "$WORK/config" "$WORK/data" "$WORK/cache" "$WORK/state" "$WORK/output" cat > "$WORK/tiny.m" <<'OBJC' #import <Foundation/Foundation.h> @protocol TinyProtocol - (void)tinyMethod; @end @interface TinyClass : NSObject <TinyProtocol> @end @implementation TinyClass - (void)tinyMethod {} @end int main(void) { return 0; } OBJC clang -framework Foundation -o "$WORK/tiny-objc" "$WORK/tiny.m" rea_probe() { env HOME="$WORK/home" \ XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" \ XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" \ TMPDIR="$WORK" REA_LOG_LEVEL=silent \ node scripts/rea.mjs "$@" } for N in 1 2 3 4 5000; do rea_probe inspect-native-dispatch-metadata "$WORK/tiny-objc" \ --max-records "$N" --json > "$WORK/output/n$N.json" done ``` Compare `normalized_result.result.objc_protocol_records` and `normalized_result.result.objc_classes`. For the class, select `name: "TinyClass"` and `is_meta_class: false`. All five calls exited 0. Repeating the five budgets with Node 24 reproduced the same results as Node 26. ### Expected behavior A returned declaration should distinguish a method list cut by the budget from a genuinely empty method list, through partial record/list coverage or another explicit omission fact. Keep the aggregate truncation warnings and retain the methods when the budget admits them. Source-derived contract: `docs/tool-design.md:51-68` requires unknown coverage to remain distinguishable from absence and truncation/partial failures to be reported. `docs/native-investigation.md:419-447` documents Objective-C declaration decoding and required/optional method facts. `src/domain/native/objcSwiftMetadata.ts:155-164` models protocol methods and record-local decode status; `src/native/AppleObjcProtocols.ts:115-118` already marks a declaration partial for a skipped empty selector. ### Impact and scope Supported low budgets produce misleading record-local method inventories. Consumers honoring aggregate partial coverage can avoid treating the entire result as complete, but the returned record's decoded state does not distinguish an omitted method list from a genuinely empty one. This reproduced on the reduced fixture with both tested Node runtimes. Rerunning this fixture at budget 5000 restored both methods and the class's adopted protocol with complete supported Objective-C metadata coverage. Larger production binaries, adequacy of higher budgets there, MCP, and other platforms were not tested. No security boundary crossing was observed. ### REA version `rea-agents` 6.7.0, source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node.js v26.12.0 and v24.22.0; macOS 27.0.1 arm64, Darwin 27.0.0; Apple clang 21.0.0, clang-2100.3.34.2. The repository's exact pinned Node 24.18.0 was not tested. No deep-analysis provider, snapshot, or persistent provider database was used. ### Target and artifact context Locally compiled Mach-O executable containing one required Objective-C protocol method and its implementing NSObject subclass. The CLI reads the bytes without executing the target. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The verifier observed these results through the built CLI. Selector lists below are projections of structured method objects, not literal method-array values. | Budget | TinyProtocol selectors | Protocol decode | Non-metaclass TinyClass selectors | Class decode | | --- | --- | --- | --- | --- | | 1 | `[]` | `decoded`, reason null | Class not returned | Not applicable | | 2 | `["tinyMethod"]` | `decoded`, reason null | Class not returned | Not applicable | | 3 | `["tinyMethod"]` | `decoded`, reason null | `[]` | `decoded`, reason null | | 4 | `["tinyMethod"]` | `decoded`, reason null | `["tinyMethod"]` | `decoded`, reason null | | 5000 | `["tinyMethod"]` | `decoded`, reason null | `["tinyMethod"]` | `decoded`, reason null | The protocol method has `method_type: "instance"`, `is_required: true`, and `is_optional: false`. At budgets 1 through 4, multiple aggregate facets report `status: "partial"` and `reason: "max_records_reached"`, including `objc_class_method_ivar_metadata`. Those warnings do not identify the affected returned declaration or its omitted list. Budget 4 restores the class method but still omits its adopted protocol. Budget 5000 also returns `protocols: ["TinyProtocol"]` and complete supported Objective-C metadata coverage. A separately compiled genuinely methodless `EmptyProtocol` and `EmptyClass` control returned empty method lists with decoded status at budget 5000. ### Typed outcome or recovery expected At budgets 1 and 3, explicitly identify the affected record/list's omitted method coverage. Preserve method admission at budgets 2 and 4, complete facts at budget 5000, and valid decoded emptiness for genuinely methodless declarations. These are proposed restoration checks, not results against a fix. ### Analysis or suspected cause Source-derived reasoning at the tested commit: `src/native/AppleObjcProtocols.ts:51-52` stops method enumeration on budget exhaustion without adding that omission to the skipped-selector state used for decode status at lines 115-118. `src/native/AppleObjcDispatchFacets.ts:115-116` similarly stops class method enumeration; lines 329-368 construct a class from admitted implementations and select decode status from superclass resolution rather than method-list truncation. The upstream check fetched `main` at `1195929fa5f039922bc899c5d536e42129ee38f1` and found no later commits touching the cited expected/failure source files. This is a source-history check, not a runtime reproduction of that newer revision. ### Additional context Prepared with AI assistance and independently reproduced by a separate verifier through the public CLI. Related #5529 concerns optional snapshot persistence; this report concerns record-local method coverage without a snapshot. No known-good version or regression boundary was established.
Author
Owner

@matbrgz commented on GitHub (Oct 20, 2026):

Cross-referencing with canonical issue #4368 ([Bug] Empty Swift conformance names escape entry recovery and invalidate dispatch metadata) and siblings #5424 and #5529. Addresses method list decode completeness and budget-omission reporting in native dispatch metadata inspection. Cataloged under Cluster AZ in consolidation tracker #4330.

<!-- gh-comment-id:6295549280 --> @matbrgz commented on GitHub (Oct 20, 2026): Cross-referencing with canonical issue #4368 (`[Bug] Empty Swift conformance names escape entry recovery and invalidate dispatch metadata`) and siblings #5424 and #5529. Addresses method list decode completeness and budget-omission reporting in native dispatch metadata inspection. Cataloged under Cluster AZ in consolidation tracker #4330.
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#3376
No description provided.