[GH-ISSUE #5686] [Bug] Process CLI JSON input masks physical read failures after late cancellation #3438

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

Originally created by @morluto on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5686

Before submitting

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

Area

CLI

Observed behavior

A controlled real-file read test of the Process CLI workflow returned code: cancelled after a descriptor read had already failed with EIO. The test abort reason was a different Error object from the physical read error. No process scenario was executed.

Reproduction

At source revision 60956c8c56475e7aaab9559f780908851677ced6, I ran a disposable TypeScript harness with Node 24.18.0:

  1. Create a fresh temporary file containing a valid process scenario.
  2. Instrument FileHandle.prototype.read for that file. On its first read, abort the caller's signal with one Error, then reject the read with a distinct Error whose code is EIO.
  3. Call the exported production function captureProcessScenarioFile(path, process.env, signal).
  4. Observe code: "cancelled" and category: "cancelled" instead of the read failure.

Executed once; reproduced once. The harness and exact JSON output are recorded separately by the reporter. The function was called directly; this was not a compiled CLI subprocess test. No target executable ran.

Expected behavior

Preserve the physical read failure as an I/O failure when that failure occurs first, even if cancellation arrives before the consumer handles it. Report cancellation when the read owner records cancellation at its own checkpoint. A successful read followed by cancellation should remain a cancellation.

Impact and scope

Observed in one controlled Process CLI source-boundary run. This demonstrates a possible loss of the actual filesystem failure in the error returned to callers; it does not establish spontaneous disk-error frequency or user incidence. Source inspection finds the same ambient-signal conversion around the shared JSON reader in evidence-bundle import and analysis-view file loading. Those paths were not separately reproduced here. The compiled CLI/MCP workflows were not tested.

REA version

6.7.0; source revision 60956c8c56475e7aaab9559f780908851677ced6.

Runtime and platform

Node.js v24.18.0; macOS arm64. No Hopper/Ghidra provider was involved.

Target and artifact context

Fresh temporary JSON process-scenario file; the scenario's executable was not launched.

Interface

Other: direct call to the Process CLI application workflow, not a compiled CLI process.

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

The actual read rejection was EIO; it was not the abort reason (physical_error_was_abort_reason: false). The signal was aborted, and the returned result was:

{"error":"Process command failed","code":"cancelled","category":"cancelled","message":"Analysis was cancelled. Start it again when ready.","retryable":true,"remediation":{"action":"Analysis was cancelled. Start it again when ready."},"details":{"operation":"capture_process_scenario","cleanup":"complete"}}

Source at the tested revision: ProcessCli.readJson converts any rejected read to cancellation when the signal is aborted, then checks the signal before examining the read result. The shared JsonFiles.readJsonFileInput also uses current signal state to decide whether to rethrow a read failure. The actual descriptor reads are in JsonInputFile.readPrefix and decodedChunks.

Typed outcome or recovery expected

Preserve the original EIO as the cause of the typed file-I/O outcome, projected by Process CLI as execution_failure with details.operation: "read" and details.reason: "io". Keep existing cancellation output for pre-aborted requests and successful reads interrupted by cancellation.

Analysis or suspected cause

Source-derived: the JSON reader does not preserve whether its in-flight descriptor read failed physically or stopped at an explicit cancellation checkpoint. The shared reader re-samples the later AbortSignal.aborted flag, and Process CLI repeats that inference in its catch and post-read checks. The structural repair should carry physical-read and cancellation origin from the producing file-read boundary to consumers, then remove downstream ambient-state reclassification. Equality with the abort reason alone is not sufficient to establish the origin of a failed descriptor read.

Additional context

Related reports are distinct. Closed #4598 fixes digest/hash consumers; its maintainer follow-up explicitly leaves raw-reader late-signal mappings outside that migration as follow-up work. Open #5397 concerns missing canonical fields on ordinary Process CLI file errors, not EIO being replaced by late cancellation. Closed #4483 and merged #4493 fix SafeOutputTree output readback; their producer/consumer path differs from this JSON input reader. Open #5332 concerns preserving the caller's abort reason through an EVM artifact-reader wrapper, not preserving physical I/O failure over cancellation. Broad tracker #4227 is not an exact duplicate. Searches found no exact open issue or PR for this Process CLI JSON-read behavior.

AI-assisted source review and controlled harness use are disclosed. No repository source change is included in this report.

Originally created by @morluto on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5686 ## 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 CLI ## Observed behavior A controlled real-file read test of the Process CLI workflow returned `code: cancelled` after a descriptor read had already failed with `EIO`. The test abort reason was a different `Error` object from the physical read error. No process scenario was executed. ## Reproduction At source revision `60956c8c56475e7aaab9559f780908851677ced6`, I ran a disposable TypeScript harness with Node 24.18.0: 1. Create a fresh temporary file containing a valid process scenario. 2. Instrument `FileHandle.prototype.read` for that file. On its first read, abort the caller's signal with one `Error`, then reject the read with a distinct `Error` whose `code` is `EIO`. 3. Call the exported production function `captureProcessScenarioFile(path, process.env, signal)`. 4. Observe `code: "cancelled"` and `category: "cancelled"` instead of the read failure. Executed once; reproduced once. The harness and exact JSON output are recorded separately by the reporter. The function was called directly; this was not a compiled CLI subprocess test. No target executable ran. ## Expected behavior Preserve the physical read failure as an I/O failure when that failure occurs first, even if cancellation arrives before the consumer handles it. Report cancellation when the read owner records cancellation at its own checkpoint. A successful read followed by cancellation should remain a cancellation. ## Impact and scope Observed in one controlled Process CLI source-boundary run. This demonstrates a possible loss of the actual filesystem failure in the error returned to callers; it does not establish spontaneous disk-error frequency or user incidence. Source inspection finds the same ambient-signal conversion around the shared JSON reader in evidence-bundle import and analysis-view file loading. Those paths were not separately reproduced here. The compiled CLI/MCP workflows were not tested. ## REA version 6.7.0; source revision `60956c8c56475e7aaab9559f780908851677ced6`. ## Runtime and platform Node.js v24.18.0; macOS arm64. No Hopper/Ghidra provider was involved. ## Target and artifact context Fresh temporary JSON process-scenario file; the scenario's executable was not launched. ## Interface Other: direct call to the Process CLI application workflow, not a compiled CLI process. ## Earliest failure stage Cleanup, cancellation, or lifecycle ## Relevant output or evidence The actual read rejection was `EIO`; it was not the abort reason (`physical_error_was_abort_reason: false`). The signal was aborted, and the returned result was: ```json {"error":"Process command failed","code":"cancelled","category":"cancelled","message":"Analysis was cancelled. Start it again when ready.","retryable":true,"remediation":{"action":"Analysis was cancelled. Start it again when ready."},"details":{"operation":"capture_process_scenario","cleanup":"complete"}} ``` Source at the tested revision: [`ProcessCli.readJson`](https://github.com/morluto/rea/blob/60956c8c56475e7aaab9559f780908851677ced6/src/application/process/ProcessCli.ts#L240-L263) converts any rejected read to cancellation when the signal is aborted, then checks the signal before examining the read result. The shared [`JsonFiles.readJsonFileInput`](https://github.com/morluto/rea/blob/60956c8c56475e7aaab9559f780908851677ced6/src/application/JsonFiles.ts#L116-L132) also uses current signal state to decide whether to rethrow a read failure. The actual descriptor reads are in [`JsonInputFile.readPrefix`](https://github.com/morluto/rea/blob/60956c8c56475e7aaab9559f780908851677ced6/src/application/JsonInputFile.ts#L568-L585) and [`decodedChunks`](https://github.com/morluto/rea/blob/60956c8c56475e7aaab9559f780908851677ced6/src/application/JsonInputFile.ts#L523-L559). ## Typed outcome or recovery expected Preserve the original `EIO` as the cause of the typed file-I/O outcome, projected by Process CLI as `execution_failure` with `details.operation: "read"` and `details.reason: "io"`. Keep existing cancellation output for pre-aborted requests and successful reads interrupted by cancellation. ## Analysis or suspected cause Source-derived: the JSON reader does not preserve whether its in-flight descriptor read failed physically or stopped at an explicit cancellation checkpoint. The shared reader re-samples the later `AbortSignal.aborted` flag, and Process CLI repeats that inference in its catch and post-read checks. The structural repair should carry physical-read and cancellation origin from the producing file-read boundary to consumers, then remove downstream ambient-state reclassification. Equality with the abort reason alone is not sufficient to establish the origin of a failed descriptor read. ## Additional context Related reports are distinct. Closed #4598 fixes digest/hash consumers; its maintainer follow-up explicitly leaves raw-reader late-signal mappings outside that migration as follow-up work. Open #5397 concerns missing canonical fields on ordinary Process CLI file errors, not EIO being replaced by late cancellation. Closed #4483 and merged #4493 fix SafeOutputTree output readback; their producer/consumer path differs from this JSON input reader. Open #5332 concerns preserving the caller's abort reason through an EVM artifact-reader wrapper, not preserving physical I/O failure over cancellation. Broad tracker #4227 is not an exact duplicate. Searches found no exact open issue or PR for this Process CLI JSON-read behavior. AI-assisted source review and controlled harness use are disclosed. No repository source change is included in this report.
bsakaguchi 2026-10-31 00:40:28 +00:00
  • closed this issue
  • added the
    bug
    triage
    labels
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#3438
No description provided.