Files
awoooi/docs/runbooks/REBOOT-RECOVERY-SOP.md

71 KiB
Raw Blame History

AWOOOI 重開機恢復 SOP

版本: v5.31 最後更新: 2026-07-11 (台北時間) 更新者: Codex 觸發事件: 2026-07-11 真實全主機 reboot drill、late recovery 與 Agent99/VMware/runtime 閉環


目錄

  1. 架構概覽與依賴圖
  2. 自動化腳本狀態
  3. 正常重啟流程 (計劃性維護)
  4. 異常重啟流程 (緊急恢復)
  5. 各主機詳細啟動序列
  6. 常見故障排查手冊
  7. E2E 驗證腳本

架構概覽與依賴圖

2026-07-11 真實 reboot drillSLA breach 與 late recovery 真相

本輪不是模擬。重啟前 Agent99 runtime 7cf83f7f59a5d72ce6c303f59c144bd5bf8566df14/14 matched、核心 task 9/9production-principal Recover baseline 已通過 full-SOP coordinator且正確標示 scope=service_recoveryrebootSloClaimed=false。七主機與六核心路由在 observer 開始時均可達。

真實重啟後,2026-07-11T08:00:07Z 五台 VMware guests 與六核心路由離線T+10 08:10:07Z 時服務仍未恢復,因此本輪 SLA 明確失敗。後續交叉比對 Windows boot time 證明 99 實際於 16:08:03+08:00 開機;舊 observer 將 host probe 從 nc 改成 curl telnet://TCP 已連線仍等待 SSH payload 到 timeout導致大量 host-down false negative。這些 host samples 不再作為「99 沒有回來」的證據route-down samples 與 T+10 breach 仍有效;修正版 observer 已改用 Python socket.create_connection

真正延遲鏈是Agent99 Startup-Recovery 於 16:08:57 啟動,卻被原本 PT10M task limit 終止boot event 又在 terminal recovery 前被消耗。VMware autostart task 直到 16:26:48 才執行188 PostgreSQL 到 16:40:05 才 ready120/121 K3s 在此之前持續等待 192.168.0.188:5432。120 與 121 又分別在 16:49:3216:56:00 收到 Windows 99 VMware VIX SoftReboot;這不是 guest crash也不是 unattended-upgrades。VMware process audit 未啟用,不能歸屬 actor任何後續 reset/stop/suspend 都必須有同一 trace、before evidence、verifier 與 Telegram/KM receipt。

服務於 16:59 後恢復SignOz upstream bridge 受控修復後 public route 也回 200。17:35 production-principal Agent99 Recover10.3 秒完成 service-recovery七主機、VMware、Harbor、K3s、service/data/freshness/backup/188 hygiene/full-SOP coordinator 全通過,且 rebootSloClaimed=false17:37 全部 23 個 public surfaces 為預期 2xx/3xx。機器可讀完整 receipt 在 docs/operations/agent99-full-host-reboot-drill-20260711.snapshot.json

因此正式 SOP 固定為三層,不能再把 99 本機排程當成完整自動化:

  1. L0 外部層99/LAN 之外):每 15 秒 public synthetic連續兩輪 outage quorum 後建立 durable incident執行繁中 Telegram down、外部 maintenance origin、具 verifier 的 99 out-of-band power。WOL 只可作第一個低風險嘗試,不是唯一電源路徑。
  2. L1 Agent99/VMware 層99 回線後由 L0 投遞同一 incidentAgent99 驗證 Windows boot、runtime manifest、tasks、VMware service、VMX、lock依序恢復並驗證 110/188/112/120/121。111 是獨立實體 Mac。
  3. L2 110 full-SOP 層110 回線後建立 fresh scorecard驗證七主機、service/data/freshness/backup、188 hygiene、edge/maintenance、VMware/update policy、版本與 callback。只有 blocker=0 且 can_claim_slo=true 才可撤維護頁與結案。

L0 source contract 是 scripts/reboot-recovery/external-l0-recovery-supervisor.pyawoooi-external-l0-recovery-supervisor.service/.timerops/reboot-recovery/external-l0-recovery-supervisor.example.json。Callback 只能位於 /usr/local/libexec/awoooi-l0 allowlist使用 direct exec 與 --event-file,禁止 arbitrary shellTelegram/token、maintenance provider 與電源憑證留在外部 host-local wrapper不寫入 repo/evidence。未部署外部 runtime、OOB power 與 maintenance callbacks前正式狀態是 slo_breached_recovered_late:目前服務正常,不代表下一次全斷可在 10 分鐘內自動恢復。

2026-07-11 P0 Cold-start 實機收旂

最新完成 artifact /home/wooo/reboot-recovery/reboot-auto-recovery-slo-20260711-172623 回報 GREEN_WITH_EVIDENCE_WARNINGS、readiness 87%、七主機 reachable、service/data/backup/post-start/188 hygiene 與 Windows99 VMware 5/5 皆綠。唯三 blockers 是 all_required_hosts_not_in_10_minute_reboot_windowfresh_all_host_reboot_event_missinghost_boot_observation_older_than_target_window;它們保留本輪逾時真相,只能由下一次真實全主機 reboot 的同一 10 分鐘 window 驗收,不能靠事後健康讀回清除。

  • 99 VMware required guest set 是 110/188/120/121/112。111 是 M1 Pro MacBook Local Ollama已用 110 public key + forced command 回傳 Darwin boot/uptime/Ollama status不授權 shell。舊版把 111 當 Windows99 VMX 的敘述依 live inventory 標記為 superseded。
  • 110 runner fail-closed authority 只能使用 flock + timeout + --ensure,不得每分鐘無條件 mask + daemon-reload。完成條件是 apply/reload count 為 0 且 PID 1 CPU 收旂。
  • edge fallback 只走 /usr/local/sbin/awoooi-edge-maintenance check|apply|rollback-latestcanonical/live SHA parity、backup、nginx -t、reload、public route verifier 缺一不可完成。/api/sentry-tunnel 必須在 generic /api/ 前且 proxy 到 web。
  • 111 host probe 只讀 boot_id=darwin_<epoch> / uptime / LaunchAgent / local OllamaUNKNOWN_UPTIME_HOSTS=[] 才可進 reboot-event detector。
  • SLO timer 使用 OnBootSec=2min + OnUnitInactiveSec=5min;禁止恢復 OnUnitActiveSec=2min,否則 2-3 分鐘 oneshot 會連續排程並製造 CPU / 告警噪音。
  • 188 production PG 由 k3s-postgres-recovery host-network container 管理host start.conf=manualawoooi-host188-hygiene reconcile 只安裝 startup source/unit、daemon-reload、reset stale failed state禁止產品 restart。startup 內 containerd/Docker metadata 刪除、kine write、ClawBot rebuild、188 legacy SignOz 均預設 fail-closed/opt-in。
  • 2026-07-10 Stock gap 來自 TWSE 颱風休市,不是 ingestion 中斷。交易日曆修正後 freshness/ingestion 皆 green不得對休市日無限重跑 ETL。

下一次 reboot drill 必須在 T+0 由 boot-id 變更自動觸發 Agent99/110 SLO laneT+10 前產生同一 run 的 VM power、host uptime、services/routes、Stock freshness、backup、Telegram lifecycle 與 KM writeback receipt。若任一主機不在 window不得宣稱 10 分鐘 SLA 完成。

2026-07-11 Agent99 full-SOP coordinator

舊版 Agent99 Recover 只驗證 vm_start / host_reachability / harbor_registry / k3s_workloads / public_routeslive evidence 曾在 10.4 秒寫入 withinSlo=true。這只能證明既有服務 baseline不能證明全主機 reboot SLOv5.28 起標記為 supersededfull_sop_scorecard 是必要 phase。

recoveryCoordinator 固定從 99 以專用 Agent99 SSH identity 讀 110 最新 /home/wooo/reboot-recovery/reboot-auto-recovery-slo-* 的 bounded summary不讀 raw log、.env、secret、session 或 backup contents。必要輸入是 summary.txthost-probe.txtpublic-maintenance-edge-fallback.txtwindows99-vmware-verify.txtscorecard.json 的 allowlisted fields。

一般告警觸發的服務恢復,至少要通過 7 host reachable、SERVICE_GREEN=1PRODUCT_DATA_GREEN=1、Stock freshness okBACKUP_CORE_GREEN=1、188 service/hygiene green、edge fallback ready、VMware ready、Windows Update policy ready、source controls 與 public fallback ready。此時 scope 只能是 service_recoveryTelegram 必須明示「沒有 fresh reboot event不宣稱全主機重啟 SLA」。

若 99 boot age 小於 10 分鐘或 boot identity 改變scope 強制為 full_host_rebootAgent99 最多等待 420 秒讓 110 的 OnBootSec=2min SLO lane 完成。除上述 baseline 外還必須同時符合artifact timestamp 新於本次 recovery start、fresh_reboot_window_observed=true、active blocker 0can_claim_all_services_recovered_within_target=true。任一缺口都要 fail-closedGet-AgentOutcomeContractfull_sop_coordinator_verified 不得通過。

部署前 gate 是PowerShell parse、Agent99 contract、synthetic fresh/blocked fixture、runtime staging hash部署後 gate 是:scripts/reboot-recovery/agent99-live-preflight.ps19/9 tasks、relay listener、queue zero、required evidence fresh、runtime manifest matched再由 production S4U principal 觸發 Recover。Administrator 直接跑 launcher 不能取代 production-principal verifier。

2026-07-11 20:09 final runtime receiptAgent99 已原子 promote 為 d0e364bfa42947190cf1e88d1d85623e23f84858deploy evidence C:\Wooo\Agent99\evidence\agent99-deploy-20260711-200939.json、rollback backup C:\Wooo\Agent99\deploy\backup-20260711-200939runtime manifest 14/14、mismatch 0。production-principal evidence C:\Wooo\Agent99\evidence\agent99-Recover-20260711-200320.json 顯示七個 phases 全部 ok,新增必要 phase host112_guest_readinessbefore/after verifier 均為 ready、applyAttempted=falsetransport 為 direct serializedrecovery completed、coordinator verifiedelapsed 44.6s,且正確維持 scope=service_recoveryrebootSloClaimed=false。SRE routing self-test 17/17、Telegram ingest self-test 16/16,後者不寫 alert、不送 Telegram。這是 service recovery closure不覆蓋原始 T+10 breach。

Windows 99 VMware task 已經由 scripts/reboot-recovery/windows99-vmware-autostart-controlled-apply.ps1 正式受控套用DryRun、Apply、Verify 同一 receipttask XML、舊 startup script、Windows Update policy 與 service start modes 都有 rollback。Evidence C:\Wooo\Agent99\evidence\windows99-vmware-autostart-apply-20260711-173505.json 回報 pre/post VMX process 都是 5、running guest rows 5、process-aware duplicate-start guard true、沒有 host reboot、沒有 VM power change、沒有 secret read。這才是 Agent99 與重啟 SOP 的 runtime 整合證據;仍不取代下一次 600 秒 E2E drill。

112 Kali 真正開機完成 Gate

112 一直存在於 Windows99 required VM inventory、host probe 與 reboot event required host set本次事故暴露的缺陷是舊流程只用 VMX process、Ping、SSH port 或 node-exporter 判定「已開機」,沒有驗證 Kali 的圖形登入與安全服務。這會讓 112 實際以 multi-user.target 無 GUI 啟動、LightDM 未執行且 Wazuh Indexer 開機逾時時仍被錯誤判成綠燈。另一個獨立現象是 SYSTEM principal 以 vmrun ... nogui 啟動的 VMX 不會出現在 Administrator 的 VMware Workstation sessionGUI 可能顯示 Powered off;在 VMX process 與 guest boot identity 已存在時,禁止因此再次按 Power on避免 exclusive lock 與重複啟動。

112 的固定完成鏈改為:VMX process -> guest boot_id/uptime -> SSH forced-command readback -> systemd running -> graphical.target -> LightDM/display-manager -> Xorg -> open-vm-tools -> Wazuh Indexer/Manager/Dashboard/Filebeat -> recovery timer -> Console-readyscripts/reboot-recovery/host112-guest-readiness.sh 提供 no-secret --check 與 allowlisted --applyapply 只可補起 graphical target、LightDM、VMware Tools以及在開機 210 秒後、600 秒 cooldown 內重試一次 Wazuh Indexer。awoooi-host112-guest-recovery.timer 於開機 20 秒後開始、每 60 秒檢查;不得 reboot host、reset/power cycle VM、修改 firewall、讀取 secret 或執行資料庫寫入。

110 到 112 使用來源限制、restrict 與 forced command 的既有公鑰,只能執行 /usr/local/sbin/awoooi-host112-guest-readiness --check,不能取得 shell 或 forwarding。Host probe 必須輸出 console_ready=1services_ready=1recovery_timer_ready=1guest_ready=1;任何一項缺失都建立具名 host112_* blocker阻止 full-host recovery 與 maintenance withdrawal。Prometheus 固定輸出 awoooi_host112_guest_readback_presentawoooi_host112_console_readyawoooi_host112_services_readyawoooi_host112_recovery_timer_readyawoooi_host112_guest_readyAgent99 收到狀態變更後執行受控修復並以同一 incident 回報 verifier 結果。

2026-07-11 runtime closureinstaller runs host112-guest-recovery-20260711T193137+0800-35698host112-guest-recovery-20260711T195449+0800-43505 已完成備份、受限公鑰、exact-command sudo、timer 與 durable rollback installer未 reboot、未改 VM power、未讀 secret。110 artifact /home/wooo/reboot-recovery/reboot-auto-recovery-slo-20260711-200338 讀回 112 systemd=running、Console/Wazuh/timer/guest 1/1/1/1、五項 Prometheus gauges 5/5host112_* blocker=0。兩條 112 告警規則 health 2/2 ok 且 healthy state 為 inactivesource/canonical/active/runtime rule SHA 均為 86fd0e56cb7633da2a5a09960b8bf2dd61ee917c55072b5a16ba68577e8379cc。Windows99 verifier 同輪讀到 VM_PROCESS alias=112 process_id=22288 session_id=0 owner=NT_AUTHORITY\SYSTEM ui_truth=runtime_running_gui_session_isolated,因此 operator power truth 固定信任 VMX process + guest readiness不信任跨 principal 的互動式 VMware UI。Agent99 Recover 也已把 112 納入必要 phase 並完成 production-principal verifier完整 receipt 見 docs/operations/host112-guest-recovery-20260711.snapshot.json。Agent99 tests 49 passed、reboot-recovery tests 142 passed。目前 scorecard 僅保留 all_required_hosts_not_in_10_minute_reboot_windowfresh_all_host_reboot_event_missinghost_boot_observation_older_than_target_window;它們只能由下一次真實全主機 600 秒 drill 關閉。

2026-07-11 20:25 Agent99 false-green closureWindows runtime 已原子部署 06509e071c8b7c538feb112e4e4774ee22abf7d1deploy receipt agent99-deploy-20260711-202021.json、rollback backup-20260711-202021、manifest 14/14 matched。新版 preflight 為 tasks 9/9、required evidence fresh/usable 7/7、parse/content failure 0。production-principal run agent99-recovery-20260711-202159-3404b5b3 在 42.9 秒完成 5/5 VM、5/5 host、5/5 public 與七個 phaseTG sent=1visualSent=1,實際圖卡 agent99-card-recovery_slo_result-20260711-202159.png 為 1200×760 phase timeline下一輪同狀態以 dedupe_window 抑制且留下 receipt。這關閉 Agent99 可見性假綠,不改寫原始全主機 T+10 breach。

2026-07-10 P0 Agent99 Transport / Verified Remediation 覆蓋

99 的 Agent99 是全主機恢復控制節點。Windows 開機後由既有 Agent99 scheduled tasks 啟動;Status 讀到 boot identity 變更時,只能用 single-flight queue 觸發一次 Recover,並以 10 分鐘 cooldown 避免併發恢復。每次執行必須寫入 bootStaterecoveryTriggerrecoveryCoordinatorrecoverySlo evidence。只有實際全主機重啟事件、七主機 reachability、必要服務、public routes、資料 freshness、備份、edge fallback、VMware/Windows policy 與 188 hygiene 全部在同一個 10 分鐘 window 通過,才可宣稱 reboot recovery SLO 達標。

Agent99 SSH transport 使用 99 本機專用 Ed25519 identity C:\Wooo\Agent99\keys\agent99_ed25519private key 不得輸出、複製到 evidence、Telegram 或 repo。只允許將 public key 以 from="192.168.0.99",restrict 授權到 110 wooo 與 112 kali。固定 route map 為 110 / 112 direct120 / 121 / 188 優先經 110 jump禁止以共用密碼或任意 interactive shell 取代。Runtime 必須由 agent99-deploy.ps1 經 parse、contract、synthetic、staging、backup、atomic promote 與 rollback gate 部署,runtime-manifest.json.sourceRevision 必須等於 Gitea commit SHA。

所有 SSH command 都必須 bounded timeout。Timeout 時先用 taskkill /T 終止 process tree再確認 process 是否仍存活;Perf / LoadShed controlled apply 執行前會清理只符合以下全部條件的 stale clientAgent99 allowlisted target、BatchMode=yes、沒有 -N/-L/-R/-D tunnel、超過 15 分鐘且 parent 已消失,或超過 60 分鐘 hard limit。guard 不記錄 command line不碰互動式 SSH 或 tunnel結果寫入 sshProcessGuard evidence。

Agent99 的 Heartbeat、Performance、手動 Status 或告警修復可能由不同 Windows process 同時啟動。所有 Invoke-SshText 必須先取得 C:\Wooo\Agent99\state\ssh-transport.lock 的 exclusive file handle跨 scheduled task process 與 RDP operator session 一次只允許一條 Agent99 SSH command程序結束時由 OS 自動釋放 handle。預設最多等待 90 秒,逾時回 ssh_transport_lock_timeout,不得再開新 client。若同輪五主機 ping 全通,但 Harbor、AWOOOI 與所有 performance readback 同時空白,優先判定為 transport contention必須等序列化後重驗不得宣稱所有服務同時故障。

99 的正式 Agent99 scheduled tasks 目前使用本機 WOOO 帳號的 S4U principal專用 private key ACL 不授權 RDP 的 Administrator。因此 operator 直接執行 agent99-run.ps1 若出現 Load key ... Permission denied,只能判定為 execution-identity mismatch不得判定五台主機或服務故障也不得為了測試放寬 private-key ACL。正式 verifier 必須用 schtasks /run /tn Wooo-Agent99-HeartbeatWooo-Agent99-Performance-Guard 走既有 principalevidence 必須包含 transportSerializedtransportLockWaitMs。長駐 Wooo-Agent99-SRE-Alert-Relay 若 task 為 Running/ok,不得因 start evidence 超過 1440 分鐘就製造 freshness warning應記錄 running_task_supersedes_stale_start_evidence

效能修復不得以 command exit code 取代 post-verifier。只要 action 配置 verifier成功判定完全由 verifier 決定verifier 失敗必須記為 failed僅建立 10 分鐘 failure backoff不得建立 success cooldown。policy 變更必須提升 policyVersion,由 deployer migration 更新 99 live config避免舊 command 或 marker 繼續造成 false green。

本輪 live receiptagent99-load-shed-marker-correction.json 已封存 188 舊 false-success markeragent99-stale-ssh-cleanup-v2.json 已受控終止 7 個逾時 orphan SSH clientagent99-Perf-20260710-224454.json 顯示 110、112、120、121、188 全部 readback OKroute 分別為 direct、direct、via110、via110、via110。110 load/core 0.60、disk 84%188 load/core 0.18、disk 由 90% 降至 88%。這證明 transport、效能讀回與 verifier 修復 lane 已恢復,不等於已完成下一次實際全主機 cold-start 的 10 分鐘 SLA 驗收。

2026-07-11 production-principal concurrency receipt同時觸發 Heartbeat 與 Performance Guard 後,agent99-Status-20260711-004148.json 顯示五台 ping=true、AWOOOI coreHealthy=true / redisUp=true、Harbor registryHealthy=true / deployReady=trueagent99-Perf-20260711-004149.json 顯示五台 severity=ok110 / 112 / 120 / 121 / 188 load/core 為 0.54 / 0.01 / 0.06 / 0.01 / 0.11disk 為 84 / 53 / 49 / 27 / 89%。同輪 public routes 全部 200。這是排程身份與並行 readback closure仍不得取代下一次真實全主機重啟的 10 分鐘 SLA drill。

2026-07-10 P0 備份/Gitea 自動驗證覆蓋

每次 host reboot 後,備份 lane 必須依序執行 /backup/scripts/backup-status.sh --no-notify/backup/scripts/verify-gitea-backup.sh --no-notify,再由 110 的每日排程執行 /backup/scripts/gitea-bundle-backup-sync-188.sh。最後讀回 110/188 backup_health.prom、Gitea restore status、bundle sync status、188 sample restore metric 與 Prometheus Backup/Gitea alerts不得只看檔案 mtime、HTTP 200 或命令 exit code。

本輪 live 驗證已證明110 13/13、188 4/4、core blocker 0Gitea full dump 為 6928031514 bytesCRC、DB/config、15/15 regular repo inventory digest 一致12/12 product private bundles 已從 110 local container 產生並完整同步 188remote SHA-256 12/12、sample clone/fsck 成功Velero missed weekly dry-run 已由 startingDeadlineSeconds=604800 自動 backfill 成功。20:17 drift guard 自動修復 read-only bind-mount inode drift 後source/canonical/active/runtime rule SHA 一致145 rules 已載入Backup/Gitea 非 inactive alerts 為空20:20 正式 cron 回 repaired=0 且 container ID/StartedAt 未變,穩態無重複 recreate。

Prometheus rules 部署不得用會置換 bind source inode 的 install / atomic rename 直接覆蓋 /home/wooo/monitoring/alerts.yml。正式 guard 會先 promtool canonical再以保留 host path 的方式更新 active若 container runtime SHA 仍不同,才用 /home/wooo/monitoring/docker-compose.yml 單獨 --no-deps --force-recreate prometheus 重新掛載TSDB volume 保留。post-verifier 必須同時通過 145 rules health、runtime SHA、required rules 與 active alert query失敗則還原舊 active file 並重建 Prometheus不得只看 reload HTTP 200。

失敗處置固定為 fail closedfull dump 或 bundle incomplete 不得更新 complete symlinkremote sync 不使用 deleterestore drill 只能在隔離暫存目錄;不得讀 raw backup contents、secret 或 private repo 名稱,不得 restore over production、prune 或刪遠端備份。Telegram 只在狀態改變或失敗時送一張繁中摘要卡,成功心跳維持每日一次。

2026-07-09 P0 AI Log Triage / Controlled Auto-Recovery 覆蓋

主機重啟後不得再靠人工逐台看 log 才判斷異常。固定第一步改為執行 scripts/reboot-recovery/ai-log-triage-auto-recovery.sh --apply;若只允許讀取,則用 --check,但 scorecard / 告警仍必須吃同一份 artifact。此 runner 會 bounded 收集 110 Docker / containerd / Harbor / Nginx、120 / 121 K3s events、188 edge Nginx / Docker / systemd、99 VMware no-secret readback 與 public route HTTP status然後輸出 findings.tsvactions.tsvsummary.txt

本輪 2026-07-09 16:23 orchestrator check evidence /tmp/awoooi-full-host-reboot-orchestrator-codex/20260709T082305Z 顯示 RECOVERY_BLOCKED_P0FINDING_COUNT=3FINDING_P0_COUNT=2P0 依序為 STOCK_UPSTREAM_NOT_READY host=110_188EDGE_502_UPSTREAM_REFUSED host=188_edge,另有 HOST188_POSTGRES_SYSTEMD_FAILED P2 hygiene。public route readback 為 AWOOOI health 200、AWOOOI web 307、Stock freshness 200、Gitea 200、registry /v2/ 401、Harbor 200;因此不得沿用稍早 Harbor 5000 refused / K3s ImagePullBackOff 舊 artifact 當作目前 truth。若後續 registry 再度不 readyK3s pod delete 只能被自動化標為 skipped_registry_not_ready,不得宣稱 502 已修復。

awoooi-reboot-auto-recovery-slo.service 必須設定 AI_LOG_TRIAGE_AUTO_RECOVERY_MODE=apply,並由 reboot-auto-recovery-slo-exporter.sh 在 host probe / readiness summary 前先跑 AI log triage。允許的 controlled apply 僅限110 Docker inactive 時 start、Harbor watchdog --repair-once / harbor-log-first recovery、registry ready 後只刪 ImagePullBackOff / ErrImagePull pods 讓 Kubernetes 重建、188 nginx/docker inactive 時 start。仍禁止 reboot、node drain、firewall cutover、DB restore/drop/truncate、Docker prune、secret/session/.env/raw-volume reads。

2026-07-03 18:19 P0-4 VMX Backup / Source Search 覆蓋

最新 via-110 no-secret locator 已成功收斂為 candidate_source_count=0source_locator_status=blocked_missing_expected_vmx_source_no_candidate_found,早先 candidate_source_count=6 / generic Ubuntu candidate 僅保留為歷史 receipt不再作為目前 relink 候選。docs/operations/windows99-vmx-source-locator-receipt.snapshot.json 已更新為 17:57 no-candidate truth。

新增 /api/v1/agents/windows99-vmx-source-backup-search-packagescripts/reboot-recovery/collect-windows99-vmx-source-backup-search.sh。此 package / collector 固定只做 filename / path-fingerprint 搜尋,不讀 VMX 內容、不輸出 raw path、不讀 secret、不寫遠端、不改 Windows、不啟停 VM、不重啟任何服務或主機。18:19 receipt120 / 121 / local 均未找到 verified 111 source99 alias 無 Linux backup host mapping110 / 188 / 112 SSH BatchMode 不可用;candidate_source_count=0blocked_host_count=4apply_allowed_by_this_package=false

P0-4 下一步固定為離線備份 inventory 或授權 console source path取得 verified source path 後才可建立 scoped relink dry-run + rollback + post-verifier不得猜 generic Ubuntu candidate、不得直接 relink、不得 restore、不得 power on VM、不得讀 Windows 密碼或 VMX 內容。

2026-07-03 17:34 P0-4 Verify Timeout 覆蓋

110→99 SSH public-key channel 可用via-110 locator 已成功收集且未讀 secret / 未寫 Windows / 未改 VM powerexpected_vmx_path_present_count=0discovery_root_present_count=2candidate_source_count=0source_locator_status=blocked_missing_expected_vmx_source_no_candidate_found。同輪 full VMware Verify 在 90 秒曾 timeout但 180 秒成功讀回 MISSING_VMX_ALIASES=111VMWARE_AUTOSTART_CONFIG_READY=0VMWARE_AUTOSTART_VERIFY_READY=0

SOP v5.19 起Windows99 remote verify 預設 timeout 使用 180 秒;仍屬 bounded no-secret verifier超過 180 秒 fail-closed。不得把 90 秒 timeout 當成 SSH channel 故障,不得因此偏離到 VM power / Windows service restart / host rebootP0-4 下一步仍是取得 111 既有 VMX source / verified backup path。

2026-07-03 17:18 P0-4 VMX Repair CLI 覆蓋

Gitea CD #4617 已完成 source 40713b2f8 投產deploy marker b85d574production deploy readback matched=truejob succeeded。production reboot SLO scorecard 已讀回 Windows99 default target 111 / 188 / 120 / 121 / 112,其中 missing_vmx_aliases=["111"]powered_off_aliases=["112","120","121","188","111"],舊 110 不得再當 Windows99 guest alias。

build-windows99-vmx-source-repair-package.py 是 no-secret / no-DB / check-mode 工具,必須能在工作站缺 DATABASE_URL 時輸出 windows99-vmx-source-repair-111 package這只表示 repair check-mode package ready不表示 111 VMX 已恢復。via-110 locator 若回 blocked_ssh_publickey_auth_missingssh_auth_probe_exit_status=124,固定視為 management-channel blocker。下一步是取得 111 既有 VMX source / verified backup / 授權 console candidate identity建立 scoped relink dry-run、rollback 與 post-verifier不得猜 generic Ubuntu candidate、不得直接 relink、不得 restore、不得 power on VM、不得讀 Windows 密碼。

2026-07-03 15:57 P0-4 Windows99 Task Run-State 覆蓋

Windows99 no-secret via-110 collector 已讀回 AWOOOI-Start-VMware-VMs scheduled taskpresent=1enabled=1state=Readytrigger_count=1action_count=1VMware service 與 Windows Update no-auto-reboot policy 也為 ready但新增 task detail 顯示 last_run_time=1999-11-30T00:00:00last_task_result=267011,等價於 0x41303,表示 task 尚未跑過 / 未在本輪 boot 觸發。2026-07-03 16:33 進一步確認舊 verifier default 把 110 誤列為 Windows99 guest最新 source-of-truth 改為 111 / 188 / 120 / 121 / 112,以對齊本輪 host probe 111 unreachable 與 99 VMware guest 需求。因此目前 P0-4 真 blocker 是 windows99_vmware_guest_power_not_readywindows99_vmware_autostart_task_never_ran,且 deployment 後必須用新版 collector 重新讀回 111。

SOP v5.17 起,windows99-vmware-autostart.ps1 -Mode Verify 必須輸出 VMWARE_AUTOSTART_TASK_DETAILVMWARE_AUTOSTART_TASK_ACTION110 textfile exporter 必須輸出 awoooi_windows99_vmware_autostart_task_start_script_presentawoooi_windows99_vmware_autostart_task_last_resultawoooi_windows99_vmware_autostart_task_never_ranproduction scorecard / API 必須把 windows99_vmware_autostart_task_never_ran 放進 active blockers 與 action matrix。固定下一步是執行已建立的 Windows99 VMware autostart check-mode package然後 rerun no-secret collector 與 reboot SLO scorecard不得直接 power on VM、重啟 Windows host / VMware service、修改 scheduled task、修改 registry、讀 Windows 密碼或讀 secret。

2026-07-03 15:35 P0-2 API Readback 覆蓋

110 textfile / Prometheus 已有 awoooi_public_maintenance_edge_fallback_ready{scope="public_routes"} 0 與 active blocker edge_public_maintenance_live_config_driftproduction API 必須把此 blocker 合併進 active_blockers。route probe 200 / route fallback ready 不能替代 edge Nginx fallback ready只有 edge_fallback_runtime_readback_present=trueedge_fallback_ready=true 才能清掉 edge drift。

本輪 source fix 將 public maintenance blockers 拆成 route-level 與 edge-level 兩組route readback present / route 0 raw 5xx 只清 route blockersedge blocker 必須由 edge readback green 才能清。這是 readback overlay 修正不授權讀密碼、Nginx reload、app restart、Docker / host restart、VM power change 或 DB / firewall 操作。

2026-07-03 15:13 P0-2 Runtime 覆蓋

110 SLO controlled install 已完成,awoooi-reboot-auto-recovery-slo.timerenabled/activeservice Result=successExecMainStatus=0。本輪只 stage SLO verifier source、啟動 verifier oneshot 與寫 textfile metric未重啟 Docker / Nginx / K3s / DB / firewall未讀 secret / token / .env / raw sessions / SQLite / auth。

installer v5.15 規定 payload 必須包含 ops/nginx。若缺少 ops/nginx/awoooi.wooo.work.conf110 runtime edge check 會在本地 source gate 先失敗成 local_nginx_conf_missing,導致無法讀到 188 live edge truth這是 verifier packaging bug不是 Nginx runtime 狀態。完成條件是 110 artifact 內 public-maintenance-edge-fallback.txt 進入遠端 readback且 blocker 必須是 live edge drift。

2026-07-03 15:13 live artifact /home/wooo/reboot-recovery/reboot-auto-recovery-slo-20260703-151219 已讀到 188 edgeREMOTE_CONF_READABLE=1LIVE_CONF_HAS_INTERCEPT=0LIVE_CONF_HAS_ERROR_PAGE_503=0LIVE_CONF_HAS_FALLBACK_HEADER=0LIVE_CONF_HAS_INTERNAL_LOCATION=0LIVE_CONF_HAS_API_VIP=1LIVE_CONF_HAS_WEB_VIP=1MAINTENANCE_FILE_PRESENT=0SUDO_N_READY=0EDGE_FALLBACK_READY=0BLOCKER edge_public_maintenance_live_config_drift。110 textfile 必須輸出 awoooi_public_maintenance_edge_fallback_ready{scope="public_routes"} 0 與 active blocker edge_public_maintenance_live_config_drift;目前 blocker count 為 8

此狀態仍不授權 --apply。P0-2 完成需要 passwordless sudo / privileged edge apply channel、live conf backup、maintenance file install、nginx -t、reload 與 public route header verifier 全綠,或完成外部 L1 cloud/CDN fallback decision record。SUDO_N_READY=0 時不得讀密碼、不得 reload Nginx、不得重啟 app / Docker / host。

2026-07-03 14:40 P0-2 Public Maintenance 現況覆蓋

最新 main 3ebeeeb4b 的 Gitea CD #4592 已推 deploy marker ee0da93production deploy readback matched、job succeededdeploy window 期間 AWOOOI API health 與 SLO route 曾回 raw 502 Bad Gateway,沒有 X-AWOOOI-FallbackRetry-After 或維護頁 body。後續 public route probe 自癒回 200,但 raw 502 exposure 仍必須列為 P0 public UX blocker。

live 188 edge check 的目前事實是:LIVE_CONF_HAS_INTERCEPT=0LIVE_CONF_HAS_ERROR_PAGE_503=0LIVE_CONF_HAS_FALLBACK_HEADER=0LIVE_CONF_HAS_INTERNAL_LOCATION=0MAINTENANCE_FILE_PRESENT=0SUDO_N_READY=0EDGE_FALLBACK_READY=0blocker 固定為 edge_public_maintenance_live_config_drift。此 blocker 不授權 app restart、Docker restart、host reboot 或讀密碼;只能先 public-maintenance-edge-fallback-apply.sh --check,具備 passwordless sudo 後才可進受控 --apply + backup + nginx -t + reload + public header verifier或走 L1 external static/CDN fallback decision record。

v5.14 起110 SLO exporter 必須把 edge check 合併到 public maintenance readback輸出 awoooi_public_maintenance_edge_fallback_ready{scope="public_routes"}production scorecard / API 必須在 routes 當下 200 但 edge fallback 未套用時,仍顯示 public_maintenance_fallback.ready=false 與 active blocker edge_public_maintenance_live_config_drift。Alertmanager 規則 PublicMaintenanceEdgeFallbackConfigDrift 必須對此 metric 告警,避免下一次 deploy / reboot raw 502 才由使用者發現。

2026-07-03 14:26 P0 現況覆蓋

Gitea CD #4589 已完成 source 33c391808 部署deploy marker 9f49651 chore(cd): deploy 33c3918 [skip ci] 已 fast-forward 回 gitea-ssh/mainpublic queue readback 顯示 current_main_cd_run_status=Successcurrent_main_cd_deploy_evidence_succeeded_from_log=truelatest_visible_cd_production_deploy_readback_matched_from_log=truelatest_visible_cd_job_succeeded_from_log=trueno_matching_online_runner_visible=false,且沒有 host pressure refusal。110 awoooi-reboot-auto-recovery-slo.service 最新 run 20260703-142122Result=successExecMainStatus=0textfile metric 顯示 awoooi_reboot_auto_recovery_slo_blocker_count=7awoooi_windows99_vmware_autostart_config_ready=1awoooi_windows99_vmware_windows_update_no_auto_reboot_ready=1awoooi_windows99_vmware_missing_vmx_alias 無 alias gaugepowered-off aliases 為 110 / 112 / 120 / 121 / 188

Production /api/v1/agents/reboot-auto-recovery-slo-scorecard 已與 runtime metric 對齊:status=blocked_reboot_auto_recovery_slo_not_readyactive_blocker_count=7runtime_metric_active_blocker_count=7runtime_metric_runtime_readback_added_blocker_count=0readiness_percent=67primary_blocker=reboot_event_required_host_unreachablecan_claim_all_services_recovered_within_target=falsewindows99_vmware_autostart_config_not_readywindows99_update_no_auto_reboot_policy_not_ready 已不得再列為目前 blocker若未來再次出現優先判定為 metric/API overlay regression不得轉成 Windows policy apply、service restart、VM power change 或 host reboot。

目前仍不得宣稱「全主機重啟後 10 分鐘內全部恢復」。剩餘 7 個 active blockers 固定為:

  • all_required_hosts_not_in_10_minute_reboot_window
  • fresh_all_host_reboot_event_missing
  • host_boot_observation_older_than_target_window
  • host_unreachable_after_reboot
  • host_uptime_unknown
  • reboot_event_required_host_unreachable
  • windows99_vmware_guest_power_not_ready

固定下一步:維持 110 timer / textfile / production scorecard readback優先補 fresh all-host reboot event / 10-minute window evidence / host reachability以及 Windows99 powered-off guest 的 check-mode package 與 post-verifier禁止讀 Windows 密碼、啟動或關閉 VM、host reboot、service restart、Docker / Nginx / K3s / DB / firewall restart、restore、prune、delete。

2026-07-03 14:10 P0 現況覆蓋

目前仍不得宣稱「全主機重啟後 10 分鐘內全部恢復」。Gitea CD #4587 已完成 source 30c89a0 部署並推 deploy marker 4da6dda110 上 awoooi-reboot-auto-recovery-slo.timerenabled/active,最新 textfile runtime metric 為 active_blocker_count=7primary blocker reboot_event_required_host_unreachablecan_claim_all_services_recovered_within_target=false。7 個 runtime active blockers 固定為:

  • all_required_hosts_not_in_10_minute_reboot_window
  • fresh_all_host_reboot_event_missing
  • host_boot_observation_older_than_target_window
  • host_unreachable_after_reboot
  • host_uptime_unknown
  • reboot_event_required_host_unreachable
  • windows99_vmware_guest_power_not_ready

最新 no-write artifact 以 110 runtime textfile、latest SLO artifact、production API readback 與本輪 Windows99 collector readback 為來源:

  • 99 no-secret VMware verify stdout 已能透過 110 / public-key SSH 收集latest artifact 顯示 missing_vmx_aliases=[]VMWARE_AUTOSTART_CONFIG_READY=1WINDOWS_UPDATE_NO_AUTO_REBOOT_READY=1VMWARE_AUTOSTART_VERIFY_READY=0
  • 111 / 188 / 120 / 121 / 112 才是 Windows99 VMware default guest set110 是 P0 host / control-plane truth不得再被 validator 或 scorecard fallback 當成 99 VMware guest default。
  • 111 / 188 / 120 / 121 / 112 VM power readback 仍需用新版 no-secret collector 確認;windows99_vmware_guest_power_not_ready 仍 blocked且此 SOP 不授權直接 power change。
  • 111 host 仍 unreachable。
  • 112 / 120 / 121 可達,但 uptime 已超過 10 分鐘目標窗口。
  • 188 可達,但 systemd_state=degradedawoooi-startup.service failed
  • reboot_event_required_host_unreachable 仍為 primary blocker因此 10 分鐘 SLO 尚未證明。

固定下一步:保留 110 timer / textfile每輪讀最新 scorecard.json 與 Prometheus metricWindows99 lane 只建立 powered-off aliases 的 check-mode / post-verifier package不能從 scorecard 直接 power on。API overlay 必須以 runtime metric 的 awoooi_windows99_vmware_autostart_config_readyawoooi_windows99_vmware_windows_update_no_auto_reboot_ready 為準;當這些 metric 為 ready 時,不得用 committed snapshot 的舊 service_blockers / policy_blockers 反加 windows99_vmware_autostart_config_not_readywindows99_update_no_auto_reboot_policy_not_ready。同時繼續補 fresh all-host reboot event / approved drill proof禁止讀 Windows 密碼、啟動 / 關閉 VM、host reboot、service restart、Docker / Nginx / K3s / DB / firewall restart、restore、prune、delete。

2026-07-03 13:10 最新 overlayGitea CD #4582 已推 deploy marker 558b9e9source ba0849f70production deploy readback matched=true 且 job_succeeded=trueGitea UI 若仍顯示 Running只能視為 run-level lag。production /api/v1/agents/windows99-vmx-source-locator-readback 已上卷 redacted locator receiptcandidate_source_count=6alias_hint_candidate_count=0unassigned_ubuntu_candidate_count=5identity_unassigned_ubuntu_candidate_count=1candidate_confirmation_required=true,狀態為 collector_readback_single_identity_candidate_confirmation_required。新的 candidate_confirmation_gate 固定輸出 candidate_identity_evidence_sufficient=falsecandidate_relink_dry_run_ready=falseapply_allowed_by_candidate_confirmation_gate=false;缺少 evidence 為 target_alias_identity_hintverified_backup_or_authorized_console_candidate_identitypre_apply_backup_planscoped_relink_dry_run。因此下一步已從「重跑 locator」收斂為取得授權 console candidate identity evidence 或 verified backup path重跑 confirmation gate再產生 scoped relink dry-run + rollback + post-verifier仍不得猜測 generic Ubuntu candidate、不得 relink、不得 restore、不得 power on VM。

2026-07-03 16:33 source-of-truth correction本輪全主機 reboot 需求與 host probe 均指向 111 是 Windows99 guest target舊的 110 -> 188 -> 120 -> 121 -> 112 default 會讓 111 unreachable 被錯誤排除。因此 repo source、API scorecard fallback、CLI scorecard fallback、validator default 必須使用 111 / 188 / 120 / 121 / 112 作為 Windows99 default VM target110 仍是 reboot SLO required host 與 control-plane host但不是 99 VMware 預設 VM。禁止用舊 110 default 清掉 111 blocker禁止為了清 blocker 修改 Windows task、relink、restore、啟動 VM 或重啟 host。

2026-07-03 13:50 no-secret verifier overlay 曾以舊 default 110 / 188 / 120 / 121 / 112 讀回 artifact2026-07-03 16:33 已判定該 default 與目前事故目標不一致。下一步必須部署新版 SLO exporter/collector 到 110、重跑 verifier service確認 validator default、Prometheus textfile、production scorecard 全部改讀 111 / 188 / 120 / 121 / 112。仍不得啟動 VM、relink、restore、重啟 host 或讀密碼。

2026-07-03 16:57 bounded verifier overlay新版 verifier 預設不再遞迴掃 VM roots避免 111 VMX 缺失時 timeout實測 via-110 no-secret collector 可回 VMX alias=111 present=0VM_POWER alias=111 vmx_present=0 running=0VMWARE_AUTOSTART_CONFIG_READY=0。SLO exporter fallback 只可使用 alias set 完全符合 111 / 188 / 120 / 121 / 112 的 artifact110 artifact 必須被跳過,不得回灌成 runtime truth。

2026-07-03 14:10 runtime metric overlay110 最新 SLO textfile 已輸出 active_blocker_count=7,且 awoooi_windows99_vmware_missing_vmx_alias 沒有 alias gauge、awoooi_windows99_vmware_powered_off_alias 只列 110 / 112 / 120 / 121 / 188。production API 在 source 修正前仍可能因 stale committed snapshot 反加 Windows99 config / Windows Update policy 假 blocker新版 API 必須讀 awoooi_windows99_vmware_autostart_config_ready gauge並以 runtime metric overlay 清掉這兩個假 blocker。若 production /api/v1/agents/reboot-auto-recovery-slo-scorecard 仍顯示 runtime_metric_active_blocker_count=7active_blocker_count>7 且多出的 blocker 是 Windows99 config / policy先部署 / 驗證 API overlay source不得回頭做 VMX locate、relink、power change 或 Windows policy apply。

五主機全貌

192.168.0.188  (OLLAMA / 主服務主機)
├── containerd              ← 基礎,必須最先啟動
├── Docker                  ← 依賴 containerd
├── PostgreSQL :5432        ← K3s kine 後端API DB
├── Redis :6380             ← Working Memory (重啟後清空,需 warm-up)
├── Ollama :11434           ← LLM 推論引擎
├── Nginx :80/:443          ← 反向代理
├── OpenClaw (clawbot) :8088 ← AI 核心 (Docker Compose)
├── MinIO                   ← Velero 備份存儲 (Docker Compose)
└── SignOz                  ← 可觀測性 (Docker Compose)

192.168.0.110  (DevOps 主機)
├── Docker
├── Harbor :5000            ← Container Registry (K3s 拉映像用)
├── Gitea :3001             ← 主要 Git / CI 管理介面
├── Gitea Act Runner        ← CD pipeline 執行者 (docker: gitea-runner)
├── Langfuse :3100          ← LLMOps 追蹤
├── Prometheus :9090        ← 指標收集
├── Alertmanager :9093      ← 告警路由
├── Grafana :3002           ← 監控儀表板
├── Sentry :9000            ← Error Tracking (2026-03-242026-04-05 加入 startup)
└── SignOz                  ← 可觀測性

192.168.0.120  (K3s Master - mon)
├── K3s server (control plane)
├── kube-proxy              ← NodePort 轉發 32334/32335
└── keepalived              ← VIP 192.168.0.125 (secondary)

192.168.0.121  (K3s Worker - mon1)
├── K3s agent (worker)
└── kube-proxy

192.168.0.125  (VIP, keepalived 管理)
├── → :32334  AWOOOI API
└── → :32335  AWOOOI Web

服務依賴關係

嚴格啟動順序:

【188 層】
containerd
  └── Docker
        ├── PostgreSQL (kine DB, API DB)
        │     └── Redis (Working Memory)
        │           └── Ollama (LLM)
        │                 └── Nginx
        │                       ├── SignOz
        │                       ├── MinIO
        │                       └── OpenClaw (依賴 aiops-network)

【110 層】
Docker
  └── harbor-log (等 healthy)
        └── Harbor 全組件 (:5000)
              └── Gitea (:3001)
                    ├── Langfuse
                    ├── Monitoring (Prometheus + Alertmanager + Grafana)
                    │         [Alertmanager → AWOOOI API 告警鏈路]
                    ├── SignOz
                    └── Gitea Act Runner (等 Gitea 就緒後才啟動)

【120/121 層】
K3s (依賴 PostgreSQL@188)
  └── kube-proxy (NodePort 規則)
        └── Pods: API / Web / Worker
              └── keepalived (VIP)

【告警鏈路】
Prometheus → Alertmanager(110)
  → AWOOOI API(VIP 192.168.0.125:32334/api/v1/webhooks/alertmanager)  ← 直接,不走 OpenClaw
  → TelegramGateway → Telegram

【CD 鏈路】
Git push → Gitea(110:3001)
  → Act Runner (gitea-runner container)
  → Build Docker image → Harbor(:5000) → kubectl → K3s pods

110 Controlled CD Lane 與 Fail-Closed Enforcer

110 runner 壓力事故後,awoooi-cd-lane.service、legacy runner、generic label 與重型 runner 仍必須維持 fail-closed。唯一可被保留的 110 CD entrypoint 是專用 awoooi-cd-lane-drain.service 的非 secret staging 狀態,且必須同時符合下列條件:

  • config.yaml 只允許 capacity <= 1awoooi-host:hostawoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04
  • awoooi_cd_lane_controlled 必須是 executable ELF不可為 fail-closed shell stub。
  • unit 必須含 ConditionPathExists=/home/wooo/awoooi-cd-lane-drain/data/.runner、CPU / Memory / Tasks accounting 與 limit、NoNewPrivileges=true
  • service staging 階段必須 inactive、MainPID=0、未 enabled / 未 maskedrunner token registration 與 .runner 內容仍不可讀、不可列印。

讀回方式固定先跑 scripts/reboot-recovery/enforce-110-runner-failclosed.sh --check,看 CONTROLLED_DRAIN_STAGING_ALLOWED;再跑 ops/runner/check-awoooi-110-controlled-cd-lane-readiness.sh,看 CONFIG_READYBINARY_READYREGISTRATION_READYSERVICE_READY。若只剩 registration / service inactive blocker代表非 secret guardrail 已收斂,下一步才是 token-safe registration path不得用手工反覆補 config / binary 取代 source enforcer 修正。

關鍵依賴說明

服務 關鍵依賴 若依賴失敗
K3s PostgreSQL@188 ready K3s 無法啟動,所有 pod 無法調度
OpenClaw Docker + aiops-network Telegram AI 對話失效
Alertmanager → API NetworkPolicy 允許 110/32 告警全面沉默
CD pipeline Gitea Act Runner online 所有部署失效
Harbor harbor-log healthy 所有其他 Harbor 容器 Exited 128
K8s pods Harbor (映像倉庫) ImagePullBackOff

自動化腳本狀態

已部署 (2026-04-05)

主機 腳本 部署位置 systemd service 狀態 類型
188 awoooi-startup.sh /usr/local/bin/ awoooi-startup.service enabled 重開機 oneshot
110 awoooi-startup-110.sh /usr/local/bin/ awoooi-startup-110.service enabled 重開機 oneshot
110 harbor-watchdog.sh /usr/local/bin/ harbor-watchdog.service active 常駐 watchdog
120 K3s 原生 系統內建 k3s.service enabled 系統服務
121 K3s 原生 系統內建 k3s-agent.service enabled 系統服務

本地原始碼: scripts/reboot-recovery/

harbor-watchdog2026-04-05 新增)

問題背景: Harbor 的 Exited (128) Race Condition

  • restart: always 在 harbor-log 未就緒時不斷重試,最終進入 backoff 放棄
  • 即使 harbor-log 後來 healthy其他容器不會自動重試
  • 只靠 startup 腳本無法處理運行中崩潰的情況

設計:

  • Type=simple 常駐進程(不是 oneshotsystemd 永久監控
  • 每 60 秒輪詢 http://127.0.0.1:5000/v2/401 = healthy
  • 偵測到不健康 → 等 5 秒再確認(避免誤報)→ 執行完整時序修復
  • 修復邏輯:清除 Exited 容器 → 只啟動 harbor-log → 等 healthy → 啟動全部

查看狀態:

journalctl -u harbor-watchdog.service -f          # 即時 log
systemctl status harbor-watchdog.service          # 服務狀態
cat /var/log/harbor-watchdog.log                  # 持久化 log

各腳本覆蓋清單

188 (7 步驟):

  • containerd BoltDB 損壞偵測與修復
  • Docker BoltDB 損壞偵測與修復
  • PostgreSQL 啟動偵測checkpoint / WAL 類資料層錯誤一律 fail-closed禁止自動 pg_resetwal
  • Redis 啟動
  • Ollama 啟動
  • Nginx 啟動
  • SignOz + MinIO + aiops-network + OpenClaw

110 (7 步驟 + harbor-watchdog 常駐):

  • Docker BoltDB 損壞偵測與修復
  • 孤兒容器清除 (Exited 128)
  • Harborharbor-log first 策略Phase 1 清除 → Phase 2 只啟 harbor-log → Phase 3 等 healthy → Phase 4 啟全部)
  • Gitea + Langfuse + Monitoring (含 Alertmanager 健康驗證)
  • SignOz
  • Gitea Act Runner (自動清除過期 .runner 配置)
  • Sentry (/opt/sentry含 PostgreSQL WAL + Redis RDB 損壞自動修復)
  • harbor-watchdog.service (常駐,每 60s 自動修復)

正常重啟流程

適用於計劃性維護、安全更新、OS 升級等有預期的重啟。

重啟前準備 (T-30 分鐘)

# 1. 確認沒有 INVESTIGATING/MITIGATING 的 incident
curl -s http://192.168.0.121:32334/api/v1/incidents | python3 -c 'import sys,json; d=json.load(sys.stdin); print("Active incidents:", d.get("count",0))'

# 2. 確認 K3s 健康
ssh wooo@192.168.0.120 "kubectl get nodes && kubectl get pods -n awoooi-prod"

# 3. 備份確認 (MinIO Velero)
ssh wooo@192.168.0.120 "kubectl get backup -n velero 2>/dev/null | head -5"

建議重啟順序

第一步: 188 + 110 同時重啟
        (兩者獨立,可並行)

等待 5 分鐘確認基礎服務就緒:
  - PostgreSQL accepting connections
  - Harbor returning HTTP 200
  - Gitea accessible

第二步: 120 + 121 同時重啟
        (K3s cluster)

等待 10 分鐘:
  - Nodes Ready
  - Pods Running

重要: 120/121 必須在 188 PostgreSQL 完全就緒後才重啟, 否則 K3s kine 連不到 DB 無法啟動。

重啟後驗證 (T+15 分鐘)

執行底部 E2E 驗證腳本。所有項目必須


異常重啟流程

適用於電源中斷、OOM、系統崩潰、強制重啟等非預期的重啟。

第一步:快速診斷 (T+2 分鐘)

# 188 狀態
ssh ollama@192.168.0.188 "
systemctl is-active containerd docker postgresql@14-main redis-server ollama nginx
docker ps --format '{{.Names}}: {{.Status}}' | grep -E 'clawbot|minio|signoz'
"

# 110 狀態
ssh wooo@192.168.0.110 "
docker ps --format '{{.Names}}: {{.Status}}' | grep -E 'harbor-log|gitea$|alertmanager|gitea-runner'
"

# K3s 狀態
ssh wooo@192.168.0.120 "
kubectl get nodes 2>/dev/null || echo 'K3s not ready'
kubectl get pods -n awoooi-prod 2>/dev/null | grep -v Running | head -10
"

# API 健康
curl -s --max-time 5 http://192.168.0.121:32334/api/v1/health 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print("API:", d["status"])' 2>/dev/null || echo 'API unreachable'

第二步:按優先級恢復

P0 (T+0~5 分鐘): 基礎設施

# 自動化腳本通常已處理,但若沒有自動啟動:
ssh ollama@192.168.0.188 "sudo /usr/local/bin/awoooi-startup.sh"
ssh wooo@192.168.0.110 "echo '0936223270' | sudo -S /usr/local/bin/awoooi-startup-110.sh"

P1 (T+5~15 分鐘): K3s 叢集

# 等 PostgreSQL@188 就緒後
ssh ollama@192.168.0.188 "pg_isready -h localhost -p 5432"

# K3s 若未自動恢復
ssh wooo@192.168.0.120 "sudo systemctl restart k3s"
ssh wooo@192.168.0.121 "sudo systemctl restart k3s-agent"

# 等待 Nodes Ready
ssh wooo@192.168.0.120 "kubectl wait --for=condition=Ready nodes --all --timeout=120s"

P2 (T+15~30 分鐘): 業務驗證

# Pods 全部 Running?
ssh wooo@192.168.0.120 "kubectl get pods -n awoooi-prod"

# API 健康 (含所有 components)?
curl -s http://192.168.0.121:32334/api/v1/health | python3 -m json.tool

# 告警鏈路 E2E 測試
curl -X POST http://192.168.0.121:32334/api/v1/webhooks/alertmanager \
  -H 'Content-Type: application/json' \
  -d '{"receiver":"test","status":"firing","alerts":[{"status":"firing","labels":{"alertname":"RebootRecoveryTest","severity":"info"},"annotations":{"summary":"重開機恢復測試,請忽略"},"startsAt":"2026-04-05T00:00:00Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":""}],"groupLabels":{},"commonLabels":{},"commonAnnotations":{},"externalURL":"","version":"4","groupKey":"test"}'
# 預期: {"success":true,...} 且 Telegram 收到測試告警

各主機詳細啟動序列

192.168.0.188 — 主服務主機

步驟 服務 驗證方式 常見失敗原因
1 containerd systemctl is-active containerd BoltDB meta.db 損壞
2 Docker systemctl is-active docker BoltDB local-kv.db 損壞
3 PostgreSQL pg_isready -h localhost -p 5432 WAL checkpoint 損壞
3a kine VACUUM psql -d k3s_datastore -c "VACUUM ANALYZE kine;" 慢查詢導致 K3s 超時
4 Redis redis-cli -p 6380 ping bind 配置錯誤 (必須 0.0.0.0:6380)
5 Ollama systemctl is-active ollama GPU 記憶體不足
6 Nginx systemctl is-active nginx port 衝突
7a aiops-network docker network ls | grep aiops-network 重啟後 external network 消失
7b OpenClaw curl http://localhost:8088/health pip 依賴損壞需 rebuild
7c MinIO docker ps | grep minio 無狀態服務,重啟即可
7d SignOz curl http://localhost:3301/-/healthy ClickHouse 起慢

BoltDB 損壞修復:

# containerd meta.db
BOLT=/var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
cp $BOLT ${BOLT}.bak.$(date +%s) && rm $BOLT && systemctl restart containerd

# Docker network BoltDB
BOLT=/var/lib/docker/network/files/local-kv.db
cp $BOLT ${BOLT}.bak.$(date +%s) && rm $BOLT && systemctl restart docker

PostgreSQL checkpoint / WAL 類錯誤處理:

2026-06-26 校正:這不是一般重啟 SOP 的自動修復步驟。pg_resetwal 可能造成不可逆資料風險,只能在 DB owner、備份/restore evidence、maintenance window、rollback owner 與 post-check plan 都具備時,作為 break-glass 人工程序。AI、startup 腳本或值班腳本不得自動執行。

# 只讀確認,不代表可執行修復
journalctl -u postgresql@14-main -n 30 | grep "could not locate a valid checkpoint"
pg_lsclusters
systemctl status postgresql@14-main --no-pager

若確認需要進入 break-glass先完成

1. DB owner approval
2. 最新本機與 offsite backup evidence
3. restore / rollback plan
4. maintenance window
5. post-checkpg_lsclusters、pg_isready、應用 DB smoke、backup-status、cold-start wrapper

192.168.0.110 — DevOps 主機

步驟 服務 驗證方式 常見失敗原因
1 Docker systemctl is-active docker BoltDB 損壞
2 孤兒容器清除 docker ps -a | grep "Exited (128)" 舊容器引用已不存在的 network
3 harbor-log docker inspect --format='{{.State.Health.Status}}' harbor-log syslog :1514 未就緒
3 Harbor 全組件 curl http://localhost:5000/v2/ harbor-log 還沒 healthy
4 Gitea curl http://localhost:3001 無特殊問題
5 Langfuse curl http://localhost:3100 DB 未就緒
6 Alertmanager curl http://localhost:9093/-/healthy docker compose 未啟動
6a 告警鏈路驗證 發送測試 webhook webhook URL 錯誤 / NetworkPolicy
7 SignOz curl http://localhost:3301/-/healthy ClickHouse 起慢
8 Gitea Runner docker logs gitea-runner | grep SUCCESS .runner 配置過期
9 Sentry curl -o /dev/null -w '%{http_code}' http://localhost:9000/ PostgreSQL WAL/Redis RDB 損壞 (見下方)

110 control-path / Harbor receipt 判讀 (2026-07-02):

重啟後若公開 Gitea queue 仍顯示舊的 Harbor repair failure、harbor_110_remote_ssh_publickey_auth_stalled、remote-control unavailable 或 jobs stale不得直接把它當成 current blocker。必須先用同一輪 read-only receipt 合併以下證據:

scripts/reboot-recovery/diagnose-110-ssh-publickey-auth.sh
ssh wooo@192.168.0.110 'sudo -n /usr/local/bin/recover-110-control-path-and-harbor-local.sh --check'
python3 ops/runner/read-public-gitea-actions-queue.py --json
curl -k -s -o /dev/null -w '%{http_code}' https://registry.wooo.work/v2/
curl -s -o /dev/null -w '%{http_code}' http://192.168.0.110:5000/v2/

SSH_COMMAND_PATH ... classification=command_path_ready 成立,且 public/internal registry /v2/401,則舊 Harbor repair SSH failure 只能列為 historical queue metadataactive blocker 應轉向實際的 controlled CD lane readiness、CD jobs SHA/readback mismatch 或 deploy marker。2026-07-02 的機器可讀證據是 docs/operations/harbor-110-control-path-recovery-readback-2026-07-02.snapshot.jsonGitea latest visible CD #4335Success,但 active blockers 仍包含 110 controlled CD lane config / binary / registration / service guardrail 與 Gitea CD jobs head-SHA / stale mismatch。

combined local-console output 只能依 marker 判讀:AWOOOI_110_CONTROLLED_CD_LANE_READY 只屬於 110 controlled lane沒有 AWOOOI_NON110_RUNNER_READY 時,不得從同一份 BLOCKER 行推導 non110 runner blocker。

Gitea repository / bundle backup 判讀 (2026-07-02):

Gitea UI/API 可見性、SSH refs、bundle backup、sample restore dry-run 是四層不同證據不得混成「repo 不見」或「backup 完成」一句話。

固定順序:

curl -s https://awoooi.wooo.work/api/v1/agents/gitea-repo-bundle-backup-readback | python3 -m json.tool
curl -s http://192.168.0.188:9100/metrics | grep '^awoooi_gitea_bundle_'
scripts/backup/gitea-bundle-sample-restore-dry-run.sh --repo wooo/awoooi --write-textfile

判讀規則:

  • expected_repo_missing_count=0failed_repo_count=0checksum_missing_count=0 代表 bundle repo / checksum 層沒有缺,不代表 freshness 或 restore drill 已完成。
  • awoooi_gitea_bundle_fresh=0 是 freshness blocker下一步是補跑 gitea-repo-bundle-backup.sh 與同步到 188不得刪 repo、改 visibility、或 restore 到 production。
  • awoooi_gitea_bundle_sample_restore_dry_run_ok absent / 0 是 restore confidence blocker只允許在暫存目錄 clone bundle + git fsck --connectivity-only,不得把 bundle restore 回 Gitea production。
  • public repo search 只代表 public visibilityprivate/internal repo 要看 authenticated inventory、SSH heads 或 bundle metrics不能用 404 直接推論 history 消失。

Backup alert receipt 判讀 (2026-07-03):

備份監控不只看 freshness / failed / age / restore drill還必須能證明告警進入 Telegram / AwoooP receipt 鏈。重啟後若使用者問「備份到底有沒有告警」,固定順序如下:

python3 scripts/ops/backup-alert-label-contract-check.py
curl -G -s http://192.168.0.110:9090/api/v1/query --data-urlencode 'query=awoooi_backup_alert_receipt_stage_fresh{host=~"110|188"}' | python3 -m json.tool
scripts/ops/backup-alert-live-visibility-check.py --prometheus-url http://192.168.0.110:9090 --alertmanager-url http://192.168.0.110:9093 --host 110
scripts/ops/backup-alert-live-visibility-check.py --prometheus-url http://192.168.0.110:9090 --alertmanager-url http://192.168.0.110:9093 --host 188

判讀規則:

  • required_alert 是原始 backup alert例如 BackupJobStaleBackupCoverageDomainStaleGiteaPrivateBundleBackupIncomplete;不得用 Prometheus 保留 label alertname 承載它。
  • 每個 required alert 都要有 sent / received / dedup / escalation 四段 marker缺段明細由 awoooi_backup_alert_receipt_stage_fresh == 0 保留,BackupAlertReceiptStageMissing 只允許聚合成每個 host / receipt_channel 一條,避免 Telegram/AwoooP 噪音淹沒真問題。
  • marker 只能是 /backup/alert-receipts/*.last_success 這類 timestamp / evidence id不得寫 Telegram token、raw payload、chat id 原文或 secret。
  • 這個 receipt proof 不取代真正 backup / restore proofGitea bundle、Gitea full dump、DB/settings/issues/packages/LFS、offsite、restore drill 仍要各自綠。

Harbor Exited 128 修復:

# 等 harbor-log healthy
until [ "$(docker inspect --format='{{.State.Health.Status}}' harbor-log)" = "healthy" ]; do
  echo "waiting..."; sleep 5
done

# 清除 Exited 128 容器
docker rm -f $(docker ps -a --filter status=exited --format "{{.Names}}" | grep -v harbor-log)

# 重新啟動
cd /home/wooo/harbor/harbor && docker compose up -d

Gitea Runner 重新註冊:

# 清除過期配置 (指向錯誤 hostname 的)
sudo rm /home/wooo/act-runner/data/.runner

# 獲取新的 registration token
curl -s -u 'wooo:TOKEN' 'http://192.168.0.110:3001/api/v1/repos/wooo/awoooi/actions/runners/registration-token'

# 更新 docker-compose.yml 的 GITEA_RUNNER_REGISTRATION_TOKEN
# 然後啟動
cd /home/wooo/act-runner && docker compose up -d

192.168.0.120/121 — K3s 叢集

步驟 項目 驗證方式
前提 PostgreSQL@188 ready pg_isready -h 192.168.0.188 -p 5432
1 K3s service systemctl is-active k3s (120)
2 K3s agent systemctl is-active k3s-agent (121)
3 Nodes Ready kubectl get nodes
4 Pods Running kubectl get pods -n awoooi-prod
5 keepalived VIP ip addr show | grep 192.168.0.125 (120)
6 NodePort nc -zv 192.168.0.121 32334

常見故障排查手冊

1. 告警沉默 (Telegram 沒收到告警)

診斷樹:
  Alertmanager healthy? (http://192.168.0.110:9093/-/healthy)
  ├── NO → docker compose up -d (在 110 /home/wooo/monitoring/)
  └── YES
        ↓
  Webhook URL 正確?
  grep 'url:' /home/wooo/monitoring/alertmanager.yml
  必須是: http://192.168.0.125:32334/api/v1/webhooks/alertmanager
  ├── NO → bash scripts/ops/deploy-alertmanager-config.sh
  └── YES
        ↓
  從 110 curl POST webhook 成功?
  curl -X POST http://192.168.0.125:32334/api/v1/webhooks/alertmanager ...
  ├── timeout → NetworkPolicy 未允許 110
  │            kubectl apply -f k8s/awoooi-prod/02-network-policy.yaml
  └── {"success":true} → 檢查 Telegram Bot Token

Alertmanager config drift 修復:

# 從專案根目錄執行;會從 K8s Secret 注入 Telegram bot token 與 SRE_GROUP_CHAT_ID
# 先用 amtool 驗證,再備份 110 live config、原 inode 覆寫、修正 0644 權限並 HUP reload。
bash scripts/ops/deploy-alertmanager-config.sh

補充診斷 — 特定服務異常但無告警Alertmanager 正常):

# 確認 Prometheus 規則數量和關鍵規則是否存在
ssh wooo@192.168.0.110 "curl -s http://localhost:9090/api/v1/rules | python3 -c \"
import sys,json
r=json.load(sys.stdin)
names=[x['name'] for g in r['data']['groups'] for x in g['rules']]
total=len(names)
key=['SentryDown','HarborDown','GiteaDown','OpenClawDown','AlertmanagerDown','AlertChainUnhealthy']
for k in key:
    print(f'{'OK' if k in names else 'MISSING'}: {k}')
print(f'Total rules: {total}')
\""

# 若規則不存在或 total < 25 → 規則未部署
# 修復: 從專案根目錄執行
bash scripts/ops/deploy-alerts.sh

# 若規則存在但 inactive → 確認 blackbox probe target
curl http://192.168.0.110:9090/api/v1/query?query=probe_success

根本教訓 (2026-04-05):

  • 舊架構: Alertmanager → OpenClaw 8088 (中間層,重開機後 OpenClaw 不健康就沉默)
  • 新架構: Alertmanager → AWOOOI API 直通 (更穩定,單一故障點少)
  • NetworkPolicy 必須允許 110/32 進入 pod

2. Gitea CD 無法部署

診斷樹:
  Gitea runner 數量?
  curl -u 'wooo:TOKEN' 'http://192.168.0.110:3001/api/v1/repos/wooo/awoooi/actions/runners'
  ├── total_count: 0 → Runner 離線
  │     docker ps | grep gitea-runner
  │     ├── 不存在 → cd /home/wooo/act-runner && docker compose up -d
  │     └── 存在但 Restarting → docker logs gitea-runner
  │           "lookup gitea" → 清除 data/.runner → docker compose up -d
  └── total_count: 1 → Runner 在線但 CD 失敗
        查看 Gitea Actions 日誌: http://192.168.0.110:3001/wooo/awoooi/actions

3. 網站數據顯示 0 / incidents 消失

原因: Redis Working Memory 重啟後清空
     新版 API (f4f454f+) 啟動時自動 warm-up
     舊版 API 沒有此邏輯

診斷:
  curl http://192.168.0.121:32334/api/v1/incidents
  → count: 0 但 Telegram 有歷史告警?
  → 確認 API pod image 版本

修復 (若 image 版本正確):
  kubectl rollout restart deployment/awoooi-api -n awoooi-prod

修復 (若 image 版本過舊):
  等待 CD 完成部署最新版本

4. NodePort 32334 從外部無法訪問

診斷:
  nc -zv 192.168.0.121 32334  ← 這個通嗎?
  ├── 通 → 用 192.168.0.121:32334 直連
  └── 不通
        kubectl get pods -n awoooi-prod
        ├── 沒有 Running pods → K3s pods 問題
        └── 有 Running pods
              iptables -t nat -L KUBE-NODEPORTS -n | grep 32334
              ├── 沒有規則 → K3s kube-proxy 問題,重啟 k3s
              └── 有規則 → NetworkPolicy 或防火牆

5. Sentry 重開機後損壞修復 (2026-04-05 事故記錄)

症狀: sentry-self-hosted-postgres-1 / redis-1 / clickhouse-1 持續 Restarting

原因: 重開機時各 DB 未正常關閉,導致資料損壞:

  • PostgreSQL: WAL 損壞 (could not locate a valid checkpoint record)
  • Redis: dump.rdb 損壞 (Wrong signature trying to load DB from file)
  • ClickHouse: system table store parts 損壞 (broken and needs manual correction)

Break-glass 修復範例,不屬於一般重啟 SOP:

先確認 Sentry DB volume 是受影響權威資料面,並具備 owner approval、volume backup / rollback ref、maintenance window 與 post-check plan。不得由 startup script、AI agent 或值班自動流程直接執行。

# Step 1: 修復 PostgreSQL WAL
docker run --rm -u 999 -v sentry-postgres:/var/lib/postgresql/data \
  postgres:14 pg_resetwal -f /var/lib/postgresql/data
echo "PostgreSQL WAL reset 完成"

# Step 2: 修復 Redis (session cache可丟失)
docker run --rm --user root -v sentry-redis:/data alpine \
  sh -c 'rm -f /data/dump.rdb && echo cleared'
echo "Redis dump.rdb 已清除"

# Step 3: 找出損壞的 ClickHouse store 目錄
docker logs sentry-self-hosted-clickhouse-1 2>&1 \
  | grep -oE 'store/[a-f0-9]{3}/[a-f0-9-]+' \
  | sort -u

# Step 4: 依據上方輸出刪除損壞目錄 (以 UUID 為準,以下為範例)
for uuid in "469/469957c9-..." "57d/57d1d567-..."; do
  docker run --rm --user root -v sentry-clickhouse:/data alpine \
    sh -c "rm -rf /data/store/$uuid && echo OK:$uuid"
done

# Step 5: 重啟 Sentry
cd /opt/sentry && docker compose up -d

# Step 6: 等待 2-3 分鐘後驗證
sleep 120
curl -o /dev/null -w "%{http_code}" http://192.168.0.110:9000/
# 預期: 200 / 302 / 400 (需登入)

2026-06-26 修正方向: 舊 startup-110.sh 曾把 PostgreSQL WAL 和 Redis RDB 損壞列入自動修復,這類資料層破壞性動作後續必須遷移到 owner-gated break-glass不得再擴大成預設自動化。ClickHouse parts 損壞同樣需人工識別 UUID、備份與 post-check。


6. Harbor ImagePullBackOff

診斷:
  kubectl describe pod <pod> -n awoooi-prod | grep -A 5 Events
  → "ImagePullBackOff" or "ErrImagePull"
  
確認 Harbor 健康:
  curl http://192.168.0.110:5000/v2/ → 應該回 {}

若 Harbor 不健康:
  - 等 harbor-log healthy 後重啟: 見 Harbor Exited 128 修復
  - 確認 Docker daemon 在 120/121 有設定 insecure registry:
    cat /etc/docker/daemon.json | grep insecure

E2E 驗證腳本

執行此腳本確認重開機後全系統正常。

#!/bin/bash
# 重開機後 E2E 驗證
# 使用: bash docs/runbooks/scripts/e2e-verify.sh
# 執行位置: 任意可 SSH 的機器

API="http://192.168.0.121:32334"
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
PASS=0; FAIL=0

check() {
    local name="$1"; local cmd="$2"; local expect="$3"
    result=$(eval "$cmd" 2>/dev/null)
    if echo "$result" | grep -q "$expect"; then
        echo -e "${GREEN}$name${NC}"
        ((PASS++))
    else
        echo -e "${RED}$name${NC} (got: ${result:0:80})"
        ((FAIL++))
    fi
}

echo "=== AWOOOI 重開機 E2E 驗證 $(date '+%Y-%m-%d %H:%M:%S') ==="

# 188 服務
check "188 PostgreSQL" "ssh ollama@192.168.0.188 'pg_isready -h localhost -p 5432'" "accepting"
check "188 Redis" "ssh ollama@192.168.0.188 'redis-cli -p 6380 ping'" "PONG"
check "188 OpenClaw" "ssh ollama@192.168.0.188 'curl -s http://localhost:8088/health'" "healthy"

# 110 服務
check "110 Harbor" "curl -s -o /dev/null -w '%{http_code}' http://192.168.0.110:5000/v2/" "200"
check "110 Gitea" "curl -s -o /dev/null -w '%{http_code}' http://192.168.0.110:3001" "200"
check "110 Alertmanager" "curl -s http://192.168.0.110:9093/-/healthy" "OK"
check "110 Gitea Runner" "curl -s -u 'wooo:TOKEN' 'http://192.168.0.110:3001/api/v1/repos/wooo/awoooi/actions/runners' | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get(\"total_count\",0))'" "1"
check "110 Sentry" "curl -s -o /dev/null -w '%{http_code}' --max-time 10 http://192.168.0.110:9000/" "[23][0-9][0-9]\|400"
check "Prometheus rules ≥25" "ssh wooo@192.168.0.110 'curl -s http://localhost:9090/api/v1/rules' | python3 -c \"import sys,json; r=json.load(sys.stdin); print(sum(len(g['rules']) for g in r['data']['groups']))\"" "[2-9][5-9]\|[3-9][0-9]"

# K3s
check "K3s Nodes Ready" "ssh wooo@192.168.0.120 'kubectl get nodes --no-headers' | awk '{print \$2}'" "Ready"
check "K3s Pods Running" "ssh wooo@192.168.0.120 'kubectl get pods -n awoooi-prod --no-headers' | grep -c Running" "3"

# AWOOOI API
check "API Health" "curl -s $API/api/v1/health" '"status":"healthy"'
check "API openclaw" "curl -s $API/api/v1/health" '"openclaw":{"status":"up"'

# 告警鏈路 E2E
PAYLOAD='{"receiver":"e2e-test","status":"firing","alerts":[{"status":"firing","labels":{"alertname":"RebootE2ETest","severity":"info"},"annotations":{"summary":"重開機 E2E 驗證,請忽略"},"startsAt":"2026-04-05T00:00:00Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":""}],"groupLabels":{},"commonLabels":{},"commonAnnotations":{},"externalURL":"","version":"4","groupKey":"e2e-test"}'
check "告警鏈路 E2E" "curl -s -X POST $API/api/v1/webhooks/alertmanager -H 'Content-Type: application/json' -d '$PAYLOAD'" '"success":true'

echo ""
echo "=== 結果: ${PASS} 通過, ${FAIL} 失敗 ==="
[ $FAIL -eq 0 ] && echo -e "${GREEN}🎉 全部通過!系統正常${NC}" || echo -e "${RED}⚠️  有 ${FAIL} 項失敗,請排查${NC}"

版本歷史

版本 日期 說明
v5.30 2026-07-11 交叉驗證 99 實際 boot time修正 observer false negative部署 durable reboot state、PT20M task、principal-aware VM verifier/parser、VMware controlled apply並以 production-principal Recover 與 23/23 public matrix 證明 late recovery
v5.29 2026-07-11 初始 observer 將 99 判為未回電;此判讀已由 v5.30 的 Windows boot/readback 與 socket probe evidence supersedeT+10 breach 本身仍有效
v1.0 2026-04-04 初版containerd + Docker + PostgreSQL WAL 修復流程
v2.0 2026-04-05 上午 188 啟動腳本 + 110 啟動腳本 + Harbor race condition 修復
v3.0 2026-04-05 下午 完整架構重盤 + Gitea Runner 自動化 + 告警鏈路根因修復 + NetworkPolicy 修正
v4.0 2026-04-05 下午 Prometheus 規則統一部署 (28條) + Sentry startup (Step 7) + Sentry損壞修復SOP + 規則未部署診斷樹 + E2E腳本加入Sentry/Prometheus驗證
v5.0 2026-04-05 下午 Harbor Exited(128) Race Condition 根治startup-110.sh 改用 harbor-log first 策略 + 新增 harbor-watchdog.service 常駐自愈curl -f bug 修正)