Files
awoooi/docs/runbooks/REBOOT-POST-START-QUICK-CHECK.md
Your Name 78418babf7
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 24s
CD Pipeline / build-and-deploy (push) Failing after 10s
CD Pipeline / post-deploy-checks (push) Has been skipped
fix(recovery): classify 110 ssh publickey auth blocker
2026-06-30 19:26:37 +08:00

445 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 主機重啟後一頁式總檢查
> Version: v1.20
> Last updated: 2026-06-30 Asia/Taipei
> Scope: 99 / 110 / 111 / 112 / 120 / 121 / 188 post-reboot service recovery. 112 Kali / Wazuh / active scan 只做可達性與託管狀態 evidence不做 active scan。
---
## 1. 使用時機
每次 110 / 120 / 121 / 188 任一台主機開機、關機、重啟、斷電恢復、VMware console fsck、Docker / K3s 大量重排後,都先跑本頁,再決定是否宣稱恢復。
最新基準2026-06-27 02:42 live revalidation / backup core recovery。`scripts/reboot-recovery/post-reboot-readiness-summary.sh --no-color` artifact `/tmp/awoooi-post-reboot-readiness-20260627-024151/summary.txt` 回傳 `POST_START_RESULT=FULL_STACK_GREEN_DR_ESCROW_BLOCKED``POST_START_PASS=38``POST_START_WARN=3``POST_START_BLOCKED=0``SERVICE_GREEN=1``PRODUCT_DATA_GREEN=1``STOCK_FRESHNESS_STATUS=ok``STOCK_LATEST_TRADING_DATE=2026-06-26``STOCK_BLOCKERS=none``BACKUP_CORE_GREEN=1``DR_ESCROW_BLOCKED=1``ESCROW_MISSING_COUNT=5``HOST_188_HYGIENE_BLOCKED=0``HOST_188_RESULT=HOST_188_HYGIENE_GREEN.``WAZUH_MANAGER_REGISTRY_ACCEPTED=0``WAZUH_COVERAGE_SCOPE=6``WAZUH_DIRECT_ACTIVE=2``WAZUH_NO_TRANSPORT=1``WAZUH_SSH_BLOCKED=3``WAZUH_ROUTE_CODE=200``WAZUH_TRANSPORT_COUNT=6``WAZUH_DASHBOARD_API_CONNECTION=pending_or_spinning``WAZUH_DASHBOARD_INDEX_OK=3``RUNTIME_ACTION_AUTHORIZED=0``OVERALL_DECLARATION=FULL_STACK_GREEN_DR_ESCROW_BLOCKED`。本輪實際修復 188 `momo_pg_daily` backup configured drift先前 00:16 summary 因 `configured_missing_188=1` 暫時 blocked00:19 已備份 188 crontab 到 `/home/ollama/momo_backups/crontab-before-momo-pg-host-owned-20260627-001925.txt`,並把 MOMO PostgreSQL daily backup 收斂到 host-owned `/home/ollama/bin/momo-pg-backup.sh`;刷新 exporter 後 `configured_missing_188=0`00:56 `backup-status``core_blockers=0`。02:41 DR checklist 回 `CORE_COLD_START_GREEN=1``RECOVERY_STATE=CORE_READY_DR_OFFSITE_PENDING`Prometheus recovery contract 回 `awoooi_recovery_core_ready=1``awoooi_recovery_dr_offsite_ready=0`。同一輪後續 `post-reboot-declaration-guard.py``post-reboot-next-gate-dispatch.sh``post-reboot-next-gate-owner-packets.py``post-reboot-owner-packet-contract-guard.py``post-reboot-owner-response-preflight.py` 必須使用這份 `summary.txt` 或由它產生的 dispatch / packet不得混用多次 live probe 的不同時間點結果。`NEXT_REQUIRED_GATES=credential_escrow_evidence,wazuh_manager_registry_export` 仍是唯一目前 next gatesDR 仍因 `escrow_missing=5` 不可宣稱 completeWazuh manager registry accepted 仍是 `0`,不可把 route `200`、transport `6`、Dashboard index pattern `3` 或脫敏 registry 計數當成全主機納管完成。v1.18 維持 route/API warmup classifierdelegated cold-start 若只因 public route 單次 502 / TLS readback或 K3s rollout 瞬間單次 `BLOCKED AWOOOI API not reachable`,但 wrapper route retry 已確認 public AWOOOI API health 為 2xx該 blocker 會降級為 evidence warningpublic API 仍失敗、其他 non-route blocker 或 retry 後未恢復仍為 hard blocked。
本頁只回答四件事:
1. 主機是否開起來。
2. 服務是否真的可用。
3. 資料與備份是否新鮮。
4. 有哪些不能宣稱完成。
### 2026-06-30 全主機重啟事故沉澱
本次重啟後不得再用單一路由或單一備份心跳宣稱恢復,必須固定讀回下列證據。
| 類別 | 2026-06-30 讀回事實 | SOP 判讀 |
|------|----------------------|----------|
| AWOOOI production 版本 | Gitea `main=3b65f8762`production runtime readback 仍為 `7890778b83`,且 readback 顯示 `runtime_build_readback_status=runtime_build_diverges_from_committed_deploy_readback`。 | 「產品都是最新版本」不可成立;必須先完成 deploy marker / runtime SHA / endpoint readback 三者一致。 |
| Full-stack cold-start | `full-stack-cold-start-check.sh --monitor-read-only --no-color``PASS=67 WARN=4 BLOCKED=5`110 registry external `/v2`、110 SSH read-only check、K3s registry pull refused、AWOOOI internal API probe、SigNoz TLS/public route 為 blocker。 | 不可宣稱 10 分鐘全服務恢復;先修第一個 cold-start blocker再重跑同一命令。 |
| Tsenyang 502 | `www.tsenyang.com` / `tsenyang.com` 起初 HTTP 502188 release `/home/ollama/tsenyang-website-releases/b369ed8` 有 source`tsenyang-website:latest` image 缺失、container 未啟動。 | 使用者可見 502 是 P0可用現有 release 做 bounded `docker build --quiet -t tsenyang-website:latest .` + `docker compose up -d --no-build`,再以 local 3000 與 public 200 驗證。 |
| Tsenyang 修復結果 | image `sha256:e25e0acb...` 建成container `tsenyang-website` runninglocal `127.0.0.1:3000``www.tsenyang.com``tsenyang.com` 均回 200。 | 下次若同樣 502先查 image/container/release symlink不先動 Nginx、DNS、DB 或 host reboot。 |
| StockPlatform freshness | public `/healthz``/api/healthz` 回 200`/api/v1/system/freshness``/api/v1/system/ingestion``status=not_configured`、blocker `postgres_not_ready`。 | service up 不等於資料最新Stock 必須修 PostgreSQL schema/readiness 或資料 source readback禁止 fake freshness、manual DB row、restore/prune。 |
| 110 control path | `diagnose-110-ssh-publickey-auth.sh` 讀回 node-exporter / SSH banner 正常;`NODE_LOAD_CLASSIFIER=high_load``NODE_PROCS_BLOCKED=0``wooo` publickey 為 `publickey_offer_timeout``root` publickey 為 `permission_denied``git` / `ollama``preauth_timeout`。 | 110 control path 是 P0 blocker下一步集中查 sshd publickey auth / authorized_keys / PAM / account lookup path同時追蹤 load / runner pressure 是否拖慢 auth。可在 110 console 跑 `repair-110-ssh-publickey-auth-local.sh --check`,確認後才 `--apply` 修 metadata 權限;未恢復前不可宣稱 Stock DB/schema、Gitea dump、110 backup completeness 已現場驗證。 |
| Gitea visibility | `https://gitea.wooo.work/api/v1/version` 回 200 / `1.25.5`public repo search 只列 4 個 public repos`stockplatform-v2` public page/API 404但 direct internal Git remote `http://192.168.0.110:3001/wooo/stockplatform-v2.git``ls-remote`。 | 不能直接說 repo 全消失;要區分 public visibility、private/auth visibility、內網 Git remote、server-side storage 四層。 |
| Gitea backup | 188 `/home/ollama/backup/110/gitea` 起初為空verified emergency bundle 後,`gitea_repo_mirror_from_110` metric fresh `1`、snapshot_count `19`。 | 子樹 metric 已能看見 emergency bundle但仍只代表部分 Git history正式 `gitea dump`、private repo non-interactive backup、repo count 與 restore drill 仍是 P0 blocker。 |
| Gitea emergency bundle | 188 已建立 verified emergency Git bundle snapshot `/home/ollama/backup/110/gitea/git-bundles/20260630-190931``awoooi``ewoooc``2026FIFAWorldCup``agent-bounty-protocol` bundle verify + `.sha256` 成功;`AwoooGo``stockplatform-v2``vibework` 因 private repo 需要非互動 credential 而 fail-closed。 | 這只保住部分 repo Git history不等於 `gitea dump`Gitea DB、settings、issues、packages、secrets、LFS、private repo completeness 與 restore drill 仍是 P0 blocker。 |
本次事故後新增固定判讀:
- `public API 200` 只能代表 route / process alive要宣稱資料最新必須讀各產品 freshness / ingestion / deploy marker。
- `backup_from_110 fresh=1` 只能代表整體 rsync 成功Gitea、Harbor、DB、網站、logs 等 domain 必須有獨立 freshness 或 sample count。
- Gitea repo 疑似消失時,順序固定為 `public search``repo page/API``GIT_TERMINAL_PROMPT=0 git ls-remote <internal-gitea-url>` → server-side storage / dump / backup readback不得先 restore 或 delete。
- 使用者可見 502 先啟用 L0 maintenance fallback 或恢復單站 container若 edge/99/188 整段不可達,才進 L1 external fallback / CDN。
- 110 SSH timeout 不得再泛化成「主機不可達」;先跑 `scripts/reboot-recovery/diagnose-110-ssh-publickey-auth.sh`,若 `wooo``publickey_offer_timeout`,修復順序固定為 110 console/local `repair-110-ssh-publickey-auth-local.sh --check``--apply` metadata 權限 → 選擇性 `RELOAD_SSH=1` reload → 外部診斷器重跑。
---
## 2. 絕對判定規則
| 層級 | 可以宣稱 | 必要證據 |
|------|----------|----------|
| `HOST_BOOTED` | 主機已開機 | ping / SSH port 回應,或 console login prompt。 |
| `HOST_READY` | 主機可管理 | SSH read-only 可登入failed units / disk / clock / network 無硬阻塞。 |
| `SERVICE_READY` | 單站服務可用 | route / container / local health / DB 或依賴健康都通過。 |
| `FULL_STACK_GREEN` | 本輪重啟服務恢復完成 | cold-start `WARN=0``BLOCKED=0`route、K3s、DB freshness、backup、alert、CronJob、exporter 都通過。 |
| `DR_COMPLETE` | 災難復原也完成 | `FULL_STACK_GREEN` 加上 credential escrow missing `0`、offsite / restore / escrow evidence 完整。 |
禁止用單一訊號取代整體判定:
- 網站 `200` 不等於資料最新。
- container `healthy` 不等於 DB / backup / alert 正常。
- K3s node `Ready` 不等於 workload 分散與 CronJob freshness 正常。
- Wazuh route `200` 不等於所有主機 agent registry accepted。
- backup fresh 不等於 DR completecredential escrow 缺口必須獨立保留。
---
## 3. 10 分鐘只讀總檢查順序
優先使用 machine-readable summary
```bash
scripts/reboot-recovery/post-reboot-readiness-summary.sh --no-color
```
此 summary 只做 read-only 檢查會委派一頁式總檢查、188 host hygiene checklist 與 Wazuh repo-side no-false-green gates並將 delegated logs 與可重放的 `summary.txt` 保留在 `/tmp/awoooi-post-reboot-readiness-*`。第一眼先看這些欄位:
- `SERVICE_GREEN=1`:服務面可宣稱恢復。
- `PRODUCT_DATA_GREEN=1`MOMO / StockPlatform 主要資料 freshness 可宣稱恢復。
- `BACKUP_CORE_GREEN=1`:備份核心可宣稱恢復。
- `DR_ESCROW_BLOCKED=1` / `ESCROW_MISSING_COUNT>0`:不可宣稱 DR complete。
- `HOST_188_HYGIENE_BLOCKED=0`188 host hygiene 已收斂;若未來回到 `1`,再走 188 專用 runbook。
- `WAZUH_MANAGER_REGISTRY_ACCEPTED=0`:不可宣稱 Wazuh 全主機納管恢復。
- `WAZUH_ROUTE_CODE=200` / `WAZUH_TRANSPORT_COUNT>0` 只能代表 route / transport evidence仍必須搭配 `WAZUH_COVERAGE_SCOPE``WAZUH_DIRECT_ACTIVE``WAZUH_NO_TRANSPORT``WAZUH_SSH_BLOCKED``WAZUH_DASHBOARD_API_CONNECTION``WAZUH_MANAGER_REGISTRY_ACCEPTED` 判讀。
- `RUNTIME_ACTION_AUTHORIZED=0`:本流程沒有授權 runtime 寫操作。
- `OVERALL_DECLARATION`:本輪可使用的最高宣告。
summary 顯示 `SERVICE_GREEN=1` 後,先跑宣告 guard確認本輪可以講什麼、不能講什麼
```bash
scripts/reboot-recovery/post-reboot-declaration-guard.py --no-color
```
若已經有 `$ARTIFACT_DIR/summary.txt`,同一輪建議固定使用它,避免重跑 live probes 時被 CI / route warmup 瞬間狀態影響:
```bash
SUMMARY_FILE=/tmp/awoooi-post-reboot-readiness-YYYYMMDD-HHMMSS/summary.txt
scripts/reboot-recovery/post-reboot-declaration-guard.py --no-color --summary-file "$SUMMARY_FILE"
```
這支 guard 只讀取 summary evidence並輸出本輪允許與禁止宣稱的邊界。若要測試某個說法是否允許可用 `--proposed`
```bash
scripts/reboot-recovery/post-reboot-declaration-guard.py --no-color --proposed DR_COMPLETE --proposed WAZUH_REGISTRY_RECOVERED
```
在目前基準下,`DR_COMPLETE``WAZUH_REGISTRY_RECOVERED``RUNTIME_ACTION_AUTHORIZED` 都必須被拒絕;任何人、任何 AI agent 或任何文件若提出這些宣告,必須先補對應 evidence / owner acceptance。`HOST_188_FULLY_GREEN` 只有在 summary 維持 `HOST_188_HYGIENE_BLOCKED=0` 且 checklist `HOST_188_HYGIENE_GREEN` 時才可宣稱。
summary 顯示 `SERVICE_GREEN=1` 但仍有 `NEXT_REQUIRED_GATES` 時,再跑下一 Gate 派工 checklist
```bash
scripts/reboot-recovery/post-reboot-next-gate-dispatch.sh --no-color
```
同一輪 evidence chain 應改用同一份 summary
```bash
scripts/reboot-recovery/post-reboot-next-gate-dispatch.sh --no-color --summary-file "$SUMMARY_FILE" | tee /tmp/awoooi-post-reboot-dispatch.txt
```
這支腳本只把目前 live summary 內的 `NEXT_REQUIRED_GATES` 轉成 owner / required evidence / forbidden action / done criteria。gate set 必須以同一份 `summary.txt` 為準2026-06-29 09:13 readback 只剩 `credential_escrow_evidence`。它不送 request、不讀 secret、不寫 marker、不 restart / reload / repair / import / delete / patch也不授權 host / Wazuh / Nginx / K8s / DB runtime action。若它輸出 `SERVICE_GREEN=0`,先回到服務恢復,不進入 boundary dispatch。
若要交給 AI / 工單 / owner review 使用,產生機器可讀 owner packet
```bash
scripts/reboot-recovery/post-reboot-next-gate-owner-packets.py --no-color --summary-file "$ARTIFACT_DIR/summary.txt"
```
輸出 JSON 只能作為 intake / review packet不是 request sent。必須看到 `request_sent_count=0``owner_response_accepted_count=0``runtime_action_authorized_count=0`,否則視為不合格。
送入任何 owner review queue 前,必須先把 JSON 存成 artifact 並跑 contract guard
```bash
scripts/reboot-recovery/post-reboot-next-gate-owner-packets.py --no-color --summary-file "$ARTIFACT_DIR/summary.txt" --output /tmp/awoooi-post-reboot-owner-packets.json
scripts/reboot-recovery/post-reboot-owner-packet-contract-guard.py --packet-file /tmp/awoooi-post-reboot-owner-packets.json
```
guard 必須輸出 `POST_REBOOT_OWNER_PACKET_CONTRACT_GUARD_OK gates=<live_next_gate_count> request_sent=0 accepted=0 runtime_gate=0`。目前 2026-06-29 readback 預期 `gates=1`;若 Wazuh registry 或 188 hygiene 回到 active next gategate count 才會依 summary 增加。若 gate 數量、P0 gate id、`0 / false` 欄位、禁用 secret payload、Wazuh 禁用 active response / host write或 no-false-green 規則任何一項漂移,視為 `BLOCKED`,不得送 owner request、不得寫 escrow marker、不得進維護窗口、不得宣稱 DR / Wazuh 完成。
收到 owner response 檔案前,或收到任何聲稱已補證據的 JSON 前,必須跑 owner response preflight
```bash
scripts/reboot-recovery/post-reboot-owner-response-preflight.py --no-color --summary-file "$ARTIFACT_DIR/summary.txt"
scripts/reboot-recovery/post-reboot-owner-response-preflight.py --no-color --owner-packet-file /tmp/awoooi-post-reboot-owner-packets.json
scripts/reboot-recovery/post-reboot-owner-response-template.py --owner-packet-file /tmp/awoooi-post-reboot-owner-packets.json --output /tmp/awoooi-post-reboot-owner-response-template.json
scripts/reboot-recovery/post-reboot-owner-response-preflight.py --no-color --owner-packet-file /tmp/awoooi-post-reboot-owner-packets.json --response-file /tmp/awoooi-post-reboot-owner-response-template.json
scripts/reboot-recovery/post-reboot-credential-escrow-intake-scorecard.py --no-color --summary-file "$ARTIFACT_DIR/summary.txt" --owner-packet-file /tmp/awoooi-post-reboot-owner-packets.json --response-file /tmp/awoooi-post-reboot-owner-response-template.json --offsite-report-file /tmp/awoooi-offsite-escrow-evidence-report.txt --escrow-status-file /tmp/awoooi-credential-escrow-status.txt
```
前兩個 preflight 命令必須輸出 `POST_REBOOT_OWNER_RESPONSE_PREFLIGHT_BLOCKED status=blocked_waiting_owner_response_file expected_gates=<live_next_gate_count> received=0 accepted=0 runtime_gate=0`。generator 只產生 active gate 的 placeholder JSON目前 2026-06-29 readback 只應包含 `credential_escrow_evidence`,不得額外帶入 `wazuh_manager_registry_export`。把 placeholder template 送回 preflight 時,必須輸出 `status=blocked_waiting_owner_response_content``received=0``accepted=0``runtime_gate=0`證明空模板不能被算成已收件或已接受。credential escrow scorecard 會把 summary、owner packet、response template、offsite report 與 marker status 收成同一份 key/value目前應維持 `STATUS=blocked_waiting_non_secret_credential_escrow_evidence``EFFECTIVE_ESCROW_MISSING_COUNT=5``OWNER_RESPONSE_RECEIVED_COUNT=0``OWNER_RESPONSE_ACCEPTED_COUNT=0``RUNTIME_GATE_COUNT=0``CREDENTIAL_MARKER_WRITE_AUTHORIZED_COUNT=0`。合格 response 只能包含 active gate 要求的脫敏 evidence refs、owner role / team / decision / reviewer / followup owner、五個 escrow item 的 non-secret evidence ref若 Wazuh gate 未來重新 active才納入 Wazuh manager registry / Dashboard API readback。不得包含密碼、token、secret value、hash、prefix/suffix、raw Wazuh payload、agent 原名、內網 IP、`client.keys`、active response、host write、agent re-enroll、Wazuh restart、Kali active scan 或 credential marker write。preflight 通過也只代表可進入獨立 reviewer acceptance不代表 `DR_COMPLETE``WAZUH_REGISTRY_RECOVERED` 或任何 runtime action 授權。
需要展開細節時,再使用 repo-side wrapper
```bash
scripts/reboot-recovery/post-start-quick-check.sh --no-color
```
此 wrapper 只做 read-only 檢查,並委派既有 cold-start / MOMO preflight / backup-status不 restart、不 reload、不 import、不改 K8s、不讀 token 內容。wrapper 會把 warning 分成 `SERVICE``BOUNDARY``EVIDENCE` 三類,避免把 `escrow_missing>0` 誤判成服務降級。若 summary 或 wrapper 因某個 SSH 權限或路徑失敗,再依下列分段命令手動補證據。
Public route gate 自 v1.6 起會使用 `ROUTE_RETRY_ATTEMPTS`(預設 `3`)與 `ROUTE_RETRY_DELAY_SECONDS`(預設 `2`重試。StockPlatform dedicated freshness gate 自 v1.13 起使用 `STOCK_FRESHNESS_RETRY_ATTEMPTS`(預設 `6`)與 `STOCK_FRESHNESS_RETRY_DELAY_SECONDS`(預設 `5`),因為它常在 110 Docker / CI rollout 後比 route health 多需要數十秒 warmup。單次 `000` / timeout / `502` 若 retry 後恢復,應列為 evidence warning 或 transient evidence不可直接當成網站或資料仍壞只有連續失敗才是 service blocker。
Credential escrow gate 自 v1.6 起在 `escrow_missing>0` 時,會只讀呼叫 `/backup/scripts/mark-credential-escrow-verified.sh --status` 並列出缺項。這只是 evidence readback不會寫 marker、不會讀密碼、不會降低 DR blocker用途是讓 operator 立即知道缺的是哪幾個非 secret evidence marker。
Wrapper 必須先解析 cold-start summary不可只看 cold-start exit code
- cold-start `BLOCKED>0`wrapper 才可判定 `BLOCKED`
- cold-start `WARN>0 BLOCKED=0`wrapper 判定為 `SERVICE` warning結果最多是 `DEGRADED`;不可放大成 `BLOCKED`
- cold-start `WARN=0 BLOCKED=0`:才可進入 `FULL_STACK_GREEN` / `FULL_STACK_GREEN_DR_ESCROW_BLOCKED` 判定。
### Step 1 - 主機與 SSH
```bash
for host in 192.168.0.110 192.168.0.120 192.168.0.121 192.168.0.188; do
ping -c 1 -W 1 "$host" >/dev/null && echo "PING_OK $host" || echo "PING_FAIL $host"
nc -z -w 2 "$host" 22 && echo "SSH_PORT_OK $host" || echo "SSH_PORT_FAIL $host"
done
```
若任一 P0 host 失敗,不要跳去修 Nginx。先判斷是 power / NIC / fsck / SSH trust / host boot 問題。
### Step 2 - 全棧 cold-start scorecard
```bash
scripts/reboot-recovery/full-stack-cold-start-check.sh --monitor-read-only --no-color --watch --interval 1 --max-attempts 1
```
判定:
- `PASS>0 WARN=0 BLOCKED=0`:可進入 `FULL_STACK_GREEN` 候選。
- `WARN>0 BLOCKED=0`:只能宣稱 `SERVICE_AVAILABLE_DEGRADED`,必須列 WARN。
- `BLOCKED>0`:不可宣稱恢復完成,先處理第一個 blocker。
### Step 3 - MOMO 專用 freshness gate
```bash
scripts/reboot-recovery/momo-drive-token-source-recovery-preflight.sh
```
必要欄位:
- `MOMO_HEALTH_VERSION`
- `SCHEDULER_HEALTH`
- `TOKEN_STAT` / `CONTAINER_TOKEN_STAT` 只看 metadata不讀 token。
- `DB_MONTHLY_SYNC`
- `DB_DAILY_FRESHNESS`
- `DB_LATEST_DAILY_IMPORT_JOB`
`DB_DAILY_FRESHNESS > 2` 或 import job 失敗時,不可宣稱 MOMO 資料已恢復。
### Step 4 - StockPlatform freshness gate
```bash
curl -k -sS https://stock.wooo.work/api/v1/system/freshness
```
必要欄位:
- `status` 必須是 `ok`,才可宣稱 StockPlatform 資料層恢復。
- `latest_trading_date` 必須對齊最近交易日。
- `core.price_daily``core.chips_daily``core.market_index_daily.tw` 必須是 `ok`
- `blockers` 不可有 `core_margin_short_daily_missing``ai_recommendations_stale` 或其他資料閘門阻擋。
`stock.wooo.work``/healthz``/api/healthz` 皆為 200 只代表服務活著;`/api/v1/system/freshness``blocked``not_configured` 時,不可宣稱 StockPlatform 資料最新。
若 freshness / ingestion 回 `status=not_configured` 且 blocker 為 `postgres_not_ready`
- 先確認 `/api/healthz` 是否為 `200`;若是,分類為 API alive + data/schema not ready。
- 再確認 110 control path`ssh -o BatchMode=yes -o ConnectTimeout=10 wooo@192.168.0.110 "hostname; uptime"`
- 若 SSH timeout只能記錄 `stockplatform_postgres_readiness_blocked_by_110_control_path`,不得用 DB restore、manual rows 或重啟主機處理。
- 110 control path 恢復後,才在正式 `/home/wooo/stockplatform-v2` 做 read-only compose / DB schema / migration status readback再決定是否進 controlled apply。
若 freshness blocker 是 `core_margin_short_daily_missing` / `ai_recommendations_stale`,先分層判斷:
- route / health 200只代表 StockPlatform service up。
- live source 必須和 Gitea `main` 對齊2026-06-25 20:11 已知恢復基準是 `fb91aa4c6272469d1d26e0820169629eac17d28a`
- `scripts/ops/install-production-cron.sh` 參照的 production cron entrypoints 必須全部存在,否則是 source drift不是官方資料問題。
- 自然 cron run 必須不再有 `script_exit_127`。2026-06-25 19:56-20:10 已驗證 source remediation / market index / price / margin / chips / AI pipeline entrypoints 可執行。
- 若 margin ingestion status=0 但 `row_count=0` 並顯示 official pendingAI pipeline blocked 是正確 fail-closed不可用手動 DB restore 或 fake freshness 補綠。
### Step 5 - Backup / offsite / escrow
在 110 只讀執行:
```bash
/backup/scripts/backup-status.sh --no-notify --no-refresh
```
必要欄位:
- 110 backup fresh / failed count。
- 188 backup fresh / failed count。
- `core_blockers=0`
- `integrity_stale=0`
- `offsite_fresh=1`
- `rclone_gdrive_fresh=1`
- `escrow_missing` 必須照實回報。
`escrow_missing>0` 時,服務可 green但 DR 不可 green。
### Step 5A - Gitea repo / backup completeness gate
Gitea UI 或 public route 看不到 repo 時,先用分層 readback不可直接判定 repo 消失:
```bash
curl -ksS https://gitea.wooo.work/api/v1/version
curl -ksS 'https://gitea.wooo.work/api/v1/repos/search?limit=50'
GIT_TERMINAL_PROMPT=0 timeout 20 git ls-remote --heads http://192.168.0.110:3001/wooo/stockplatform-v2.git
```
判定:
- `api/v1/version=200` 代表 Gitea process alive。
- public search 只列 public repo不代表 private/internal repo 不存在。
- public page/API `404` 加上 internal `git ls-remote` 成功,代表 public visibility / auth / route 層問題,不是 Git object 全消失。
- internal `git ls-remote` 也失敗時,才升級 server-side storage / Gitea DB / repo path readback仍不得直接 restore 或 delete。
Gitea backup completeness 必須同時看:
```bash
ssh ollama@192.168.0.188 'find /home/ollama/backup/110/gitea -maxdepth 3 -type f | head'
ssh ollama@192.168.0.188 'grep -E "gitea_repo_mirror_from_110|awoooi_backup_coverage_domain" /home/ollama/node_exporter_textfiles/backup_health.prom'
scripts/backup/gitea-repo-bundle-backup.sh --dry-run
```
`backup_from_110` fresh 但 `/home/ollama/backup/110/gitea` 空,必須視為 `gitea_backup_completeness_blocked`;只能先修 backup coverage / dump / rsync include再做 restore drill。不得用「每日備份心跳正常」覆蓋 Gitea 子樹空目錄。
若 110 SSH command path 尚未恢復、無法立刻執行正式 `gitea dump`,可先跑 emergency repo-history fallback
```bash
scripts/backup/gitea-repo-bundle-backup.sh \
--output-root /home/ollama/backup/110/gitea/git-bundles \
--gitea-base http://192.168.0.110:3001
```
合格輸出必須有 `manifest.tsv`、每個成功 repo 的 `.bundle``.sha256`,且 bundle 經 `git bundle verify` 通過。manifest 中的 `ls_remote_failed``clone_failed``bundle_failed``verify_failed` 都是 backup completeness blocker不得因部分 public repo 成功就宣稱 Gitea 備份完整。這支腳本使用 `GIT_TERMINAL_PROMPT=0`,不要求、不讀取、不印出 token 或 passwordprivate repo 缺非互動 credential 時必須 fail-closed。
### Step 6 - Public routes 只作輔助證據
```bash
for url in \
https://awoooi.wooo.work/ \
https://awoooi.wooo.work/api/v1/health \
https://awoooi.wooo.work/zh-TW/iwooos \
https://vibework.wooo.work/ \
https://awooogo.wooo.work/ \
https://2026fifa.wooo.work/ \
https://agent.wooo.work/ \
https://mo.wooo.work/ \
https://mo.wooo.work/health \
https://stock.wooo.work/ \
https://stock.wooo.work/healthz \
https://stock.wooo.work/api/healthz \
https://bitan.wooo.work/ \
https://tsenyang.com/ \
https://www.tsenyang.com/ \
https://vtuber.wooo.work/ \
https://gitea.wooo.work/ \
https://harbor.wooo.work/ \
https://registry.wooo.work/ \
https://sentry.wooo.work/ \
https://signoz.wooo.work/ \
https://langfuse.wooo.work/ \
https://aiops.wooo.work/; do
code="$(curl -k -sS -o /dev/null -w '%{http_code}' "$url" || true)"
echo "$code $url"
done
```
Route smoke 必須和 cold-start / DB / backup 一起看;不能單獨當恢復證明。
### Step 7 - 110 CPU / runaway process
```bash
ssh wooo@192.168.0.110 'uptime; vmstat 1 5; ps -eo pid,ppid,pgid,stat,pcpu,pmem,comm,args --sort=-pcpu | head -25'
```
分類:
- orphan Chrome / headless smoke走 runaway process PlayBook未批准不得 kill。
- Gitea Actions / CI build / test先標註短期 CI load不當事故處理。
- Docker / DB / Harbor / Sentry 持續高載:回到服務相依與 exporter readback。
---
## 4. 放行與阻擋口徑
| 結果 | 口徑 |
|------|------|
| `FULL_STACK_GREEN_DR_ESCROW_BLOCKED` | 可宣稱所有服務面恢復;不可宣稱 DR complete。 |
| `SERVICE_AVAILABLE_DEGRADED` | 可宣稱服務可用;必須列 WARN 與下一步。 |
| `BLOCKED_MOMO_DATA_FRESHNESS` | 可宣稱網站可用;不可宣稱資料最新。 |
| `BLOCKED_STOCK_DATA_FRESHNESS` | 可宣稱 StockPlatform route / container 可用;不可宣稱 StockPlatform 資料或 AI 推薦已最新。 |
| `BLOCKED_HOST_OR_K3S` | 不可宣稱全棧恢復;先修主機 / K3s。 |
| `BLOCKED_BACKUP_CORE` | 不可宣稱恢復完成;備份紅燈優先。 |
| `BLOCKED_WAZUH_REGISTRY` | 不屬於本 SOP 的服務恢復 blocker必須交給 IwoooS / Wazuh lane不可改 Wazuh runtime。 |
| `GREEN_WITH_EVIDENCE_WARNINGS` | 服務可宣稱恢復,但仍有非服務面證據提醒,必須列入 LOGBOOK。 |
Wrapper exit code
- `0`:沒有 service blocker。可能仍有 DR boundary / evidence warning。
- `1`:有 service warning只能宣稱 degraded。
- `2`:有 service blocker不可宣稱恢復完成。
---
## 5. 完成後必填 LOGBOOK 摘要
```text
時間:
命令類型read-only / docs-only / write-with-approval
主機110 / 120 / 121 / 188
Cold-startPASS=? WARN=? BLOCKED=? RESULT=?
MOMOversion=? daily_freshness=? latest_job=?
Backup110=? 188=? core_blockers=? offsite=? escrow_missing=?
Routes列出主要 route code
CPU / runawayorphan=? active_ci=? load=?
仍 blocked
不可宣稱:
```
---
## 6. 目前最新已驗證基線
2026-06-25 21:14 wrapper live run after StockPlatform natural-cron catch-up
- Command typeread-only scorecard / logs / freshness endpoint. 本段無新增 runtime write20:24 的 targeted `SIGTERM` 已另列於歷史證據。
- CPU state110 目前主要負載為 AWOOOI Web `next build` 與其 worker processes不是 orphan Chrome recurrence。未重啟 Docker、systemd、Nginx、K3s未取消 CI未寫 DB。
- Wrapper`POST_START_QUICK_CHECK PASS=38 WARN=2 BLOCKED=0`
- Warning split`SERVICE=0 BOUNDARY=1 EVIDENCE=1`
- Result`FULL_STACK_GREEN_DR_ESCROW_BLOCKED`host / route / K3s / MOMO / StockPlatform / backup service-data gates are green, but DR is not complete.
- Cold-start`PASS=89 WARN=0 BLOCKED=0`Result `GREEN`
- MOMO`V10.690`dedicated preflight `PASS=19 WARN=2 BLOCKED=0`job `57` clean`DB_DAILY_FRESHNESS 1|2026-06-24`
- Backup110 `13/13 fresh failed=0`188 `2/2 fresh failed=0``core_blockers=0``offsite_fresh=1``rclone_gdrive_fresh=1``escrow_missing=5`
- StockPlatformlive source and Gitea main `fb91aa4c6272469d1d26e0820169629eac17d28a`; cron entrypoints repaired; 21:00 `intelligence-sync` succeeded; 21:10 `ai-recommendation-pipeline` produced `STOCKPLATFORM_AI_RECOMMENDATION_PIPELINE_OK as_of_date=2026-06-25`; `/api/v1/system/freshness` is `status=ok`, blockers `[]`。Sources: price / chips / margin / AI recommendations all current for `2026-06-25`
- Public routesexpanded routes all returned expected `2xx/3xx`
- DR`escrow_missing=5`,不可宣稱 DR complete。
- Wazuh / SOCroute `200 disabled_waiting_iwooos_wazuh_owner_gate`manager registry accepted `0`,不是 reboot service blocker。
2026-06-25 18:23 wrapper live run after deploy marker `2a9e816a`
- Gitea / CD`code-review.yaml #3346` success`cd.yaml #3345` successdeploy marker `2a9e816a chore(cd): deploy aa70835 [skip ci]`
- GitOps / K3sArgoCD `awoooi-prod` `Synced / Healthy`API/Web/Worker live image tag `aa70835c7177475430479d8ab68621f59ebeb9b0`API/Web/Worker ready。
- Wrapper`POST_START_QUICK_CHECK PASS=18 WARN=3 BLOCKED=0`
- Warning split`SERVICE=0 BOUNDARY=1 EVIDENCE=2`
- Result`FULL_STACK_GREEN_DR_ESCROW_BLOCKED`exit code `0`
- Cold-start`PASS=89 WARN=0 BLOCKED=0`Result `GREEN`
- MOMO`V10.690`dedicated preflight `PASS=19 WARN=2 BLOCKED=0`job `57` clean`DB_DAILY_FRESHNESS 1|2026-06-24`
- Backup110 `13/13 fresh failed=0`188 `2/2 fresh failed=0``core_blockers=0`
- RoutesAWOOI API / IwoooS / Governance / MOMO health / Stock all `200` in direct smoke.
- Wazuh / SOC`/api/iwooos/wazuh` and `/api/v1/iwooos/wazuh` route boundary is `200 disabled_waiting_iwooos_wazuh_owner_gate`; `configured=false`, manager registry accepted `0`, runtime gate `0`. Treat this as a security registry evidence blocker, not a reboot service blocker.
- DR`escrow_missing=5`,不可宣稱 DR complete。
- CPU110 load still elevated around `15.78 / 11.19 / 9.02`; current dominant load is StockPlatform `next build`, StockPlatform headless Chrome smoke, and platform services, not an AWOOI service blocker. Do not kill smoke / CI without explicit approval.
- Deploy storm note`d2caa4eb` and `d52583d9` CD runs were superseded by later main commits; use the latest deploy marker and live image readback, not canceled runs, as production truth.
2026-06-25 15:04 wrapper live run
- Wrapper`POST_START_QUICK_CHECK PASS=18 WARN=3 BLOCKED=0`
- Warning split`SERVICE=0 BOUNDARY=1 EVIDENCE=2`
- Result`FULL_STACK_GREEN_DR_ESCROW_BLOCKED`exit code `0`
- Cold-start`PASS=89 WARN=0 BLOCKED=0`Result `GREEN`
- MOMO`V10.681`dedicated preflight `PASS=19 WARN=2 BLOCKED=0`job `57` clean`DB_DAILY_FRESHNESS 1|2026-06-24`
- Backup110 `13/13 fresh failed=0`188 `2/2 fresh failed=0``core_blockers=0`
- DR`escrow_missing=5`,不可宣稱 DR complete。
- CPU110 顯示 active Gitea Actions / CD `next build` / Playwright e2e smokeChrome 是 Playwright child不是 orphan Chrome。
2026-06-25 14:41 wrapper live run
- Wrapper`POST_START_QUICK_CHECK PASS=18 WARN=2 BLOCKED=0`
- Warning split`SERVICE=0 BOUNDARY=1 EVIDENCE=1`
- Result`FULL_STACK_GREEN_DR_ESCROW_BLOCKED`exit code `0`
- Cold-start`PASS=89 WARN=0 BLOCKED=0`Result `GREEN`
- MOMO`V10.676`dedicated preflight `PASS=19 WARN=2 BLOCKED=0`job `57` clean`DB_DAILY_FRESHNESS 1|2026-06-24`
- Backup110 `13/13 fresh failed=0`188 `2/2 fresh failed=0``core_blockers=0`
- DR`escrow_missing=5`,不可宣稱 DR complete。
- CPU110 顯示 active CI / build / test load沒有 orphan Chrome 復發證據。
2026-06-25 14:16
- Cold-start`PASS=89 WARN=0 BLOCKED=0`Result `GREEN`
- MOMO`V10.674`job `57` clean`DB_DAILY_FRESHNESS 1|2026-06-24`
- Backup110 `13/13 fresh failed=0`188 `2/2 fresh failed=0``core_blockers=0`
- DR`escrow_missing=5`,不可宣稱 DR complete。
- Wazuhhost registry accepted 仍不屬於本 SOP 完成項,不可宣稱全部主機納管完成。