fix(builder): scope stale process cleanup to the work folder #2250
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2250
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/build-cleanup-scope"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Starting a Windows build could stop Python or compiler processes belonging to another work folder. Cleanup now requires positive work-folder or output ownership and preserves processes whose ownership cannot be established. Fixes #2142.
Technical changes
taskkill /T; report successful stops only and retain best-effort cleanup.Validation
Current tested head
40321e87, rebased onto main355453de. Default-work cleanup now recognizes previous packaged Builder versions under the same home, including their proven build child. Other homes, sibling prefixes, unexpected layouts and custom-work mismatches remain excluded. Eleven tests pass on Windows and Linux, including 500 quoted-argument controls; the previous production source fails the two new cross-version/query-diagnostic regressions on both systems. All process queries and termination calls are intercepted. No real process was stopped. Fresh hosted checks are separate exact-head evidence.Earlier validation evidence and limits
Earlier tested head
e14e3a8c, rebased onto main6df80a8d. The selector, test and documentation patch is unchanged by range-diff; the worklist conflict preserves both main's existing row and this PR's row. Ten focused tests pass on Windows and Linux, including 500 deterministic quoted-argument round trips. All process queries and termination calls are intercepted; no real process was stopped. Fresh CI checks run on this head.At
6a3af365on baseebbba2ea, the unmodified helper selected unrelated synthetic processes as well as the intended control. Four causal mutations removing work ownership, path boundaries, ancestor protection or individual termination were rejected. Full Windows: 342 passed / 3 failed / 30 skipped, versus exact base 341 / 3 / 30, with the same failure names. Full Linux: 352 / 0 / 23; a separate release-script run with jq supplied its missing internal coverage (24 cases passed). These full/causal results refer to that earlier head, not the current rebase.This is a synthetic selector regression, not a real termination or PID-reuse guarantee. Unknown orphan build.py processes and outputs known only through relative paths or response files remain untouched. Linux cleanup behavior is unchanged; gameplay does not exercise this Windows process selector.
Dev-work claim. Coordination with #2324 and #2373 preserves this engine fix independently of retained-lift and launcher UI changes.
This is a real safety fix, and the selector reads carefully. The new rules are sound: ownership has to be positive, paths are compared at component boundaries, the ancestor chain is walked across non-Python launchers now that the query lists every process, and
taskkillno longer uses/T. I traced the rules against howmake_game.pyactually launches its steps.lift.pygets an absolute--work, so it's still matched.build.pyis matched asnx2/build.py --standaloneunder a proven parent. Its compilers write absolute-opaths underOOT_WORK(nx2/kit.py:20), so the clang/lld rule matches them.PY's-X utf8is handled by_cleanup_python. CI is green.should fix — after a builder update, the earlier build on the default work folder survives (
nx2/make_game.py:897-900): with no--work, amake_game.pyis owned only when its script path equals this__file__. But the packaged builder runsmake_game.pyfrom its own version folder:Runner.cs:133usestools.Root, which is%LOCALAPPDATA%\HookshotBuilder\versions\<version>\HookshotBuilder\tools. Meanwhile the default work folder (%LOCALAPPDATA%\HookshotBuilder, line 1567) is shared by every version, and the builder only passes--workwhen the player chose a folder (MainWindow.xaml.cs:891). So if a build is still running from version N (the builder crashed, or was killed by an update) and version N+1 starts a build:make_game.pyisn't recognized, so it's preserved;build.pychild isn't selected either, becauseownedonly holds processes that are already doomed;build.pykeeps starting new ones in the samework\sa\build.That's the "replaced by an update mid-build" case the old docstring named for #501/#530. A normal Cancel or Close still kills the whole tree (
Runner.CancelusesKill(entireProcessTree: true)), so this is limited to crashes and killed builders. Still, it's the case this function exists for. Two possible fixes:make_game.pywhose absolute path matches<LOCALAPPDATA>\HookshotBuilder\versions\*\HookshotBuilder\tools\nx2\make_game.py, i.e. any version of this builder, not only this one; or--work Storage.Work, so ownership is always explicit.Either way, please add a test row for "earlier version's make_game, default work".
minor — worklist row in the wrong table (
docs/worklist.md:27): the row goes into Open, butdocs/worklist.md:15says a row moves to Fixed, waiting for a release when its PR merges. Since this PR is the fix, put the row there with this PR's link, or leave it out.minor — silent return on a failed query (
nx2/make_game.py:943-944):if r.returncode: returnskips cleanup without a word. Before this change, a failed query reached theexceptand printed "could not look for an earlier build's processes". A one-line message here would keep that diagnostic for build-problem reports.question:
docs/build-cleanup-scope.mdis a whole page for one helper, and the docstring it replaces lost the symptoms (OSError: [Errno 22]ona64_fpx.h, WinError 1224). Would a few lines of that in the docstring serve the next reader better than a separate page? Not blocking.Thanks, the cross-version case was missing. Fixed in
40321e87on main355453de: default-work ownership accepts the exact packagedversions/<version>/HookshotBuilder/tools/nx2/make_game.pyshape under that same home, then follows only its proven build child. Other homes, sibling prefixes, extra path components and custom-work mismatches stay excluded.Eleven intercepted-process tests pass on Windows and Linux; the previous source fails the new cross-version and failed-query diagnostic cases. I restored the query diagnostic and original lock symptoms in the docstring, and removed the worklist row as suggested. Fresh CI is running.
The cross-version case is fixed: only
<home>\versions\<v>\HookshotBuilder\tools\nx2\make_game.pyunder the same home is accepted, and only a provenbuild.pychild is followed. All 11 tests pass.Trade-off to note: an orphaned
build.pywhosemake_gameis gone is now left running (make_game.py:904,:974). Its compilers still get stopped by their-opath, but it can start new ones. The process query also lists every process now, which is slower but stays inside the 90 s timeout.github-sync referenced this pull request2026-11-12 06:22:54 +00:00