[GH-ISSUE #4848] [Bug] CLI failure logging overwrites doctor cancellation exit status #3015

Closed
opened 2026-10-31 00:34:51 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

  • Searched SIGINT/130 reports; #1126 addressed web commands and is closed, while this reproduction uses doctor. Related #3053 documents command-specific exit conventions.
  • No credentials or private target data included.

Area

CLI

Observed behavior

The public doctor CLI returns typed cancellation JSON and exits 1 after SIGINT, although its commandCancellation boundary records 130. The selected Java prerequisite owned group is empty when the command returns, so this report concerns exit disposition rather than leaked cleanup.

Reproduction

Controlled public CLI on Node24.18/macOS arm64 using source3ad1032b1 plus the current owned JADX preflight fix. An authored selected Java launcher announces its run identity only for --list-modules, then idles. Run node scripts/rea.mjs doctor --provider jadx --json, wait for that announcement and send SIGINT through the acquired ChildProcess handle. The command emits code cancelled, exits1/signalnull, and its token-verified Java group is empty. Reproduced twice with the corrected fixture. This is not a real JVM failure or an APK execution.

Expected behavior

The owning interruption boundary should retain its conventional130 disposition through generic failure logging; SIGTERM analog143 is source-derived and not yet tested for doctor.

Impact and scope

Observed doctor CLI cancellation cannot be distinguished from ordinary failure by process status. Other commands and production frequency: NOT_ENOUGH_INFO. Lifecycle cleanup was independently verified for the tested group.

REA version

6.5.0, main3ad1032b11edea2dcb054e78f951cc43159ae83d plus in-progress owned Java readiness migration; CLI logger and registration unchanged from that commit.

Runtime and platform

Node24.18.0/macOS arm64; authored prerequisite fixture with real CLI/doctor/process ownership boundaries.

Target and artifact context

Caller-selected prerequisite Java shim and pinned JADX0.7.1 JAR for metadata admission. No APK/engine launch.

Interface

CLI

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

exit={code:1,signal:null}; JSON code=cancelled; selected prerequisite args=[--list-modules]; token-verified process group state=empty.

Typed outcome or recovery expected

Retain both typed cancellation and the disposition authored by commandCancellation.

Analysis or suspected cause

Doctor registers logCliCommand outside withCommandCancellation. The inner finally sets process.exitCode=130; logCliCommand then unconditionally assigns1 in its failure/catch paths. Generic logging overwrites the more specific owner observation. Inspect affected consumers and fix the owning rule rather than adding a doctor-specific result patch.

Additional context

Found during #4845 public validation. Earlier harness failures were CommonJS/ES module fixture configuration and interception of the informational Ghidra probe; corrected before this observation. Proposed regression: actual public doctor SIGINT/SIGTERM with joined cleanup, generic failure/success, and existing authored exit dispositions.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4848 ### Before submitting - [x] Searched SIGINT/130 reports; #1126 addressed web commands and is closed, while this reproduction uses doctor. Related #3053 documents command-specific exit conventions. - [x] No credentials or private target data included. ### Area CLI ### Observed behavior The public doctor CLI returns typed cancellation JSON and exits 1 after SIGINT, although its commandCancellation boundary records 130. The selected Java prerequisite owned group is empty when the command returns, so this report concerns exit disposition rather than leaked cleanup. ### Reproduction Controlled public CLI on Node24.18/macOS arm64 using source3ad1032b1 plus the current owned JADX preflight fix. An authored selected Java launcher announces its run identity only for --list-modules, then idles. Run `node scripts/rea.mjs doctor --provider jadx --json`, wait for that announcement and send SIGINT through the acquired ChildProcess handle. The command emits code cancelled, exits1/signalnull, and its token-verified Java group is empty. Reproduced twice with the corrected fixture. This is not a real JVM failure or an APK execution. ### Expected behavior The owning interruption boundary should retain its conventional130 disposition through generic failure logging; SIGTERM analog143 is source-derived and not yet tested for doctor. ### Impact and scope Observed doctor CLI cancellation cannot be distinguished from ordinary failure by process status. Other commands and production frequency: NOT_ENOUGH_INFO. Lifecycle cleanup was independently verified for the tested group. ### REA version 6.5.0, main3ad1032b11edea2dcb054e78f951cc43159ae83d plus in-progress owned Java readiness migration; CLI logger and registration unchanged from that commit. ### Runtime and platform Node24.18.0/macOS arm64; authored prerequisite fixture with real CLI/doctor/process ownership boundaries. ### Target and artifact context Caller-selected prerequisite Java shim and pinned JADX0.7.1 JAR for metadata admission. No APK/engine launch. ### Interface CLI ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence exit={code:1,signal:null}; JSON code=cancelled; selected prerequisite args=[--list-modules]; token-verified process group state=empty. ### Typed outcome or recovery expected Retain both typed cancellation and the disposition authored by commandCancellation. ### Analysis or suspected cause Doctor registers logCliCommand outside withCommandCancellation. The inner finally sets process.exitCode=130; logCliCommand then unconditionally assigns1 in its failure/catch paths. Generic logging overwrites the more specific owner observation. Inspect affected consumers and fix the owning rule rather than adding a doctor-specific result patch. ### Additional context Found during #4845 public validation. Earlier harness failures were CommonJS/ES module fixture configuration and interception of the informational Ghidra probe; corrected before this observation. Proposed regression: actual public doctor SIGINT/SIGTERM with joined cleanup, generic failure/success, and existing authored exit dispositions.
bsakaguchi 2026-10-31 00:34:51 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Fixed on main in 662fad907 (fix(cli): finalize doctor cancellation after failure logging).

The doctor registration was the sole direct composition placing logCliCommand outside withCommandCancellation. The cancellation boundary now owns failure logging and projection, then assigns the final signal disposition after joined cleanup. Generic failure logging is unchanged.

Both public CLI controls fail on the baseline with exit 1 and pass with SIGINT 130 / SIGTERM 143 after the fix. They also verify typed cancellation and the selected Java prerequisite process group is empty before fixture cleanup. Normal doctor success/failure retain exits 0/1.

Validation: 20 passing tests across five focused files; check:fast, docs:check, test discovery (1548 files), commit and push hooks passed. The fixtures use authored Node launchers, not a JVM; native Linux/Windows and performance were not measured. Heavy CPU tests/profiling remain stopped.

<!-- gh-comment-id:6238315243 --> @morluto commented on GitHub (Oct 17, 2026): Fixed on main in 662fad907 (`fix(cli): finalize doctor cancellation after failure logging`). The doctor registration was the sole direct composition placing `logCliCommand` outside `withCommandCancellation`. The cancellation boundary now owns failure logging and projection, then assigns the final signal disposition after joined cleanup. Generic failure logging is unchanged. Both public CLI controls fail on the baseline with exit 1 and pass with SIGINT 130 / SIGTERM 143 after the fix. They also verify typed cancellation and the selected Java prerequisite process group is empty before fixture cleanup. Normal doctor success/failure retain exits 0/1. Validation: 20 passing tests across five focused files; check:fast, docs:check, test discovery (1548 files), commit and push hooks passed. The fixtures use authored Node launchers, not a JVM; native Linux/Windows and performance were not measured. Heavy CPU tests/profiling remain stopped.
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#3015
No description provided.