Skip to content

fix(windows): spawn the deferred update helper with a console it never shows - #572

Merged
padak merged 1 commit into
mainfrom
fix/windows-deferred-update-571
Aug 11, 2026
Merged

fix(windows): spawn the deferred update helper with a console it never shows#572
padak merged 1 commit into
mainfrom
fix/windows-deferred-update-571

Conversation

@padak

@padak padak commented Aug 11, 2026

Copy link
Copy Markdown
Member

Fixes #571. The deferred Windows self-update has never applied since it landed in 0.78.0 — kbagent update reports (scheduled), the marker is written, and then nothing: no exit file, no install log, no version change.

Cause

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.

Zero-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 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_WINDOW still 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:

flag updated pending_update.exit
DETACHED_PROCESS (shipped) 0/3 never written
CREATE_NO_WINDOW (this PR) 3/3 written, with full install log

Separately, polling the process list every 1.5 s for 46 s during a DETACHED_PROCESS run 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

  1. I claimed this exact cause once before, from observations taken while the test laptop was suspending every few minutes — a machine that sleeps mid-run also produces "no exit file, no log".
  2. I then retracted it on three successful runs, which I now believe executed against an already-patched install.

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:

  • cross-platform: pins the flag choice so DETACHED_PROCESS cannot come back;
  • Windows-only: performs the real spawn and asserts the helper is still alive afterwards.

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 through subprocess.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 update does not help — it takes the same broken path. Recorded in gotchas.md so agents give the reinstall instead:

uv tool install --force --reinstall "keboola-cli @ https://github.com/keboola/cli/releases/download/v0.80.2/keboola_cli-0.80.2-py3-none-any.whl"

Local: 5411 passed. Windows: 44 passed in test_update_runner.py, 2 of them failing on demand when the bug is restored.


Open in Devin Review

…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

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@padak
padak merged commit f0d0b04 into main Aug 11, 2026
5 checks passed
@padak
padak deleted the fix/windows-deferred-update-571 branch August 11, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deferred Windows self-update is intermittent: reports (scheduled), then silently never applies

1 participant