""" GovernanceRemediationDispatch Pydantic Schemas ================================================ Wave 2 D: 治理事件修復派遣的輸入/輸出驗證 schema。 用途: - DecisionContextV1: JSONB 欄位結構驗證(service 層寫入前必須通過) - DispatchCreate: 建立 dispatch 的輸入驗證 - DispatchResponse: 單筆 dispatch API 回應 - DispatchListItem: 列表頁輕量回應(含 /governance Queue tab) 設計原則: - Pydantic V2(對齊 models/ 目錄) - DecisionContextV1 版本化:version 欄位方便 fine-tune pipeline 過濾相容版本 - 所有時間欄位使用 datetime(含 timezone,台北時區) 2026-05-03 ogt + Claude Sonnet 4.6(亞太): Wave 2 D db-expert spec 實作 """ from __future__ import annotations from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, Field # ============================================================================= # DecisionContextV1 — JSONB 欄位驗證(service 層寫入 DB 前強制驗證) # ============================================================================= class DecisionContextV1(BaseModel): """治理派遣決策上下文 v1. service 層必須用此 model 驗證後序列化為 dict 再寫入 decision_context 欄位。 版本欄位方便未來 schema 演進時過濾不相容記錄。 欄位均 optional:允許部分感官缺失(MCP 呼叫失敗時為 None)。 """ version: Literal["v1"] = Field( default="v1", description="schema 版本,固定為 v1", ) trigger_source: str | None = Field( default=None, description="觸發來源(如 governance_agent / trust_drift_watchdog)", ) triggered_metric: str | None = Field( default=None, description="觸發指標名稱(如 avg_trust_score / hallucination_rate)", ) metric_value: float | None = Field( default=None, description="觸發時的指標數值", ) threshold: float | None = Field( default=None, description="觸發閾值", ) affected_resources: list[str] = Field( default_factory=list, description="受影響的資源列表(如 playbook_id / km_entry_id)", ) suggested_action: str | None = Field( default=None, description="AI 建議的修復動作摘要(≤200 字)", ) extra: dict[str, Any] = Field( default_factory=dict, description="其他擴充欄位(預留 forward compatibility)", ) # ============================================================================= # DispatchCreate — 建立 dispatch 的輸入驗證 # ============================================================================= class DispatchCreate(BaseModel): """建立新 dispatch 的輸入 schema. service 層呼叫 create_dispatch() 前先用此 schema 驗證輸入。 decision_context 在此層以 DecisionContextV1 驗證,序列化後寫入 DB。 """ governance_event_id: str = Field( description="關聯的 ai_governance_events.id(UUID)" ) event_type: Literal[ "trust_drift", "knowledge_degradation", "llm_hallucination", "execution_blast_radius", "governance_slo_data_gap", ] = Field(description="治理事件類型") executor_type: str = Field( max_length=80, description="執行器類型(如 playbook_executor / manual / slo_repair)", ) playbook_id: str | None = Field( default=None, description="可選,關聯 playbooks.playbook_id", ) incident_id: str | None = Field( default=None, description="可選,關聯 incidents.incident_id", ) approval_id: str | None = Field( default=None, description="可選,關聯 approval_records.id", ) decision_context: DecisionContextV1 = Field( default_factory=DecisionContextV1, description="決策上下文(DecisionContextV1 強制驗證)", ) max_attempts: int = Field( default=3, ge=1, description="最大重試次數(含首次,必須 >= 1)", ) created_by: str | None = Field( default="governance_dispatcher", description="建立者(系統自動派遣時為 governance_dispatcher)", ) # ============================================================================= # DispatchResponse — 單筆 dispatch 完整回應 # ============================================================================= class DispatchResponse(BaseModel): """單筆 GovernanceRemediationDispatch API 回應.""" id: str governance_event_id: str event_type: str dispatch_status: str playbook_id: str | None = None incident_id: str | None = None approval_id: str | None = None decision_context: dict[str, Any] executor_type: str attempt_count: int max_attempts: int last_error: str | None = None dispatched_at: datetime started_at: datetime | None = None completed_at: datetime | None = None created_by: str | None = None model_config = {"from_attributes": True} # ============================================================================= # DispatchListItem — 列表頁輕量回應(/governance Queue tab 用) # ============================================================================= class DispatchListItem(BaseModel): """列表頁輕量 dispatch 回應. 僅回傳 Queue / Events tab 所需欄位,避免傳輸完整 decision_context。 """ id: str governance_event_id: str event_type: str dispatch_status: str executor_type: str playbook_id: str | None = None attempt_count: int max_attempts: int dispatched_at: datetime completed_at: datetime | None = None model_config = {"from_attributes": True}