diff --git a/apps/api/src/services/approval_db.py b/apps/api/src/services/approval_db.py index 9ae36fff..677d2fea 100644 --- a/apps/api/src/services/approval_db.py +++ b/apps/api/src/services/approval_db.py @@ -606,13 +606,33 @@ class ApprovalDBService: """ 2026-04-06 ogt: Phase 26 — 回寫 incident_id 到 approval_records 讓 Playbook 萃取和 KM 寫入能找到對應的 Incident + + 2026-04-14 Claude Sonnet 4.6 診斷: Live-fire #7 發現 approval.incident_id 仍 NULL + 加 rowcount 與 pre/post 值檢查,若 0 rows affected 則 log warning """ async with get_db_context() as db: - await db.execute( + result = await db.execute( update(ApprovalRecord) .where(ApprovalRecord.id == str(approval_id)) .values(incident_id=incident_id) ) + rowcount = result.rowcount if hasattr(result, "rowcount") else -1 + if rowcount == 0: + # 找不到對應 approval — 可能 id 型別或 session 不同步 + logger.warning( + "update_incident_id_zero_rows", + approval_id=str(approval_id), + approval_id_type=type(approval_id).__name__, + incident_id=incident_id, + reason="UPDATE 0 rows affected — approval 不存在或 id mismatch", + ) + else: + logger.info( + "update_incident_id_success", + approval_id=str(approval_id), + incident_id=incident_id, + rowcount=rowcount, + ) async def update_telegram_message( self, incident_id: str, telegram_message_id: int, telegram_chat_id: int | None = None diff --git a/apps/api/src/services/openclaw.py b/apps/api/src/services/openclaw.py index 5ef58e18..ee887690 100644 --- a/apps/api/src/services/openclaw.py +++ b/apps/api/src/services/openclaw.py @@ -140,10 +140,15 @@ class OpenClawService: self._signoz = get_signoz_client() async def _get_client(self) -> httpx.AsyncClient: - """取得 HTTP 客戶端""" + """取得 HTTP 客戶端 + + 2026-04-14 Claude Sonnet 4.6: 從硬編 120s 改用 OPENCLAW_TIMEOUT 設定 (30s) + 對齊 ADR-052 GAP-B4 的 25s + 5s buffer 設計。原 120s 違反 defense-in-depth。 + """ if self._http_client is None or self._http_client.is_closed: + _t = float(settings.OPENCLAW_TIMEOUT) self._http_client = httpx.AsyncClient( - timeout=httpx.Timeout(120.0, connect=10.0), + timeout=httpx.Timeout(_t, connect=10.0), ) return self._http_client @@ -342,10 +347,12 @@ class OpenClawService: "affected_services": affected_services, "expert_context": _to_serializable(expert_context) if expert_context else None, } + # 2026-04-14 Claude Sonnet 4.6: 從硬編 130s 改用 OPENCLAW_TIMEOUT + # 原 130s 讓 LLM 能卡 2m10s,超過 Ollama 真實返回時間(P95 54s) resp = await client.post( f"{settings.OPENCLAW_URL}/api/v1/analyze/incident", json=payload, - timeout=httpx.Timeout(130.0, connect=5.0), + timeout=httpx.Timeout(float(settings.OPENCLAW_TIMEOUT), connect=5.0), ) resp.raise_for_status() data = resp.json()