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>
The freeze diagnosis (T-424) was going to need a dedicated Windows VM to soak-
test. It doesn't: GitHub's windows-latest already runs our ConPTY suite green,
and tools/windows-verify/soak-conpty.ps1 detects the leak by counting the
conhost/OpenConsole hosts that survive each run — it never tries to crash the
box, so a throwaway runner works. The repeated runs happen inside one job, so
the orphan count can climb there even though the runner is discarded after.
New windows-soak.yml: workflow_dispatch + triggers when the soak kit changes.
Diagnostic only (always exits 0); publishes the verdict to the job summary and
uploads the CSV. This removes the GCP/VM requirement from the human entirely.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>