[PR #6931] test(ghidra): verify PSP Allegrex unresolved indirect branches #7457

Open
opened 2026-11-01 21:47:59 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/6931
Author: @jaelliot
Created: 10/24/2026
Status: 🔄 Open

Base: main ← Head: codex/rea-psp-indirect-conformance-upstream-20261023


📝 Commits (10+)

  • b3e2368 test(ghidra): verify PSP Allegrex computed branch uncertainty
  • ca3d3ca style(ghidra): format PSP indirect verifier
  • 5808136 test(ghidra): await owned PSP prerequisite inspection
  • e36cc8c fix(ghidra): finish PSP verifier cleanup after client close failure
  • 9b2ffce test(ghidra): preserve failed cleanup diagnostics and pin PSP control flows
  • 4c1a102 style(ghidra): format PSP verifier review corrections
  • c80a844 fix(ghidra): retain original errors when lineage verification fails
  • 5e16b34 merge(main): refresh PSP control-flow conformance
  • 7a7b30d test(ghidra): require inspected boundaries for all PSP controls
  • b71a0c6 merge(main): refresh PSP indirect-branch conformance onto current REA

📊 Changes

6 files changed (+512 additions, -0 deletions)

View changed files

📝 docs/ghidra-psp.md (+23 -0)
📝 knip.json (+1 -0)
➕ scripts/verify-real-ghidra-psp-indirect.mjs (+411 -0)
➕ tests/conformance/psp/control-flow/Makefile (+8 -0)
➕ tests/conformance/psp/control-flow/control-flow.S (+51 -0)
➕ tests/conformance/psp/control-flow/main.c (+18 -0)

📄 Description

Summary

Add an opt-in, source-owned PSP/Allegrex control-flow verifier, as a separate follow-up requested by the author of #2977. Related: #1330.

Dependency: #2977 → #6931. The verifier requires the unresolved computed-branch inventory from canonical #2977. That implementation stays with its author; #5137 was incorporated there and closed as superseded. This PR remains six conformance/fixture/documentation files and does not copy production bridge or schema changes.

Problem and expected behavior

Once #2977 is present, two synthetic parameter-derived jr $t9 sites must remain explicitly unresolved, with no invented listing destinations and with retained reachability unknowns. An ordinary jr $ra return and direct j must be inspected and excluded from that inventory. Snapshot reuse must retain the observation and identify its replay provenance.

Review fixes

Commits d7360ed and 1dc5521 address the four review findings in the existing verifier only: 30 additions, 14 deletions.

  • Reuse createVerifierCommands and await commands.close() before completing the verifier, so timeout cleanup retains ownership of compiler descendants.
  • Require unresolved_indirect_branches to be an array; omission or null cannot establish an inspected empty result.
  • Require empty listing_targets for both synthetic computed jumps.
  • Retain replayed Evidence and require the owner's SNAPSHOT_REPLAY_LIMITATION before comparing values. Recognize the provider/operation attribution added by REA's composed-Evidence formatter, following the existing Ghidra MCP replay test.

Change and scope

The existing source-owned ELF32/Allegrex fixture is compiled and statically analyzed through public REA MCP operations. The verifier checks independent ELF/ABI facts, listing observations, Evidence, residual unknowns, snapshot identity/replay, unchanged target bytes, and owned cleanup. Its entry is registered in knip.json; invocation and prerequisites are documented in docs/ghidra-psp.md.

  • Semantic owner: PSP conformance verifier. Process ownership and snapshot provenance reuse the existing owners.
  • Scope decision: routine test-only static analysis within existing PSP admission; the author requested this separate follow-up.
  • Contracts/package: no production provider, bridge, schema, CLI/MCP, dependency, installation, or release changes.
  • Host/provider scope: Linux x64, Ghidra 12.1.3 with compatible Allegrex v21.4, PSPDEV v20261001, and JDK 21 for the pinned qualification lane.
  • Authority: the verifier invokes local build tools and an isolated Ghidra analyzer, writing disposable fixture/project files. It does not execute the synthesized PSP target or use game assets. No toolchain installation or network operation is performed by the verifier.

Expected effects on the test host:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

The checked effects describe host compilation, analyzer execution, and temporary files; target code is never executed.

Evidence and validation

Current verifier revision

  • Node 24.22.1 / npm 11.16.0, locked npm ci: passed.
  • npm run test:focused -- tests/boundary/process/nativeVerifierCommandOwnership.test.ts tests/boundary/process/verifierCommandSemantics.test.ts tests/boundary/process/verifierSourceLoading.test.ts tests/conformance/ghidra/psp-checks.test.ts tests/boundary/mcp/ghidraNativeApiMcp.test.ts: 55 tests passed in five files. This includes real timed-out leader/descendant cleanup with zero survivors, retained artifacts, command cleanup retry, and simulated Ghidra MCP snapshot behavior.
  • Controlled execution of the actual original, intermediate, and final assertion blocks: 9 scenarios / 27 executions. The final source accepts all four valid controls, including a replay limitation produced by REA's actual source formatter, and rejects all five bad observations: omitted/null inspection, missing/fabricated listing targets, and an identical recomputed value without replay provenance. The original accepts those bad cases; the intermediate exact-array check incorrectly rejects the qualified positive control. This is source-assertion evidence, not a real-provider run.
  • After the final marker-format correction, npm run test:focused -- tests/boundary/mcp/ghidraNativeApiMcp.test.ts: 11/11 passed again.
  • node --check, focused formatter check, and git diff --check: passed.
  • npm run check: passed, including typecheck, ordinary/typed lint, formatting, Knip, metadata, module boundaries, and architecture guards. Typed lint reported zero errors with repository advisories. The final two-line assertion adjustment additionally passed focused syntax, formatting, and lint checks.

Dependent real-provider qualification

Current fork run 41854251564 passed at 173c85a. It retains the existing #2977 integration and pinned workflow, using the exact final PR verifier blob 9e335c7f71e795f14b3b7ac7d154c9b47dd91fdd. Its parents are the previous qualification f093496 and current PR commit 1dc5521.

The pinned Linux Ghidra 12.1.3 / Allegrex v21.4 / PSPDEV v20261001 / JDK 21 lane passed 153 focused contract tests, missing-extension refusal, the unchanged PSP acceptance baseline, and the final indirect-branch verifier. Both computed jr $t9 sites remained unresolved with empty listing targets; return/direct controls had inspected empty inventories. The replay assertion passed, the snapshot retained 26 Evidence records, ELF bytes stayed unchanged, and cleanup was verified with zero surviving descendants. Source/working-tree hygiene also passed. This qualifies the final verifier against the retained #2977 integration; it does not establish standalone success against plain main.

The first review-fix qualification, 41852710078, passed the branch checks but failed the new replay assertion: exact array membership did not recognize REA's provider/operation-qualified replay marker. The follow-up corrects that verifier mismatch; the canonical marker remains mandatory. This failed run is retained as evidence.

Current upstream CI 41854491389 completed successfully on 1dc5521: 17 successful jobs, 23 intentionally skipped jobs, and no failures or cancellations. All eight built-test shards, source tests, static checks, documentation, package build, bundled Windows-controls build, Linux native package verification, Portable tests, and CI required passed. Skipped provider/platform lanes remain unexecuted. This standard CI result is separate from the successful dependent real-provider qualification above.

Historical evidence — earlier verifier revisions

Standard upstream CI 41757456999 passed at b71a0c6. Dependent real-Ghidra run 41766913011 passed at 191d759 with Ghidra 12.1.3 / Allegrex v21.4 / PSPDEV v20261001 / JDK 21: 153 focused tests, two unresolved computed branches, ordinary controls excluded, 26 snapshot Evidence records, unchanged ELF bytes, and complete cleanup. These runs predate the new assertions and do not validate the current 1dc5521 revision.

The earlier main-only negative control observed listing-computed branches without #2977's unresolved inventory. Earlier pcap worker-OOM observations and retries concern historical runs; they are not evidence about this revision.

Remaining limits

The dependent provider run and current-head upstream CI both passed. The optional verifier still requires #2977. No runtime game behavior, VFPU semantics, PRX/PBP/ISO/CSO, arbitrary PSP binary support, or cross-platform qualification is claimed.

For evidence-bearing changes:

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

Author readiness

Human owner: @jaelliot

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related PR #2977 and issue #1330 are linked.
  • Tests cover changed observable behavior and meaningful failure paths on the current source revision.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative historical output (no new contract).
  • I checked the final diff 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/6931 **Author:** [@jaelliot](https://github.com/jaelliot) **Created:** 10/24/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `codex/rea-psp-indirect-conformance-upstream-20261023` --- ### 📝 Commits (10+) - [`b3e2368`](https://github.com/morluto/rea/commit/b3e23685379778726058e766b309a44ce673576e) test(ghidra): verify PSP Allegrex computed branch uncertainty - [`ca3d3ca`](https://github.com/morluto/rea/commit/ca3d3ca43951385d80930a6442db47130ba76d1d) style(ghidra): format PSP indirect verifier - [`5808136`](https://github.com/morluto/rea/commit/580813633e38d7e5cc618af0bffda9f84c7b3907) test(ghidra): await owned PSP prerequisite inspection - [`e36cc8c`](https://github.com/morluto/rea/commit/e36cc8c5c1e55e1b9e1e08e1cbfcac44ed56f895) fix(ghidra): finish PSP verifier cleanup after client close failure - [`9b2ffce`](https://github.com/morluto/rea/commit/9b2ffce89498e98952f2cf503576fc1ab789b7a7) test(ghidra): preserve failed cleanup diagnostics and pin PSP control flows - [`4c1a102`](https://github.com/morluto/rea/commit/4c1a102f41f2521b56bfe80bb3ff9a3edb36784a) style(ghidra): format PSP verifier review corrections - [`c80a844`](https://github.com/morluto/rea/commit/c80a8445e5013ea881be89b5ba87697af292cc9d) fix(ghidra): retain original errors when lineage verification fails - [`5e16b34`](https://github.com/morluto/rea/commit/5e16b34688a13d6dae6ae513e34585c4414b15e5) merge(main): refresh PSP control-flow conformance - [`7a7b30d`](https://github.com/morluto/rea/commit/7a7b30d7345619082a2513a864e1b68b738e5ad9) test(ghidra): require inspected boundaries for all PSP controls - [`b71a0c6`](https://github.com/morluto/rea/commit/b71a0c691e56734f5e6b68e5dd879baedd0fa426) merge(main): refresh PSP indirect-branch conformance onto current REA ### 📊 Changes **6 files changed** (+512 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `docs/ghidra-psp.md` (+23 -0) 📝 `knip.json` (+1 -0) ➕ `scripts/verify-real-ghidra-psp-indirect.mjs` (+411 -0) ➕ `tests/conformance/psp/control-flow/Makefile` (+8 -0) ➕ `tests/conformance/psp/control-flow/control-flow.S` (+51 -0) ➕ `tests/conformance/psp/control-flow/main.c` (+18 -0) </details> ### 📄 Description ## Summary Add an opt-in, source-owned PSP/Allegrex control-flow verifier, as a separate follow-up [requested by the author of #2977](https://github.com/morluto/rea/pull/2977#issuecomment-6223631572). Related: #1330. **Dependency: #2977 → #6931.** The verifier requires the unresolved computed-branch inventory from canonical #2977. That implementation stays with its author; #5137 was incorporated there and closed as superseded. This PR remains six conformance/fixture/documentation files and does not copy production bridge or schema changes. ## Problem and expected behavior Once #2977 is present, two synthetic parameter-derived `jr $t9` sites must remain explicitly unresolved, with no invented listing destinations and with retained reachability unknowns. An ordinary `jr $ra` return and direct `j` must be inspected and excluded from that inventory. Snapshot reuse must retain the observation and identify its replay provenance. ## Review fixes Commits [`d7360ed`](https://github.com/jaelliot/rea/commit/d7360edfa25e6709ec4de8495e96ae0ca6ac5865) and [`1dc5521`](https://github.com/jaelliot/rea/commit/1dc5521b8a65b3e9550a71303c2bbbe531e49078) address the [four review findings](https://github.com/morluto/rea/pull/6931#pullrequestreview-5763786014) in the existing verifier only: **30 additions, 14 deletions**. - Reuse `createVerifierCommands` and await `commands.close()` before completing the verifier, so timeout cleanup retains ownership of compiler descendants. - Require `unresolved_indirect_branches` to be an array; omission or null cannot establish an inspected empty result. - Require empty `listing_targets` for both synthetic computed jumps. - Retain replayed Evidence and require the owner's `SNAPSHOT_REPLAY_LIMITATION` before comparing values. Recognize the provider/operation attribution added by REA's composed-Evidence formatter, following the existing Ghidra MCP replay test. ## Change and scope The existing source-owned ELF32/Allegrex fixture is compiled and statically analyzed through public REA MCP operations. The verifier checks independent ELF/ABI facts, listing observations, Evidence, residual unknowns, snapshot identity/replay, unchanged target bytes, and owned cleanup. Its entry is registered in `knip.json`; invocation and prerequisites are documented in `docs/ghidra-psp.md`. - **Semantic owner:** PSP conformance verifier. Process ownership and snapshot provenance reuse the existing owners. - **Scope decision:** routine test-only static analysis within existing PSP admission; the author requested this separate follow-up. - **Contracts/package:** no production provider, bridge, schema, CLI/MCP, dependency, installation, or release changes. - **Host/provider scope:** Linux x64, Ghidra 12.1.3 with compatible Allegrex v21.4, PSPDEV v20261001, and JDK 21 for the pinned qualification lane. - **Authority:** the verifier invokes local build tools and an isolated Ghidra analyzer, writing disposable fixture/project files. It does not execute the synthesized PSP target or use game assets. No toolchain installation or network operation is performed by the verifier. Expected effects on the test host: - [x] Read existing files or captured data. - [x] Launch or attach to a process. - [x] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. The checked effects describe host compilation, analyzer execution, and temporary files; target code is never executed. ## Evidence and validation ### Current verifier revision - Node 24.22.1 / npm 11.16.0, locked `npm ci`: passed. - `npm run test:focused -- tests/boundary/process/nativeVerifierCommandOwnership.test.ts tests/boundary/process/verifierCommandSemantics.test.ts tests/boundary/process/verifierSourceLoading.test.ts tests/conformance/ghidra/psp-checks.test.ts tests/boundary/mcp/ghidraNativeApiMcp.test.ts`: **55 tests passed in five files**. This includes real timed-out leader/descendant cleanup with zero survivors, retained artifacts, command cleanup retry, and simulated Ghidra MCP snapshot behavior. - Controlled execution of the actual original, intermediate, and final assertion blocks: **9 scenarios / 27 executions**. The final source accepts all four valid controls, including a replay limitation produced by REA's actual source formatter, and rejects all five bad observations: omitted/null inspection, missing/fabricated listing targets, and an identical recomputed value without replay provenance. The original accepts those bad cases; the intermediate exact-array check incorrectly rejects the qualified positive control. This is source-assertion evidence, not a real-provider run. - After the final marker-format correction, `npm run test:focused -- tests/boundary/mcp/ghidraNativeApiMcp.test.ts`: **11/11 passed again**. - `node --check`, focused formatter check, and `git diff --check`: passed. - `npm run check`: **passed**, including typecheck, ordinary/typed lint, formatting, Knip, metadata, module boundaries, and architecture guards. Typed lint reported zero errors with repository advisories. The final two-line assertion adjustment additionally passed focused syntax, formatting, and lint checks. ### Dependent real-provider qualification [Current fork run 41854251564](https://github.com/jaelliot/rea/actions/runs/41854251564) **passed** at [`173c85a`](https://github.com/jaelliot/rea/commit/173c85aadfb59c7dd9680da9b5f582365cda67c4). It retains the existing #2977 integration and pinned workflow, using the exact final PR verifier blob `9e335c7f71e795f14b3b7ac7d154c9b47dd91fdd`. Its parents are the previous qualification `f093496` and current PR commit `1dc5521`. The pinned Linux Ghidra 12.1.3 / Allegrex v21.4 / PSPDEV v20261001 / JDK 21 lane passed **153 focused contract tests**, missing-extension refusal, the unchanged PSP acceptance baseline, and the final indirect-branch verifier. Both computed `jr $t9` sites remained unresolved with empty listing targets; return/direct controls had inspected empty inventories. The replay assertion passed, the snapshot retained **26 Evidence records**, ELF bytes stayed unchanged, and cleanup was verified with **zero surviving descendants**. Source/working-tree hygiene also passed. This qualifies the final verifier against the retained #2977 integration; it does not establish standalone success against plain `main`. [The first review-fix qualification, 41852710078](https://github.com/jaelliot/rea/actions/runs/41852710078), passed the branch checks but **failed the new replay assertion**: exact array membership did not recognize REA's provider/operation-qualified replay marker. The follow-up corrects that verifier mismatch; the canonical marker remains mandatory. This failed run is retained as evidence. [Current upstream CI 41854491389](https://github.com/morluto/rea/actions/runs/41854491389) **completed successfully on `1dc5521`**: 17 successful jobs, 23 intentionally skipped jobs, and no failures or cancellations. All eight built-test shards, source tests, static checks, documentation, package build, bundled Windows-controls build, Linux native package verification, Portable tests, and CI required passed. Skipped provider/platform lanes remain unexecuted. This standard CI result is separate from the successful dependent real-provider qualification above. <details> <summary>Historical evidence — earlier verifier revisions</summary> [Standard upstream CI 41757456999](https://github.com/morluto/rea/actions/runs/41757456999) passed at `b71a0c6`. [Dependent real-Ghidra run 41766913011](https://github.com/jaelliot/rea/actions/runs/41766913011) passed at `191d759` with Ghidra 12.1.3 / Allegrex v21.4 / PSPDEV v20261001 / JDK 21: 153 focused tests, two unresolved computed branches, ordinary controls excluded, 26 snapshot Evidence records, unchanged ELF bytes, and complete cleanup. These runs predate the new assertions and do not validate the current `1dc5521` revision. The earlier [main-only negative control](https://github.com/jaelliot/rea/actions/runs/38855215478) observed listing-computed branches without #2977's unresolved inventory. Earlier pcap worker-OOM observations and retries concern historical runs; they are not evidence about this revision. </details> ### Remaining limits The dependent provider run and current-head upstream CI both passed. The optional verifier still requires #2977. No runtime game behavior, VFPU semantics, PRX/PBP/ISO/CSO, arbitrary PSP binary support, or cross-platform qualification is claimed. For evidence-bearing changes: - [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. ## Author readiness Human owner: @jaelliot - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related PR #2977 and issue #1330 are linked. - [x] Tests cover changed observable behavior and meaningful failure paths on the current source revision. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative historical output (no new contract). - [x] I checked the final diff 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>
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#7457
No description provided.