+
+
+
{copy.functions}
+
+ {payload.nist_csf_functions.map((item) => (
+
+
{item.label}
+
+ {item.controlled_percent}%
+
+
+
= 80
+ ? "bg-[#2f8a50]"
+ : item.controlled_percent > 0
+ ? "bg-[#c58a2e]"
+ : "bg-[#c9584d]"
+ )}
+ style={{ width: `${Math.min(100, Math.max(0, item.controlled_percent))}%` }}
+ />
+
+
+ ))}
+
+
+
+
+
+ {copy.scope}
+
+ {payload.summary.controlled_scope_count}/{payload.summary.scope_count}
+
+
+
+ {payload.asset_scopes.map((scope) => (
+
+ {scope.label}
+
+ {scope.managed_asset_count}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
{copy.audit}
+
+
+
+ {payload.security_audit.automation_operation_count_24h}
+
+
OPS
+
+
+
+ {payload.security_audit.mcp_tool_audit_count_24h}
+
+
MCP
+
+
+
+ {payload.security_audit.ai_trace_count_24h}
+
+
{copy.aiTrace}
+
+
+ {!payload.ai_automation.same_run_closed_loop_proven ? (
+
+
+ {copy.sameRunMissing}
+
+ ) : null}
+
+
+
+
{copy.priority}
+
+ {priorityItems.map((item) => (
+
+
+ {item.priority}
+
+
+ {item.title}
+
+ {item.gap_count}
+
+ ))}
+
+
+
+
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/lib/__tests__/security-asset-control-plane.test.ts b/apps/web/src/lib/__tests__/security-asset-control-plane.test.ts
new file mode 100644
index 000000000..866df2e92
--- /dev/null
+++ b/apps/web/src/lib/__tests__/security-asset-control-plane.test.ts
@@ -0,0 +1,135 @@
+import { describe, expect, it } from "vitest";
+
+import {
+ isSecurityAssetControlPlanePayload,
+ securityControlPlaneTone,
+ topSecurityControlPlaneWorkItems,
+ type SecurityAssetControlPlanePayload,
+} from "../security-asset-control-plane";
+
+function payload(): SecurityAssetControlPlanePayload {
+ return {
+ schema_version: "iwooos_security_asset_control_plane_v1",
+ generated_at: "2026-07-11T04:00:00+00:00",
+ status: "ready",
+ source_status: "live_database_aggregate",
+ summary: {
+ managed_asset_count: 24,
+ expected_asset_type_count: 28,
+ present_asset_type_count: 20,
+ asset_type_coverage_percent: 71,
+ scope_count: 6,
+ controlled_scope_count: 3,
+ unowned_asset_count: 0,
+ stale_asset_count: 0,
+ orphan_asset_count: 0,
+ relationship_count: 40,
+ automation_coverage_green_percent: 85,
+ automation_coverage_unknown_count: 0,
+ compliance_violation_count: 0,
+ compliance_unknown_count: 0,
+ nist_controlled_percent: 82,
+ siem_stage_count: 8,
+ siem_observed_stage_count: 8,
+ siem_stage_coverage_percent: 100,
+ ai_loop_stage_count: 7,
+ ai_loop_observed_stage_count: 7,
+ ai_loop_stage_coverage_percent: 100,
+ verified_remediation_receipt_count_24h: 2,
+ active_work_item_count: 2,
+ },
+ discovery: {
+ latest_status: "success",
+ latest_success_at: "2026-07-11T03:50:00+00:00",
+ age_seconds: 600,
+ freshness_slo_seconds: 7200,
+ fresh: true,
+ },
+ asset_scopes: [],
+ nist_csf_functions: [],
+ siem: { pipeline: [] },
+ ai_automation: {
+ stages: [],
+ aggregate_stage_coverage_percent: 100,
+ accepted_ai_trace_count: 2,
+ verified_remediation_receipt_count: 2,
+ rollback_receipt_count: 0,
+ failed_operation_count: 0,
+ same_run_closed_loop_proven: false,
+ same_run_closed_loop_count: 0,
+ },
+ security_audit: {
+ k8s_execution_audit_count_24h: 2,
+ k8s_execution_failure_count_24h: 0,
+ mcp_tool_audit_count_24h: 4,
+ mcp_tool_failure_count_24h: 0,
+ asset_change_event_count_24h: 3,
+ automation_operation_count_24h: 12,
+ automation_failure_count_24h: 0,
+ ai_trace_count_24h: 4,
+ accepted_ai_trace_count_24h: 2,
+ immutable_external_audit_store_evidenced: false,
+ },
+ work_items: [
+ {
+ work_item_id: "AIA-P1-001-01",
+ priority: "P1",
+ control_id: "audit",
+ title: "audit",
+ gap_count: 1,
+ status: "open",
+ next_action: "audit",
+ },
+ {
+ work_item_id: "AIA-P0-007-01",
+ priority: "P0",
+ control_id: "siem",
+ title: "siem",
+ gap_count: 2,
+ status: "open",
+ next_action: "siem",
+ },
+ ],
+ boundaries: {
+ aggregate_only: true,
+ raw_asset_identity_returned: false,
+ raw_event_payload_returned: false,
+ secret_value_collection_allowed: false,
+ live_scan_triggered: false,
+ runtime_action_triggered: false,
+ completion_requires_same_run_receipts: true,
+ },
+ };
+}
+
+describe("security asset control plane projection", () => {
+ it("accepts only the public-safe aggregate contract", () => {
+ const safe = payload();
+ expect(isSecurityAssetControlPlanePayload(safe)).toBe(true);
+
+ const unsafe = {
+ ...safe,
+ boundaries: { ...safe.boundaries, raw_asset_identity_returned: true },
+ };
+ expect(isSecurityAssetControlPlanePayload(unsafe)).toBe(false);
+ });
+
+ it("does not show healthy before same-run closure is proven", () => {
+ const value = payload();
+ expect(securityControlPlaneTone(value)).toBe("warning");
+
+ value.ai_automation.same_run_closed_loop_proven = true;
+ expect(securityControlPlaneTone(value)).toBe("healthy");
+
+ value.discovery.fresh = false;
+ expect(securityControlPlaneTone(value)).toBe("critical");
+ });
+
+ it("keeps P0 work ahead of P1 regardless of API order", () => {
+ const items = topSecurityControlPlaneWorkItems(payload(), 2);
+ expect(items.map((item) => item.work_item_id)).toEqual([
+ "AIA-P0-007-01",
+ "AIA-P1-001-01",
+ ]);
+ });
+});
diff --git a/apps/web/src/lib/security-asset-control-plane.ts b/apps/web/src/lib/security-asset-control-plane.ts
new file mode 100644
index 000000000..ee8d2cf72
--- /dev/null
+++ b/apps/web/src/lib/security-asset-control-plane.ts
@@ -0,0 +1,190 @@
+export type SecurityControlStatus = "ready" | "degraded";
+
+export type SecurityControlPlaneSummary = {
+ managed_asset_count: number;
+ expected_asset_type_count: number;
+ present_asset_type_count: number;
+ asset_type_coverage_percent: number;
+ scope_count: number;
+ controlled_scope_count: number;
+ unowned_asset_count: number;
+ stale_asset_count: number;
+ orphan_asset_count: number;
+ relationship_count: number;
+ automation_coverage_green_percent: number;
+ automation_coverage_unknown_count: number;
+ compliance_violation_count: number;
+ compliance_unknown_count: number;
+ nist_controlled_percent: number;
+ siem_stage_count: number;
+ siem_observed_stage_count: number;
+ siem_stage_coverage_percent: number;
+ ai_loop_stage_count: number;
+ ai_loop_observed_stage_count: number;
+ ai_loop_stage_coverage_percent: number;
+ verified_remediation_receipt_count_24h: number;
+ active_work_item_count: number;
+};
+
+export type SecurityControlPlaneFunction = {
+ function_id: string;
+ label: string;
+ controlled_percent: number;
+ status: string;
+};
+
+export type SecurityControlPlaneStage = {
+ stage_id: string;
+ label: string;
+ status: "observed" | "missing";
+ evidence_count_24h?: number;
+ receipt_count_24h?: number;
+};
+
+export type SecurityControlPlaneScope = {
+ scope_id: string;
+ label: string;
+ managed_asset_count: number;
+ expected_type_count: number;
+ present_type_count: number;
+ missing_type_count: number;
+ type_coverage_percent: number;
+ status: string;
+};
+
+export type SecurityControlPlaneWorkItem = {
+ work_item_id: string;
+ priority: string;
+ control_id: string;
+ title: string;
+ gap_count: number;
+ status: string;
+ next_action: string;
+};
+
+export type SecurityAssetControlPlanePayload = {
+ schema_version: "iwooos_security_asset_control_plane_v1";
+ generated_at: string;
+ status: SecurityControlStatus;
+ source_status: string;
+ reason_code?: string;
+ summary: SecurityControlPlaneSummary;
+ discovery: {
+ latest_status: string;
+ latest_success_at: string | null;
+ age_seconds: number | null;
+ freshness_slo_seconds: number;
+ fresh: boolean;
+ };
+ asset_scopes: SecurityControlPlaneScope[];
+ nist_csf_functions: SecurityControlPlaneFunction[];
+ siem: {
+ pipeline: SecurityControlPlaneStage[];
+ incident_total_24h?: number;
+ open_incident_count_24h?: number;
+ resolved_incident_count_24h?: number;
+ noisy_rule_count?: number;
+ mean_time_to_resolve_minutes_24h?: number | null;
+ };
+ ai_automation: {
+ stages: SecurityControlPlaneStage[];
+ aggregate_stage_coverage_percent: number;
+ accepted_ai_trace_count: number;
+ verified_remediation_receipt_count: number;
+ rollback_receipt_count: number;
+ failed_operation_count: number;
+ same_run_closed_loop_proven: boolean;
+ same_run_closed_loop_count: number;
+ };
+ security_audit: {
+ k8s_execution_audit_count_24h: number;
+ k8s_execution_failure_count_24h: number;
+ mcp_tool_audit_count_24h: number;
+ mcp_tool_failure_count_24h: number;
+ asset_change_event_count_24h: number;
+ automation_operation_count_24h: number;
+ automation_failure_count_24h: number;
+ ai_trace_count_24h: number;
+ accepted_ai_trace_count_24h: number;
+ immutable_external_audit_store_evidenced: boolean;
+ };
+ work_items: SecurityControlPlaneWorkItem[];
+ boundaries: {
+ aggregate_only: boolean;
+ raw_asset_identity_returned: boolean;
+ raw_event_payload_returned: boolean;
+ secret_value_collection_allowed: boolean;
+ live_scan_triggered: boolean;
+ runtime_action_triggered: boolean;
+ completion_requires_same_run_receipts: boolean;
+ };
+};
+
+function isRecord(value: unknown): value is Record
{
+ return typeof value === "object" && value !== null && !Array.isArray(value);
+}
+
+export function isSecurityAssetControlPlanePayload(
+ value: unknown
+): value is SecurityAssetControlPlanePayload {
+ if (!isRecord(value)) return false;
+ if (value.schema_version !== "iwooos_security_asset_control_plane_v1") return false;
+ if (!isRecord(value.summary) || !isRecord(value.boundaries)) return false;
+ if (!Array.isArray(value.asset_scopes) || !Array.isArray(value.nist_csf_functions)) {
+ return false;
+ }
+ if (!isRecord(value.siem) || !Array.isArray(value.siem.pipeline)) return false;
+ if (!isRecord(value.ai_automation) || !Array.isArray(value.ai_automation.stages)) {
+ return false;
+ }
+ return (
+ typeof value.summary.managed_asset_count === "number" &&
+ typeof value.summary.nist_controlled_percent === "number" &&
+ value.boundaries.aggregate_only === true &&
+ value.boundaries.raw_asset_identity_returned === false &&
+ value.boundaries.raw_event_payload_returned === false &&
+ value.boundaries.secret_value_collection_allowed === false &&
+ value.boundaries.live_scan_triggered === false &&
+ value.boundaries.runtime_action_triggered === false
+ );
+}
+
+export type SecurityControlPlaneTone = "healthy" | "warning" | "critical";
+
+export function securityControlPlaneTone(
+ payload: SecurityAssetControlPlanePayload
+): SecurityControlPlaneTone {
+ if (payload.status !== "ready" || !payload.discovery.fresh) return "critical";
+ if (
+ payload.summary.compliance_violation_count > 0 ||
+ payload.summary.nist_controlled_percent < 50 ||
+ payload.summary.siem_stage_coverage_percent < 50 ||
+ payload.summary.ai_loop_stage_coverage_percent < 50
+ ) {
+ return "critical";
+ }
+ if (
+ payload.summary.unowned_asset_count > 0 ||
+ payload.summary.orphan_asset_count > 0 ||
+ payload.summary.automation_coverage_unknown_count > 0 ||
+ payload.summary.compliance_unknown_count > 0 ||
+ !payload.ai_automation.same_run_closed_loop_proven
+ ) {
+ return "warning";
+ }
+ return "healthy";
+}
+
+export function topSecurityControlPlaneWorkItems(
+ payload: SecurityAssetControlPlanePayload,
+ limit = 3
+): SecurityControlPlaneWorkItem[] {
+ const rank: Record = { P0: 0, P1: 1, P2: 2, P3: 3 };
+ return [...payload.work_items]
+ .sort(
+ (left, right) =>
+ (rank[left.priority] ?? 99) - (rank[right.priority] ?? 99) ||
+ left.work_item_id.localeCompare(right.work_item_id)
+ )
+ .slice(0, Math.max(0, limit));
+}