fix: log swallowed exceptions in detect_threads try/except (T80.3)

The broad ``except Exception`` around detect_threads silently dropped
programmer errors (wrong kwargs, import-time failures, etc), making
diagnostics painful. Log at DEBUG with full exc_info so the failure
surfaces in local logs without breaking the close pipeline's
failure-tolerant contract.

Adds test_detect_threads_failure_is_logged using caplog.
This commit is contained in:
Joseph Doherty
2026-04-26 21:49:17 -04:00
parent dae481eb92
commit 9d06eaf57a
2 changed files with 56 additions and 1 deletions
+8 -1
View File
@@ -29,6 +29,7 @@ keeps moving.
from __future__ import annotations from __future__ import annotations
import json import json
import logging
import uuid import uuid
from datetime import datetime, timezone from datetime import datetime, timezone
from sqlite3 import Connection from sqlite3 import Connection
@@ -39,6 +40,8 @@ from chat.eventlog.log import append_and_apply
from chat.llm.classify import classify from chat.llm.classify import classify
from chat.llm.client import LLMClient from chat.llm.client import LLMClient
_log = logging.getLogger(__name__)
class ScenePOVSummary(BaseModel): class ScenePOVSummary(BaseModel):
"""Classifier output: one witness's view of a closing scene. """Classifier output: one witness's view of a closing scene.
@@ -589,7 +592,11 @@ async def apply_scene_close_summary(
open_threads=list_open_threads(conn, chat_id), open_threads=list_open_threads(conn, chat_id),
timeout_s=timeout_s, timeout_s=timeout_s,
) )
except Exception: except Exception as exc:
# T80.3: log the swallowed exception at DEBUG so a
# programmer-error flap (e.g. wrong kwarg name) surfaces in
# local logs without breaking the close pipeline.
_log.debug("detect_threads failed: %s", exc, exc_info=True)
from chat.services.thread_detection import ThreadDetectionResult from chat.services.thread_detection import ThreadDetectionResult
thread_result = ThreadDetectionResult() thread_result = ThreadDetectionResult()
+48
View File
@@ -1625,3 +1625,51 @@ async def test_thread_detection_uses_scene_scoped_transcript(
joined = " ".join(t.get("text", "") for t in scene_two_transcript) joined = " ".join(t.get("text", "") for t in scene_two_transcript)
assert "SCENE_TWO" in joined assert "SCENE_TWO" in joined
assert "SCENE_ONE" not in joined assert "SCENE_ONE" not in joined
@pytest.mark.asyncio
async def test_detect_threads_failure_is_logged(tmp_path, monkeypatch, caplog):
"""T80.3: when ``detect_threads`` raises, the broad except must log
the failure at DEBUG so a programmer-error flap surfaces in local
logs even though the close pipeline keeps moving."""
import logging
from chat.services import thread_detection as td_mod
canned = json.dumps(
{
"summary": "BotA had a quick chat.",
"knowledge_facts": [],
"relationship_summary": "Steady.",
}
)
async def boom(client, **kwargs):
raise RuntimeError("test-detect-threads-boom")
monkeypatch.setattr(td_mod, "detect_threads", boom)
db = tmp_path / "t.db"
apply_migrations(db)
with open_db(db) as conn:
_seed_single_bot_scene(conn)
project(conn)
caplog.set_level(logging.DEBUG, logger="chat.services.scene_summarize")
client = MockLLMClient(canned=[canned])
# Close should NOT raise even though detect_threads did.
await apply_scene_close_summary(
conn,
client,
classifier_model="x",
chat_id="chat_bot_a",
scene_id=1,
host_bot_id="bot_a",
)
# Log carries the error message.
assert any(
"detect_threads failed" in rec.message
and "test-detect-threads-boom" in rec.message
for rec in caplog.records
), [r.message for r in caplog.records]