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>
102 lines
4.0 KiB
YAML
102 lines
4.0 KiB
YAML
name: windows-soak
|
|
|
|
# ConPTY orphan-leak soak on a GitHub-hosted Windows runner — the cheap
|
|
# alternative to a dedicated Windows VM. The freeze hypothesis (T-424) is that
|
|
# each WindowsPty.start() leaks its conhost/OpenConsole host because the child
|
|
# is not in a kill-on-close Job Object; across many runs those hosts pile up
|
|
# until the box starves. tools/windows-verify/soak-conpty.ps1 reproduces that
|
|
# WITHOUT crashing: it runs the ConPTY suite many times IN ONE job and counts
|
|
# the hosts that survive each dart.exe exit. A throwaway runner is fine — we
|
|
# watch the accumulation (the leading indicator), not the reboot. The repeated
|
|
# runs happen inside this single job, so the leak can build up here even though
|
|
# the runner is discarded afterwards (cf. the note in windows.yml, which only
|
|
# runs the suite once).
|
|
#
|
|
# Diagnostic, never a gate: it always exits 0 and just publishes the verdict +
|
|
# CSV. Runs on demand (workflow_dispatch) and when the soak kit itself changes.
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
iterations:
|
|
description: How many times to run the ConPTY suite (clean-path soak)
|
|
default: "25"
|
|
kill_iterations:
|
|
description: Spawn+force-kill cycles (abrupt-death orphan probe)
|
|
default: "15"
|
|
ptys_per_iter:
|
|
description: WindowsPty sessions spawned per kill cycle
|
|
default: "2"
|
|
push:
|
|
branches: [windows-support]
|
|
paths:
|
|
- tools/windows-verify/**
|
|
- .github/workflows/windows-soak.yml
|
|
|
|
jobs:
|
|
conpty-soak:
|
|
runs-on: windows-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: subosito/flutter-action@v2
|
|
with:
|
|
channel: stable
|
|
- run: flutter --version
|
|
- run: flutter pub get
|
|
- name: ConPTY orphan-leak soak
|
|
shell: pwsh
|
|
run: |
|
|
$iters = "${{ github.event.inputs.iterations }}"
|
|
if (-not $iters) { $iters = "25" }
|
|
tools/windows-verify/soak-conpty.ps1 -Iterations ([int]$iters) -OutDir "$env:GITHUB_WORKSPACE/soak-out"
|
|
- name: Publish verdict to job summary
|
|
if: always()
|
|
shell: pwsh
|
|
run: |
|
|
$s = Get-ChildItem "$env:GITHUB_WORKSPACE/soak-out/*.summary.txt" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($s) { Get-Content $s.FullName | Add-Content $env:GITHUB_STEP_SUMMARY }
|
|
- name: Upload soak CSV + summary
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: conpty-soak
|
|
path: soak-out
|
|
if-no-files-found: warn
|
|
|
|
conpty-kill-probe:
|
|
# Abrupt-death half: force-kill the parent dart.exe mid-life (no close(),
|
|
# no Job Object) and count the ConPTY hosts that survive. This is the path
|
|
# the freeze hypothesis (T-424) actually implicates — the clean-path soak
|
|
# above never exercises it. Diagnostic only; always succeeds.
|
|
runs-on: windows-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: subosito/flutter-action@v2
|
|
with:
|
|
channel: stable
|
|
- run: flutter --version
|
|
- run: flutter pub get
|
|
- name: ConPTY abrupt-death orphan probe
|
|
shell: pwsh
|
|
run: |
|
|
$iters = "${{ github.event.inputs.kill_iterations }}"
|
|
if (-not $iters) { $iters = "15" }
|
|
$ptys = "${{ github.event.inputs.ptys_per_iter }}"
|
|
if (-not $ptys) { $ptys = "2" }
|
|
tools/windows-verify/soak-conpty-kill.ps1 -Iterations ([int]$iters) -PtysPerIter ([int]$ptys) -OutDir "$env:GITHUB_WORKSPACE/kill-out"
|
|
- name: Publish verdict to job summary
|
|
if: always()
|
|
shell: pwsh
|
|
run: |
|
|
$s = Get-ChildItem "$env:GITHUB_WORKSPACE/kill-out/*.summary.txt" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($s) { Get-Content $s.FullName | Add-Content $env:GITHUB_STEP_SUMMARY }
|
|
- name: Upload kill-probe CSV + summary
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: conpty-kill-probe
|
|
path: kill-out
|
|
if-no-files-found: warn
|