HarperFast / HarperFast/harper
Use a Windows Job Object for spawned process-tree lifetime instead of reconstructing identity from Win32_Process creation times
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
`server/threads/windowsProcessTree.ts` identifies a spawned process tree by reconstructing it from `Win32_Process` creation times: the root by `(PID, creation time)` bounded by the interval measured around `spawn()`, descendants by parentage plus their own creation times, with a 50 ms allowance on the one cross-clock bound. That is ~360 lines of bounds reasoning standing in for an identity the OS can give us directly.
A **Job Object** assigned at process creation and retained by handle makes the tree an OS-level set: `TerminateJobObject` kills exactly the members, and PID reuse stops being part of the problem at all.
### What it would close
Each of these is individually bounded by a heuristic today, and each was found only after the previous one was fixed — which is the argument for replacing the mechanism rather than adding another bound:
- **Ancestry lost before the first snapshot.** A grandchild whose linking ancestors all exited before the first scan cannot be reached by parentage scanning. No heuristic closes this one; it is why the Job Object has been the standing alternative since round 7 of #2470.
- **Scan-to-kill PID reuse.** A member selected by `(PID, creation time)` can exit and have its PID recycled between the scan and the `taskkill`, which names PIDs only.
- **A root PID held by a process with no `CreationDate`.** WMI reports none for some protected processes, so the root's identity never resolves and the confirmation never returns.
- **Recycled process-group ids across threads.** Fixed in #2470 by stamping each group with its owner, but the fix took three rounds — ownership on clear, then ownership on the *stamp* rather than membership, then ownership before the kill and not only before the wait. It also left a trade: filtering a recycled id out of the old owner's sweep abandons that owner's wait for it, where harper#2076's recorded policy prefers a wedged deployment over releasing on an unconfirmed tree. A Job Object dissolves the trade instead of choosing a side.
### Cost
A native dependency (native code or `ffi`), which needs `dependencies.md` justification and review. It also obsoletes `windowsProcessTree.ts` rather than extending it, so it is a replacement, not an increment.
### Related
- harper#2076 — the deadline-free confirmation wait. The Job Object makes the wait unnecessary rather than bounding it.
- harper#2273 — the unrelated-process kill this module exists to prevent; every item above is a path back to it.
### Provenance
Named as the better framing for the Windows half by the `--mode plan` recheck on [Stop a recycled Windows PID from wedging deploy_component and release dropped databases on every thread](https://github.com/HarperFast/harper/pull/2470), twice. @kriszyp ruled it into its own issue rather than into that PR.
Contributor guide
Research direction
Start by reading server/threads/windowsProcessTree.ts and tracing the spawn() path, then review dependencies.md for the required native-dependency justification. The replacement is done when process creation assigns and retains a Windows Job Object, termination targets its members directly, and the existing creation-time and PID-reuse heuristics are no longer needed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- operating-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100