Add stack trace dumping to watchdog
When a hang is detected, now logs:
- Full stack trace of all threads
- Exact file:line of blocking code
- Function names in the call chain
This shows you WHY the event loop is blocked, not just that it's blocked.
* Add lightweight event loop watchdog monitoring
- Thread-based watchdog detects event loop hangs >15s
- Runs independently, won't interfere with normal operation
- Disabled in test environments
- Minimal overhead, just heartbeat checks every 5s
* actually test it
* Add test script to validate watchdog detects hangs
Run with: uv run python test_watchdog_hang.py
Tests:
- Normal operation (no false positives)
- Short blocks under threshold (no alerts)
- Long blocks over threshold (correctly alerts)