feat(governance): process hermes km healthchecks
All checks were successful
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / tests (push) Successful in 2m13s
CD Pipeline / build-and-deploy (push) Successful in 5m14s
CD Pipeline / post-deploy-checks (push) Successful in 1m55s

This commit is contained in:
Your Name
2026-05-19 22:32:55 +08:00
parent bda857a8f3
commit edf97ad8ca
4 changed files with 503 additions and 0 deletions

View File

@@ -356,6 +356,75 @@ async def list_pending(
return list(result.scalars().all())
async def list_pending_by_executor(
executor_type: str,
*,
limit: int = 50,
) -> list[GovernanceRemediationDispatch]:
"""列出指定 executor 的 pending dispatch按 dispatched_at ASC
用於 Hermes / 其他 worker 消費自己的 work item。由 repository 層集中查詢,
避免 job 直接散落表名與狀態條件。
Args:
executor_type: dispatch.executor_type例如 hermes_kb_growth_healthcheck
limit: 本輪最多取幾筆,避免 backlog 一次拖垮 worker
Returns:
最舊優先的 pending dispatch 列表。
"""
async with get_db_context() as db:
result = await db.execute(
select(GovernanceRemediationDispatch)
.where(GovernanceRemediationDispatch.dispatch_status == "pending")
.where(GovernanceRemediationDispatch.executor_type == executor_type)
.order_by(GovernanceRemediationDispatch.dispatched_at.asc())
.limit(limit)
)
return list(result.scalars().all())
async def update_decision_context(
dispatch_id: str,
decision_context: dict[str, Any],
) -> GovernanceRemediationDispatch:
"""更新 dispatch 的 decision_context保留同一 row 的 audit trail。
這只更新 dispatch work item 的讀模型上下文,不修改 immutable
ai_governance_events也不代表治理事件已被解決。
Args:
dispatch_id: governance_remediation_dispatch.id
decision_context: 新的 JSONB context
Returns:
更新後的 GovernanceRemediationDispatch ORM 物件
Raises:
DispatchNotFound: 找不到 dispatch_id
"""
async with get_db_context() as db:
result = await db.execute(
select(GovernanceRemediationDispatch)
.where(GovernanceRemediationDispatch.id == dispatch_id)
)
row = result.scalar_one_or_none()
if row is None:
raise DispatchNotFound(f"dispatch_id={dispatch_id!r} 不存在")
row.decision_context = decision_context
await db.flush()
await db.refresh(row)
logger.info(
"dispatch_decision_context_updated",
dispatch_id=dispatch_id,
event_id=row.governance_event_id,
executor_type=row.executor_type,
)
return row
async def list_by_event(
event_id: str,
) -> list[GovernanceRemediationDispatch]: