feat(types): ADR-046 IncidentConverter + IncidentEngineAdapter
實作 ADR-046 Option B: IncidentConverter 轉換層,解決 BrainIncident (lewooogo-brain) 與 LocalIncident (apps/api) 型別邊界問題。 變更: - 新增 src/utils/incident_converter.py - brain_to_local(): BrainIncident → LocalIncident - local_to_brain(): LocalIncident → BrainIncident - ESCALATED → MITIGATING 映射 (brain 無 ESCALATED) - incident_engine.py: 新增 IncidentEngineAdapter 包裝層 - process_signal() / get_incident() 輸出轉換為 LocalIncident - get_incident_engine() 返回 IncidentEngineAdapter - incident_memory.py: 加入 brain_to_local import,更新 _record_to_incident 說明 - ADR-046: 標記三個轉換點全部完成 解鎖: #123 proposal_service.py 清理 (下一步) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ from src.core.redis_client import get_redis
|
||||
from src.models.incident import Incident
|
||||
from src.services.graph_rag import BlastRadiusResult, topology_graph
|
||||
from src.services.incident_memory import get_incident_memory
|
||||
from src.utils.incident_converter import brain_to_local
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -69,11 +70,11 @@ class IIncidentEngine(Protocol):
|
||||
self,
|
||||
signal_data: dict[str, Any],
|
||||
) -> Incident | None:
|
||||
"""處理 Signal: 原子建立或聚合 Incident"""
|
||||
"""處理 Signal: 原子建立或聚合 Incident (返回 LocalIncident,ADR-046)"""
|
||||
...
|
||||
|
||||
async def get_incident(self, incident_id: str) -> Incident | None:
|
||||
"""取得指定 Incident"""
|
||||
"""取得指定 Incident (返回 LocalIncident,ADR-046)"""
|
||||
...
|
||||
|
||||
async def update_status(
|
||||
@@ -106,7 +107,13 @@ class IncidentMemoryAdapter:
|
||||
self._memory = memory
|
||||
|
||||
async def load_incident(self, incident_id: str) -> Any:
|
||||
"""從 Working Memory 載入 Incident"""
|
||||
"""
|
||||
從 Working Memory 載入 Incident (返回 BrainIncident,供 brain engine 內部使用)
|
||||
|
||||
注意: 此 adapter 注入 brain engine,brain 內部呼叫時期望 BrainIncident。
|
||||
本地服務透過 IncidentEngineAdapter.get_incident() 取得 LocalIncident。
|
||||
(ADR-046 - 2026-04-01 ogt)
|
||||
"""
|
||||
return await self._memory.load_incident(incident_id)
|
||||
|
||||
async def save_incident(self, incident: Any, ttl_seconds: int = 604800) -> bool:
|
||||
@@ -188,18 +195,56 @@ class BlastRadiusAdapter:
|
||||
return [target] if target != "unknown" else []
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# IncidentEngineAdapter (ADR-046: brain 輸出轉換為 LocalIncident)
|
||||
# =============================================================================
|
||||
|
||||
class IncidentEngineAdapter:
|
||||
"""
|
||||
Incident Engine Adapter - 包裝 lewooogo-brain IncidentEngine
|
||||
|
||||
ADR-046 (2026-04-01 ogt): brain 引擎輸出 BrainIncident,
|
||||
透過 brain_to_local() 轉換為 LocalIncident,供本地服務消費。
|
||||
|
||||
這是本地服務與 brain 引擎之間的邊界層。
|
||||
讓 IIncidentEngine Protocol 的返回型別宣告 Incident 得以成立。
|
||||
"""
|
||||
|
||||
def __init__(self, brain_engine: Any) -> None:
|
||||
self._engine = brain_engine
|
||||
|
||||
async def process_signal(self, signal_data: dict[str, Any]) -> Incident | None:
|
||||
"""處理 Signal,返回 LocalIncident (brain 輸出轉換)"""
|
||||
brain_incident = await self._engine.process_signal(signal_data)
|
||||
if brain_incident is None:
|
||||
return None
|
||||
return brain_to_local(brain_incident)
|
||||
|
||||
async def get_incident(self, incident_id: str) -> Incident | None:
|
||||
"""取得 Incident,返回 LocalIncident (brain 輸出轉換)"""
|
||||
brain_incident = await self._engine.get_incident(incident_id)
|
||||
if brain_incident is None:
|
||||
return None
|
||||
return brain_to_local(brain_incident)
|
||||
|
||||
async def update_status(self, incident_id: str, status: Any) -> bool:
|
||||
"""更新狀態 (直接委派,brain status 與 local status 值相容)"""
|
||||
return await self._engine.update_status(incident_id, status)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Singleton (Phase R-R2: 僅保留 lewooogo-brain 版本)
|
||||
# =============================================================================
|
||||
|
||||
_new_incident_engine: Any | None = None
|
||||
_new_incident_engine: IncidentEngineAdapter | None = None
|
||||
|
||||
|
||||
def get_incident_engine() -> Any:
|
||||
def get_incident_engine() -> IncidentEngineAdapter:
|
||||
"""
|
||||
取得 Incident Engine 實例 (Singleton)
|
||||
|
||||
Phase R-R2: 統一使用 lewooogo-brain IncidentEngine。
|
||||
ADR-046: 返回 IncidentEngineAdapter,輸出已轉換為 LocalIncident。
|
||||
回滾方式: git revert Phase R-R2 commit + redeploy。
|
||||
|
||||
Raises:
|
||||
@@ -214,12 +259,13 @@ def get_incident_engine() -> Any:
|
||||
memory_adapter = IncidentMemoryAdapter(get_incident_memory())
|
||||
blast_adapter = BlastRadiusAdapter()
|
||||
|
||||
_new_incident_engine = NewIncidentEngine(
|
||||
brain_engine = NewIncidentEngine(
|
||||
memory=memory_adapter,
|
||||
blast_analyzer=blast_adapter,
|
||||
logger=logger,
|
||||
)
|
||||
logger.info("incident_engine_initialized", version="lewooogo-brain")
|
||||
_new_incident_engine = IncidentEngineAdapter(brain_engine)
|
||||
logger.info("incident_engine_initialized", version="lewooogo-brain", adapter="IncidentEngineAdapter")
|
||||
|
||||
except ImportError as e:
|
||||
logger.error("lewooogo_brain_engines_not_available", error=str(e))
|
||||
|
||||
@@ -25,6 +25,7 @@ from src.core.redis_client import get_redis
|
||||
from src.db.base import get_db_context
|
||||
from src.db.models import IncidentRecord
|
||||
from src.models.incident import Incident
|
||||
from src.utils.incident_converter import brain_to_local
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -121,9 +122,13 @@ class IncidentDbAdapter:
|
||||
return False
|
||||
|
||||
def _record_to_incident(self, record: IncidentRecord) -> Any:
|
||||
# 2026-04-01 ogt: 返回 BrainIncident (lewooogo-brain),非本地 Incident
|
||||
# 型別為 Any 避免靜態分析誤報,實際為 lewooogo_brain.interfaces.incident_processor.Incident
|
||||
"""將 DB Record 轉換為 Incident (lewooogo-brain 版本)"""
|
||||
"""
|
||||
將 DB Record 轉換為 BrainIncident (lewooogo-brain 版本)
|
||||
|
||||
注意: 返回 BrainIncident 供 lewooogo-brain DualIncidentMemory 內部使用。
|
||||
本地服務消費時透過 IncidentConverter.brain_to_local() 轉換。
|
||||
(ADR-046 - 2026-04-01 ogt)
|
||||
"""
|
||||
from lewooogo_brain.interfaces.incident_processor import (
|
||||
Incident as BrainIncident,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user