feat(governance): surface km archive audit history
All checks were successful
Code Review / ai-code-review (push) Successful in 12s
Type Sync Check / check-type-sync (push) Successful in 27s
CD Pipeline / tests (push) Successful in 4m9s
CD Pipeline / build-and-deploy (push) Successful in 3m57s
CD Pipeline / post-deploy-checks (push) Successful in 1m45s

This commit is contained in:
Your Name
2026-05-20 09:52:30 +08:00
parent 967d4b77b6
commit 14697ba20e
8 changed files with 305 additions and 0 deletions

View File

@@ -105,6 +105,9 @@ class DispatchItem(BaseModel):
human_owner: str | None = None
kb_draft_entry_id: str | None = None
worker_status: str | None = None
dry_run_plan_fingerprint: str | None = None
archived_count: int | None = None
stale_ratio_snapshot: dict | None = None
class GovernanceQueueResponse(BaseModel):

View File

@@ -427,6 +427,9 @@ async def _query_dispatch_table(
human_owner=_extract_human_owner(decision_ctx),
kb_draft_entry_id=_extract_kb_draft_entry_id(decision_ctx),
worker_status=_extract_worker_status(decision_ctx),
dry_run_plan_fingerprint=_extract_dry_run_plan_fingerprint(decision_ctx),
archived_count=_extract_archived_count(decision_ctx),
stale_ratio_snapshot=_extract_stale_ratio_snapshot(decision_ctx),
))
return GovernanceQueueResponse(
@@ -562,6 +565,57 @@ def _extract_worker_status(decision_ctx: dict) -> str | None:
return val[:80] if isinstance(val, str) and val else None
def _extract_dry_run_plan_fingerprint(decision_ctx: dict) -> str | None:
for source in (
decision_ctx,
decision_ctx.get("workflow"),
):
if not isinstance(source, dict):
continue
val = source.get("dry_run_plan_fingerprint")
if isinstance(val, str) and val:
return val[:80]
return None
def _extract_archived_count(decision_ctx: dict) -> int | None:
raw = decision_ctx.get("archived_count")
if isinstance(raw, int):
return max(raw, 0)
archived = decision_ctx.get("archived_entry_ids")
if isinstance(archived, list):
return len(archived)
workflow = decision_ctx.get("workflow")
if isinstance(workflow, dict):
archived = workflow.get("archived_entry_ids")
if isinstance(archived, list):
return len(archived)
return None
def _extract_stale_ratio_snapshot(decision_ctx: dict) -> dict | None:
for source in (
decision_ctx,
decision_ctx.get("workflow"),
):
if not isinstance(source, dict):
continue
snapshot = source.get("stale_ratio_snapshot")
if isinstance(snapshot, dict):
return {
key: snapshot.get(key)
for key in (
"stale_count",
"total_count",
"stale_ratio",
"threshold",
"stale_days",
)
if key in snapshot
}
return None
# =============================================================================
# Endpoint 2B: KM review draft dedupe
# =============================================================================