[PR #3002] [MERGED] fix(ghidra): preserve function facet and call coverage #5551

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

📋 Pull Request Information

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

Base: main ← Head: fix/2951-ghidra-dossier-coverage


📝 Commits (10+)

  • cd87d86 fix(ghidra): preserve observed function facet and call coverage
  • 7838157 fix(ghidra): retain unresolved call coverage in observations
  • af2256f fix(ghidra): separate reference targets from callee coverage
  • 746a6a4 fix(ghidra): measure incoming call coverage across function bodies
  • 3428cb1 chore: sync verification branch with latest main
  • c29598e fix(ghidra): preserve whole-scope directional call coverage
  • 8b0a281 chore: sync verification branch with latest main
  • 89aad57 chore: sync upstream Hopper test corrections
  • 08822d7 chore: sync upstream Hopper test formatting
  • dd1c73b fix(mcp): retain compact Evidence field types

📊 Changes

18 files changed (+1018 additions, -189 deletions)

View changed files

📝 bridge/ghidra/ReaGhidraBridge.java (+277 -92)
📝 scripts/lib/native-value-e2e.mjs (+82 -0)
📝 scripts/lib/real-ghidra-boundaries.mjs (+1 -1)
📝 src/domain/callPath.test.ts (+36 -0)
📝 src/domain/callPath.ts (+2 -2)
📝 src/domain/functionCallCoverage.test.ts (+33 -7)
📝 src/domain/functionCallCoverage.ts (+27 -10)
📝 src/domain/relationshipCoverage.ts (+17 -6)
📝 src/ghidra/GhidraAnalysisProfile.ts (+4 -2)
📝 src/ghidra/GhidraFunctionValues.test.ts (+113 -0)
📝 src/ghidra/GhidraFunctionValues.ts (+16 -1)
📝 src/ghidra/GhidraProvider.behavior.test.ts (+11 -2)
📝 src/ghidra/GhidraProviderCapabilities.ts (+0 -17)
📝 src/ghidra/GhidraProviderClient.ts (+5 -2)
📝 src/ghidra/GhidraSnapshotCache.test.ts (+120 -36)
➕ tests/boundary/mcp/functionCallDirectionsMcp.test.ts (+138 -0)
📝 tests/boundary/mcp/ghidraEvidenceMcp.test.ts (+21 -11)
📝 tests/conformance/ghidra/ReaNoReturnProbe.java (+115 -0)

📄 Description

Ghidra dossiers omitted the availability of successfully collected function facets, so explicit function comparison could remain unknown. Call coverage also claimed completeness when its inventories omitted unresolved calls or body-and-entry references, and caller-only gaps incorrectly made forward path reconstruction incomplete.

This change declares collected facets, preserves producer-owned relationship coverage through the adapter/cache/snapshots, and records unresolved sites only when their evidence is requested. One reference visitor owns the full function body plus exact entry: inventory reads stream omission counts, while dossiers reuse their collected references. Known containing-function targets remain resolved even when Ghidra's exact-entry getter omits them. Typed limited_directions lets forward searches retain caller explanations without weakening complete callee coverage. Old call-coverage snapshot profiles are rejected under v5. Comment collection uses Ghidra's indexed comment-address iterator. Shared optional diagnostics keep three tagged coverage states instead of six duplicate Schema branches, preserving compact Evidence field types within the existing expansion budget.

Validation on 80daf923fe224ab6c9110f3756361e1b0c768705, based on main 1f122c02b71dae7f4109f35ed834f82b96fbf247:

  • Full static gate, normal pre-push checks, runtime build, and docs checks pass; 268 related source cases and 43 MCP boundary cases (including all compact profile checks) pass. The actual SDK-advertised schemas enforce direction cardinality and reject duplicates.
  • Real Linux Ghidra 12.1.4 / Java 21 producer regression checks manual references on non-call instructions, interior target ownership, omitted callers/callees, directional dossier coverage, and no-return behavior. The old bridge fails the manual-reference coverage assertion; the new bridge passes. Input bytes and owned-process cleanup are verified.
  • Public MCP direct/self-comparison, comment write/read/invalidation, and unresolved callback/path/comparison workflows pass. Incomplete calls remain unknown.
  • A real 128-call ELF returns a 7,239-byte callee inventory instead of its explicitly requested 2,048,517-byte full dossier. Repeated inventory requests take 7.37–8.25 ms with stable Evidence IDs. Cold startup is measured separately; these are shared-host client timings, not isolated producer speedups or token estimates.
  • The complete native/AArch64 lane passed on frozen pre-Schema-cleanup head 08822d779f: 384 successful public boundary calls, 52 expected rejections, CLI/MCP parity, snapshot/mutation/permission/cancellation and cleanup checks; 713.59 s wall and 1377.01 s waited-child CPU. Every recorded source/runtime hash matched after completion. Final post-cleanup/head 80daf923fe public direct/annotation, unresolved callback and real producer golden workflows pass; the exact-head full lane also passes: 384 successful boundary calls, 52 expected rejections, native plus crosscompiled AArch64 fixtures, 688.13 s wall / 1332.78 s waited-child CPU / approximately 4140 MiB summed-family RSS estimate. All 3,614 source and 1,540 runtime hashes match after completion, input immutability and owned-process cleanup are verified. Shared pages may be counted more than once; CPU/latency are shared-host observations.

The new head fixes this PR's compact input-schema CI regression. Upstream moved the JavaScript worker test into the compiled boundary lane. Additional local upstream PowerPC tests fail installation admission because their mock properties omit application.java.min; exact main/test/installation blobs match, and coverage parameters are never reached. The extended source selection has 291 passes and these three unrelated failures. No unrelated repair is included; fresh required CI remains the merge gate. Both PRs also fail the same unchanged ciTestReports.test.ts blob-report diagnostic fixture (Partial test diagnostics absent); test/report/artifact code blobs match main.

Closes #2951.


🔄 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/3002 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/2951-ghidra-dossier-coverage` --- ### 📝 Commits (10+) - [`cd87d86`](https://github.com/morluto/rea/commit/cd87d86dcb20a5ab0601590eff86e0db24dc15cc) fix(ghidra): preserve observed function facet and call coverage - [`7838157`](https://github.com/morluto/rea/commit/78381579da776c36a4dfd2fc26e6910e975acd8d) fix(ghidra): retain unresolved call coverage in observations - [`af2256f`](https://github.com/morluto/rea/commit/af2256f84c2589fd2656382b6b733bf38108cedf) fix(ghidra): separate reference targets from callee coverage - [`746a6a4`](https://github.com/morluto/rea/commit/746a6a45bd31c1ddc19792534e758bd6aa9c3346) fix(ghidra): measure incoming call coverage across function bodies - [`3428cb1`](https://github.com/morluto/rea/commit/3428cb101b435adeed0fc17baaf61f0abd15cb44) chore: sync verification branch with latest main - [`c29598e`](https://github.com/morluto/rea/commit/c29598e8b6030da3a5e11dce1e5c60d17e8ee3ac) fix(ghidra): preserve whole-scope directional call coverage - [`8b0a281`](https://github.com/morluto/rea/commit/8b0a281507aea181df0d671173e559e30df8272d) chore: sync verification branch with latest main - [`89aad57`](https://github.com/morluto/rea/commit/89aad57cad2c912d833940d899b30f4b8a2d68e4) chore: sync upstream Hopper test corrections - [`08822d7`](https://github.com/morluto/rea/commit/08822d779fa13522f680c45efc35a8c5bb33dbde) chore: sync upstream Hopper test formatting - [`dd1c73b`](https://github.com/morluto/rea/commit/dd1c73b7981af376f03ce73a1436bbd12ca502df) fix(mcp): retain compact Evidence field types ### 📊 Changes **18 files changed** (+1018 additions, -189 deletions) <details> <summary>View changed files</summary> 📝 `bridge/ghidra/ReaGhidraBridge.java` (+277 -92) 📝 `scripts/lib/native-value-e2e.mjs` (+82 -0) 📝 `scripts/lib/real-ghidra-boundaries.mjs` (+1 -1) 📝 `src/domain/callPath.test.ts` (+36 -0) 📝 `src/domain/callPath.ts` (+2 -2) 📝 `src/domain/functionCallCoverage.test.ts` (+33 -7) 📝 `src/domain/functionCallCoverage.ts` (+27 -10) 📝 `src/domain/relationshipCoverage.ts` (+17 -6) 📝 `src/ghidra/GhidraAnalysisProfile.ts` (+4 -2) 📝 `src/ghidra/GhidraFunctionValues.test.ts` (+113 -0) 📝 `src/ghidra/GhidraFunctionValues.ts` (+16 -1) 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+11 -2) 📝 `src/ghidra/GhidraProviderCapabilities.ts` (+0 -17) 📝 `src/ghidra/GhidraProviderClient.ts` (+5 -2) 📝 `src/ghidra/GhidraSnapshotCache.test.ts` (+120 -36) ➕ `tests/boundary/mcp/functionCallDirectionsMcp.test.ts` (+138 -0) 📝 `tests/boundary/mcp/ghidraEvidenceMcp.test.ts` (+21 -11) 📝 `tests/conformance/ghidra/ReaNoReturnProbe.java` (+115 -0) </details> ### 📄 Description Ghidra dossiers omitted the availability of successfully collected function facets, so explicit function comparison could remain unknown. Call coverage also claimed completeness when its inventories omitted unresolved calls or body-and-entry references, and caller-only gaps incorrectly made forward path reconstruction incomplete. This change declares collected facets, preserves producer-owned relationship coverage through the adapter/cache/snapshots, and records unresolved sites only when their evidence is requested. One reference visitor owns the full function body plus exact entry: inventory reads stream omission counts, while dossiers reuse their collected references. Known containing-function targets remain resolved even when Ghidra's exact-entry getter omits them. Typed `limited_directions` lets forward searches retain caller explanations without weakening complete callee coverage. Old call-coverage snapshot profiles are rejected under v5. Comment collection uses Ghidra's indexed comment-address iterator. Shared optional diagnostics keep three tagged coverage states instead of six duplicate Schema branches, preserving compact Evidence field types within the existing expansion budget. Validation on `80daf923fe224ab6c9110f3756361e1b0c768705`, based on main `1f122c02b71dae7f4109f35ed834f82b96fbf247`: - Full static gate, normal pre-push checks, runtime build, and docs checks pass; 268 related source cases and 43 MCP boundary cases (including all compact profile checks) pass. The actual SDK-advertised schemas enforce direction cardinality and reject duplicates. - Real Linux Ghidra 12.1.4 / Java 21 producer regression checks manual references on non-call instructions, interior target ownership, omitted callers/callees, directional dossier coverage, and no-return behavior. The old bridge fails the manual-reference coverage assertion; the new bridge passes. Input bytes and owned-process cleanup are verified. - Public MCP direct/self-comparison, comment write/read/invalidation, and unresolved callback/path/comparison workflows pass. Incomplete calls remain unknown. - A real 128-call ELF returns a 7,239-byte callee inventory instead of its explicitly requested 2,048,517-byte full dossier. Repeated inventory requests take 7.37–8.25 ms with stable Evidence IDs. Cold startup is measured separately; these are shared-host client timings, not isolated producer speedups or token estimates. - The complete native/AArch64 lane passed on frozen pre-Schema-cleanup head `08822d779f`: 384 successful public boundary calls, 52 expected rejections, CLI/MCP parity, snapshot/mutation/permission/cancellation and cleanup checks; 713.59 s wall and 1377.01 s waited-child CPU. Every recorded source/runtime hash matched after completion. Final post-cleanup/head `80daf923fe` public direct/annotation, unresolved callback and real producer golden workflows pass; the exact-head full lane also passes: 384 successful boundary calls, 52 expected rejections, native plus crosscompiled AArch64 fixtures, 688.13 s wall / 1332.78 s waited-child CPU / approximately 4140 MiB summed-family RSS estimate. All 3,614 source and 1,540 runtime hashes match after completion, input immutability and owned-process cleanup are verified. Shared pages may be counted more than once; CPU/latency are shared-host observations. The new head fixes this PR's compact input-schema CI regression. Upstream moved the JavaScript worker test into the compiled boundary lane. Additional local upstream PowerPC tests fail installation admission because their mock properties omit `application.java.min`; exact main/test/installation blobs match, and coverage parameters are never reached. The extended source selection has 291 passes and these three unrelated failures. No unrelated repair is included; fresh required CI remains the merge gate. Both PRs also fail the same unchanged `ciTestReports.test.ts` blob-report diagnostic fixture (`Partial test diagnostics` absent); test/report/artifact code blobs match main. Closes #2951. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:07:32 +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#5551
No description provided.