The clean-path soak found no leak on windows-latest — because orderly close() reaps every host. That never exercises the freeze hypothesis (T-424), which is the parent dying WITHOUT teardown while a child is live. This probe does. conpty_orphan_probe.dart starts N real WindowsPty sessions on long-lived children and blocks WITHOUT ever calling close(); soak-conpty-kill.ps1 force-kills only the dart.exe parent (taskkill /F, no /T) once the hosts are up and counts the conhost/OpenConsole/cmd processes that SURVIVE. Absent a kill-on-close Job Object, abrupt parent death should orphan them — a survivor count that climbs across cycles is the leak signature. The same probe will prove the T-424 fix: with the job, survivors should drop to ~0. Wired as a second job in windows-soak.yml (workflow_dispatch + when the kit changes). Diagnostic only, never a gate, always exits 0; publishes the verdict to the job summary and uploads the CSV. Not part of the regular test suite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
windows-verify — ConPTY leak verification kit
Tooling to verify (or refute) the Windows test-freeze assessment for the
windows-support branch on a real Windows VM. See the full analysis in
docs/windows-freeze-analysis.md (or the report shared in the session).
Status: nothing here runs automatically. These scripts are inert until you invoke them.
provision-vm.shis a dry run unless you pass--go.
What this verifies — and what it can't
| Hypothesis | In scope here? | Why |
|---|---|---|
#1 orphaned conhost.exe/cmd.exe accumulation (no Job Object) |
✅ yes | soak-conpty.ps1 measures the orphan count directly — this is the headline result. |
| #2 unkillable blocked-FFI isolate threads | ✅ partial | Per-run dart.exe peak handle/thread footprint is sampled; the leak is reclaimed at process exit, so it shows as a within-run spike, not cross-run growth. |
| #3 narrow-terminal CRLF conhost spin | ⚠️ manual | Surfaces as a host that pegs a CPU core; watch Task Manager during a soak. The real fix is clamping cols/rows ≥ 2 + a unit test. |
#4 ClosePseudoConsole hang (pre-24H2) |
⚠️ partial | Run on a pre-24H2 image (build < 26100) and a 24H2+ image to see the version-gated intermittency. |
#5 GPU/display-driver TDR (0x116) — the real black-screen |
❌ no | A stock VM uses a software (WARP) adapter; make run cannot trigger a hardware TDR. Needs GPU passthrough or bare metal — see the appendix. |
The leak (#1) is the test-path explanation and the actionable one. A VM is the right instrument for it; it is the wrong instrument for #5.
On a cloud VM (GCP) — no local hypervisor
If the host has no KVM (e.g. VT-x disabled in firmware), run this on a GCP
Windows Server instance instead — real hardware acceleration, nothing installed
locally. From the GCP Cloud Shell (browser; gcloud preinstalled):
gcloud compute instances create clide-win-verify \
--zone=us-central1-a --machine-type=e2-standard-4 \
--image-family=windows-2022 --image-project=windows-cloud \
--boot-disk-size=100GB --boot-disk-type=pd-ssd
gcloud compute reset-windows-password clide-win-verify --zone=us-central1-a --user=admin
RDP to the printed IP with the printed credentials (KDE: KRDC; or
flatpak install flathub org.remmina.Remmina). Then run steps 2-3 below inside
Windows (bootstrap-windows.ps1 -SkipVS is winget-free and Server-compatible).
Stop the VM when idle, delete it when done:
gcloud compute instances stop clide-win-verify --zone=us-central1-a # idle
gcloud compute instances delete clide-win-verify --zone=us-central1-a # done
The three steps
-
Provision the VM (on the Fedora/KVM host — "danoontje"):
WIN_ISO=~/iso/Win11.iso VIRTIO_ISO=~/iso/virtio-win.iso \ tools/windows-verify/provision-vm.sh # dry run — prints the plan WIN_ISO=... VIRTIO_ISO=... tools/windows-verify/provision-vm.sh --go # executeFinish the interactive Windows install in
virt-viewer(load the virtio disk driver from the second CD during setup). -
Bootstrap the toolchain (inside Windows, elevated PowerShell). No winget dependency, so this also works on Windows Server / GCP images. For the soak,
-SkipVSinstalls only Flutter/Dart:powershell -ExecutionPolicy Bypass -File tools\windows-verify\bootstrap-windows.ps1 -SkipVSDrop
-SkipVSto also install VS 2022 Build Tools (needed only forflutter build windows+ the C CLI). Clones + checks outwindows-support. -
Run the soak (new shell, so PATH is fresh):
powershell -ExecutionPolicy Bypass -File tools\windows-verify\soak-conpty.ps1 -Iterations 40
Reading the result
soak-conpty.ps1 runs the ConPTY suite in a fresh dart.exe per
iteration and, after each one exits, counts the conhost/OpenConsole/cmd
processes that survived (baseline-subtracted). It writes a per-iteration
CSV + a summary to %LOCALAPPDATA%\clide\windows-verify\ (flushed each line,
so the data survives even if a later run wedges the box).
- Orphan count climbs and stays up (e.g. +1 per iteration, never reclaimed) → leak confirmed (#1): ConPTY hosts outlive the test process. This is the cumulative starvation that, across many runs, thrashes the session to a power-cycle.
- Orphan count hovers at ~0 → not reproduced in this config (more iterations may be needed, or the Job-Object fix is already in place).
dart_peak_handles/threadsratchet up within a run → corroborates #2 (blocked reader/waiter isolates), reclaimed whendart.exeexits.
The script never tries to crash the machine — it proves the mechanism (an unreclaimed, monotonically growing host population), which is the safe and sufficient verification.
Safety notes
- Snapshot the VM before soaking (
virsh snapshot-create-as clide-win-verify clean) so you can roll back instead of reinstalling. - If hosts strand after a run:
Get-Process conhost,OpenConsole,cmd | Stop-Process -Force. - Do this in a VM, not a machine you care about — the whole point is to provoke a resource leak.
Appendix — chasing the GPU/TDR hypothesis (#5)
A software-rendered VM can't reproduce a real display-driver TDR. To test #5
you need GPU passthrough (bind the GPU to vfio-pci, pass it with
--hostdev, install the vendor WDDM driver in the guest) or, more simply, run
make run / make run-testmode on the bare-metal Windows box that
actually froze. Then, as a diagnostic only, raise TdrDelay (or set
TdrLevel=0) under
HKLM\System\CurrentControlSet\Control\GraphicsDrivers and see whether a
previously-rebooting make run now only stutters/recovers — and read Event
Viewer for Display 4101 / BugCheck 0x116 after any freeze. Revert the
registry change afterward.