fix(governance): drain km healthcheck backlog
All checks were successful
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / tests (push) Successful in 6m2s
CD Pipeline / build-and-deploy (push) Successful in 4m26s
CD Pipeline / post-deploy-checks (push) Successful in 1m37s

This commit is contained in:
Your Name
2026-05-19 21:43:19 +08:00
parent 271aadcefe
commit 2f68b3f472
2 changed files with 63 additions and 12 deletions

View File

@@ -253,6 +253,38 @@ class TestDispatchGovernanceEvent:
assert dispatch_kwargs["decision_context"]["next_action"] == "run_kb_growth_healthcheck"
assert dispatch_kwargs["decision_context"]["workflow"]["current_stage"] == "queued_kb_healthcheck"
@pytest.mark.asyncio
async def test_knowledge_degradation_intake_ignores_legacy_skip_cooldown(self):
"""舊 skip cooldown 不可阻止 KM healthcheck 補建 work item。"""
event = _make_governance_event(event_type="knowledge_degradation")
event.details = {
"remediation": {"next_action": "run_kb_growth_healthcheck"},
"ownership": {"lead_agent": "Hermes"},
}
mock_dispatch_row = MagicMock()
mock_dispatch_row.id = "dispatch-kb-cooldown"
with (
patch(
"src.services.governance_dispatcher.get_active_for_event",
new=AsyncMock(return_value=None),
),
patch(
"src.services.governance_dispatcher._is_skip_cooldown",
new=AsyncMock(return_value=True),
) as mock_skip_cooldown,
patch(
"src.services.governance_dispatcher.create_dispatch",
new=AsyncMock(return_value=mock_dispatch_row),
) as mock_create,
):
from src.services.governance_dispatcher import dispatch_governance_event
result = await dispatch_governance_event(event)
assert result == "dispatch-kb-cooldown"
mock_skip_cooldown.assert_not_awaited()
mock_create.assert_awaited_once()
@pytest.mark.asyncio
async def test_llm_failure_fallback_to_skip(self):
"""fusion adapter 拋 Exception → fallback skip不寫 dispatch返回 None。"""
@@ -467,6 +499,17 @@ class TestDecisionFusionAdapterHelpers:
class TestRunGovernanceDispatcherLoop:
"""run_governance_dispatcher_loop 排程迴圈行為測試。"""
def test_poll_unresolved_events_excludes_active_dispatch_rows(self):
"""poll SQL 必須跳過已有 active dispatch 的事件,避免 backlog 餓死。"""
import inspect
from src.services import governance_dispatcher
source = inspect.getsource(governance_dispatcher._poll_unresolved_events)
assert "GovernanceRemediationDispatch" in source
assert "ACTIVE_STATUSES" in source
assert ".where(~active_dispatch_exists)" in source
@pytest.mark.asyncio
async def test_loop_processes_events_and_sleeps(self):
"""loop 一次 cycle 應處理 events 並 sleep。"""