A successful Windows termination request can end the process before Node publishes exitCode or signalCode. If a child error wins the shutdown race, give that accepted exit a bounded observation window before escalating or reporting fallback refusal.
Cover a delayed real exit edge, preserve prompt refusal behavior for a genuinely live child, and document the launcher grace without weakening the complete stdio and parser drain boundary.
Model the requested signal setting a child termination marker before the launcher begins fallback handling. The regression proves close drains inherited stdio and propagates the original process error without sending a redundant SIGKILL.
This complements the post-check fallback-refusal race and restores the launcher's required 100% per-file statement and branch coverage.
Pass the fake descendant the parent process's stdout and stderr stream handles instead of Unix-style numeric file descriptors. This lets Windows duplicate the live ACP and diagnostic pipes so launcher shutdown can prove that inherited handles, buffered frames, and stderr all drain after the parent exits.
Observe the pending update promise before initiating shutdown as well, preventing a missing late frame from becoming a transient unhandled rejection before the assertion reports the fixture failure.
Treat a fallback kill refusal as successful termination when the child already carries an OS exit marker. Windows maps Node's supported signal names to forced termination, so the requested signal can end the process between the launcher error race and its fallback SIGKILL.
Drain inherited stdio, the ACP parser, and in-flight callbacks before propagating the original child error in either exit-race path. Preserve AggregateError reporting only for a refused fallback while the process is still live, and add a deterministic cross-platform regression for that ordering.
Three tests in the shared acp-snapshot package hardcoded POSIX path
separators in their assertions, so they failed on Windows where
node:path.join produces backslash paths:
- childFixturePaths (suite.spec.ts): expected literal '/snap/s/session.1.jsonl'
but join returns '\snap\s\...' on Windows; use join() for the expected value.
- harness.spec.ts (env-forwarding test): substring-matched a JSON-encoded
path against raw stdout text, where backslash escaping makes the compare
byte-fragile; parse the env-probe chunk and compare the structured value.
- harness.spec.ts (harvested-cwd test): substring-matched the raw cwd
against JSONL text where the cwd is JSON-escaped; parse the session line
and compare the cwd field.
These were master's latent bugs (the package's tests never ran on Windows
until the Windows CI lane observed them). Verified green on Windows via
scripts/caohuanqi-private/run-ci.py --windows.
formatSystemPromptSnapshot's insert-join ternary had its already-newline-
terminated arm unexercised (a delta whose insert ends in a blank line),
failing the per-file 100% branch gate on suite.ts (99.24%).
The ACP bridge registers the first real approval answerer: an ask for an
agent it owns becomes session/request_permission attached to the already-
streamed tool call (one-shot allow_once/reject_once only), outcomes map
conservatively (unknown optionId never grants, client cancel → cancelled),
and foreign or call-less requests delegate down the waterfall. The snapshot
harness accepts scripted permissionAnswers (FIFO; an unscripted prompt
answers cancelled, fail closed) so recorded scenarios can drive the wire
keylessly.