feat(governance): surface stale km owner review inbox
All checks were successful
CD Pipeline / tests (push) Successful in 5m29s
Code Review / ai-code-review (push) Successful in 16s
Type Sync Check / check-type-sync (push) Successful in 28s
CD Pipeline / build-and-deploy (push) Successful in 4m12s
CD Pipeline / post-deploy-checks (push) Successful in 1m30s
All checks were successful
CD Pipeline / tests (push) Successful in 5m29s
Code Review / ai-code-review (push) Successful in 16s
Type Sync Check / check-type-sync (push) Successful in 28s
CD Pipeline / build-and-deploy (push) Successful in 4m12s
CD Pipeline / post-deploy-checks (push) Successful in 1m30s
This commit is contained in:
@@ -42,6 +42,8 @@ from src.models.governance import (
|
||||
KnowledgeStaleOwnerReviewBatchQueueResponse,
|
||||
KnowledgeStaleOwnerReviewCompleteRequest,
|
||||
KnowledgeStaleOwnerReviewCompleteResponse,
|
||||
KnowledgeStaleOwnerReviewInboxItem,
|
||||
KnowledgeStaleOwnerReviewInboxResponse,
|
||||
KnowledgeStaleOwnerReviewRequest,
|
||||
KnowledgeStaleOwnerReviewResponse,
|
||||
map_severity,
|
||||
@@ -60,6 +62,7 @@ from src.services.governance_km_stale_review_service import (
|
||||
_build_batch_queue_plan_fingerprint,
|
||||
_build_completion_plan_fingerprint,
|
||||
_build_owner_review_completion_audit_context,
|
||||
_build_owner_review_inbox_item,
|
||||
_build_stale_owner_review_decision_context,
|
||||
_completion_stage_for_outcome,
|
||||
)
|
||||
@@ -878,6 +881,124 @@ class TestKmReviewDraftDedupe:
|
||||
assert r.status_code == 409
|
||||
assert "batch queue plan" in r.json()["detail"]
|
||||
|
||||
def test_owner_review_inbox_endpoint_returns_sorted_work_items(self, client):
|
||||
"""Owner-review inbox 應回傳 pending dispatch 與 KM priority context。"""
|
||||
fake = KnowledgeStaleOwnerReviewInboxResponse(
|
||||
project_id="awoooi",
|
||||
dispatch_status="pending",
|
||||
total=1,
|
||||
returned=1,
|
||||
items=[
|
||||
KnowledgeStaleOwnerReviewInboxItem(
|
||||
dispatch_id="dispatch-001",
|
||||
governance_event_id="event-001",
|
||||
entry_id="km-001",
|
||||
project_id="awoooi",
|
||||
title="Sentry checkout failure repair",
|
||||
dispatch_status="pending",
|
||||
workflow_stage="waiting_owner_review",
|
||||
next_action="owner_review_stale_km_candidate",
|
||||
owner="operator_console",
|
||||
owner_note="p0_p1_stale_km_batch",
|
||||
batch_governance_event_id="event-batch-001",
|
||||
batch_dispatch_id="dispatch-batch-001",
|
||||
priority_tier="P0",
|
||||
priority_score=265,
|
||||
recommended_action="refresh_with_evidence",
|
||||
stale_days=35,
|
||||
view_count=7,
|
||||
correlation_sources=["incident", "playbook", "sentry"],
|
||||
reasons=["linked_incident", "linked_playbook"],
|
||||
related_incident_id="INC-20260513-79ED5E",
|
||||
related_playbook_id="pb:auto-repair-canary",
|
||||
queued_at=NOW,
|
||||
)
|
||||
],
|
||||
generated_at=NOW,
|
||||
)
|
||||
captured: dict = {}
|
||||
|
||||
async def mock_inbox(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return fake
|
||||
|
||||
with patch(
|
||||
"src.api.v1.ai_governance.query_km_stale_owner_review_inbox",
|
||||
new=mock_inbox,
|
||||
):
|
||||
r = client.get(
|
||||
"/api/v1/ai/governance/km-stale-owner-reviews"
|
||||
"?project_id=awoooi&dispatch_status=pending&limit=20"
|
||||
)
|
||||
|
||||
assert r.status_code == 200
|
||||
assert captured == {
|
||||
"project_id": "awoooi",
|
||||
"dispatch_status": "pending",
|
||||
"limit": 20,
|
||||
}
|
||||
data = r.json()
|
||||
assert data["schema_version"] == "km_stale_owner_review_inbox_v1"
|
||||
assert data["total"] == 1
|
||||
assert data["writes_on_read"] is False
|
||||
assert data["manual_review_required"] is True
|
||||
assert data["items"][0]["dispatch_id"] == "dispatch-001"
|
||||
assert data["items"][0]["workflow_stage"] == "waiting_owner_review"
|
||||
assert data["items"][0]["batch_dispatch_id"] == "dispatch-batch-001"
|
||||
|
||||
def test_owner_review_inbox_context_keeps_batch_and_priority_visible(self):
|
||||
record = KnowledgeEntryRecord(
|
||||
id="km-001",
|
||||
project_id="awoooi",
|
||||
title="Sentry checkout failure repair",
|
||||
content="Use Sentry and SigNoz evidence before writeback.",
|
||||
entry_type=EntryType.AUTO_RUNBOOK,
|
||||
category="AI系統",
|
||||
tags=["sentry", "signoz"],
|
||||
source=EntrySource.AI_EXTRACTED,
|
||||
status=EntryStatus.REVIEW,
|
||||
related_incident_id="INC-20260513-79ED5E",
|
||||
related_playbook_id="pb:auto-repair-canary",
|
||||
view_count=7,
|
||||
updated_at=NOW - timedelta(days=35),
|
||||
)
|
||||
candidate = _build_km_stale_candidate(record, now=NOW, threshold_days=7)
|
||||
row = type("Row", (), {
|
||||
"id": "dispatch-001",
|
||||
"governance_event_id": "event-001",
|
||||
"dispatch_status": "pending",
|
||||
"dispatched_at": NOW,
|
||||
"started_at": None,
|
||||
"completed_at": None,
|
||||
})()
|
||||
ctx = {
|
||||
"owner": "operator_console",
|
||||
"owner_note": "p0_p1_stale_km_batch",
|
||||
"next_action": "owner_review_stale_km_candidate",
|
||||
"workflow": {
|
||||
"entry_id": "km-001",
|
||||
"project_id": "awoooi",
|
||||
"batch_governance_event_id": "event-batch-001",
|
||||
"batch_dispatch_id": "dispatch-batch-001",
|
||||
"current_stage": "waiting_owner_review",
|
||||
"stage_by_dispatch_status": {"pending": "waiting_owner_review"},
|
||||
},
|
||||
}
|
||||
|
||||
item = _build_owner_review_inbox_item(
|
||||
row=row,
|
||||
candidate=candidate,
|
||||
decision_context=ctx,
|
||||
)
|
||||
|
||||
assert item.dispatch_id == "dispatch-001"
|
||||
assert item.batch_dispatch_id == "dispatch-batch-001"
|
||||
assert item.priority_tier == "P0"
|
||||
assert item.priority_score > 200
|
||||
assert item.workflow_stage == "waiting_owner_review"
|
||||
assert item.recommended_action == "refresh_with_evidence"
|
||||
assert item.correlation_sources == ["incident", "playbook", "sentry", "signoz"]
|
||||
|
||||
def test_stale_owner_review_batch_context_is_operator_visible(self):
|
||||
request = KnowledgeStaleOwnerReviewBatchQueueRequest(
|
||||
project_id="awoooi",
|
||||
|
||||
Reference in New Issue
Block a user