fix(windows): spawn the deferred update helper with a console it never shows - #572
Merged
Conversation
…r shows The deferred Windows self-update has never applied since it landed in 0.78.0. `kbagent update` reports `(scheduled)`, the marker is written, and nothing else happens -- no exit file, no install log, no version change. `DETACHED_PROCESS` gives the child no console at all, and `powershell.exe` is a console application whose host cannot start without one: it exits 0 in under a second having executed nothing. A zero exit code with no output is the worst shape this failure can take -- `Popen` returns a live-looking handle, so the single-flight guard then suppresses every retry for the full 24-hour staleness window while each launch keeps promising an update that cannot happen. It fails safe, unlike the original #528, which is why it went unnoticed for three releases. A/B on one Windows 11 box, back to back, fresh install of the same wheel per trial, only this flag changed: DETACHED_PROCESS 0/3 updated, no exit file, and the helper never appears in the process list across 46 s of 1.5 s sampling (instrument validated against a live decoy first) CREATE_NO_WINDOW 3/3 updated, exit file and full install log written I got this wrong twice before landing it. First I claimed the same cause from observations taken while the test laptop was suspending mid-run; then I retracted that on three successes that I now believe ran against an already-patched install. Both times I generalised one batch of runs into a mechanism instead of holding everything constant and flipping one variable. This commit is the A/B I should have run first. Two tests, both confirmed to fail with the old flag restored on real Windows: a cross-platform assertion pinning the flag choice, and a Windows-only test that performs the real spawn and asserts on the *process*. The latter matters because "never spawned" and "spawned and died instantly" leave identical evidence on disk, which is what made this take three rounds to pin down -- and is why the existing tests, which pin the script's text and mock `Popen`, could not see it. The Windows CI test ran the script through `subprocess.run`, which supplies the very console the real flags withheld. Closes #571
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #571. The deferred Windows self-update has never applied since it landed in 0.78.0 —
kbagent updatereports(scheduled), the marker is written, and then nothing: no exit file, no install log, no version change.Cause
DETACHED_PROCESSgives the child no console at all, andpowershell.exeis a console application whose host cannot start without one. It exits 0, in under a second, having executed nothing.Zero-with-no-output is the worst shape this failure can take.
Popenreturns a live-looking handle, so the single-flight guard then suppresses every retry for the full 24-hour staleness window while each launch keeps printing "Updating in the background". It fails safe — nothing is corrupted, unlike the original #528 — which is exactly why it survived three releases unnoticed.CREATE_NO_WINDOWstill creates a console, it just never shows it.A/B on a real Windows 11 box
Back to back, same machine, fresh install of the same wheel per trial, only the flag changed:
pending_update.exitDETACHED_PROCESS(shipped)CREATE_NO_WINDOW(this PR)Separately, polling the process list every 1.5 s for 46 s during a
DETACHED_PROCESSrun never sees the helper at all. I validated that instrument against a live decoy process carrying the same command-line marker before trusting the negative.I got this wrong twice first, and it is worth saying why
Both times I generalised one batch of runs into a mechanism instead of holding everything constant and flipping a single variable. The table above is the experiment I should have run first, and it is the only evidence in this PR I would defend.
Tests
Two, both confirmed to fail with the old flag restored on real Windows:
DETACHED_PROCESScannot come back;The second asserts on the process, not on a file, deliberately. "Never spawned" and "spawned and died instantly" leave identical evidence on disk — that indistinguishability is what made this take three rounds, and it is why the existing tests could not catch it: they pin the script's text and mock
Popen, and the Windows CI test runs the script throughsubprocess.run, which supplies the very console the real flags withheld.Impact on users
Anyone on Windows between 0.78.0 and 0.80.1 is stuck and is missing every fix from 0.80.1. Telling them to run
kbagent updatedoes not help — it takes the same broken path. Recorded ingotchas.mdso agents give the reinstall instead:Local: 5411 passed. Windows: 44 passed in
test_update_runner.py, 2 of them failing on demand when the bug is restored.