feat(governance): expose km draft dedupe plan
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
Type Sync Check / check-type-sync (push) Successful in 33s
CD Pipeline / tests (push) Successful in 4m3s
E2E Health Check / e2e-health (push) Successful in 23s
CD Pipeline / build-and-deploy (push) Successful in 4m54s
CD Pipeline / post-deploy-checks (push) Successful in 2m9s
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
Type Sync Check / check-type-sync (push) Successful in 33s
CD Pipeline / tests (push) Successful in 4m3s
E2E Health Check / e2e-health (push) Successful in 23s
CD Pipeline / build-and-deploy (push) Successful in 4m54s
CD Pipeline / post-deploy-checks (push) Successful in 2m9s
This commit is contained in:
@@ -29,10 +29,14 @@ from src.models.governance import (
|
||||
GovernanceEventsResponse,
|
||||
GovernanceQueueResponse,
|
||||
GovernanceSummaryResponse,
|
||||
KnowledgeReviewDraftDedupeGroup,
|
||||
KnowledgeReviewDraftDedupeResponse,
|
||||
map_severity,
|
||||
)
|
||||
from src.services.governance_query_service import (
|
||||
_build_km_review_draft_dedupe_groups,
|
||||
_extract_kb_draft_entry_id,
|
||||
_extract_governance_event_id_from_tags,
|
||||
_extract_remediation,
|
||||
_extract_worker_status,
|
||||
_merge_dispatch_ids,
|
||||
@@ -402,6 +406,90 @@ class TestQueueEndpoint:
|
||||
assert "d.operator_note" not in source
|
||||
|
||||
|
||||
class TestKmReviewDraftDedupe:
|
||||
def test_endpoint_passes_limit_and_returns_owner_review_plan(self, client):
|
||||
"""Work Items 需要 read-only canonical/duplicate plan,不直接封存 KM。"""
|
||||
fake = KnowledgeReviewDraftDedupeResponse(
|
||||
total_review_drafts=3,
|
||||
event_group_total=1,
|
||||
duplicate_draft_total=2,
|
||||
generated_at=NOW,
|
||||
groups=[
|
||||
KnowledgeReviewDraftDedupeGroup(
|
||||
governance_event_id="event-001",
|
||||
canonical_entry_id="km-canonical",
|
||||
canonical_title="KM healthcheck review draft - event",
|
||||
preferred_source="dispatch_context",
|
||||
duplicate_entry_ids=["km-dup-1", "km-dup-2"],
|
||||
duplicate_count=2,
|
||||
total_entries=3,
|
||||
suggested_action="owner_review_canonical_then_archive_duplicates",
|
||||
owner_action="review_canonical_and_archive_duplicate_drafts",
|
||||
writes_on_read=False,
|
||||
can_archive_without_owner_approval=False,
|
||||
)
|
||||
],
|
||||
)
|
||||
captured: dict = {}
|
||||
|
||||
async def mock_query(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return fake
|
||||
|
||||
with patch("src.api.v1.ai_governance.query_km_review_draft_dedupe", new=mock_query):
|
||||
r = client.get("/api/v1/ai/governance/km-review-drafts/dedupe?limit=50")
|
||||
|
||||
assert r.status_code == 200
|
||||
assert captured["limit"] == 50
|
||||
data = r.json()
|
||||
assert data["duplicate_draft_total"] == 2
|
||||
assert data["groups"][0]["canonical_entry_id"] == "km-canonical"
|
||||
assert data["groups"][0]["writes_on_read"] is False
|
||||
assert data["groups"][0]["can_archive_without_owner_approval"] is False
|
||||
|
||||
def test_governance_event_tag_extraction(self):
|
||||
assert _extract_governance_event_id_from_tags([
|
||||
"agent:Hermes",
|
||||
"governance_event:event-001",
|
||||
]) == "event-001"
|
||||
assert _extract_governance_event_id_from_tags(["agent:Hermes"]) is None
|
||||
|
||||
def test_build_dedupe_groups_prefers_dispatch_context_draft(self):
|
||||
"""若 dispatch context 指出 canonical draft,dedupe plan 應以它為準。"""
|
||||
rows = [
|
||||
{
|
||||
"id": "km-latest",
|
||||
"title": "latest draft",
|
||||
"tags": ["governance_event:event-001"],
|
||||
"updated_at": datetime(2026, 5, 2, 14, 0, tzinfo=TAIPEI),
|
||||
},
|
||||
{
|
||||
"id": "km-canonical",
|
||||
"title": "canonical draft",
|
||||
"tags": ["governance_event:event-001"],
|
||||
"updated_at": datetime(2026, 5, 2, 13, 0, tzinfo=TAIPEI),
|
||||
},
|
||||
{
|
||||
"id": "km-other",
|
||||
"title": "other event draft",
|
||||
"tags": ["governance_event:event-002"],
|
||||
"updated_at": datetime(2026, 5, 2, 12, 0, tzinfo=TAIPEI),
|
||||
},
|
||||
]
|
||||
|
||||
groups = _build_km_review_draft_dedupe_groups(
|
||||
rows,
|
||||
{"event-001": "km-canonical"},
|
||||
)
|
||||
|
||||
first = groups[0]
|
||||
assert first.governance_event_id == "event-001"
|
||||
assert first.canonical_entry_id == "km-canonical"
|
||||
assert first.preferred_source == "dispatch_context"
|
||||
assert first.duplicate_entry_ids == ["km-latest"]
|
||||
assert first.writes_on_read is False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 4. summary endpoint compliance_rate
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user