Closes the observability loop: the log + breadcrumb + watchdog files are now
collected by CI so a wedged run leaves downloadable evidence instead of
nothing.
- logDirectory(): CLIDE_LOG_DIR overrides the per-platform default, so CI can
point the logs at an uploadable workspace dir (and tests at a temp dir).
Now takes an injectable env map; tested.
- test_app.dart: when CLIDE_LOG_DIR is set, the testmode harness tees its
logger to a FileLogSink + spawns the watchdog (off by default — normal
run-testmode keeps the stderr-only path, no isolate). _say breadcrumbs each
test into the file.
- conpty_orphan_probe.dart: with CLIDE_LOG_DIR set it passes a verbose PtyLog,
so when soak-conpty-kill.ps1 force-kills the parent, the reader/waiter
isolates' LAST crumb is fsynced to disk — naming what the wedged isolate was
doing at the instant of death.
- bundle-smoke job: runs the real release app with CLIDE_LOG=debug +
CLIDE_LOG_DIR, uploads clide-logs (watchdog heartbeat/sample + FileLogSink)
in an always() step.
- windows-soak kill-probe job: sets CLIDE_LOG_DIR, uploads the FFI crumbs.
Coverage gate 95.08%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
First real execution of soak-conpty.ps1 on GitHub's windows-latest proved the
harness works — it spawned real ConPTY children, ran the suite (6 tests), and
measured the first iteration — then died printing the per-iter line: `{3,+4}`
is a printf-ism, not valid .NET composite formatting (the `+` is rejected with
"Expected an ASCII digit"). The script had never run on Windows before, so the
typo was latent. Drop to `{3,4}` (plain width).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GCP only offers Windows Server images, which lack winget. Rewrite
bootstrap-windows.ps1 to be winget-free (Chocolatey for git + VS Build Tools,
direct-from-Google for the Flutter SDK) and add a -SkipVS fast path — the
ConPTY soak only needs Flutter/Dart. Runs under Windows PowerShell 5.1. README
gains a self-contained GCP Cloud Shell runbook (create / reset-password / RDP /
stop / delete).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verification tooling for the Windows freeze assessment (T-424).
provision-vm.sh stands up a Windows KVM guest (dry-run unless --go);
bootstrap-windows.ps1 installs Flutter + VS C++ Build Tools and checks out
the branch; soak-conpty.ps1 runs the pty suite in a fresh dart.exe per
iteration and measures the orphaned conhost/cmd count that survives each
exit (the leak signature), with a per-iteration timeout so a wedged test
can't stall the run. Verifies the ConPTY leak (#1-#4); the GPU/TDR
hypothesis (#5) needs passthrough/bare metal (README appendix).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>