[GH-ISSUE #4805] [Bug] Active Electron capture discards incomplete process and transport cleanup owners #2497

Closed
opened 2026-10-17 21:05:45 +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/4805

Area

Cleanup, cancellation, or lifecycle / active Electron capture (CLI and MCP).

Observed behavior

Source-derived at main bf54c46264: when cleanupElectronProcesses(ownership, lineage) returns cleaned: false, PlaywrightElectronActiveProvider.capture() reports cleanup_failed and process labels, then discards the local application, exact token-bound OwnedProcessGroup, and lineage. It has no retained process cleanup capability that can retry later. A failed application.close() after confirmed process cleanup similarly has no transport cleanup retry.

Reproduction and evidence

Source-only finding: the owning capture and teardown keep application, ownership, and lineage only as invocation locals. The !cleanup.cleaned branch returns a new error containing strings, rather than retaining the exact capability and binding its release status. Existing source tests simulate incomplete process cleanup, but this report does not claim a failed real Electron kill or OS-level reproduction.

Expected behavior

Retain exact independently retryable transport and token/process-group cleanup owners until release is confirmed. Retry unresolved peers only, bind originating and aggregate cleanup status to the owners, and refuse replacement capture while cleanup remains unresolved. Refresh ownership using existing process supervision; PID or diagnostic labels alone must never authorize a kill. Unknown identity must stay unknown.

Impact and scope

Potential repeated active acquisition after unconfirmed teardown, stale resource diagnostics, and no explicit retry route. Runtime frequency and natural OS reproduction: NOT_ENOUGH_INFO.

REA version / runtime / target

Source bf54c4626, 6.5.0. Source audit on macOS arm64; target, real Electron version and failing host scenario: NOT_ENOUGH_INFO (no target executed for this finding).

Interface / earliest failure stage

Shared active Electron provider behind CLI/MCP / final cleanup.

Separate from #4658 admitted fuse-descriptor cleanup and from #4282 Linux lineage observation support. Dedup search also found lifecycle tracker #4227 and browser tracker #4027. A prepared #4658 repair scopes file preflight cleanup; it does not retain failed process/transport owners.

Add controlled mixed process/transport outcomes, unknown ownership, repeated close, new capture admission while cleanup is pending, and successful retry clearing only confirmed owners. Real OS kill failure remains unverified.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4805 ### Area Cleanup, cancellation, or lifecycle / active Electron capture (CLI and MCP). ### Observed behavior Source-derived at main bf54c462649049e525cbe9030bfe5ddb1d92ba6c: when `cleanupElectronProcesses(ownership, lineage)` returns `cleaned: false`, `PlaywrightElectronActiveProvider.capture()` reports `cleanup_failed` and process labels, then discards the local application, exact token-bound `OwnedProcessGroup`, and lineage. It has no retained process cleanup capability that can retry later. A failed `application.close()` after confirmed process cleanup similarly has no transport cleanup retry. ### Reproduction and evidence Source-only finding: [the owning capture and teardown](https://github.com/morluto/rea/blob/bf54c462649049e525cbe9030bfe5ddb1d92ba6c/src/browser/PlaywrightElectronActiveProvider.ts) keep `application`, `ownership`, and `lineage` only as invocation locals. The `!cleanup.cleaned` branch returns a new error containing strings, rather than retaining the exact capability and binding its release status. Existing source tests simulate incomplete process cleanup, but this report does not claim a failed real Electron kill or OS-level reproduction. ### Expected behavior Retain exact independently retryable transport and token/process-group cleanup owners until release is confirmed. Retry unresolved peers only, bind originating and aggregate cleanup status to the owners, and refuse replacement capture while cleanup remains unresolved. Refresh ownership using existing process supervision; PID or diagnostic labels alone must never authorize a kill. Unknown identity must stay unknown. ### Impact and scope Potential repeated active acquisition after unconfirmed teardown, stale resource diagnostics, and no explicit retry route. Runtime frequency and natural OS reproduction: NOT_ENOUGH_INFO. ### REA version / runtime / target Source bf54c4626, 6.5.0. Source audit on macOS arm64; target, real Electron version and failing host scenario: NOT_ENOUGH_INFO (no target executed for this finding). ### Interface / earliest failure stage Shared active Electron provider behind CLI/MCP / final cleanup. ### Related work and proposed checks Separate from #4658 admitted fuse-descriptor cleanup and from #4282 Linux lineage observation support. Dedup search also found lifecycle tracker #4227 and browser tracker #4027. A prepared #4658 repair scopes file preflight cleanup; it does not retain failed process/transport owners. Add controlled mixed process/transport outcomes, unknown ownership, repeated close, new capture admission while cleanup is pending, and successful retry clearing only confirmed owners. Real OS kill failure remains unverified.
Author
Owner

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

Fixed on main in e7df00e807.

The provider now retains independent transport and exact process-family cleanup leases. Failed teardown blocks replacement capture, provider close retries unresolved owners, and successful peers are not repeated. Original and aggregate errors follow the owners' live release status. Pending close promises are reused after wait expiry; only physical rejection permits another call. Cancellation arriving during failed cleanup preserves its exact reason through recovery.

Moved process cleanup to its owning module and migrated consumers. Fresh Windows lineage is required; root tree termination is followed by a passive family census, without redundant cached descendant PID kills. POSIX unavailable lineage can recover only through safe canonical cleanup and confirmed family absence. Unknown identity stays unknown.

Validation: 172 focused checks passed across 14 files, one platform skip; additional final native boundary rerun passed. Build, typecheck/lint, docs checks (including five README checks), and commit/push hooks passed. Three controlled regression cases failed on the baseline. Two read-only source reviews found no remaining blockers.

The native boundary uses an authored idle Node child with real POSIX ownership/cleanup and a controlled transport denial. Six completed built-provider capture/close tasks before/after returned byte-identical results. Repeated-process medians: baseline/candidate elapsed 1.050/1.077s, CPU 0.954/0.955s, sampled family peak 243.0/242.7 MB, estimated full reply 478/478 cl100k tokens. Small samples, separate first processes, no speedup or true-cold claim; simulated Electron API, no real Electron app, native Windows, public CLI/MCP active capture, whole-agent costs, natural kill failure, or heavy profiler/stress verification.

Context7 and DeepWiki informed upstream close semantics; installed Playwright 1.58.2 source was checked. Transport closure does not substitute for REA's independent family absence proof.

<!-- gh-comment-id:6234573526 --> @morluto commented on GitHub (Oct 17, 2026): Fixed on main in e7df00e80777757b329bbe8aba6d421d8892b9d5. The provider now retains independent transport and exact process-family cleanup leases. Failed teardown blocks replacement capture, provider close retries unresolved owners, and successful peers are not repeated. Original and aggregate errors follow the owners' live release status. Pending close promises are reused after wait expiry; only physical rejection permits another call. Cancellation arriving during failed cleanup preserves its exact reason through recovery. Moved process cleanup to its owning module and migrated consumers. Fresh Windows lineage is required; root tree termination is followed by a passive family census, without redundant cached descendant PID kills. POSIX unavailable lineage can recover only through safe canonical cleanup and confirmed family absence. Unknown identity stays unknown. Validation: 172 focused checks passed across 14 files, one platform skip; additional final native boundary rerun passed. Build, typecheck/lint, docs checks (including five README checks), and commit/push hooks passed. Three controlled regression cases failed on the baseline. Two read-only source reviews found no remaining blockers. The native boundary uses an authored idle Node child with real POSIX ownership/cleanup and a controlled transport denial. Six completed built-provider capture/close tasks before/after returned byte-identical results. Repeated-process medians: baseline/candidate elapsed 1.050/1.077s, CPU 0.954/0.955s, sampled family peak 243.0/242.7 MB, estimated full reply 478/478 cl100k tokens. Small samples, separate first processes, no speedup or true-cold claim; simulated Electron API, no real Electron app, native Windows, public CLI/MCP active capture, whole-agent costs, natural kill failure, or heavy profiler/stress verification. Context7 and DeepWiki informed upstream close semantics; installed Playwright 1.58.2 source was checked. Transport closure does not substitute for REA's independent family absence proof.
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#2497
No description provided.