[PR #1583] [MERGED] feat(process): bound a finalization interval before forced capture timeout #2988

Closed
opened 2026-10-17 21:12:35 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1583
Author: @nikolay-dementiev
Created: 10/10/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @N0zoM1z0

Base: main ← Head: feat/1253-capture-finalization-interval


📝 Commits (10+)

  • 20b7f99 test(process): expect a bounded finalization interval before forced capture timeout
  • 4c7f2ca feat(process): bound a finalization interval before forced capture timeout
  • 34bd229 docs(process): document the capture finalization interval
  • 365def2 test(process): cover idle-initiated finalization and a stable cooperative deadline
  • f518030 docs(process): state exit code and timing semantics of finalization
  • fbecb13 test(process): pin finalization evidence, output capture and cancellation reason
  • 9f2e9c6 fix(process): reject finalization evidence without a deadline exit
  • de04ad9 test(process): pin SIGKILL as the forced finalization signal
  • 000abb7 test(process): pin cancellation before any deadline with a finalization interval
  • 821d031 test(process): attribute finalization outcome to the observed exit

📊 Changes

23 files changed (+3569 additions, -74 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/references/evidence-workflows.md (+8 -0)
📝 docs/mcp-contracts.md (+3 -0)
📝 docs/process-capture.md (+94 -0)
📝 src/contracts/sessionToolContracts.ts (+1 -1)
📝 src/contracts/toolContractExamples.ts (+2 -0)
📝 src/domain/process/processCapture.ts (+147 -1)
📝 src/domain/process/processCapture.validation.test.ts (+642 -0)
📝 src/domain/process/processCaptureExample.ts (+28 -0)
📝 src/domain/process/processCaptureValidation.ts (+140 -1)
📝 src/domain/process/processScenario.test.ts (+126 -0)
📝 src/domain/process/processScenario.ts (+35 -5)
📝 src/process/ProcessOwnershipObservation.ts (+41 -6)
📝 src/process/ProcessStartIdentity.test.ts (+48 -0)
➕ src/process/capture/ProcessCaptureLifecycle.test.ts (+548 -0)
📝 src/process/capture/ProcessCaptureLifecycle.ts (+241 -10)
📝 src/process/capture/ProcessHarness.test.ts (+181 -1)
📝 src/process/capture/ProcessHarness.ts (+118 -1)
➕ tests/acceptance/process/processFinalization.test.ts (+560 -0)
📝 tests/boundary/process/processCaptureLifecycle.test.ts (+370 -30)
📝 tests/boundary/process/processFilesystemCoverageAdapters.test.ts (+22 -0)

...and 3 more files

📄 Description

A capture deadline previously killed the target before its SIGTERM handler could write a final report. This extends the existing CLI/MCP process-capture scenario with optional finalization_ms (default 0): send SIGTERM to the captured root, continue collecting observations, then attempt SIGKILL once if the requested interval expires.

Fixes #1253. Supports the usability work in #1065.

The initiating timeout or idle timeout remains exit.reason, and deadline exits retain exit.code: null. Optional exit.finalization records the requested and observed interval, the actual finalizer exit code (or null), and each signal attempt with its delivery result and any unavailable reason. Incomplete captures retain the same finalization facts. A zero interval preserves existing scenario commitments; the combined timeout, finalization and settlement budget must be a safe integer.

For example, add "finalization_ms": 1500 to an existing capture scenario. A cooperative target can then return:

{
  "code": null,
  "signal": 0,
  "reason": "timeout",
  "finalization": {
    "requested_ms": 1500,
    "elapsed_ms": 12,
    "exit_code": 0,
    "signals": [
      { "signal": "SIGTERM", "sent_at_ms": 0, "delivery": "signaled" }
    ]
  }
}

The first retained root identity is bound to the captured run token between two OS identity observations. Finalization signals recheck that identity; unavailable ownership or identity is reported without a bare-PID fallback. Identity inspection and signaling remain separate OS operations. Cancellation during finalization stops it immediately. Only the root receives finalization signals; owned descendant cleanup follows, and cleanup uncertainty preserves collected facts.

The contributor's implementation and commits are preserved. Maintenance follow-ups bind the initial identity to captured ownership, validate complete observations inside cleanup-partial envelopes, and cover a detached descendant that survives root finalization before owned cleanup. The shared acceptance client still validates the full advertised schema dialect and uses the normal SDK call path, while compiling its additional validators only for tools it calls. This removes duplicated cold test-client work; it does not resolve upstream SDK #2997.

Integrated frozen main 29cc1b87 after #1664 fixed the source-qualified Electron API fixtures and the resulting merge conflicts. The three fixtures use main's implementation, preserving the contributor history and keeping them out of this PR's final diff.

Validation:

  • Contributor-reported macOS coverage and independent Linux baseline results are recorded in the review comments.
  • Independent integrated Linux checks: npm run check:fast, npm run build:cached, and npm run docs:check passed. Final head e980e6b0 passed all 250 cases in 13 focused files, covering the process/schema cases, real compiled finalization workflows, and adjacent Electron CLI/MCP workflows. npm run verify:test-discovery previously found all 796 test files exactly once; no test files were added or removed afterward.
  • Real compiled CLI/MCP workflows exercise cooperative and nonzero finalizer exits, forced escalation, cancellation, default commitments, invalid budgets, file-hash omissions, and detached owned cleanup.
  • Three representative OS-observation regressions demonstrate the initial binding gap and pass with the follow-up. They do not manufacture real OS PID reuse or signal foreign processes.

Windows capture remains unsupported and is rejected before PTY launch. No Hopper/Ghidra verification applies. Signal-attempt evidence does not establish which concurrent action caused an exit, and PTY exit notification can arrive after the OS exit. The requested interval is not an end-to-end wall-clock bound over snapshots and cleanup. No package release was performed.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1583 **Author:** [@nikolay-dementiev](https://github.com/nikolay-dementiev) **Created:** 10/10/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `feat/1253-capture-finalization-interval` --- ### 📝 Commits (10+) - [`20b7f99`](https://github.com/morluto/rea/commit/20b7f99016ced5ae68eb6c4a0ed2487076c2a663) test(process): expect a bounded finalization interval before forced capture timeout - [`4c7f2ca`](https://github.com/morluto/rea/commit/4c7f2ca8874511d4793a0df4fbe8d45fd88f521c) feat(process): bound a finalization interval before forced capture timeout - [`34bd229`](https://github.com/morluto/rea/commit/34bd229cf817dc10c48b52d21641308905c65cf5) docs(process): document the capture finalization interval - [`365def2`](https://github.com/morluto/rea/commit/365def2798df42c477d3a92ea6c2b33eaf85843e) test(process): cover idle-initiated finalization and a stable cooperative deadline - [`f518030`](https://github.com/morluto/rea/commit/f518030f4cb62ef1c68ee1c02ffdaa066d10f349) docs(process): state exit code and timing semantics of finalization - [`fbecb13`](https://github.com/morluto/rea/commit/fbecb1314e361a2d3e88da7b6703f74dccd15f78) test(process): pin finalization evidence, output capture and cancellation reason - [`9f2e9c6`](https://github.com/morluto/rea/commit/9f2e9c68ec8cc3abc3f97ca7bc29cafb215da344) fix(process): reject finalization evidence without a deadline exit - [`de04ad9`](https://github.com/morluto/rea/commit/de04ad9f69c43f04e7523cb821544219d366a516) test(process): pin SIGKILL as the forced finalization signal - [`000abb7`](https://github.com/morluto/rea/commit/000abb78bd9cf13b8fbf989e0f7722bc7495de8b) test(process): pin cancellation before any deadline with a finalization interval - [`821d031`](https://github.com/morluto/rea/commit/821d031e37510c0469af6fbcdea42fc0c87e47c0) test(process): attribute finalization outcome to the observed exit ### 📊 Changes **23 files changed** (+3569 additions, -74 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/references/evidence-workflows.md` (+8 -0) 📝 `docs/mcp-contracts.md` (+3 -0) 📝 `docs/process-capture.md` (+94 -0) 📝 `src/contracts/sessionToolContracts.ts` (+1 -1) 📝 `src/contracts/toolContractExamples.ts` (+2 -0) 📝 `src/domain/process/processCapture.ts` (+147 -1) 📝 `src/domain/process/processCapture.validation.test.ts` (+642 -0) 📝 `src/domain/process/processCaptureExample.ts` (+28 -0) 📝 `src/domain/process/processCaptureValidation.ts` (+140 -1) 📝 `src/domain/process/processScenario.test.ts` (+126 -0) 📝 `src/domain/process/processScenario.ts` (+35 -5) 📝 `src/process/ProcessOwnershipObservation.ts` (+41 -6) 📝 `src/process/ProcessStartIdentity.test.ts` (+48 -0) ➕ `src/process/capture/ProcessCaptureLifecycle.test.ts` (+548 -0) 📝 `src/process/capture/ProcessCaptureLifecycle.ts` (+241 -10) 📝 `src/process/capture/ProcessHarness.test.ts` (+181 -1) 📝 `src/process/capture/ProcessHarness.ts` (+118 -1) ➕ `tests/acceptance/process/processFinalization.test.ts` (+560 -0) 📝 `tests/boundary/process/processCaptureLifecycle.test.ts` (+370 -30) 📝 `tests/boundary/process/processFilesystemCoverageAdapters.test.ts` (+22 -0) _...and 3 more files_ </details> ### 📄 Description A capture deadline previously killed the target before its SIGTERM handler could write a final report. This extends the existing CLI/MCP process-capture scenario with optional `finalization_ms` (default `0`): send SIGTERM to the captured root, continue collecting observations, then attempt SIGKILL once if the requested interval expires. Fixes #1253. Supports the usability work in #1065. The initiating timeout or idle timeout remains `exit.reason`, and deadline exits retain `exit.code: null`. Optional `exit.finalization` records the requested and observed interval, the actual finalizer exit code (or null), and each signal attempt with its delivery result and any unavailable reason. Incomplete captures retain the same finalization facts. A zero interval preserves existing scenario commitments; the combined timeout, finalization and settlement budget must be a safe integer. For example, add `"finalization_ms": 1500` to an existing capture scenario. A cooperative target can then return: ```json { "code": null, "signal": 0, "reason": "timeout", "finalization": { "requested_ms": 1500, "elapsed_ms": 12, "exit_code": 0, "signals": [ { "signal": "SIGTERM", "sent_at_ms": 0, "delivery": "signaled" } ] } } ``` The first retained root identity is bound to the captured run token between two OS identity observations. Finalization signals recheck that identity; unavailable ownership or identity is reported without a bare-PID fallback. Identity inspection and signaling remain separate OS operations. Cancellation during finalization stops it immediately. Only the root receives finalization signals; owned descendant cleanup follows, and cleanup uncertainty preserves collected facts. The contributor's implementation and commits are preserved. Maintenance follow-ups bind the initial identity to captured ownership, validate complete observations inside cleanup-partial envelopes, and cover a detached descendant that survives root finalization before owned cleanup. The shared acceptance client still validates the full advertised schema dialect and uses the normal SDK call path, while compiling its additional validators only for tools it calls. This removes duplicated cold test-client work; it does not resolve [upstream SDK #2997](https://github.com/modelcontextprotocol/typescript-sdk/issues/2997). Integrated frozen main `29cc1b87` after #1664 fixed the source-qualified Electron API fixtures and the resulting merge conflicts. The three fixtures use main's implementation, preserving the contributor history and keeping them out of this PR's final diff. Validation: - Contributor-reported macOS coverage and independent Linux baseline results are recorded in the review comments. - Independent integrated Linux checks: `npm run check:fast`, `npm run build:cached`, and `npm run docs:check` passed. Final head `e980e6b0` passed all 250 cases in 13 focused files, covering the process/schema cases, real compiled finalization workflows, and adjacent Electron CLI/MCP workflows. `npm run verify:test-discovery` previously found all 796 test files exactly once; no test files were added or removed afterward. - Real compiled CLI/MCP workflows exercise cooperative and nonzero finalizer exits, forced escalation, cancellation, default commitments, invalid budgets, file-hash omissions, and detached owned cleanup. - Three representative OS-observation regressions demonstrate the initial binding gap and pass with the follow-up. They do not manufacture real OS PID reuse or signal foreign processes. Windows capture remains unsupported and is rejected before PTY launch. No Hopper/Ghidra verification applies. Signal-attempt evidence does not establish which concurrent action caused an exit, and PTY exit notification can arrive after the OS exit. The requested interval is not an end-to-end wall-clock bound over snapshots and cleanup. No package release was performed. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:12:35 +00:00
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#2988
No description provided.