[PR #5671] [MERGED] fix(errors): preserve caller abort reasons at admission #7025

Closed
opened 2026-11-01 21:44:49 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

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

Base: main ← Head: cursor/caller-abort-reason-6040


📝 Commits (2)

  • 026ee20 fix(errors): preserve caller abort reasons at admission
  • ae52ee0 fix(reverse): keep a foreign digest ABORT_ERR as an adapter failure

📊 Changes

6 files changed (+324 additions, -10 deletions)

View changed files

➕ src/application/pcap/PcapAnalysisService.test.ts (+28 -0)
📝 src/application/pcap/PcapAnalysisService.ts (+5 -1)
📝 src/application/reverse/ReverseEngineeringService.ts (+60 -8)
📝 src/application/sqlite/SqliteDatabaseService.test.ts (+22 -0)
📝 src/application/sqlite/SqliteDatabaseService.ts (+5 -1)
📝 tests/composition/reverseEngineeringAdmission.test.ts (+204 -0)

📄 Description

Summary

Fixes #5670. Reverse, pcap, and SQLite application admission were dropping the caller's abort reason, and a reverse-engineering digest or command failure could be reclassified as cancellation whenever the caller signal was already aborted.

Problem and expected behavior

docs/tool-design.md requires the exact caller abort reason as AnalysisCancelledError.cause, including cancellation observed after provider completion, and requires a recognized primary failure to keep its classification.

On 40428da1dd6308f6f407547fd23b0a912232895a, an injected probe with AbortController.abort({ requested: "stop" }) observed:

  • inspectWithObjdump before launch returned AnalysisCancelledError with cause absent and did not run the provider.
  • The same call, aborted after the command returned stdout, kept partial Evidence and still omitted cause.
  • An injected digest that aborted and then rejected EACCES returned AnalysisCancelledError whose cause was that EACCES error.
  • PcapAnalysisService.execute and SqliteDatabaseService.inspect did the same at admission: cause absent, provider not called.

Change and scope

Cancellation is now published with signal.reason. A recognized physical code (EACCES, EPERM, ETIMEDOUT, ENOENT, and the other host failures already classified by this service) stays that failure when a late abort is also observed. A non-physical rejection while the signal is aborted, including the existing plain digest cancelled case, remains cancellation and now carries the caller reason.

A command ABORT_ERR remains cancellation, which is the previous command contract, and uses the caller reason when the signal is aborted. A digest or stat ABORT_ERR without an aborted signal stays ProviderAdapterError.

Follow the contribution scope. This is an ordinary classification fix inside existing reverse, pcap, and SQLite boundaries. Not applicable: no new provider, target execution, injection, mutation, or protection recovery.

Intentionally not included: GDB, native command, owned-command, pcap command, SQLite provider, and EVM cleanup bugs in the same audit cluster. Those already preserve the caller reason or primary failure on this main. Other application services that still omit signal.reason at admission are left for a separate change.

Contract and boundary impact

  • Semantic owner and earliest changed stage: application admission and reverse-engineering failure projection, before provider launch or after a settled command/digest result.
  • Contribution scope fit and linked maintainer decision: ordinary fix within existing boundaries; not applicable.
  • CLI and MCP/tool-catalog contract: no schema or catalog change. Typed cancellation cause now carries the caller reason for these three services.
  • Provider, bridge, target-format, or platform compatibility: none. Injected service ports only.
  • Evidence, artifact, provenance, or reconstruction contract: post-output cancellation still retains partial Evidence and now also retains the abort reason.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): no target launch and no cleanup-owner change.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects (check known effects; use documentation-only on its own).

  • 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.

Evidence and regression coverage

  • Tests added or updated: tests/composition/reverseEngineeringAdmission.test.ts (pre-abort reason, post-output reason, digest EACCES precedence, foreign digest ABORT_ERR, and aborted command EACCES/ETIMEDOUT/ABORT_ERR with and without captured output); src/application/sqlite/SqliteDatabaseService.test.ts; src/application/pcap/PcapAnalysisService.test.ts.
  • Base reproduction or other evidence: executed in-process probe on 40428da1d before the change. Reverse pre-abort was { tag: "AnalysisCancelledError", exact: false, causeAbsent: true, runs: 0 }. Digest denial was { tag: "AnalysisCancelledError", code: "EACCES" }. Pcap and SQLite pre-abort had causeAbsent: true and zero provider calls. The new assertions fail on that base because they require cause === reason or the physical error tag.
  • User-visible CLI/MCP output (if applicable): not exercised. These are service-boundary results.
  • Remaining proof gaps: no real objdump, tshark, capinfos, or SQLite worker. CLI/MCP delivery of the reason was not rechecked. Other application services that still construct a cause-less AnalysisCancelledError from a caller signal were not changed.

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.

Validation performed

  • npm run test:local -- tests/composition/reverseEngineeringAdmission.test.ts tests/composition/reverseEngineeringEdgeCases.test.ts tests/composition/reverseEngineering.test.ts tests/composition/reverseEngineeringCancellation.test.ts tests/composition/reverseEngineeringUnknownFailures.test.ts src/application/sqlite/SqliteDatabaseService.test.ts src/application/pcap/PcapAnalysisService.test.ts — 125 passed after ae52ee01d.
  • npm run verify:test-discovery — 1850 test files exactly once, on the previous commit.
  • npm run check:fast — typecheck and lint succeeded after ae52ee01d.
  • Node.js 24.18.0 on Linux. Real Hopper, Ghidra, objdump, tshark, and SQLite were not run.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Callers that previously saw cause === undefined on these cancellations now see the abort reason. Recognized physical failures are no longer replaced by cancellation solely because the signal is aborted. A digest ABORT_ERR without an aborted signal stays an adapter failure, matching the previous preflight classification.
  • Real Hopper/Ghidra, browser, or OS coverage: not run. Injected service ports only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new process, network, or target authority. The opaque abort reason is returned only as the typed error cause the caller supplied.

Author readiness

Human owner: @morluto

  • 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 issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.
Open in Web Open in Cursor 

🔄 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/5671 **Author:** [@morluto](https://github.com/morluto) **Created:** 10/20/2026 **Status:** ✅ Merged **Merged:** 10/20/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `cursor/caller-abort-reason-6040` --- ### 📝 Commits (2) - [`026ee20`](https://github.com/morluto/rea/commit/026ee2075e85d5a64f2d51f4d4ba9ba41d76023b) fix(errors): preserve caller abort reasons at admission - [`ae52ee0`](https://github.com/morluto/rea/commit/ae52ee01db16f32ece3b948740b9c4441a7a0f54) fix(reverse): keep a foreign digest ABORT_ERR as an adapter failure ### 📊 Changes **6 files changed** (+324 additions, -10 deletions) <details> <summary>View changed files</summary> ➕ `src/application/pcap/PcapAnalysisService.test.ts` (+28 -0) 📝 `src/application/pcap/PcapAnalysisService.ts` (+5 -1) 📝 `src/application/reverse/ReverseEngineeringService.ts` (+60 -8) 📝 `src/application/sqlite/SqliteDatabaseService.test.ts` (+22 -0) 📝 `src/application/sqlite/SqliteDatabaseService.ts` (+5 -1) 📝 `tests/composition/reverseEngineeringAdmission.test.ts` (+204 -0) </details> ### 📄 Description <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Fixes #5670. Reverse, pcap, and SQLite application admission were dropping the caller's abort reason, and a reverse-engineering digest or command failure could be reclassified as cancellation whenever the caller signal was already aborted. ## Problem and expected behavior `docs/tool-design.md` requires the exact caller abort reason as `AnalysisCancelledError.cause`, including cancellation observed after provider completion, and requires a recognized primary failure to keep its classification. On `40428da1dd6308f6f407547fd23b0a912232895a`, an injected probe with `AbortController.abort({ requested: "stop" })` observed: - `inspectWithObjdump` before launch returned `AnalysisCancelledError` with `cause` absent and did not run the provider. - The same call, aborted after the command returned stdout, kept partial Evidence and still omitted `cause`. - An injected digest that aborted and then rejected `EACCES` returned `AnalysisCancelledError` whose cause was that `EACCES` error. - `PcapAnalysisService.execute` and `SqliteDatabaseService.inspect` did the same at admission: `cause` absent, provider not called. ## Change and scope Cancellation is now published with `signal.reason`. A recognized physical code (`EACCES`, `EPERM`, `ETIMEDOUT`, `ENOENT`, and the other host failures already classified by this service) stays that failure when a late abort is also observed. A non-physical rejection while the signal is aborted, including the existing plain `digest cancelled` case, remains cancellation and now carries the caller reason. A command `ABORT_ERR` remains cancellation, which is the previous command contract, and uses the caller reason when the signal is aborted. A digest or stat `ABORT_ERR` without an aborted signal stays `ProviderAdapterError`. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). This is an ordinary classification fix inside existing reverse, pcap, and SQLite boundaries. Not applicable: no new provider, target execution, injection, mutation, or protection recovery. Intentionally not included: GDB, native command, owned-command, pcap command, SQLite provider, and EVM cleanup bugs in the same audit cluster. Those already preserve the caller reason or primary failure on this main. Other application services that still omit `signal.reason` at admission are left for a separate change. ## Contract and boundary impact - Semantic owner and earliest changed stage: application admission and reverse-engineering failure projection, before provider launch or after a settled command/digest result. - Contribution scope fit and linked maintainer decision: ordinary fix within existing boundaries; not applicable. - CLI and MCP/tool-catalog contract: no schema or catalog change. Typed cancellation `cause` now carries the caller reason for these three services. - Provider, bridge, target-format, or platform compatibility: none. Injected service ports only. - Evidence, artifact, provenance, or reconstruction contract: post-output cancellation still retains partial Evidence and now also retains the abort reason. - Target selection, authority, upstream behavior, and cleanup details (if applicable): no target launch and no cleanup-owner change. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects (check known effects; use documentation-only on its own). - [x] 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. ## Evidence and regression coverage - Tests added or updated: `tests/composition/reverseEngineeringAdmission.test.ts` (pre-abort reason, post-output reason, digest `EACCES` precedence, foreign digest `ABORT_ERR`, and aborted command `EACCES`/`ETIMEDOUT`/`ABORT_ERR` with and without captured output); `src/application/sqlite/SqliteDatabaseService.test.ts`; `src/application/pcap/PcapAnalysisService.test.ts`. - Base reproduction or other evidence: executed in-process probe on `40428da1d` before the change. Reverse pre-abort was `{ tag: "AnalysisCancelledError", exact: false, causeAbsent: true, runs: 0 }`. Digest denial was `{ tag: "AnalysisCancelledError", code: "EACCES" }`. Pcap and SQLite pre-abort had `causeAbsent: true` and zero provider calls. The new assertions fail on that base because they require `cause === reason` or the physical error tag. - User-visible CLI/MCP output (if applicable): not exercised. These are service-boundary results. - Remaining proof gaps: no real objdump, tshark, capinfos, or SQLite worker. CLI/MCP delivery of the reason was not rechecked. Other application services that still construct a cause-less `AnalysisCancelledError` from a caller signal were not changed. 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. ## Validation performed - `npm run test:local -- tests/composition/reverseEngineeringAdmission.test.ts tests/composition/reverseEngineeringEdgeCases.test.ts tests/composition/reverseEngineering.test.ts tests/composition/reverseEngineeringCancellation.test.ts tests/composition/reverseEngineeringUnknownFailures.test.ts src/application/sqlite/SqliteDatabaseService.test.ts src/application/pcap/PcapAnalysisService.test.ts` — 125 passed after `ae52ee01d`. - `npm run verify:test-discovery` — 1850 test files exactly once, on the previous commit. - `npm run check:fast` — typecheck and lint succeeded after `ae52ee01d`. - Node.js 24.18.0 on Linux. Real Hopper, Ghidra, objdump, tshark, and SQLite were not run. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Callers that previously saw `cause === undefined` on these cancellations now see the abort reason. Recognized physical failures are no longer replaced by cancellation solely because the signal is aborted. A digest `ABORT_ERR` without an aborted signal stays an adapter failure, matching the previous preflight classification. - Real Hopper/Ghidra, browser, or OS coverage: not run. Injected service ports only. - Package or release metadata impact: none. - Security, privacy, process, or containment review: no new process, network, or target authority. The opaque abort reason is returned only as the typed error cause the caller supplied. ## Author readiness Human owner: @morluto - [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 issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-f69ddd61-6ad5-558f-825d-393e2ec56040?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-f69ddd61-6ad5-558f-825d-393e2ec56040&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:44:49 +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#7025
No description provided.