[PR #5270] [MERGED] fix(process): retain unresolved descendants during lineage observation #6850

Closed
opened 2026-11-01 21:43:31 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5270
Author: @kwakhyun
Created: 10/19/2026
Status: ✅ Merged
Merged: 10/22/2026
Merged by: @morluto

Base: main ← Head: codex/fix-lineage-descendant-evidence


📝 Commits (8)

  • 7f32f28 fix(process): retain unresolved descendants during lineage observation
  • f9a8894 fix(process): preserve lineage across ancestor generation changes
  • 831201f Merge remote-tracking branch 'origin/main' into codex/fix-lineage-descendant-evidence
  • 15196f5 Merge remote-tracking branch 'origin/main' into codex/fix-lineage-descendant-evidence
  • ed450ca fix(process): avoid retaining replacements of exited candidates
  • ff9cba6 test(cli): avoid unused cache writes in module trace acceptance
  • 452b92d fix(process): retire replaced lineage candidates
  • b48da93 fix(process): preserve uncertain owners and validate launcher scope

📊 Changes

7 files changed (+1645 additions, -58 deletions)

View changed files

📝 src/process/ProcessOwnership.identity.test.ts (+92 -0)
➕ src/process/ProcessOwnership.lineage.test.ts (+1073 -0)
📝 src/process/ProcessOwnershipEvidence.ts (+81 -26)
📝 src/process/ProcessOwnershipFacts.test.ts (+170 -4)
📝 src/process/ProcessOwnershipObservation.ts (+64 -27)
📝 tests/acceptance/webModuleCli.test.ts (+5 -1)
➕ tests/boundary/process/processLineageRetention.test.ts (+160 -0)

📄 Description

Summary

Native lineage observation can lose an already observed descendant when its first identity or relation is unavailable, or when an intermediate ancestor exits. A later process-table omission can then report cleaned: true while that descendant remains alive.

Retain unresolved descendants as explicit uncertainty, settle native-confirmed exits, and distinguish possible run ownership from a disproven launcher relation. Current native identity, run-token, and process-group checks remain required before signaling. Related to #5206; this does not close its broader containment and platform qualification gaps.

Changes

  • Keep incomplete ancestry as discovery scope and retain partial ownership evidence even when a complete lineage cannot be published. Same-generation native relations take precedence over stale table rows; a replacement ancestor cannot erase a surviving descendant's earlier scope.
  • Use the shared native exit predicate: absent, zombie, and dead settle candidates, including previously unresolved candidates that reparented outside the lineage. Exited rows remain ancestry bridges; exiting, unreadable state, and table omission do not prove exit.
  • Address Greptile P1: a replacement with a raw matching token remains identity-unresolved across omission. Retire the prior generation's authority and require fresh same-generation identity/token proof before signaling. Foreign replacements and native-confirmed exits still retire.
  • Address Codex P2: validate the initial native launcher before granting capture scope. A readable parent/group/command mismatch disables captured PID/group anchors while preserving independent token-owned ancestry and existing candidates. Later movement of the same initially valid generation preserves its earlier scope.

The evidence owner applies these rules centrally; cleanup and final verification consume its retained facts. CLI/MCP schemas and installation are unchanged. The identityless custom-host path and Windows native cleanup are outside the lineage fix.

Validation of b48da93

macOS 26.6.2 ARM64, Node 24.18.0, npm 11.16.0; one worker, no file parallelism, normal host permissions:

  • Against a detached, unmodified production checkout of 452b92d, the three updated regression files produce 17 failures, 77 passes, 1 Linux-only skip: four P1 failures (including a false-success cleanup retry) and thirteen P2 failures.
  • With the fix, the exact 26-file selection below passes 307 tests, with 2 Linux-only skips (25 files passed, 1 skipped). This includes all 50 lineage cases, 21 fact-owner cases, 24 capture-lifecycle cases, and all 12 compiled CLI/MCP finalization cases. Existing PID reuse, unknown identity, exited-ancestor, reparenting, cancellation, mixed-child and cleanup-retry controls pass. No assertions or deadlines were relaxed.
  • The real native macOS regression passes with an inherited pipe keeping a detached child alive after launcher exit, native identity/token reads and actual owned group cleanup. Only the first child identity denial and later table omission are injected. The new PID-reuse races use controlled hosts, not naturally occurring kernel PID reuse.
  • Build and npm run check passed: 6/6 tasks and architecture guards; lint 0 errors, 1,763 warnings. git diff --check passed. No test paths were added or renamed.
  • The previously reported local SIGTERM-marker timeout also occurred on unmodified ff9cba6. That cancellation case passes in this run with unchanged assertions and deadlines; its historical cause remains unestablished.

The upstream CI for b48da93 and Greptile review are running. The automatic Codex re-review stopped at the repository code-review usage limit; no new Codex validation is claimed. Linux/Windows CI for this new commit is separate from the local results above. No real Hopper/Ghidra provider verification, atomic containment guarantee, or coverage of never-observed descendants is claimed. Electron checks use authored fixtures.

Exact regression selection
npm run build:cached
node scripts/run-exact-tests.mjs run \
  src/process/ProcessOwnership.lineage.test.ts \
  src/process/ProcessOwnershipFacts.test.ts \
  src/process/ProcessOwnership.identity.test.ts \
  src/process/ProcessOwnership.finalSweep.test.ts \
  src/process/ProcessOwnership.test.ts \
  src/process/ProcessOwnership.part2.test.ts \
  src/process/ProcessOwnership.part3.test.ts \
  src/process/ProcessOwnership.observation.test.ts \
  src/process/ProcessOwnership.validation.test.ts \
  src/process/ProcessOwnership.nativeExit.test.ts \
  src/process/ProcessOwnership.sweepExit.test.ts \
  src/process/ProcessOwnership.exiting.test.ts \
  src/process/ProcessOwnership.procIdentity.test.ts \
  src/process/ProcessOwnership.runId.test.ts \
  src/process/capture/ProcessCaptureOwnershipEvidence.test.ts \
  src/process/LinuxProcessStat.test.ts \
  src/browser/ElectronProcessCleanup.test.ts \
  src/browser/ElectronCaptureCleanup.test.ts \
  src/browser/ElectronCaptureCleanup.boundary.test.ts \
  tests/boundary/process/providerProcess.test.ts \
  tests/boundary/process/processCleanupRetryOwnership.test.ts \
  tests/boundary/process/processLineageRetention.test.ts \
  tests/boundary/process/processBaselineAbsence.test.ts \
  tests/boundary/process/processCaptureLifecycle.test.ts \
  tests/boundary/mcp/processCleanupRetryMcp.test.ts \
  tests/acceptance/process/processFinalization.test.ts \
  --maxWorkers=1 --no-file-parallelism

Windows test mitigation already on this branch

ff9cba6 disables the optional Node compile cache for one CLI invocation in webModuleCli.test.ts, which cannot reuse that cache. The original 15-second deadline and CLI/MCP assertions remain unchanged. The original timeout was not reproduced and its cause remains unknown.

A controlled base/PR cache comparison measured unused shutdown I/O: PR invocations took 2.49–2.87 s with fresh caches versus 1.44–1.59 s with cache generation disabled; the base showed the same behavior. This does not prove cache writes caused the historical timeout. Windows validation of the committed mitigation passed 5/5 focused tests and the 516-test curated selection with 31 existing skips. Full upstream CI on the previous head 452b92d, including Windows, passed. Those results do not establish CI success for the new follow-up.

Readiness

The initial human declarations below remain valid across follow-up pushes under this repository's contribution policy. The earlier fork-association blocker has cleared. Readiness for the current b48da93 head is success: the human owner and all three initial declarations are filled. No status override or readiness bypass was applied.

Author readiness

Human owner: @kwakhyun

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

AI-assisted implementation and verification. On 2026-10-20 (KST), @kwakhyun explicitly confirmed reviewing the final diff and validation evidence, understanding the change and its validation limits, taking responsibility for the PR, and authorizing the initial review request. These declarations are recorded at the human owner’s direction.


🔄 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/5270 **Author:** [@kwakhyun](https://github.com/kwakhyun) **Created:** 10/19/2026 **Status:** ✅ Merged **Merged:** 10/22/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `codex/fix-lineage-descendant-evidence` --- ### 📝 Commits (8) - [`7f32f28`](https://github.com/morluto/rea/commit/7f32f288ad1b32c70293b56e72be0242b4ffac45) fix(process): retain unresolved descendants during lineage observation - [`f9a8894`](https://github.com/morluto/rea/commit/f9a8894bee4c75d4eb5e504f0c7b8794c324facd) fix(process): preserve lineage across ancestor generation changes - [`831201f`](https://github.com/morluto/rea/commit/831201f15a137140ad039df678f4f10a3b040474) Merge remote-tracking branch 'origin/main' into codex/fix-lineage-descendant-evidence - [`15196f5`](https://github.com/morluto/rea/commit/15196f56fb2e8b70c2cb9f401f6dfc3cabd95ee9) Merge remote-tracking branch 'origin/main' into codex/fix-lineage-descendant-evidence - [`ed450ca`](https://github.com/morluto/rea/commit/ed450cafb43d87475bc9a072b85c1086b65c2b4d) fix(process): avoid retaining replacements of exited candidates - [`ff9cba6`](https://github.com/morluto/rea/commit/ff9cba6fe7ae048bfe800eb23caa6d6f0b395df0) test(cli): avoid unused cache writes in module trace acceptance - [`452b92d`](https://github.com/morluto/rea/commit/452b92d769102c0758434cbc31e564799302fa1a) fix(process): retire replaced lineage candidates - [`b48da93`](https://github.com/morluto/rea/commit/b48da932faf32228ebd2a7201fc9d697ba27b49d) fix(process): preserve uncertain owners and validate launcher scope ### 📊 Changes **7 files changed** (+1645 additions, -58 deletions) <details> <summary>View changed files</summary> 📝 `src/process/ProcessOwnership.identity.test.ts` (+92 -0) ➕ `src/process/ProcessOwnership.lineage.test.ts` (+1073 -0) 📝 `src/process/ProcessOwnershipEvidence.ts` (+81 -26) 📝 `src/process/ProcessOwnershipFacts.test.ts` (+170 -4) 📝 `src/process/ProcessOwnershipObservation.ts` (+64 -27) 📝 `tests/acceptance/webModuleCli.test.ts` (+5 -1) ➕ `tests/boundary/process/processLineageRetention.test.ts` (+160 -0) </details> ### 📄 Description ## Summary Native lineage observation can lose an already observed descendant when its first identity or relation is unavailable, or when an intermediate ancestor exits. A later process-table omission can then report `cleaned: true` while that descendant remains alive. Retain unresolved descendants as explicit uncertainty, settle native-confirmed exits, and distinguish possible run ownership from a disproven launcher relation. Current native identity, run-token, and process-group checks remain required before signaling. Related to #5206; this does not close its broader containment and platform qualification gaps. ## Changes - Keep incomplete ancestry as discovery scope and retain partial ownership evidence even when a complete lineage cannot be published. Same-generation native relations take precedence over stale table rows; a replacement ancestor cannot erase a surviving descendant's earlier scope. - Use the shared native exit predicate: absent, zombie, and dead settle candidates, including previously unresolved candidates that reparented outside the lineage. Exited rows remain ancestry bridges; exiting, unreadable state, and table omission do not prove exit. - Address [Greptile P1](https://github.com/morluto/rea/pull/5270#discussion_r4318421251): a replacement with a raw matching token remains `identity-unresolved` across omission. Retire the prior generation's authority and require fresh same-generation identity/token proof before signaling. Foreign replacements and native-confirmed exits still retire. - Address [Codex P2](https://github.com/morluto/rea/pull/5270#discussion_r4318464523): validate the initial native launcher before granting capture scope. A readable parent/group/command mismatch disables captured PID/group anchors while preserving independent token-owned ancestry and existing candidates. Later movement of the same initially valid generation preserves its earlier scope. The evidence owner applies these rules centrally; cleanup and final verification consume its retained facts. CLI/MCP schemas and installation are unchanged. The identityless custom-host path and Windows native cleanup are outside the lineage fix. ## Validation of `b48da93` macOS 26.6.2 ARM64, Node 24.18.0, npm 11.16.0; one worker, no file parallelism, normal host permissions: - Against a detached, unmodified production checkout of `452b92d`, the three updated regression files produce **17 failures, 77 passes, 1 Linux-only skip**: four P1 failures (including a false-success cleanup retry) and thirteen P2 failures. - With the fix, the exact 26-file selection below passes **307 tests, with 2 Linux-only skips** (25 files passed, 1 skipped). This includes all 50 lineage cases, 21 fact-owner cases, 24 capture-lifecycle cases, and all 12 compiled CLI/MCP finalization cases. Existing PID reuse, unknown identity, exited-ancestor, reparenting, cancellation, mixed-child and cleanup-retry controls pass. No assertions or deadlines were relaxed. - The real native macOS regression passes with an inherited pipe keeping a detached child alive after launcher exit, native identity/token reads and actual owned group cleanup. Only the first child identity denial and later table omission are injected. The new PID-reuse races use controlled hosts, not naturally occurring kernel PID reuse. - Build and `npm run check` passed: **6/6 tasks and architecture guards; lint 0 errors, 1,763 warnings**. `git diff --check` passed. No test paths were added or renamed. - The previously reported local SIGTERM-marker timeout also occurred on unmodified `ff9cba6`. That cancellation case passes in this run with unchanged assertions and deadlines; its historical cause remains unestablished. The [upstream CI for `b48da93`](https://github.com/morluto/rea/actions/runs/39355637034) and Greptile review are running. The automatic Codex re-review [stopped at the repository code-review usage limit](https://github.com/morluto/rea/pull/5270#issuecomment-6281447872); no new Codex validation is claimed. Linux/Windows CI for this new commit is separate from the local results above. No real Hopper/Ghidra provider verification, atomic containment guarantee, or coverage of never-observed descendants is claimed. Electron checks use authored fixtures. <details> <summary>Exact regression selection</summary> ```sh npm run build:cached node scripts/run-exact-tests.mjs run \ src/process/ProcessOwnership.lineage.test.ts \ src/process/ProcessOwnershipFacts.test.ts \ src/process/ProcessOwnership.identity.test.ts \ src/process/ProcessOwnership.finalSweep.test.ts \ src/process/ProcessOwnership.test.ts \ src/process/ProcessOwnership.part2.test.ts \ src/process/ProcessOwnership.part3.test.ts \ src/process/ProcessOwnership.observation.test.ts \ src/process/ProcessOwnership.validation.test.ts \ src/process/ProcessOwnership.nativeExit.test.ts \ src/process/ProcessOwnership.sweepExit.test.ts \ src/process/ProcessOwnership.exiting.test.ts \ src/process/ProcessOwnership.procIdentity.test.ts \ src/process/ProcessOwnership.runId.test.ts \ src/process/capture/ProcessCaptureOwnershipEvidence.test.ts \ src/process/LinuxProcessStat.test.ts \ src/browser/ElectronProcessCleanup.test.ts \ src/browser/ElectronCaptureCleanup.test.ts \ src/browser/ElectronCaptureCleanup.boundary.test.ts \ tests/boundary/process/providerProcess.test.ts \ tests/boundary/process/processCleanupRetryOwnership.test.ts \ tests/boundary/process/processLineageRetention.test.ts \ tests/boundary/process/processBaselineAbsence.test.ts \ tests/boundary/process/processCaptureLifecycle.test.ts \ tests/boundary/mcp/processCleanupRetryMcp.test.ts \ tests/acceptance/process/processFinalization.test.ts \ --maxWorkers=1 --no-file-parallelism ``` </details> ## Windows test mitigation already on this branch `ff9cba6` disables the optional Node compile cache for one CLI invocation in `webModuleCli.test.ts`, which cannot reuse that cache. The original 15-second deadline and CLI/MCP assertions remain unchanged. The original timeout was not reproduced and its cause remains unknown. A [controlled base/PR cache comparison](https://github.com/kwakhyun/rea/actions/runs/39306912908) measured unused shutdown I/O: PR invocations took 2.49–2.87 s with fresh caches versus 1.44–1.59 s with cache generation disabled; the base showed the same behavior. This does not prove cache writes caused the historical timeout. [Windows validation of the committed mitigation](https://github.com/kwakhyun/rea/actions/runs/39307933571/job/118249732752) passed 5/5 focused tests and the 516-test curated selection with 31 existing skips. [Full upstream CI on the previous head `452b92d`](https://github.com/morluto/rea/actions/runs/39317681665), including Windows, passed. Those results do not establish CI success for the new follow-up. ## Readiness The initial human declarations below remain valid across follow-up pushes under this repository's contribution policy. The earlier fork-association blocker has cleared. [Readiness for the current `b48da93` head is success](https://github.com/morluto/rea/actions/runs/39355699879): the human owner and all three initial declarations are filled. No status override or readiness bypass was applied. ## Author readiness Human owner: @kwakhyun - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. AI-assisted implementation and verification. On 2026-10-20 (KST), @kwakhyun explicitly confirmed reviewing the final diff and validation evidence, understanding the change and its validation limits, taking responsibility for the PR, and authorizing the initial review request. These declarations are recorded at the human owner’s direction. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:43:31 +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#6850
No description provided.