The os.killpg call sits below an early 'if sys.platform == win32: return'
so it can never execute on Windows; the scanner is line-based and needs
the inline marker.
- run_bounded_async: cancel + abandon the inner task when the CALLER is
cancelled (leak the telegram original also had)
- kill_process_tree: check taskkill exit code (Windows contract parity),
suppress console flash via windows_hide_flags, and sweep a psutil
descendant snapshot taken before signalling — reaches grandchildren in
their own setsid sessions and the non-group-leader case (#71148 class)
- resolve_timeout: reject bool (YAML true would become a 1s deadline) and
NaN config values with fall-through instead of resolving unbounded
- BoundedResult: kw_only to prevent positional transposition
- tests: real clamped-value time_t regression proof, own-session
descendant kill, external-cancellation task cleanup, bool/NaN config
fall-through; pin already-dead-pid contract
One shared foundation for the timeout/hang backlog instead of per-incident
site-local fixes:
- agent/deadline.py: run_bounded_async (thread-timer deadline that survives
a blocked event loop, generalizing the telegram adapter primitive),
run_bounded_sync, clamp_timeout (kills the #83220 time_t OverflowError
class at the boundary), resolve_timeout (config.yaml timeouts: section >
legacy env bridge > default), kill_process_tree (whole-tree termination
for the #71148 orphan class), DeadlineExpired (our deadline, mechanically
distinct from provider timeouts).
- tool_executor._resolve_concurrent_tool_timeout migrates onto the resolver;
exact legacy env-var contract preserved (default 420, 0 disables).
- timeouts: accepted as a known config root; documented in
cli-config.yaml.example.
Pure addition otherwise — no behavior change, no new env vars, no cache
impact. Later phases (#85125) migrate tool-execution, MCP, and subprocess
call sites onto these primitives.