[PR #2757] [MERGED] fix(native): preserve unresolved calls in untyped route fallback #5368

Closed
opened 2026-10-31 01:06:05 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2757
Author: @IvenKooLab
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/native-unresolved-call-fallback


📝 Commits (3)

  • 7593347 fix(native): preserve unresolved calls in untyped route fallback
  • 143224d Merge remote-tracking branch 'upstream/main' into fix/native-unresolved-call-fallback
  • f34720d fix(native): preserve partial unresolved call evidence and coverage

📊 Changes

5 files changed (+186 additions, -57 deletions)

View changed files

📝 src/application/native/EnhancedNativeInvestigation.test.ts (+43 -0)
📝 src/application/native/NativeCallRoutes.test.ts (+53 -0)
📝 src/application/native/NativeCallRoutes.ts (+57 -36)
📝 src/application/native/NativeUiActionTrace.ts (+31 -21)
📝 src/domain/native/objcSwiftMetadata.ts (+2 -0)

📄 Description

Summary

Preserve observed targetless call sites when native call-route discovery falls back to an untyped callee inventory. trace_native_ui_action now retains the unresolved edge, call-site address, original reason, and producing provider alongside inferred callee routes.

Problem and expected behavior

Hopper's bridge returns reference_kinds_available: false together with unresolved_calls. readNativeCallRoutes previously discarded these observations when it called procedure_callees, replacing them with unknowns: []. For example, an unresolved call at 0x1008 disappeared even when the provider had already reported it. Lack of detailed reference flags must not erase independently observed targetless calls.

No issue is linked: this is a small, independently reproduced correction to an existing workflow.

Change and scope

Retain validated unresolved-call facts at the call-route boundary before choosing the typed or fallback route path. Bind each observation to its producing provider and use that identity when constructing trace Evidence, so a fallback provider is not credited with another provider's observation.

This ordinary static-analysis correction fits the existing contribution scope. A new-capability maintainer scope decision is not applicable.

Contract and boundary impact

  • Semantic owner: readNativeCallRoutes, after parsing procedure_references and before fallback selection.
  • CLI/MCP/tool catalog: no input or schema changes; the existing trace unresolved array now includes previously discarded facts.
  • Provider/bridge compatibility: unchanged bridge protocol; uses existing Hopper observations. Typed Ghidra routing retains its existing behavior.
  • Evidence/provenance: preserve original reason, call-site address, target binding, and producing provider. The evidence description identifies that provider.
  • Authority and cleanup: existing provider workflow; no added target execution, injection, mutation, network operations, or resource acquisition.
  • Generated metadata, packages, and installation: no changes.

Expected effects of the corrected analysis path:

  • Read existing files or captured data.

Evidence and regression coverage

  • Empty and nonempty fallback inventories preserve targetless calls and the original provider, including when the fallback provider differs.
  • Signal and provider-derived selector options reach both provider requests.
  • An EnhancedTools.execute("trace_native_ui_action", ...) regression retains both an inferred callee edge and unresolved call-site Evidence.
  • All three new cases fail against the original production implementation at 2995ec6; the other 19 selected cases pass.
  • Existing cancellation, invalid typed output, omitted unresolved-call observations, typed ambiguity, and trace-boundary tests remain covered.

Representative corrected trace fragment:

{
  "from": "native:function:0x1000",
  "to": null,
  "relation": "indirect_call",
  "resolution": "unresolved",
  "reason": "No static target",
  "evidence": [{
    "kind": "reference",
    "description": "Hopper reported an unresolved call: No static target",
    "location": { "address": "0x1008", "file_offset": null }
  }]
}

The fragment omits unchanged identity and limitation fields for readability. It comes from the simulated-provider regression, not a real Hopper run.

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • Fixed toolchain: Node 24.18.0, npm 11.16.0; npm ci completed.
  • npm run test:local -- src/application/native/NativeCallRoutes.test.ts src/application/native/EnhancedNativeInvestigation.test.ts — 22 tests passed.
  • npm run check — typecheck, lint, format, knip, package metadata, module boundaries, and architecture guards passed.
  • git diff HEAD --check — passed.

Compatibility, safety, and release

No breaking schema change or migration. Real Hopper/Ghidra verification was not run because those engines are unavailable on this host; evidence is from production application functions, simulated provider boundaries, and the existing Hopper bridge producer source. No real-provider compatibility expansion is claimed. No package/release metadata changes or new authority, persistence, or cleanup behavior.

Before merge

  • This PR addresses a concrete problem.
  • Scope and authority questions for this routine fix are resolved.
  • One focused outcome and Conventional Commit title.
  • Reason for not linking an issue is stated above.
  • Changed behavior and relevant failure paths are tested.
  • No owning docs/contracts/generated metadata change is required.
  • Representative user-visible output is included.
  • Final diff checked for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2757 **Author:** [@IvenKooLab](https://github.com/IvenKooLab) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/native-unresolved-call-fallback` --- ### 📝 Commits (3) - [`7593347`](https://github.com/morluto/rea/commit/7593347a71adc5e9dfb7a828049e647f44dc16e2) fix(native): preserve unresolved calls in untyped route fallback - [`143224d`](https://github.com/morluto/rea/commit/143224d254441cd040e3799297bcf985748dd779) Merge remote-tracking branch 'upstream/main' into fix/native-unresolved-call-fallback - [`f34720d`](https://github.com/morluto/rea/commit/f34720dd2128fb1c32705693557650d2c14d61db) fix(native): preserve partial unresolved call evidence and coverage ### 📊 Changes **5 files changed** (+186 additions, -57 deletions) <details> <summary>View changed files</summary> 📝 `src/application/native/EnhancedNativeInvestigation.test.ts` (+43 -0) 📝 `src/application/native/NativeCallRoutes.test.ts` (+53 -0) 📝 `src/application/native/NativeCallRoutes.ts` (+57 -36) 📝 `src/application/native/NativeUiActionTrace.ts` (+31 -21) 📝 `src/domain/native/objcSwiftMetadata.ts` (+2 -0) </details> ### 📄 Description ## Summary Preserve observed targetless call sites when native call-route discovery falls back to an untyped callee inventory. `trace_native_ui_action` now retains the unresolved edge, call-site address, original reason, and producing provider alongside inferred callee routes. ## Problem and expected behavior Hopper's bridge returns `reference_kinds_available: false` together with `unresolved_calls`. `readNativeCallRoutes` previously discarded these observations when it called `procedure_callees`, replacing them with `unknowns: []`. For example, an unresolved call at `0x1008` disappeared even when the provider had already reported it. Lack of detailed reference flags must not erase independently observed targetless calls. No issue is linked: this is a small, independently reproduced correction to an existing workflow. ## Change and scope Retain validated unresolved-call facts at the call-route boundary before choosing the typed or fallback route path. Bind each observation to its producing provider and use that identity when constructing trace Evidence, so a fallback provider is not credited with another provider's observation. This ordinary static-analysis correction fits the existing [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). A new-capability maintainer scope decision is not applicable. ## Contract and boundary impact - Semantic owner: `readNativeCallRoutes`, after parsing `procedure_references` and before fallback selection. - CLI/MCP/tool catalog: no input or schema changes; the existing trace `unresolved` array now includes previously discarded facts. - Provider/bridge compatibility: unchanged bridge protocol; uses existing Hopper observations. Typed Ghidra routing retains its existing behavior. - Evidence/provenance: preserve original reason, call-site address, target binding, and producing provider. The evidence description identifies that provider. - Authority and cleanup: existing provider workflow; no added target execution, injection, mutation, network operations, or resource acquisition. - Generated metadata, packages, and installation: no changes. Expected effects of the corrected analysis path: - [x] Read existing files or captured data. ## Evidence and regression coverage - Empty and nonempty fallback inventories preserve targetless calls and the original provider, including when the fallback provider differs. - Signal and provider-derived selector options reach both provider requests. - An `EnhancedTools.execute("trace_native_ui_action", ...)` regression retains both an inferred callee edge and unresolved call-site Evidence. - All three new cases fail against the original production implementation at `2995ec6`; the other 19 selected cases pass. - Existing cancellation, invalid typed output, omitted unresolved-call observations, typed ambiguity, and trace-boundary tests remain covered. Representative corrected trace fragment: ```json { "from": "native:function:0x1000", "to": null, "relation": "indirect_call", "resolution": "unresolved", "reason": "No static target", "evidence": [{ "kind": "reference", "description": "Hopper reported an unresolved call: No static target", "location": { "address": "0x1008", "file_offset": null } }] } ``` The fragment omits unchanged identity and limitation fields for readability. It comes from the simulated-provider regression, not a real Hopper run. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - Fixed toolchain: Node `24.18.0`, npm `11.16.0`; `npm ci` completed. - `npm run test:local -- src/application/native/NativeCallRoutes.test.ts src/application/native/EnhancedNativeInvestigation.test.ts` — 22 tests passed. - `npm run check` — typecheck, lint, format, knip, package metadata, module boundaries, and architecture guards passed. - `git diff HEAD --check` — passed. ## Compatibility, safety, and release No breaking schema change or migration. Real Hopper/Ghidra verification was not run because those engines are unavailable on this host; evidence is from production application functions, simulated provider boundaries, and the existing Hopper bridge producer source. No real-provider compatibility expansion is claimed. No package/release metadata changes or new authority, persistence, or cleanup behavior. ## Before merge - [x] This PR addresses a concrete problem. - [x] Scope and authority questions for this routine fix are resolved. - [x] One focused outcome and Conventional Commit title. - [x] Reason for not linking an issue is stated above. - [x] Changed behavior and relevant failure paths are tested. - [x] No owning docs/contracts/generated metadata change is required. - [x] Representative user-visible output is included. - [x] Final diff checked for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:06:05 +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#5368
No description provided.