Merge feat/297-cheaper-ai into feat/299-correlation-simplify

Resolve upload.py (no-scene fallback uses the new _correlate with #298's
non_event_chatter reason) and chatter_classifier docstring (gate built, off by
default). Fold intelligence._llm_bool into incident_correlator.parse_llm_bool (#88).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-10-27 20:31:54 -04:00
co-authored by Claude Opus 5.5
22 changed files with 2046 additions and 231 deletions
@@ -65,7 +65,11 @@ def pipeline_worst_case_seconds(n_scenes: int = _BOUND_SCENES) -> float:
_run_intelligence_pipeline."""
openai_attempts = 1 + max(0, settings.openai_max_retries)
stt_rounds = 2 if settings.stt_retry_on_degenerate else 1
stt = stt_rounds * openai_attempts * settings.stt_timeout_seconds
# A failed primary STT provider falls back to OpenAI (server-26#297), so
# the worst case is every configured target timing out in turn.
from app.internal.transcription import stt_targets
stt_providers = max(1, len(stt_targets()))
stt = stt_providers * stt_rounds * openai_attempts * settings.stt_timeout_seconds
# Transcript correction (inside transcribe_call). gemini.generate_json only
# re-issues a request when the model rejects a thinking level — a fast
# 400, not a timeout — and google-genai itself does not retry.