[GH-ISSUE #5670] [Bug] Reverse, pcap, and SQLite cancellation drop the caller abort reason #3432

Closed
opened 2026-10-31 00:40:24 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @cursor[bot] on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5670

Before submitting

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

Area

Process capture or runtime observation

Observed behavior

On source 40428da1dd6308f6f407547fd23b0a912232895a, three application boundaries drop an opaque caller abort reason, and the reverse-engineering digest classifier can replace a physical denial with cancellation:

  1. ReverseEngineeringService.inspectWithObjdump with an already-aborted signal returns AnalysisCancelledError whose cause is absent. The provider is not launched.
  2. The same operation, aborted after the injected command returns stdout, keeps partial Evidence but still leaves cause absent.
  3. An injected digest that aborts and then rejects with EACCES returns AnalysisCancelledError whose cause is that EACCES error, not an access-denied result.
  4. PcapAnalysisService.execute and SqliteDatabaseService.inspect with an already-aborted signal likewise return AnalysisCancelledError with cause absent and do not call the provider.

This is an injected application-boundary reproduction. No objdump, tshark, or SQLite worker was launched.

Reproduction

Node 24.18.0, Linux. From a clean checkout of 40428da1dd6308f6f407547fd23b0a912232895a, call each service with AbortController.abort(Object.freeze({ requested: "stop" })) before the call, and for the digest case abort inside an injected digest that then throws Object.assign(new Error("permission denied"), { code: "EACCES" }). Observed tags and cause identity:

  • reverse pre-abort: AnalysisCancelledError, cause absent, provider runs = 0
  • reverse post-output abort: AnalysisCancelledError, cause absent, partial observation present
  • reverse digest EACCES after abort: AnalysisCancelledError, cause code EACCES
  • pcap and sqlite pre-abort: AnalysisCancelledError, cause absent, provider calls = 0

Expected behavior

docs/tool-design.md requires the caller's abort reason as the typed cancellation error's cause, including when cancellation is observed after provider completion, and requires an existing primary failure to keep its classification. Pre-abort and post-output cancellation should satisfy error.cause === reason. A digest EACCES should stay AnalysisAccessDeniedError with that error as its cause.

Impact and scope

Observed only at these injected application ports. Callers cannot recover the opaque abort reason from the typed error. The digest case also hides a permission denial behind cancellation. NOT_ENOUGH_INFO: CLI/MCP delivery, real objdump/tshark/SQLite frequency, and other platforms. No target execution or resource escape was observed.

Related open reports #5642, #5279, #5284, and #5373 describe earlier classification gaps. #5642's null/undefined rejection path and the GDB pre-abort path are already fixed on this revision; this report is the remaining admission/classifier gap found while rechecking them.

REA version

Source 40428da1dd6308f6f407547fd23b0a912232895a (package 6.7.0).

Runtime and platform

Node.js 24.18.0; Linux x64. No Hopper, Ghidra, objdump, tshark, or SQLite worker.

Target and artifact context

Inert local file or an absolute path that the aborted admission never reads. Not a target workload.

Interface

Other: shared application service boundary.

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

Executed in-process probe at the revision above. Representative result: reverse pre-abort { "tag": "AnalysisCancelledError", "exact": false, "causeAbsent": true, "runs": 0 }; digest denial { "tag": "AnalysisCancelledError", "code": "EACCES" }; pcap and sqlite pre-abort causeAbsent: true with zero provider calls.

Typed outcome or recovery expected

AnalysisCancelledError.cause is the exact opaque reason. A recognized physical digest or command failure stays that failure when a late abort is also observed.

Analysis or suspected cause

Source-derived: ReverseEngineeringService.#observe, #observeProvider, and the post-command abort branch construct AnalysisCancelledError without signal.reason. The digest catch returns cancellation whenever signal.aborted is true, before errno classification. PcapAnalysisService.execute and SqliteDatabaseService.inspect do the same at admission. Other application services already pass { cause: options.signal.reason }.

Additional context

Prepared while auditing the owned-command cancellation cluster. AI-assisted report; the probe above was executed as stated.

Originally created by @cursor[bot] on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5670 ### 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 Process capture or runtime observation ### Observed behavior On source `40428da1dd6308f6f407547fd23b0a912232895a`, three application boundaries drop an opaque caller abort reason, and the reverse-engineering digest classifier can replace a physical denial with cancellation: 1. `ReverseEngineeringService.inspectWithObjdump` with an already-aborted signal returns `AnalysisCancelledError` whose `cause` is absent. The provider is not launched. 2. The same operation, aborted after the injected command returns stdout, keeps partial Evidence but still leaves `cause` absent. 3. An injected digest that aborts and then rejects with `EACCES` returns `AnalysisCancelledError` whose cause is that `EACCES` error, not an access-denied result. 4. `PcapAnalysisService.execute` and `SqliteDatabaseService.inspect` with an already-aborted signal likewise return `AnalysisCancelledError` with `cause` absent and do not call the provider. This is an injected application-boundary reproduction. No objdump, tshark, or SQLite worker was launched. ### Reproduction Node 24.18.0, Linux. From a clean checkout of `40428da1dd6308f6f407547fd23b0a912232895a`, call each service with `AbortController.abort(Object.freeze({ requested: "stop" }))` before the call, and for the digest case abort inside an injected `digest` that then throws `Object.assign(new Error("permission denied"), { code: "EACCES" })`. Observed tags and cause identity: - reverse pre-abort: `AnalysisCancelledError`, `cause` absent, provider runs = 0 - reverse post-output abort: `AnalysisCancelledError`, `cause` absent, partial observation present - reverse digest `EACCES` after abort: `AnalysisCancelledError`, cause code `EACCES` - pcap and sqlite pre-abort: `AnalysisCancelledError`, `cause` absent, provider calls = 0 ### Expected behavior `docs/tool-design.md` requires the caller's abort reason as the typed cancellation error's cause, including when cancellation is observed after provider completion, and requires an existing primary failure to keep its classification. Pre-abort and post-output cancellation should satisfy `error.cause === reason`. A digest `EACCES` should stay `AnalysisAccessDeniedError` with that error as its cause. ### Impact and scope Observed only at these injected application ports. Callers cannot recover the opaque abort reason from the typed error. The digest case also hides a permission denial behind cancellation. NOT_ENOUGH_INFO: CLI/MCP delivery, real objdump/tshark/SQLite frequency, and other platforms. No target execution or resource escape was observed. Related open reports #5642, #5279, #5284, and #5373 describe earlier classification gaps. #5642's null/undefined rejection path and the GDB pre-abort path are already fixed on this revision; this report is the remaining admission/classifier gap found while rechecking them. ### REA version Source `40428da1dd6308f6f407547fd23b0a912232895a` (package 6.7.0). ### Runtime and platform Node.js 24.18.0; Linux x64. No Hopper, Ghidra, objdump, tshark, or SQLite worker. ### Target and artifact context Inert local file or an absolute path that the aborted admission never reads. Not a target workload. ### Interface Other: shared application service boundary. ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence Executed in-process probe at the revision above. Representative result: reverse pre-abort `{ "tag": "AnalysisCancelledError", "exact": false, "causeAbsent": true, "runs": 0 }`; digest denial `{ "tag": "AnalysisCancelledError", "code": "EACCES" }`; pcap and sqlite pre-abort `causeAbsent: true` with zero provider calls. ### Typed outcome or recovery expected `AnalysisCancelledError.cause` is the exact opaque reason. A recognized physical digest or command failure stays that failure when a late abort is also observed. ### Analysis or suspected cause Source-derived: `ReverseEngineeringService.#observe`, `#observeProvider`, and the post-command abort branch construct `AnalysisCancelledError` without `signal.reason`. The digest `catch` returns cancellation whenever `signal.aborted` is true, before errno classification. `PcapAnalysisService.execute` and `SqliteDatabaseService.inspect` do the same at admission. Other application services already pass `{ cause: options.signal.reason }`. ### Additional context Prepared while auditing the owned-command cancellation cluster. AI-assisted report; the probe above was executed as stated.
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#3432
No description provided.