feat(governance): surface km completion callback evidence
Some checks failed
CD Pipeline / tests (push) Successful in 1m10s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 4m19s
E2E Health Check / e2e-health (push) Failing after 34s
CD Pipeline / post-deploy-checks (push) Successful in 1m46s
Some checks failed
CD Pipeline / tests (push) Successful in 1m10s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 4m19s
E2E Health Check / e2e-health (push) Failing after 34s
CD Pipeline / post-deploy-checks (push) Successful in 1m46s
This commit is contained in:
@@ -281,6 +281,40 @@ interface EventRecurrenceResponse {
|
||||
items: EventRecurrenceItem[];
|
||||
}
|
||||
|
||||
interface KmStaleCompletionSummaryItem {
|
||||
entry_id?: string | null;
|
||||
title?: string | null;
|
||||
dispatch_id?: string | null;
|
||||
governance_event_id?: string | null;
|
||||
readiness?: string | null;
|
||||
workflow_stage?: string | null;
|
||||
next_action?: string | null;
|
||||
priority_tier?: string | null;
|
||||
recommended_completion_outcome?: string | null;
|
||||
can_preview?: boolean | null;
|
||||
}
|
||||
|
||||
interface KmStaleCompletionSummary {
|
||||
schema_version?: string;
|
||||
project_id?: string | null;
|
||||
incident_id?: string | null;
|
||||
status?: string | null;
|
||||
missing_reason?: string | null;
|
||||
total?: number;
|
||||
returned?: number;
|
||||
pending_count?: number;
|
||||
ready_count?: number;
|
||||
blocked_count?: number;
|
||||
completed_count?: number;
|
||||
failed_count?: number;
|
||||
writes_on_read?: boolean | null;
|
||||
manual_review_required?: boolean | null;
|
||||
batch_writes_allowed?: boolean | null;
|
||||
items_truncated?: boolean | null;
|
||||
related_total?: number;
|
||||
related_items?: KmStaleCompletionSummaryItem[];
|
||||
}
|
||||
|
||||
interface CallbackReplyEvent {
|
||||
message_id: string;
|
||||
run_id: string;
|
||||
@@ -301,6 +335,7 @@ interface CallbackReplyEvent {
|
||||
agent_id?: string | null;
|
||||
run_detail_href?: string | null;
|
||||
awooop_status_chain?: AwoooPStatusChain | null;
|
||||
km_stale_completion_summary?: KmStaleCompletionSummary | null;
|
||||
}
|
||||
|
||||
interface CallbackRepliesResponse {
|
||||
@@ -660,6 +695,18 @@ function normalizeCallbackReplyEventStatus(statusValue?: string | null): Callbac
|
||||
return "observed";
|
||||
}
|
||||
|
||||
function normalizeKmCompletionStatus(statusValue?: string | null) {
|
||||
if (
|
||||
statusValue === "matched_owner_review" ||
|
||||
statusValue === "no_related_owner_review" ||
|
||||
statusValue === "fetch_failed" ||
|
||||
statusValue === "no_incident"
|
||||
) {
|
||||
return statusValue;
|
||||
}
|
||||
return "observed";
|
||||
}
|
||||
|
||||
function RemediationEvidenceCell({ summary }: { summary?: RemediationSummary | null }) {
|
||||
const t = useTranslations("awooop.listEvidence");
|
||||
const status = normalizeRemediationStatus(summary);
|
||||
@@ -1409,6 +1456,66 @@ function GroupedAlertEventsPanel({ events }: { events: PlatformEvent[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
function CallbackKmCompletionSummary({
|
||||
summary,
|
||||
}: {
|
||||
summary?: KmStaleCompletionSummary | null;
|
||||
}) {
|
||||
const t = useTranslations("awooop.callbackReply.events.kmCompletion");
|
||||
if (!summary) return null;
|
||||
|
||||
const statusKey = normalizeKmCompletionStatus(summary.status);
|
||||
const related = Array.isArray(summary.related_items)
|
||||
? summary.related_items[0]
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="mt-3 border-t border-[#e0ddd4] pt-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<ShieldCheck className="h-3.5 w-3.5 text-[#17602a]" aria-hidden="true" />
|
||||
<p className="text-xs font-semibold text-[#141413]">{t("title")}</p>
|
||||
</div>
|
||||
<div className="mt-2 grid gap-1 text-xs leading-5 text-[#5f5b52]">
|
||||
<p>
|
||||
{t("status", {
|
||||
status: t(`statuses.${statusKey}` as never),
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{t("counts", {
|
||||
ready: summary.ready_count ?? 0,
|
||||
blocked: summary.blocked_count ?? 0,
|
||||
completed: summary.completed_count ?? 0,
|
||||
failed: summary.failed_count ?? 0,
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{t("guardrail", {
|
||||
writesOnRead: String(summary.writes_on_read ?? false),
|
||||
batchWrite: String(summary.batch_writes_allowed ?? false),
|
||||
manualReview: String(summary.manual_review_required ?? true),
|
||||
})}
|
||||
</p>
|
||||
{related ? (
|
||||
<p className="truncate font-mono text-[#77736a]">
|
||||
{t("related", {
|
||||
entryId: related.entry_id ?? "--",
|
||||
readiness: related.readiness ?? "--",
|
||||
nextAction: related.next_action ?? "--",
|
||||
})}
|
||||
</p>
|
||||
) : statusKey === "fetch_failed" ? (
|
||||
<p className="text-[#9f2f25]">
|
||||
{t("fetchFailed", { reason: summary.missing_reason ?? "--" })}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[#77736a]">{t("noRelated")}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CallbackReplyEvidencePanel({
|
||||
events,
|
||||
total,
|
||||
@@ -1499,6 +1606,9 @@ function CallbackReplyEvidencePanel({
|
||||
compact
|
||||
className="mt-3"
|
||||
/>
|
||||
<CallbackKmCompletionSummary
|
||||
summary={event.km_stale_completion_summary}
|
||||
/>
|
||||
<Link
|
||||
href={runHref as never}
|
||||
className="mt-3 inline-flex items-center gap-1.5 border border-[#d8d3c7] bg-[#faf9f3] px-2 py-1 text-xs font-semibold text-[#2e2b26] hover:border-[#1f6feb] hover:bg-[#edf4ff] hover:text-[#0f4fa8]"
|
||||
|
||||
Reference in New Issue
Block a user