mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
0b4f77db33
The judges and the regex ReDoS probe ran a blocking call on a ThreadPoolExecutor and abandoned the worker with shutdown(wait=False) on timeout or cancel. concurrent.futures joins every executor worker from an atexit hook regardless of wait=False, so a wedged call could pin interpreter exit — and hang the test suite at shutdown. Add turnstone/core/deadline.py::run_with_deadline: run a blocking callable on a daemon thread bounded by a wall-clock timeout and an optional cancel event. A daemon worker is never joined at exit, so abandoning one is safe. Migrate three sites onto it: - OutputGuardJudge.evaluate() - IntentJudge._evaluate_single / _run_judge — this also removes _ExecutorPoisonedError and the executor-restart dance: per-call daemon threads can't poison a shared single-slot pool, so a timeout now returns None and the caller delivers one fallback verdict. - console/server.py _validate_regex_pattern (regex ReDoS probe) Also: - Double the default judge LLM timeouts for slower local models: judge.timeout 60->120s and judge.output_guard_llm_timeout 30->60s (settings registry, JudgeConfig dataclass, --judge-timeout CLI default, class docstring, docs). Correct a stale doc that described the per-turn timeout as a total budget across turns. - Raise the regex probe bound 0.5->3.0s so a legitimately complex pattern isn't false-flagged as catastrophic backtracking. - CI: run pytest with -v instead of -q so a hang names the offending test instead of riding the job timeout. - Tests: cover deadline.py and the regex validator; move test_judge.py off fixed sleeps onto the existing _wait_for helper.