feat(web): show owner response validation rollup

This commit is contained in:
Your Name
2026-05-21 11:47:20 +08:00
parent f592a13274
commit f4c3befa70
9 changed files with 641 additions and 68 deletions

View File

@@ -3778,7 +3778,7 @@
}
}
},
"githubPrimaryReadiness": {
"githubPrimaryReadiness": {
"title": "GitHub Primary Readiness",
"subtitle": "AwoooP home mirrors the source-control readiness gap for moving from Gitea to GitHub. It is framework-phase visibility only: no repo creation, refs mutation, secret value collection, or primary switch.",
"badge": "Read-only summary",
@@ -3809,19 +3809,104 @@
"detail": "Workflow / secret name inventory is still incomplete for 7 repos."
}
},
"readinessRefs": {
"primaryReadiness": "The GitHub primary readiness gate remains a candidate and must not trigger repo creation or visibility changes.",
"ownerValidation": "The owner response validation rollup shows all four response packets still waiting for human reply and acceptance.",
"rollbackAdr": "The rollback ADR has no owner-approved dry-run yet, so GitHub cannot become primary.",
"workflowInventory": "Workflow / secret name inventory collects names and routing only; it does not collect secret values or change GitHub secrets."
"readinessRefs": {
"primaryReadiness": "The GitHub primary readiness gate remains a candidate and must not trigger repo creation or visibility changes.",
"ownerValidation": "The owner response validation rollup shows all four response packets still waiting for human reply and acceptance.",
"rollbackAdr": "The rollback ADR has no owner-approved dry-run yet, so GitHub cannot become primary.",
"workflowInventory": "Workflow / secret name inventory collects names and routing only; it does not collect secret values or change GitHub secrets."
}
},
"ownerResponseValidation": {
"title": "Owner Response Validation Rollup",
"subtitle": "AwoooP home shows the S4.9-S4.12 owner response packets, intake, validation, and audit checks in one read-only board. received / accepted / rejected all remain 0, so this is not approval or execution authorization.",
"badge": "Read-only validation",
"openIwooos": "Open IwoooS",
"packetsTitle": "Four Waiting Response Packets",
"validationTitle": "Validation And Audit Checks",
"boundaryLabel": "Validation Boundary",
"boundaryTitle": "Still waiting for owner evidence",
"boundaryDetail": "This rollup only displays source_control_owner_response_validation_rollup_v1. It must not be treated as owner response received, owner response accepted, GitHub primary approval, repo / refs / workflow / secret authorization, or runtime execution.",
"fields": {
"templates": "Templates",
"received": "Received",
"accepted": "Accepted",
"rejected": "Rejected"
},
"metrics": {
"packets": {
"label": "Response Packets",
"detail": "S4.9-S4.12 are all still waiting for owner responses."
},
"templates": {
"label": "Response Templates",
"detail": "22 templates are questions for owners, not sent requests."
},
"received": {
"label": "Received",
"detail": "Still 0; visibility is not receipt completion."
},
"accepted": {
"label": "Accepted",
"detail": "Still 0; GitHub primary and runtime gates remain blocked."
},
"rejected": {
"label": "Rejected",
"detail": "Still 0; raw payload or secret values must be quarantined."
}
},
"quality": {
"packets": {
"giteaInventory": {
"title": "Gitea Inventory Owner Attestation",
"detail": "Collect public-only / local gap, org / user endpoint, 110 adjacent scope, canonical owner, and legacy disposition."
},
"githubTarget": {
"title": "GitHub Target Owner Decision",
"detail": "Confirm target, visibility, and canonical owner per repo; do not create repos or change visibility."
},
"refTruth": {
"title": "Refs Truth Owner Response",
"detail": "Confirm main / dev truth, deprecated drift, release tags, and GitHub-only refs; do not sync, delete, or force push refs."
},
"workflowSecret": {
"title": "Workflow / Secret Name Owner Response",
"detail": "Collect workflow, runner, deploy key, branch protection, secret names, and owner metadata only; never collect secret values."
}
},
"checks": {
"crossPacket": {
"label": "Cross-Packet Checks",
"detail": "10 cross-packet checks only validate consistency."
},
"evidenceRouting": {
"label": "Evidence Routing",
"detail": "6 routing rules only route to more evidence, quarantine, or read-only updates."
},
"displaySections": {
"label": "Display Sections",
"detail": "8 sections define AwoooP read-only display order."
},
"stateTransitions": {
"label": "State Transitions",
"detail": "7 rules define review semantics only; no execution."
},
"reviewerChecklist": {
"label": "Reviewer Checklist",
"detail": "9 checklist items guide human review."
},
"reviewerOutcomes": {
"label": "Reviewer Outcomes",
"detail": "7 lanes only route to more evidence, quarantine, rejection, or later gates."
}
}
},
"quality": {
"title": "Automation Quality",
"subtitle": "Whether recent alerts actually reached AI auto-repair, verification, and learning writeback in the last 24 hours.",
"claimReady": "Full Loop Claim Ready",
"claimBlocked": "Full Loop Claim Blocked",
"unavailable": "Unavailable",
"claimReady": "Full Loop Claim Ready",
"claimBlocked": "Full Loop Claim Blocked",
"claimReadyDetail": "Every alert completed the verified loop",
"claimBlockedDetail": "Some alerts still lack execution, verification, or learning records",
"unavailable": "Unavailable",
"loadFailed": "Unable to load the automation quality summary. Check Operator permissions and the truth-chain API.",
"empty": "No alert quality data is available yet.",
"yes": "Yes",

View File

@@ -3724,106 +3724,191 @@
"home": {
"eyebrow": "AI 自動化飛輪控制面",
"title": "AwoooP 治理總覽",
"subtitle": "把租戶、合約、Run、審批與通道狀態收斂到同一個操作面,避免 AI 自動化飛輪和治理面各自長出一套邏輯。",
"subtitle": "把租戶、合約、執行紀錄、審批與通道狀態收斂到同一個操作面,避免 AI 自動化飛輪和治理面各自長出一套邏輯。",
"refresh": "重新整理",
"snapshotStatus": "快照狀態",
"lastUpdated": "最後更新",
"migrationMode": "遷移模式",
"migrationValue": "mirror / shadow",
"migrationValue": "鏡像 / 影子模式",
"ready": "同步中",
"loading": "讀取中",
"degraded": "降級",
"securityMirror": {
"title": "IwoooS 資安鏡像",
"subtitle": "AwoooP 首頁以只讀候選方式顯示 IwoooS / 資安鏡像狀態,讓使用者理解資安網進度與邊界;這不是 production landing enabled,也不接執行路由器。",
"subtitle": "AwoooP 首頁以只讀候選方式顯示 IwoooS / 資安鏡像狀態,讓使用者理解資安網進度與邊界;這不是正式入口啟用,也不接執行路由器。",
"badge": "只讀候選",
"openIwooos": "開啟 IwoooS",
"checkpointsTitle": "接入檢查",
"boundaryLabel": "安全邊界",
"boundaryTitle": "仍維持低摩擦框架期",
"boundaryDetail": "這個面板只顯示已提交快照與 guard 口徑,不呼叫 Kali、GitHub、Gitea 或 runtime API也不提供掃描、執行、修復、部署、主要來源切換或 refs 動作。",
"boundaryDetail": "這個面板只顯示已提交快照與防護檢查口徑,不呼叫 Kali、GitHub、Gitea 或執行期 API也不提供掃描、執行、修復、部署、主要來源切換或分支 / 標籤參照動作。",
"metrics": {
"headline": {
"label": "整體資安網",
"detail": "headline 仍等負責人回覆、脫敏匯入、runtime gate、GitHub 主要來源或 AwoooP production landing evidence。"
"detail": "整體百分比仍等負責人回覆、脫敏匯入、執行期閘門、GitHub 主要來源或 AwoooP 正式入口證據。"
},
"framework": {
"label": "框架成熟度",
"detail": "治理、文件、schema、只讀 evidence 與 IwoooS 投影已接近完整。"
"detail": "治理、文件、結構定義、只讀證據與 IwoooS 投影已接近完整。"
},
"runtime": {
"label": "落地執行",
"detail": "runtime ingestion、GitHub 主要來源與 AwoooP production landing 仍需後續 evidence。"
"detail": "執行期匯入、GitHub 主要來源與 AwoooP 正式入口仍需後續證據。"
},
"activeGates": {
"label": "主動執行閘門",
"detail": "目前維持 0任何主機或 blocking control 都仍需獨立批准。"
"detail": "目前維持 0任何主機或阻擋型控制都仍需獨立批准。"
}
},
"checkpoints": {
"iwooosProjection": {
"title": "IwoooS 投影可讀",
"detail": "AwoooP 只顯示 IwoooS 態勢、進度、evidence refs 與禁止動作。"
"detail": "AwoooP 只顯示 IwoooS 態勢、進度、證據參照與禁止動作。"
},
"rollupGuard": {
"title": "Guard 口徑一致",
"title": "防護檢查口徑一致",
"detail": "接手前維持 security-mirror-progress-guard.py 與 source-control-owner-response-guard.py 綠燈。"
},
"ownerResponse": {
"title": "負責人回覆仍等待",
"detail": "S4.9 到 S4.12 received / accepted 都仍為 0不把顯示狀態當驗收完成。"
"detail": "S4.9 到 S4.12 收到 / 接受都仍為 0不把顯示狀態當驗收完成。"
},
"productionLanding": {
"title": "Production landing 尚未完成",
"detail": "AwoooP 主線仍需 deployment proof 與只讀消費 evidence 才能進入 headline 重估。"
"title": "正式入口尚未完成",
"detail": "AwoooP 主線仍需部署證據與只讀消費證據才能進入整體百分比重估。"
}
}
},
"githubPrimaryReadiness": {
"title": "GitHub 主要來源就緒度",
"subtitle": "AwoooP 首頁同步顯示 Gitea 轉 GitHub 的原始碼管控就緒度缺口;目前只做框架期可視化,不建立 repo、不改 refs、不收 secret value,也不切換主要來源。",
"badge": "只讀摘要",
"githubPrimaryReadiness": {
"title": "GitHub 主要來源就緒度",
"subtitle": "AwoooP 首頁同步顯示 Gitea 轉 GitHub 的原始碼管控就緒度缺口;目前只做框架期可視化,不建立專案庫、不改分支 / 標籤參照、不收機密明文值,也不切換主要來源。",
"badge": "只讀摘要",
"openIwooos": "開啟 IwoooS",
"readinessRefsTitle": "就緒度 evidence refs",
"readinessRefsTitle": "就緒度證據參照",
"boundaryLabel": "GitHub 主要來源邊界",
"boundaryTitle": "目前仍不可推進主要來源切換",
"boundaryDetail": "這個摘要只顯示已提交快照與負責人回覆缺口,不能被解讀成 GitHub 主要來源批准、repo 建立授權、refs 變更、secret 收集、Gitea 停用或 runtime execution。",
"boundaryDetail": "這個摘要只顯示已提交快照與負責人回覆缺口,不能被解讀成 GitHub 主要來源批准、專案庫建立授權、分支 / 標籤參照變更、機密值收集、Gitea 停用或執行期執行。",
"metrics": {
"candidateRepos": {
"label": "候選 repo",
"detail": "S2.63 起已盤點 8 個候選 repo;這不是建立 GitHub repo 的授權。"
"label": "候選專案庫",
"detail": "S2.63 起已盤點 8 個候選專案庫;這不是建立 GitHub 專案庫的授權。"
},
"inScopeRepos": {
"label": "範圍內 repo",
"detail": "目前 7 個 repo 進入主要來源就緒度範圍,仍等待負責人回覆。"
"label": "範圍內專案庫",
"detail": "目前 7 個專案庫進入主要來源就緒度範圍,仍等待負責人回覆。"
},
"primaryReady": {
"label": "主要來源就緒數",
"detail": "ready count 維持 0不能切換 GitHub 主要來源或停用 Gitea。"
"detail": "就緒數維持 0不能切換 GitHub 主要來源或停用 Gitea。"
},
"ownerResponses": {
"label": "負責人回覆",
"detail": "22 個回覆範本仍為 0 received / 0 accepted。"
"detail": "22 個回覆範本仍為 0 收到 / 0 接受。"
},
"workflowInventory": {
"label": "工作流程清冊",
"detail": "7 個 repo 的 workflow / secret 名稱清冊尚未完成。"
"detail": "7 個專案庫的工作流程 / 機密名稱清冊尚未完成。"
}
},
"readinessRefs": {
"primaryReadiness": "GitHub 主要來源就緒度閘門仍是候選狀態,不能觸發 repo 建立或可見性變更。",
"ownerValidation": "負責人回覆驗證彙總顯示四包回覆資料都仍等待人工回覆與驗收。",
"rollbackAdr": "Rollback ADR 尚未完成 owner approved dry-run,因此不能把 GitHub 切為主要來源。",
"workflowInventory": "Workflow / secret 名稱清冊只收集名稱與路由,不收 secret value、不改 GitHub secrets。"
"readinessRefs": {
"primaryReadiness": "GitHub 主要來源就緒度閘門仍是候選狀態,不能觸發專案庫建立或可見性變更。",
"ownerValidation": "負責人回覆驗證彙總顯示四包回覆資料都仍等待人工回覆與驗收。",
"rollbackAdr": "回復架構決策紀錄尚未完成負責人批准的演練,因此不能把 GitHub 切為主要來源。",
"workflowInventory": "工作流程 / 機密名稱清冊只收集名稱與路由,不收機密明文值、不改 GitHub 機密設定。"
}
},
"ownerResponseValidation": {
"title": "負責人回覆驗收總覽",
"subtitle": "AwoooP 首頁把 S4.9 到 S4.12 四包負責人回覆的收件、驗收與稽核檢查放在同一張只讀看板;目前收到 / 接受 / 拒收都是 0不代表任何批准或執行授權。",
"badge": "只讀驗收",
"openIwooos": "開啟 IwoooS",
"packetsTitle": "四包待收回覆",
"validationTitle": "驗收與稽核檢查",
"boundaryLabel": "驗收邊界",
"boundaryTitle": "仍等待負責人證據,不開執行權限",
"boundaryDetail": "這個總覽只顯示 source_control_owner_response_validation_rollup_v1 的只讀狀態不能被解讀成負責人回覆已收到、已接受、GitHub 主要來源已批准、專案庫 / 分支與標籤參照 / 工作流程 / 機密設定可修改,或執行期可執行。",
"fields": {
"templates": "範本",
"received": "收到",
"accepted": "接受",
"rejected": "拒收"
},
"metrics": {
"packets": {
"label": "回覆包",
"detail": "S4.9 到 S4.12 四包都仍是等待收件狀態。"
},
"templates": {
"label": "回覆範本",
"detail": "22 個範本只是負責人要回覆的問題,不代表請求已送出。"
},
"received": {
"label": "已收到",
"detail": "目前仍為 0不得把可見看板當成收件完成。"
},
"accepted": {
"label": "已接受",
"detail": "目前仍為 0不得推進 GitHub 主要來源或執行期閘門。"
},
"rejected": {
"label": "已拒收",
"detail": "目前仍為 0若收到原始載荷或機密明文值必須隔離。"
}
},
"quality": {
"title": "自動化品質",
"subtitle": "最近 24 小時告警是否真正走到 AI 自動修復、驗證與學習回寫。",
"claimReady": "可宣稱完整閉環",
"claimBlocked": "不可宣稱完整閉環",
"unavailable": "無法讀取",
"loadFailed": "無法讀取自動化品質總覽。請確認 Operator 權限與 truth-chain API 狀態。",
"packets": {
"giteaInventory": {
"title": "Gitea 清冊負責人聲明",
"detail": "先收公開範圍 / 本地缺口、組織 / 使用者端點、110 相鄰範圍、標準負責人與舊版處置五題。"
},
"githubTarget": {
"title": "GitHub 目標負責人判定",
"detail": "逐專案庫確認 GitHub 目標、可見性、標準負責人;不能自動建立專案庫或變更可見性。"
},
"refTruth": {
"title": "分支 / 標籤真相來源負責人回覆",
"detail": "確認 main / dev 真相來源、棄用漂移、release tag 與 GitHub-only 分支 / 標籤參照;不能自動同步、刪除或強制推送。"
},
"workflowSecret": {
"title": "工作流程 / 機密名稱負責人回覆",
"detail": "只收工作流程、執行器、部署金鑰、分支保護、機密名稱與負責人中繼資料;不收機密明文值。"
}
},
"checks": {
"crossPacket": {
"label": "跨包驗收",
"detail": "10 個跨包檢查只做一致性檢查。"
},
"evidenceRouting": {
"label": "證據路由",
"detail": "6 條路由規則只分流補證、隔離或只讀更新。"
},
"displaySections": {
"label": "顯示區塊",
"detail": "8 個區塊固定 AwoooP 只讀呈現順序。"
},
"stateTransitions": {
"label": "狀態轉移",
"detail": "7 條規則只定義審查狀態語義,不執行。"
},
"reviewerChecklist": {
"label": "審查清單",
"detail": "9 個清單項目給人工審查者判讀。"
},
"reviewerOutcomes": {
"label": "審查結果",
"detail": "7 條結果分流只導向補證、隔離、拒收或等待後續閘門。"
}
}
},
"quality": {
"title": "自動化品質",
"subtitle": "最近 24 小時告警是否真正走到 AI 自動修復、驗證與學習回寫。",
"claimReady": "可宣稱完整閉環",
"claimBlocked": "不可宣稱完整閉環",
"claimReadyDetail": "所有告警都完成驗證閉環",
"claimBlockedDetail": "仍有告警缺少執行、驗證或學習記錄",
"unavailable": "無法讀取",
"loadFailed": "無法讀取自動化品質總覽。請確認操作員權限與真相鏈 API 狀態。",
"empty": "尚無可評估的告警品質資料。",
"yes": "是",
"no": "否",
@@ -3857,15 +3942,15 @@
},
"gates": {
"sourcePersisted": "來源已落庫",
"outboundRecorded": "Outbound 記錄",
"outboundRecorded": "外送記錄",
"evidenceCollected": "證據收集",
"mcpGatewayObserved": "MCP Gateway",
"mcpGatewayObserved": "MCP 閘道",
"approvalState": "審批狀態",
"executionRecorded": "執行記錄",
"autoRepairRecorded": "自動修復記錄",
"verificationRecorded": "驗證記錄",
"learningRecorded": "學習回寫",
"timelineRecorded": "Timeline 記錄"
"timelineRecorded": "時間軸記錄"
},
"gateStatuses": {
"failed": "失敗",
@@ -3874,7 +3959,7 @@
},
"metrics": {
"tenants": "租戶",
"tenantsDetail": "{active} 個啟用,{shadow} 個 shadow",
"tenantsDetail": "{active} 個啟用,{shadow} 個影子模式",
"runs": "操作執行",
"runsDetail": "執行狀態是非同步任務的唯一觀測入口",
"approvals": "待審批",
@@ -3893,13 +3978,13 @@
"approval": {
"title": "人工閘門",
"signal": "高風險待批准",
"owner": "負責SRE approve / reject",
"owner": "負責SRE 批准 / 拒絕",
"route": "流向:審批佇列"
},
"execute": {
"title": "自動執行",
"signal": "低風險可閉環",
"owner": "負責MCP Gateway 執行並稽核",
"owner": "負責MCP 閘道執行並稽核",
"route": "流向:執行狀態 / 稽核"
},
"manual": {
@@ -3912,21 +3997,21 @@
"lanes": {
"title": "飛輪鏈路",
"live": "已接線",
"mirror": "Mirror",
"providerName": "Provider 順序",
"providerDetail": "GCP-A Ollama -> GCP-B Ollama -> 111 Ollama -> OpenClaw/Nemo -> Gemini",
"mcpName": "MCP Gateway",
"mcpDetail": "MCP Gateway 先 mirror / wrap確認 audit 與 redaction 後才切成唯一閘門",
"channelName": "Channel Hub",
"channelDetail": "Telegram / LINE / Slack 先進 Channel Event,再逐步切換發送責任",
"approvalName": "Approval Plane",
"mirror": "鏡像",
"providerName": "模型供應順序",
"providerDetail": "GCP-A Ollama GCP-B Ollama 111 Ollama OpenClaw / Nemo Gemini",
"mcpName": "MCP 閘道",
"mcpDetail": "MCP 閘道先鏡像 / 包裝,確認稽核與脫敏後才切成唯一閘門",
"channelName": "通道中心",
"channelDetail": "Telegram / LINE / Slack 先進通道事件,再逐步切換發送責任",
"approvalName": "審批平面",
"approvalDetail": "執行狀態與審批平面共享同一條審批語義"
},
"next": {
"title": "下一步操作",
"item1": "查看執行監控與 provider fallback",
"item1": "查看執行監控與模型供應備援",
"item2": "處理等待審批的高風險操作",
"item3": "審查 Contract lifecycle",
"item3": "審查合約生命週期",
"item4": "查看 AwoooP 工作鏈路地圖"
}
},

View File

@@ -58,7 +58,7 @@ export default function AwoooPLayout({
return (
<AppLayout locale={params.locale} showBackground={false}>
<div className="min-h-[calc(100vh-116px)] bg-[#f7f5ee] border border-[#e0ddd4]">
<div className="min-h-[calc(100vh-116px)] w-[calc(100vw-48px)] max-w-full overflow-x-hidden border border-[#e0ddd4] bg-[#f7f5ee] md:w-full">
<div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-5 py-4">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-3">

View File

@@ -79,6 +79,29 @@ type GitHubPrimaryReadinessRef = {
tone: "good" | "warn" | "neutral";
};
type OwnerResponseValidationMetric = {
key: string;
value: string;
icon: typeof ShieldCheck;
tone: "good" | "warn" | "neutral";
};
type OwnerResponseValidationPacket = {
key: string;
lane: string;
templates: string;
received: string;
accepted: string;
rejected: string;
icon: typeof ShieldCheck;
};
type OwnerResponseValidationCheck = {
key: string;
value: string;
tone: "good" | "warn" | "neutral";
};
type QualityVerdict = {
verdict: string;
total: number;
@@ -183,6 +206,75 @@ const githubPrimaryReadinessBoundaries = [
"action_buttons_allowed=false",
];
const ownerResponseValidationMetrics: OwnerResponseValidationMetric[] = [
{ key: "packets", value: "4", icon: ListChecks, tone: "warn" },
{ key: "templates", value: "22", icon: FileText, tone: "neutral" },
{ key: "received", value: "0", icon: Lock, tone: "warn" },
{ key: "accepted", value: "0", icon: ShieldCheck, tone: "warn" },
{ key: "rejected", value: "0", icon: TriangleAlert, tone: "neutral" },
];
const ownerResponseValidationPackets: OwnerResponseValidationPacket[] = [
{
key: "giteaInventory",
lane: "S4.9",
templates: "5",
received: "0",
accepted: "0",
rejected: "0",
icon: GitBranch,
},
{
key: "githubTarget",
lane: "S4.10",
templates: "7",
received: "0",
accepted: "0",
rejected: "0",
icon: ShieldCheck,
},
{
key: "refTruth",
lane: "S4.11",
templates: "5",
received: "0",
accepted: "0",
rejected: "0",
icon: Waypoints,
},
{
key: "workflowSecret",
lane: "S4.12",
templates: "5",
received: "0",
accepted: "0",
rejected: "0",
icon: SearchCheck,
},
];
const ownerResponseValidationChecks: OwnerResponseValidationCheck[] = [
{ key: "crossPacket", value: "10", tone: "warn" },
{ key: "evidenceRouting", value: "6", tone: "neutral" },
{ key: "displaySections", value: "8", tone: "neutral" },
{ key: "stateTransitions", value: "7", tone: "neutral" },
{ key: "reviewerChecklist", value: "9", tone: "neutral" },
{ key: "reviewerOutcomes", value: "7", tone: "neutral" },
];
const ownerResponseValidationBoundaries = [
"owner_response_validation_received_count=0",
"owner_response_validation_accepted_count=0",
"owner_response_validation_rejected_count=0",
"repo_creation_authorized=false",
"refs_sync_authorized=false",
"workflow_modification_authorized=false",
"secret_value_collection_allowed=false",
"github_primary_switch_authorized=false",
"runtime_execution_authorized=false",
"action_buttons_allowed=false",
];
function numberValue(value: unknown): number {
return typeof value === "number" && Number.isFinite(value) ? value : 0;
}
@@ -606,6 +698,149 @@ function GitHubPrimaryReadinessHomePanel() {
);
}
function OwnerResponseValidationRollupPanel() {
const t = useTranslations("awooop.home.ownerResponseValidation");
return (
<section className="border border-[#e0ddd4] bg-white">
<div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
<div className="flex items-start gap-2">
<ListChecks className="mt-0.5 h-4 w-4 text-[#d97757]" aria-hidden="true" />
<div>
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
<p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
</div>
</div>
<div className="flex flex-wrap items-center gap-2">
<span className="inline-flex border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 text-xs font-semibold text-[#8a5a08]">
{t("badge")}
</span>
<Link
href="/iwooos"
className="inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-1.5 text-xs font-semibold text-[#141413] hover:border-[#d97757]"
>
{t("openIwooos")}
<ArrowRight className="h-3.5 w-3.5 text-[#77736a]" aria-hidden="true" />
</Link>
</div>
</div>
<div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-5">
{ownerResponseValidationMetrics.map((metric) => {
const Icon = metric.icon;
return (
<div key={metric.key} className="min-h-[124px] bg-white px-4 py-3">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-xs font-semibold text-[#77736a]">
{t(`metrics.${metric.key}.label` as never)}
</p>
<p className="mt-2 font-mono text-2xl font-semibold leading-none text-[#141413]">
{metric.value}
</p>
</div>
<span
className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center border",
metric.tone === "good" && "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]",
metric.tone === "warn" && "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]",
metric.tone === "neutral" && "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]"
)}
>
<Icon className="h-4 w-4" aria-hidden="true" />
</span>
</div>
<p className="mt-3 text-xs leading-5 text-[#5f5b52]">
{t(`metrics.${metric.key}.detail` as never)}
</p>
</div>
);
})}
</div>
<div className="grid min-w-0 gap-4 p-4 xl:grid-cols-[1.25fr_0.75fr]">
<div className="min-w-0 border border-[#e0ddd4] bg-white">
<div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs font-semibold text-[#141413]">
{t("packetsTitle")}
</div>
<div className="divide-y divide-[#eee9dd]">
{ownerResponseValidationPackets.map((packet) => {
const Icon = packet.icon;
return (
<div key={packet.key} className="grid min-w-0 gap-3 px-4 py-3 lg:grid-cols-[minmax(0,1fr)_240px]">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<Icon className="h-4 w-4 text-[#d97757]" aria-hidden="true" />
<span className="border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 font-mono text-xs font-semibold text-[#8a5a08]">
{packet.lane}
</span>
<p className="text-sm font-semibold text-[#141413]">
{t(`packets.${packet.key}.title` as never)}
</p>
</div>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">
{t(`packets.${packet.key}.detail` as never)}
</p>
</div>
<div className="grid min-w-0 grid-cols-4 gap-px bg-[#e0ddd4] text-center">
{[
{ label: t("fields.templates"), value: packet.templates },
{ label: t("fields.received"), value: packet.received },
{ label: t("fields.accepted"), value: packet.accepted },
{ label: t("fields.rejected"), value: packet.rejected },
].map((item) => (
<div key={item.label} className="bg-white px-2 py-2">
<p className="text-[10px] font-semibold text-[#77736a]">{item.label}</p>
<p className="mt-1 font-mono text-base font-semibold text-[#141413]">
{item.value}
</p>
</div>
))}
</div>
</div>
);
})}
</div>
</div>
<div className="grid min-w-0 gap-4">
<div className="min-w-0 border border-[#e0ddd4] bg-white">
<div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs font-semibold text-[#141413]">
{t("validationTitle")}
</div>
<div className="grid min-w-0 gap-px bg-[#e0ddd4] sm:grid-cols-2">
{ownerResponseValidationChecks.map((check) => (
<div key={check.key} className="min-h-[88px] bg-white px-4 py-3">
<p className="text-xs font-semibold text-[#77736a]">
{t(`checks.${check.key}.label` as never)}
</p>
<p className="mt-2 font-mono text-2xl font-semibold leading-none text-[#141413]">
{check.value}
</p>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">
{t(`checks.${check.key}.detail` as never)}
</p>
</div>
))}
</div>
</div>
<div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
<p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
<p className="mt-2 break-words text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
<div className="mt-4 grid gap-2 break-all font-mono text-xs text-[#141413]">
{ownerResponseValidationBoundaries.map((boundary) => (
<span key={boundary}>{boundary}</span>
))}
</div>
</div>
</div>
</div>
</section>
);
}
function AutomationQualityPanel({
summary,
error,
@@ -939,6 +1174,8 @@ export default function AwoooPPage() {
<GitHubPrimaryReadinessHomePanel />
<OwnerResponseValidationRollupPanel />
<section className="border border-[#e0ddd4] bg-[#e0ddd4]">
<div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
<div className="flex items-center gap-2">