[GH-ISSUE #5267] [Bug] Process lifecycle waits depend on replaceable application timers #3215

Closed
opened 2026-10-31 00:37:57 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

  • Searched open/closed issues and the related work in #5249.
  • Reduced authored fixtures only; no credentials or private target data.

Area

Process capture or runtime observation

Observed behavior

Controlled production-boundary regressions on main aacf740a0: replacing the application's global setTimeout with a throwing function prevents native process cleanup and capture-journal finalization from completing through their expected paths. Cleanup deadlines use monotonic elapsed time, but several waits use the replaceable application timer.

One final ownership sweep reports final process ownership verification failed: application timer is unavailable; a live unreadable-token retry rejects with the timer exception instead of returning its existing fail-closed cleanup result. settleProcessCaptureJournal likewise rejects from the global timer before its quiet window can settle.

Reproduction

Executed with the three new controlled regressions over unchanged production source at aacf740a0:

npm run test:local -- src/process/ProcessOwnership.finalSweep.test.ts src/process/capture/ProcessHarness.test.ts

The fixtures replace only globalThis.setTimeout, then call exported cleanupOwnedProcessGroup or settleProcessCaptureJournal. The cleanup hosts retain native identity/token/group facts through the normal application boundary; the journal case uses an empty journal and a zero quiet interval. All three new cases fail on the baseline. No target program or real Jadx engine was needed.

Expected behavior

Process lifecycle waits must continue on the same real scheduling basis as their elapsed-time budgets. Unreadable live ownership remains a cleanup failure; replacing an application timer must not bypass ownership checks or replace that result with an unrelated timer exception. Capture settlement must retain its trailing-callback drain and existing timing limits.

Impact and scope

Observed under controlled same-process application-timer replacement, as used by tests or embeddings. Related #5249 already proposes the ownership timer correction; this report also verifies the adjacent capture-journal wait. NOT_ENOUGH_INFO: ordinary Jadx/CLI incidence without timer replacement, real Linux/Windows behavior, and fake-clock frameworks that also replace performance are not established.

REA version

Source main aacf740a047078e79c71d528e8e188afe2ba1aff; package 6.7.0.

Runtime and platform

Node 24.18.0 / npm 11.16.0; macOS arm64. Host/process observations were controlled seams, not native Linux qualification.

Target and artifact context

Synthetic process-ownership rows and capture journal; no external target.

Interface

Other — exported process lifecycle production boundaries.

Earliest failure stage

Cleanup, cancellation, or lifecycle.

Relevant output or evidence

Baseline: three new tests fail with application timer is unavailable; ordinary controls remain passing. A candidate using node:timers/promises for the four ownership waits and the journal wait passes 93 tests across six files (one existing Linux-only test skipped on this macOS host). Timing budgets, retry counts, signal authority, and cancellation paths are unchanged.

Analysis or suspected cause

Source-confirmed: four waits in src/process/ProcessOwnership.ts and the quiet-window wait in src/process/capture/ProcessCaptureLifecycle.ts use global setTimeout. The capture module already uses the native promise timer in its other finalization waits. The owning boundary should use that scheduler consistently; consumers should not repair timer exceptions downstream. Node 24's built-in timer implementation was inspected in addition to Context7/DeepWiki navigation; no immunity to arbitrary mutation of built-in modules or all fake-clock APIs is claimed.

Originally created by @morluto on GitHub (Oct 19, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5267 ### Before submitting - [x] Searched open/closed issues and the related work in #5249. - [x] Reduced authored fixtures only; no credentials or private target data. ### Area Process capture or runtime observation ### Observed behavior Controlled production-boundary regressions on main `aacf740a0`: replacing the application's global `setTimeout` with a throwing function prevents native process cleanup and capture-journal finalization from completing through their expected paths. Cleanup deadlines use monotonic elapsed time, but several waits use the replaceable application timer. One final ownership sweep reports `final process ownership verification failed: application timer is unavailable`; a live unreadable-token retry rejects with the timer exception instead of returning its existing fail-closed cleanup result. `settleProcessCaptureJournal` likewise rejects from the global timer before its quiet window can settle. ### Reproduction Executed with the three new controlled regressions over unchanged production source at `aacf740a0`: ```sh npm run test:local -- src/process/ProcessOwnership.finalSweep.test.ts src/process/capture/ProcessHarness.test.ts ``` The fixtures replace only `globalThis.setTimeout`, then call exported `cleanupOwnedProcessGroup` or `settleProcessCaptureJournal`. The cleanup hosts retain native identity/token/group facts through the normal application boundary; the journal case uses an empty journal and a zero quiet interval. All three new cases fail on the baseline. No target program or real Jadx engine was needed. ### Expected behavior Process lifecycle waits must continue on the same real scheduling basis as their elapsed-time budgets. Unreadable live ownership remains a cleanup failure; replacing an application timer must not bypass ownership checks or replace that result with an unrelated timer exception. Capture settlement must retain its trailing-callback drain and existing timing limits. ### Impact and scope Observed under controlled same-process application-timer replacement, as used by tests or embeddings. Related #5249 already proposes the ownership timer correction; this report also verifies the adjacent capture-journal wait. **NOT_ENOUGH_INFO:** ordinary Jadx/CLI incidence without timer replacement, real Linux/Windows behavior, and fake-clock frameworks that also replace `performance` are not established. ### REA version Source main `aacf740a047078e79c71d528e8e188afe2ba1aff`; package 6.7.0. ### Runtime and platform Node 24.18.0 / npm 11.16.0; macOS arm64. Host/process observations were controlled seams, not native Linux qualification. ### Target and artifact context Synthetic process-ownership rows and capture journal; no external target. ### Interface Other — exported process lifecycle production boundaries. ### Earliest failure stage Cleanup, cancellation, or lifecycle. ### Relevant output or evidence Baseline: three new tests fail with `application timer is unavailable`; ordinary controls remain passing. A candidate using `node:timers/promises` for the four ownership waits and the journal wait passes 93 tests across six files (one existing Linux-only test skipped on this macOS host). Timing budgets, retry counts, signal authority, and cancellation paths are unchanged. ### Analysis or suspected cause Source-confirmed: four waits in `src/process/ProcessOwnership.ts` and the quiet-window wait in `src/process/capture/ProcessCaptureLifecycle.ts` use global `setTimeout`. The capture module already uses the native promise timer in its other finalization waits. The owning boundary should use that scheduler consistently; consumers should not repair timer exceptions downstream. Node 24's built-in timer implementation was inspected in addition to Context7/DeepWiki navigation; no immunity to arbitrary mutation of built-in modules or all fake-clock APIs is claimed.
bsakaguchi 2026-10-31 00:37:57 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

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

Fixed on main in 5199c672f. Process ownership and journal-finalization waits now use the native promise timer rather than replaceable application setTimeout. Retry budgets, cancellation behavior, and fail-closed ownership classification remain intact.

The three new regressions failed against the previous implementation. Validation: 93 source tests passed with one skip, 94 focused public CLI/MCP/process tests passed, and npm run check passed. This verifies replacement of global setTimeout, not every fake-clock configuration or every platform. Adopted the timer correction from @gensokyo-dev's #5249 with coauthor credit; that PR remains open because it contains distinct trace-policy work. Full current-main CI is still running.

<!-- gh-comment-id:6272532034 --> @morluto commented on GitHub (Oct 19, 2026): Fixed on main in 5199c672f. Process ownership and journal-finalization waits now use the native promise timer rather than replaceable application `setTimeout`. Retry budgets, cancellation behavior, and fail-closed ownership classification remain intact. The three new regressions failed against the previous implementation. Validation: 93 source tests passed with one skip, 94 focused public CLI/MCP/process tests passed, and `npm run check` passed. This verifies replacement of global `setTimeout`, not every fake-clock configuration or every platform. Adopted the timer correction from @gensokyo-dev's #5249 with coauthor credit; that PR remains open because it contains distinct trace-policy work. Full current-main CI is still running.
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#3215
No description provided.