diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 25c468067..b0cdf58ef 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -9182,16 +9182,21 @@ }, "managerSituation": { "eyebrow": "Manager overview", - "title": "StockPlatform P0", - "subtitle": "Blocker, impact, and next action are pinned to the first screen.", + "title": "P0 manager overview", + "titles": { + "reboot": "P0-006 reboot recovery SLO", + "stockplatform": "StockPlatform P0" + }, + "subtitle": "The active P0, blocker, impact, and next action are pinned to the first screen.", "loading": "Reading production readback.", - "head": "Deployed source", + "head": "Readiness / deployed", "decision": "Decision", "decisionValue": "Fix P0, no side lane", "decisionParallel": "P0 waits for data; advance {id}", "blockingSources": "Blocking sources", "noSourceNames": "Waiting for source contract readback", "states": { + "rebootSlo": "10-minute recovery SLO not proven", "sourceContract": "Source contract blocked", "preflight": "Recovery preflight blocked", "publicApi": "Public API blocked", @@ -9206,18 +9211,25 @@ "impact": { "label": "Impact", "value": "Public API not green", - "detail": "Source trust is not sufficient." + "detail": "Source trust is not sufficient.", + "rebootValue": "Reboot recovery is not closed", + "rebootDetail": "Fresh reboot window, service green, and backup readback are not all true." }, "evidence": { "label": "Evidence", "value": "{count} sources failed", "receipted": "receipt provided", - "missing": "receipt missing" + "missing": "receipt missing", + "rebootValue": "{count} SLO blockers", + "rebootReceipted": "timer/source readback exists", + "rebootMissing": "waiting for live SLO readback" }, "next": { "label": "Next step", "value": "Repair source contract", - "detail": "Run verifier immediately after repair." + "detail": "Run verifier immediately after repair.", + "rebootValue": "Collect public readback", + "rebootDetail": "Collect service data backup readback first; {count} backup blockers remain." }, "parallel": { "label": "Parallel mainline", @@ -13452,6 +13464,24 @@ "noSecret": "不讀 secret", "noHostWrite": "不寫主機", "postcheck": "postcheck 先行" + }, + "executionLabel": "runtime controlled apply chain", + "execution": { + "preflight": { + "label": "Preflight", + "value": "{ready} ready / {targets} targets", + "detail": "diff {diff}, check {check}, rollback {rollback}, verifier {verifier}" + }, + "review": { + "label": "Review packet", + "value": "{accepted}/{ready} accepted", + "detail": "supplement {supplement}; runtime gate {runtime}" + }, + "dryRun": { + "label": "Allowlisted dry-run", + "value": "{accepted}/{result} result", + "detail": "check-mode {check}, postcheck {verifier}, host write {writes}" + } } }, "commandRail": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 1485d76fe..2cf118967 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -9182,16 +9182,21 @@ }, "managerSituation": { "eyebrow": "管理者總覽", - "title": "StockPlatform P0", - "subtitle": "卡點、影響、下一步先放第一屏。", + "title": "P0 管理者總覽", + "titles": { + "reboot": "P0-006 重啟恢復 SLO", + "stockplatform": "StockPlatform P0" + }, + "subtitle": "目前 P0、卡點、影響、下一步先放第一屏。", "loading": "正在讀取正式 readback。", - "head": "正式部署", + "head": "Readiness / 部署", "decision": "決策", "decisionValue": "先修 P0,不開支線", "decisionParallel": "P0 等資料;並行推進 {id}", "blockingSources": "阻塞來源", "noSourceNames": "等待 source contract readback", "states": { + "rebootSlo": "10 分鐘恢復 SLO 未證明", "sourceContract": "來源合約卡住", "preflight": "修復預檢卡住", "publicApi": "公開 API 卡住", @@ -9206,18 +9211,25 @@ "impact": { "label": "影響", "value": "公開 API 未綠燈", - "detail": "資料來源可信度不足" + "detail": "資料來源可信度不足", + "rebootValue": "重啟後恢復未閉環", + "rebootDetail": "fresh reboot window、service green 與 backup readback 尚未同時成立" }, "evidence": { "label": "證據", "value": "{count} 個來源未通過", "receipted": "receipt 已收件", - "missing": "receipt 未到" + "missing": "receipt 未到", + "rebootValue": "{count} 個 SLO blocker", + "rebootReceipted": "timer/source readback 已存在", + "rebootMissing": "等待 live SLO readback" }, "next": { "label": "下一步", "value": "補來源合約", - "detail": "修完直接跑 verifier" + "detail": "修完直接跑 verifier", + "rebootValue": "補 public readback", + "rebootDetail": "先收 service data backup readback;目前 {count} 個 backup blocker" }, "parallel": { "label": "並行主線", @@ -13452,6 +13464,24 @@ "noSecret": "不讀 secret", "noHostWrite": "不寫主機", "postcheck": "postcheck 先行" + }, + "executionLabel": "runtime controlled apply 鏈", + "execution": { + "preflight": { + "label": "Preflight", + "value": "{ready} ready / {targets} targets", + "detail": "diff {diff}、check {check}、rollback {rollback}、verifier {verifier}" + }, + "review": { + "label": "Review packet", + "value": "{accepted}/{ready} accepted", + "detail": "supplement {supplement};runtime gate {runtime}" + }, + "dryRun": { + "label": "Allowlisted dry-run", + "value": "{accepted}/{result} result", + "detail": "check-mode {check}、postcheck {verifier}、host write {writes}" + } } }, "commandRail": { diff --git a/apps/web/src/app/[locale]/awooop/work-items/page.tsx b/apps/web/src/app/[locale]/awooop/work-items/page.tsx index 2d912f84f..52c54e114 100644 --- a/apps/web/src/app/[locale]/awooop/work-items/page.tsx +++ b/apps/web/src/app/[locale]/awooop/work-items/page.tsx @@ -1087,6 +1087,9 @@ type PriorityWorkOrderResponse = { } | null; summary?: { active_p0_state?: string | null; + active_p0_workplan_id?: string | null; + active_p0_readiness_percent?: number | null; + active_p0_live_active_blockers?: string[] | null; next_executable_mainline_workplan_id?: string | null; next_executable_mainline_state?: string | null; parallel_mainline_execution_enabled?: boolean | null; @@ -1145,6 +1148,11 @@ type PriorityWorkOrderResponse = { controlled_cd_lane_live_gitea_actions_active_process_count?: number | null; controlled_cd_lane_live_metric_blocker_count?: number | null; controlled_cd_lane_live_metric_blockers?: string[] | null; + controlled_service_data_backup_blocker_count?: number | null; + controlled_service_data_backup_can_clear_blockers?: boolean | null; + controlled_service_data_backup_next_safe_action?: string | null; + windows99_verify_collection_blocker_count?: number | null; + windows99_verify_collection_blockers?: string[] | null; ai_loop_log_source_grouping_key_count?: number | null; ai_loop_log_source_grouping_keys?: string[] | null; ai_loop_log_source_tagging_contract_count?: number | null; @@ -1168,7 +1176,21 @@ type PriorityWorkOrderResponse = { stockplatform_source_contract_non_ok_source_count?: number | null; } | null; in_progress_or_blocked_in_priority_order?: Array<{ + id?: string | null; + title?: string | null; + status?: string | null; + next_action?: string | null; evidence?: { + active_blockers?: string[] | null; + live_slo_metric_present?: boolean | null; + live_slo_service_last_result?: string | null; + live_slo_timer_active?: boolean | null; + live_slo_timer_enabled?: boolean | null; + latest_live_slo_artifact?: string | null; + controlled_service_data_backup_blocker_count?: number | null; + controlled_service_data_backup_can_clear_blockers?: boolean | null; + windows99_verify_collection_blockers?: string[] | null; + drill_preflight_blocker_count?: number | null; ai_loop_current_blocker_log_source_tags?: AiLoopLogSourceTag[] | null; ai_loop_log_source_tagging_contract?: AiLoopLogSourceContract[] | null; ai_loop_current_blocker_resolved_by_production_readback?: boolean | null; @@ -8769,8 +8791,6 @@ function stockplatformCompactTone(value: string | boolean | null | undefined) { const STOCKPLATFORM_SOURCE_CONTRACT_FALLBACK_SOURCES = [ "raw.source_quality_observations.unit_sanity", - "core.margin_short_daily", - "ai.recommendations", ] as const; function shortSha(value: string | null | undefined) { @@ -8779,6 +8799,7 @@ function shortSha(value: string | null | undefined) { function stockplatformManagerStateKey(value: string | null | undefined) { const state = String(value ?? ""); + if (state.includes("reboot")) return "rebootSlo"; if (state.includes("source_contract")) return "sourceContract"; if (state.includes("preflight")) return "preflight"; if (state.includes("public_api")) return "publicApi"; @@ -8795,14 +8816,24 @@ function ManagerSituationBoard({ }) { const t = useTranslations("awooop.workItems.managerSituation"); const summary = priority?.summary; - const evidence = priority?.in_progress_or_blocked_in_priority_order?.find( + const activeState = + summary?.active_p0_state ?? + "blocked_reboot_auto_recovery_slo_not_ready"; + const activeWorkplan = + summary?.active_p0_workplan_id ?? + summary?.next_executable_mainline_workplan_id ?? + "P0-006"; + const activeItem = priority?.in_progress_or_blocked_in_priority_order?.find( + (item) => + item.id === activeWorkplan || + item.status === activeState || + item.status?.includes("reboot") + ); + const evidence = activeItem?.evidence ?? priority?.in_progress_or_blocked_in_priority_order?.find( (item) => item.evidence?.stockplatform_source_contract_readback_status || item.evidence?.stockplatform_public_api_runtime_status )?.evidence; - const activeWorkplan = - summary?.next_executable_mainline_workplan_id ?? - "P0-006-STOCKPLATFORM-PUBLIC-API-CONTROLLED-RECOVERY-PREFLIGHT"; const parallelOverlay = priority?.mainline_parallel_execution; const parallelEnabled = summary?.parallel_mainline_execution_enabled === true || @@ -8819,12 +8850,25 @@ function ManagerSituationBoard({ summary?.parallel_mainline_retry_readback_at ?? parallelOverlay?.retry_readback_at ?? "--"; - const activeState = - summary?.active_p0_state ?? - "blocked_stockplatform_public_api_controlled_recovery_preflight"; const activeStateLabel = t( `states.${stockplatformManagerStateKey(activeState)}` as never ); + const isRebootP0 = activeState.includes("reboot"); + const boardTitle = isRebootP0 + ? t("titles.reboot") + : activeState.includes("stockplatform") + ? t("titles.stockplatform") + : t("title"); + const activeBlockers = + summary?.active_p0_live_active_blockers ?? + evidence?.active_blockers ?? + []; + const activeBlockerCount = activeBlockers.length; + const readinessPercent = summary?.active_p0_readiness_percent ?? null; + const rebootEvidenceReady = + evidence?.live_slo_metric_present === true && + evidence?.live_slo_timer_enabled === true && + evidence?.live_slo_timer_active === true; const sourceContractStatus = summary?.stockplatform_source_contract_readback_status ?? evidence?.stockplatform_source_contract_readback_status ?? @@ -8838,8 +8882,12 @@ function ManagerSituationBoard({ evidence?.stockplatform_source_contract_receipt_provided ?? true; const blockingSources = - evidence?.stockplatform_source_contract_blocking_sources?.slice(0, 3) ?? - STOCKPLATFORM_SOURCE_CONTRACT_FALLBACK_SOURCES.map((source) => ({ source })); + isRebootP0 + ? activeBlockers.slice(0, 4).map((source) => ({ source })) + : ( + evidence?.stockplatform_source_contract_blocking_sources?.slice(0, 3) ?? + STOCKPLATFORM_SOURCE_CONTRACT_FALLBACK_SOURCES.map((source) => ({ source })) + ); const sourceNames = blockingSources .map((source) => source.source) .filter(Boolean) @@ -8862,24 +8910,32 @@ function ManagerSituationBoard({ key: "impact", icon: Database, label: t("cards.impact.label"), - value: t("cards.impact.value"), - detail: t("cards.impact.detail"), + value: isRebootP0 ? t("cards.impact.rebootValue") : t("cards.impact.value"), + detail: isRebootP0 ? t("cards.impact.rebootDetail") : t("cards.impact.detail"), tone: "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]", }, { key: "evidence", icon: SearchCheck, label: t("cards.evidence.label"), - value: t("cards.evidence.value", { count: nonOkSourceCount }), - detail: receiptProvided ? t("cards.evidence.receipted") : t("cards.evidence.missing"), - tone: stockplatformCompactTone(sourceContractStatus), + value: isRebootP0 + ? t("cards.evidence.rebootValue", { count: activeBlockerCount }) + : t("cards.evidence.value", { count: nonOkSourceCount }), + detail: isRebootP0 + ? (rebootEvidenceReady ? t("cards.evidence.rebootReceipted") : t("cards.evidence.rebootMissing")) + : receiptProvided ? t("cards.evidence.receipted") : t("cards.evidence.missing"), + tone: isRebootP0 ? stockplatformCompactTone(activeState) : stockplatformCompactTone(sourceContractStatus), }, { key: "next", icon: ArrowRight, label: t("cards.next.label"), - value: t("cards.next.value"), - detail: t("cards.next.detail"), + value: isRebootP0 ? t("cards.next.rebootValue") : t("cards.next.value"), + detail: isRebootP0 + ? t("cards.next.rebootDetail", { + count: summary?.controlled_service_data_backup_blocker_count ?? evidence?.controlled_service_data_backup_blocker_count ?? 0, + }) + : t("cards.next.detail"), tone: "border-[#cbd7bf] bg-[#f4faef] text-[#3d6b24]", }, { @@ -8908,7 +8964,7 @@ function ManagerSituationBoard({ {t("eyebrow")}
{loading ? t("loading") : t("subtitle")} @@ -8919,7 +8975,7 @@ function ManagerSituationBoard({ {t("head")}