[GH-ISSUE #3923] [Bug] Firmware CLI prints successful Evidence after request cancellation #1531

Closed
opened 2026-10-16 21:06:46 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

Both inspect-firmware-regions and extract-firmware print successful Evidence when their provider resolves successfully after the request signal has been cancelled. Controlled source CLI integrations set process.exitCode to 130 but omit the structured cancelled outcome and partial-observation context. Each cancelled case and its non-cancelled control ran once. No real firmware engine or packaged subprocess was exercised.

Reproduction

  1. Construct the production createCli({}) dispatcher with an isolated home and a simulated firmware provider at its production port. Capture the SIGINT callback registered by the production cancellation wrapper, without sending an OS signal to the runner.
  2. Dispatch ["inspect-firmware-regions", "/artifacts/input.bin", "--json"] and ["extract-firmware", "/artifacts/input.bin", "/artifacts/output", "--json"] through serve.
  3. In the provider's execute, confirm its received signal is active, invoke the captured callback, confirm signal.aborted, then return a successful schema-valid AnalysisExecution with a file subject, provider identity, and normalized result. Let close resolve normally.
  4. Parse stdout and inspect process.exitCode. Repeat without invoking the callback as the control.

The inspection result used input size 1, empty regions and signature_scan coverage. The extraction result used offset 0, length 1, complete coverage, zero published bytes and empty result arrays. Both used a synthetic engine identity and subject SHA-256 of 64 lowercase a characters. This controlled timing was executed through the actual CLI parser, registrations, service and serializer.

Expected behavior

Cancellation before completion should produce the structured cancelled outcome, retain completed provider facts as a partial observation, and preserve the signal-derived status. docs/mcp-contracts.md:442-456 applies cancellation through cleanup to direct CLI analysis. src/application/ProviderOperationExecution.ts:67-75 establishes retention of completed-provider observations.

Impact and scope

A bounded late-provider-success condition gives CLI callers a success-shaped payload after interruption. The observed exit-code property still signals cancellation, so callers can honor that nonzero status while retaining access to the emitted facts. Real-engine frequency is unknown. No corrupted firmware facts, filesystem publication, data loss or successful MCP reply after protocol cancellation was observed.

REA version

rea 6.5.0 at source commit 4692bb3330

Runtime and platform

Node 24.18.0; macOS arm64

Target and artifact context

not applicable

Interface

CLI

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

The four source CLI integration cases produced:

Operation Signal aborted at provider return stdout Cancellation code Exit-code property
inspect_firmware_regions false Evidence absent 0
inspect_firmware_regions true Evidence absent 130
extract_firmware false Evidence absent 0
extract_firmware true Evidence absent 130

These are in-process dispatcher results and process.exitCode observations, not subprocess exit measurements. src/cli.ts:119 registers the commands; scripts/rea.mjs:72-103 invokes the same dispatcher. The failing service and CLI code are unchanged at current upstream main 22ec8bdb2f7d4626587f23b1eed4a207df600386. The intervening launcher change only normalizes global output flags.

Typed outcome or recovery expected

Return cancellation with completed facts in partial-observation context; keep non-cancelled controls as successful Evidence.

Analysis or suspected cause

Source-derived: src/application/firmware/FirmwareAnalysisService.ts:31-56 checks cancellation before dispatch but not after successful provider completion. src/cli/firmwareCommands.ts:31-39 emits that success. src/firmware/FirmwareProvider.ts:459-476,510-544 can retain success across asynchronous workspace cleanup without another signal check. Real-provider timing was not exercised.

Additional context

Related #3887 concerns a FIFO blocking acquisition and cancellation, a different trigger and outcome. The MCP SDK suppresses replies after protocol cancellation; this report concerns observed CLI output.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3923 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior Both `inspect-firmware-regions` and `extract-firmware` print successful Evidence when their provider resolves successfully after the request signal has been cancelled. Controlled source CLI integrations set `process.exitCode` to 130 but omit the structured `cancelled` outcome and partial-observation context. Each cancelled case and its non-cancelled control ran once. No real firmware engine or packaged subprocess was exercised. ### Reproduction 1. Construct the production `createCli({})` dispatcher with an isolated home and a simulated firmware provider at its production port. Capture the SIGINT callback registered by the production cancellation wrapper, without sending an OS signal to the runner. 2. Dispatch `["inspect-firmware-regions", "/artifacts/input.bin", "--json"]` and `["extract-firmware", "/artifacts/input.bin", "/artifacts/output", "--json"]` through `serve`. 3. In the provider's `execute`, confirm its received signal is active, invoke the captured callback, confirm `signal.aborted`, then return a successful schema-valid `AnalysisExecution` with a file subject, provider identity, and normalized result. Let `close` resolve normally. 4. Parse stdout and inspect `process.exitCode`. Repeat without invoking the callback as the control. The inspection result used input size 1, empty regions and `signature_scan` coverage. The extraction result used offset 0, length 1, `complete` coverage, zero published bytes and empty result arrays. Both used a synthetic engine identity and subject SHA-256 of 64 lowercase `a` characters. This controlled timing was executed through the actual CLI parser, registrations, service and serializer. ### Expected behavior Cancellation before completion should produce the structured `cancelled` outcome, retain completed provider facts as a partial observation, and preserve the signal-derived status. `docs/mcp-contracts.md:442-456` applies cancellation through cleanup to direct CLI analysis. `src/application/ProviderOperationExecution.ts:67-75` establishes retention of completed-provider observations. ### Impact and scope A bounded late-provider-success condition gives CLI callers a success-shaped payload after interruption. The observed exit-code property still signals cancellation, so callers can honor that nonzero status while retaining access to the emitted facts. Real-engine frequency is unknown. No corrupted firmware facts, filesystem publication, data loss or successful MCP reply after protocol cancellation was observed. ### REA version rea 6.5.0 at source commit 4692bb33300c7cb77b095b6cc0c33da861c1b860 ### Runtime and platform Node 24.18.0; macOS arm64 ### Target and artifact context not applicable ### Interface CLI ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence The four source CLI integration cases produced: | Operation | Signal aborted at provider return | stdout | Cancellation code | Exit-code property | | --- | --- | --- | --- | --- | | `inspect_firmware_regions` | false | Evidence | absent | 0 | | `inspect_firmware_regions` | true | Evidence | absent | 130 | | `extract_firmware` | false | Evidence | absent | 0 | | `extract_firmware` | true | Evidence | absent | 130 | These are in-process dispatcher results and `process.exitCode` observations, not subprocess exit measurements. `src/cli.ts:119` registers the commands; `scripts/rea.mjs:72-103` invokes the same dispatcher. The failing service and CLI code are unchanged at current upstream main `22ec8bdb2f7d4626587f23b1eed4a207df600386`. The intervening launcher change only normalizes global output flags. ### Typed outcome or recovery expected Return cancellation with completed facts in partial-observation context; keep non-cancelled controls as successful Evidence. ### Analysis or suspected cause Source-derived: `src/application/firmware/FirmwareAnalysisService.ts:31-56` checks cancellation before dispatch but not after successful provider completion. `src/cli/firmwareCommands.ts:31-39` emits that success. `src/firmware/FirmwareProvider.ts:459-476,510-544` can retain success across asynchronous workspace cleanup without another signal check. Real-provider timing was not exercised. ### Additional context Related #3887 concerns a FIFO blocking acquisition and cancellation, a different trigger and outcome. The MCP SDK suppresses replies after protocol cancellation; this report concerns observed CLI output.
Author
Owner

@XinwangTao commented on GitHub (Oct 15, 2026):

Confirmed: when the request is cancelled, printing success-shaped Evidence on stdout is actively misleading — exit code 130 is easy to miss or override in wrappers, while automation parsing --json will treat the result as a successful operation. The cancelled outcome (and the partial-observation context) should be emitted as the structured result instead of success Evidence.

<!-- gh-comment-id:6186449643 --> @XinwangTao commented on GitHub (Oct 15, 2026): Confirmed: when the request is cancelled, printing success-shaped Evidence on stdout is actively misleading — exit code 130 is easy to miss or override in wrappers, while automation parsing --json will treat the result as a successful operation. The cancelled outcome (and the partial-observation context) should be emitted as the structured result instead of success Evidence.
Author
Owner

@yankikucuk commented on GitHub (Oct 15, 2026):

Working on this. Source-confirmed: FirmwareAnalysisService.execute checked the request signal only before dispatch, so a provider that resolved after cancellation produced successful Evidence while the CLI exit status said 130. The service now rechecks the signal once the Evidence exists and returns the typed cancelled error with that Evidence as partial_observation, the same rule the shared provider operation execution already applies; non-cancelled runs are unchanged. A unit test with a late-completing port pins both cases. Draft PR follows shortly.

<!-- gh-comment-id:6191402488 --> @yankikucuk commented on GitHub (Oct 15, 2026): Working on this. Source-confirmed: `FirmwareAnalysisService.execute` checked the request signal only before dispatch, so a provider that resolved after cancellation produced successful Evidence while the CLI exit status said 130. The service now rechecks the signal once the Evidence exists and returns the typed `cancelled` error with that Evidence as `partial_observation`, the same rule the shared provider operation execution already applies; non-cancelled runs are unchanged. A unit test with a late-completing port pins both cases. Draft PR follows shortly.
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#1531
No description provided.