feat(work-items): surface AI runbook loop coverage
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m19s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled

This commit is contained in:
ogt
2026-07-10 11:29:10 +08:00
parent f169f21ee3
commit c578bcdcfa
5 changed files with 675 additions and 0 deletions

View File

@@ -1067,6 +1067,56 @@ type CommanderInsertedRequirementWorkItem = {
source?: string | null;
};
type AiControlledRepairLoopRunbookRow = {
work_item_id?: string | null;
priority?: string | null;
order?: number | null;
status?: string | null;
lane?: string | null;
mapped_workplan_id?: string | null;
coverage_state?: "ready" | "partial" | "queued" | "break_glass" | string | null;
ready_field_count?: number | null;
required_field_count?: number | null;
missing_fields?: string[] | null;
target_selector_ready?: boolean | null;
source_truth_diff_ready?: boolean | null;
candidate_action_ready?: boolean | null;
check_mode_or_dry_run_ready?: boolean | null;
controlled_apply_boundary_ready?: boolean | null;
controlled_apply_allowed?: boolean | null;
break_glass_required?: boolean | null;
rollback_or_no_write_ready?: boolean | null;
post_verifier_ready?: boolean | null;
km_playbook_trust_writeback_ready?: boolean | null;
manual_terminal_allowed?: boolean | null;
next_action?: string | null;
};
type AiControlledRepairLoopRunbookMatrix = {
schema_version?: string | null;
status?: string | null;
metadata_only?: boolean | null;
source?: string | null;
required_fields?: string[] | null;
manual_as_default_terminal_allowed?: boolean | null;
hard_blockers_preserved?: string[] | null;
rows?: AiControlledRepairLoopRunbookRow[] | null;
summary?: {
p0_runbook_count?: number | null;
ready_runbook_count?: number | null;
partial_runbook_count?: number | null;
queued_runbook_count?: number | null;
break_glass_runbook_count?: number | null;
controlled_apply_allowed_count?: number | null;
manual_terminal_count?: number | null;
required_field_total?: number | null;
ready_field_total?: number | null;
completion_percent?: number | null;
next_work_item_id?: string | null;
next_missing_fields?: string[] | null;
} | null;
};
type PriorityWorkOrderResponse = {
current_head?: {
gitea_main_sha?: string | null;
@@ -1434,6 +1484,7 @@ type PriorityWorkOrderResponse = {
metadata_only?: boolean | null;
hard_blockers_preserved?: string[] | null;
} | null;
ai_controlled_repair_loop_runbook_matrix?: AiControlledRepairLoopRunbookMatrix | null;
};
type SecurityCockpitRuntimeReadback = {
@@ -8523,6 +8574,196 @@ function aiAutomationNodeStatusTone(status: string) {
}
}
function aiControlledRunbookCoverageTone(status: string) {
switch (status) {
case "ready":
return "border-[#b9d9c2] bg-[#f2fbf3] text-[#236332]";
case "break_glass":
return "border-[#d4c1ef] bg-[#f8f4ff] text-[#5b3a8a]";
case "queued":
return "border-[#ead5bd] bg-[#fff8ef] text-[#7a3d00]";
default:
return "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]";
}
}
function AiControlledRunbookCoveragePanel({
priority,
loading,
}: {
priority: PriorityWorkOrderResponse | null;
loading: boolean;
}) {
const t = useTranslations("awooop.workItems.aiControlledRunbookCoverage");
const matrix = priority?.ai_controlled_repair_loop_runbook_matrix;
const summary = matrix?.summary;
const rows = matrix?.rows ?? [];
const nextId = summary?.next_work_item_id ?? "--";
const spotlightIds = new Set([
nextId,
"CIR-P0-006",
"CIR-P0-007",
"CIR-P0-LOG-001",
"CIR-P0-TG-001",
]);
const spotlightRows = rows
.filter((row) => row.work_item_id && spotlightIds.has(row.work_item_id))
.slice(0, 6);
const metricCards = [
{
key: "completion",
label: t("metrics.completion"),
value: loading ? "--" : `${summary?.completion_percent ?? 0}%`,
detail: loading
? "--"
: `${summary?.ready_field_total ?? 0}/${summary?.required_field_total ?? 0}`,
icon: Gauge,
tone: "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]",
},
{
key: "controlled",
label: t("metrics.controlled"),
value: loading
? "--"
: `${summary?.controlled_apply_allowed_count ?? 0}/${summary?.p0_runbook_count ?? 0}`,
detail: t("metrics.controlledDetail"),
icon: ShieldCheck,
tone: "border-[#b9d9c2] bg-[#f2fbf3] text-[#236332]",
},
{
key: "breakGlass",
label: t("metrics.breakGlass"),
value: loading ? "--" : summary?.break_glass_runbook_count ?? 0,
detail: t("metrics.breakGlassDetail"),
icon: Lock,
tone: "border-[#d4c1ef] bg-[#f8f4ff] text-[#5b3a8a]",
},
{
key: "manual",
label: t("metrics.manual"),
value: loading ? "--" : summary?.manual_terminal_count ?? 0,
detail: t("metrics.manualDetail"),
icon: CheckCircle2,
tone: "border-[#b9d9c2] bg-[#f2fbf3] text-[#236332]",
},
];
return (
<section
className="border border-[#e0ddd4] bg-white"
data-testid="ai-controlled-runbook-coverage-panel"
>
<div className="grid gap-px bg-[#e0ddd4] xl:grid-cols-[minmax(260px,0.36fr)_minmax(0,1fr)]">
<div className="bg-[#101411] p-4 text-white">
<div className="inline-flex items-center gap-2 border border-[#315a39] bg-[#17241a] px-2 py-0.5 text-xs font-semibold text-[#b8e2bf]">
<Radar className="h-3.5 w-3.5" aria-hidden="true" />
{t("eyebrow")}
</div>
<h3 className="mt-3 text-base font-semibold tracking-normal">
{t("title")}
</h3>
<div className="mt-4 grid grid-cols-2 gap-2">
<div className="border border-[#314034] bg-[#151b17] p-3">
<div className="text-[11px] font-semibold text-[#9fa8a1]">
{t("next")}
</div>
<div className="mt-1 break-words font-mono text-sm font-semibold text-white">
{loading ? "--" : nextId}
</div>
</div>
<div className="border border-[#314034] bg-[#151b17] p-3">
<div className="text-[11px] font-semibold text-[#9fa8a1]">
{t("manualTerminal")}
</div>
<div className="mt-1 text-sm font-semibold text-[#d8f5dc]">
{loading
? "--"
: matrix?.manual_as_default_terminal_allowed
? t("allowed")
: t("disabled")}
</div>
</div>
</div>
<p className="mt-3 text-xs leading-5 text-[#b8c0b9]">
{t("subtitle")}
</p>
</div>
<div className="bg-white p-4">
<div className="grid gap-2 md:grid-cols-4">
{metricCards.map((metric) => {
const Icon = metric.icon;
return (
<div key={metric.key} className={cn("border p-3", metric.tone)}>
<div className="flex items-center justify-between gap-2 text-[11px] font-semibold">
<span>{metric.label}</span>
<Icon className="h-3.5 w-3.5" aria-hidden="true" />
</div>
<div className="mt-1 font-mono text-lg font-semibold text-[#141413]">
{metric.value}
</div>
<div className="mt-1 break-words text-[11px] leading-4 text-[#5f5b52]">
{metric.detail}
</div>
</div>
);
})}
</div>
<div className="mt-3 grid gap-2 xl:grid-cols-3">
{spotlightRows.map((row) => {
const state = String(row.coverage_state ?? "partial");
return (
<div
key={row.work_item_id ?? row.order}
className={cn("min-w-0 border p-3", aiControlledRunbookCoverageTone(state))}
>
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
<div className="truncate font-mono text-xs font-semibold text-[#141413]">
{row.work_item_id}
</div>
<div className="mt-1 truncate text-[11px] font-semibold text-[#5f5b52]">
{row.lane}
</div>
</div>
<span className="border border-current px-2 py-0.5 text-[11px] font-semibold">
{t(`states.${state}` as never)}
</span>
</div>
<div className="mt-2 font-mono text-[11px] text-[#141413]">
{t("fieldProgress", {
ready: row.ready_field_count ?? 0,
total: row.required_field_count ?? 0,
})}
</div>
<div className="mt-2 flex flex-wrap gap-1">
{(row.missing_fields ?? []).slice(0, 4).map((field) => (
<span
key={field}
className="border border-[#d8d3c7] bg-white px-2 py-0.5 font-mono text-[10px] text-[#5f5b52]"
>
{field}
</span>
))}
</div>
</div>
);
})}
</div>
<div className="mt-3 border border-[#c9d8ea] bg-[#eef5ff] p-3 text-xs leading-5 text-[#1f5b9b]">
<span className="font-semibold">{t("source")}</span>{" "}
<span className="font-mono text-[#141413]">
{loading ? "--" : matrix?.source ?? "--"}
</span>
</div>
</div>
</div>
</section>
);
}
function AiLoopLogSourceTagsPanel({
priority,
loading,
@@ -12325,6 +12566,11 @@ export default function AwoooPWorkItemsPage() {
>
<AutonomousRuntimeReceiptPanel mode="compact" />
<AiControlledRunbookCoveragePanel
priority={priorityWorkOrder}
loading={priorityWorkOrderLoading && !priorityWorkOrder}
/>
<AiLoopLogSourceTagsPanel
priority={priorityWorkOrder}
loading={priorityWorkOrderLoading && !priorityWorkOrder}