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
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:
@@ -9573,6 +9573,32 @@
|
||||
"backup": "backup evidence"
|
||||
}
|
||||
},
|
||||
"aiControlledRunbookCoverage": {
|
||||
"eyebrow": "AI Loop Coverage",
|
||||
"title": "P0 Runbook AI Controlled Coverage",
|
||||
"subtitle": "Turns each P0 runbook's target selector, source truth, candidate, check-mode, controlled apply, rollback, post verifier, and KM / PlayBook trust writeback into one matrix.",
|
||||
"next": "Next gap",
|
||||
"manualTerminal": "Manual terminal",
|
||||
"allowed": "allowed",
|
||||
"disabled": "disabled",
|
||||
"source": "source",
|
||||
"fieldProgress": "ready {ready}/{total}",
|
||||
"metrics": {
|
||||
"completion": "Field coverage",
|
||||
"controlled": "controlled apply",
|
||||
"controlledDetail": "Executable after break-glass exclusions",
|
||||
"breakGlass": "break-glass",
|
||||
"breakGlassDetail": "Incident-grade blockers such as secret, destructive, or reboot work",
|
||||
"manual": "manual terminal",
|
||||
"manualDetail": "Manual is not the default terminal state for low/medium/high work"
|
||||
},
|
||||
"states": {
|
||||
"ready": "ready",
|
||||
"partial": "partial",
|
||||
"queued": "queued",
|
||||
"break_glass": "break-glass"
|
||||
}
|
||||
},
|
||||
"commanderInsertedRequirements": {
|
||||
"eyebrow": "Mainline priority",
|
||||
"title": "Commander Inserted Requirement Work Items",
|
||||
|
||||
@@ -9573,6 +9573,32 @@
|
||||
"backup": "backup evidence"
|
||||
}
|
||||
},
|
||||
"aiControlledRunbookCoverage": {
|
||||
"eyebrow": "AI Loop Coverage",
|
||||
"title": "P0 Runbook AI Controlled Coverage",
|
||||
"subtitle": "把每個 P0 runbook 的 target selector、source truth、candidate、check-mode、controlled apply、rollback、post verifier 與 KM / PlayBook trust 回寫狀態收成矩陣。",
|
||||
"next": "下一個缺口",
|
||||
"manualTerminal": "人工終局",
|
||||
"allowed": "allowed",
|
||||
"disabled": "disabled",
|
||||
"source": "source",
|
||||
"fieldProgress": "ready {ready}/{total}",
|
||||
"metrics": {
|
||||
"completion": "欄位覆蓋",
|
||||
"controlled": "controlled apply",
|
||||
"controlledDetail": "排除 break-glass 後可受控推進",
|
||||
"breakGlass": "break-glass",
|
||||
"breakGlassDetail": "secret / destructive / reboot 等事故級硬阻擋",
|
||||
"manual": "manual terminal",
|
||||
"manualDetail": "人工不得是 low/medium/high 預設終局"
|
||||
},
|
||||
"states": {
|
||||
"ready": "ready",
|
||||
"partial": "partial",
|
||||
"queued": "queued",
|
||||
"break_glass": "break-glass"
|
||||
}
|
||||
},
|
||||
"commanderInsertedRequirements": {
|
||||
"eyebrow": "主線優先序",
|
||||
"title": "統帥插入需求工作項",
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user