fix(cold-start): split stale evidence from live blockers
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 1m51s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
Your Name
2026-07-01 21:34:13 +08:00
parent 2cfb891e57
commit 10275a9d7b
5 changed files with 107 additions and 11 deletions

View File

@@ -1,3 +1,29 @@
## 2026-07-01 — 21:32 cold-start 假 WARN 收斂與 live monitor 同步
**照主線修正的問題**
- MOMO current-month false warning`momo-drive-token-source-recovery-preflight.sh` 新增 `MOMO_LATEST_IMPORT_CLEAN``MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE` 機器可讀欄位;`full-stack-cold-start-check.sh` 先吃 dedicated preflight再把 `MOMO_MONTHLY_SYNC 0|0|-|-|-|-` + latest clean import + no newer Drive source 判為 not applicable不再把沒有本月新來源的 0|0 當成 cold-start WARN。
- 110 backup aggregate false warningcold-start 現在把 current component freshness / critical config gap 與舊 `backup-all failed_count` 分開。`BACKUP_HEALTH_110 total=13 stale=0 missing_cron=0 missing_script=0 failed_count=5 config_failed=0 integrity_total=2 integrity_stale=0` 會列為 current backup health OK並把舊 aggregate failed_count 只輸出 INFO evidence。
- live 110 monitor 已同步本輪 source`full-stack-cold-start-check.sh` hash `d0711f75dfb1ee680442c9d6cf2191741f3b27605f347c9ef2a25a4fed6d40ac``momo-drive-token-source-recovery-preflight.sh` hash `571d75e81c509683eb8a38fabbe81fc7822befe45206145f4fb4e865473f5254`crontab 仍為每 10 分鐘執行 `cold-start-textfile-exporter.sh`
**驗證**
- `bash -n scripts/reboot-recovery/full-stack-cold-start-check.sh scripts/reboot-recovery/momo-drive-token-source-recovery-preflight.sh`:通過。
- `python3.11 -m pytest scripts/reboot-recovery/tests/test_cold_start_monitor_bounded_probes.py -q``14 passed`
- `git diff --check`:通過。
- live cold-start final`PASS=95 WARN=1 BLOCKED=0`artifact `/tmp/awoooi-cold-start-final-20260701-212632.log`。public routes / TLS 全部通過StockPlatform 前一輪 502 已確認是 21:22 左右 web/admin/edge 替換 warmup之後外部連續 5 次 `https://stock.wooo.work/``200`final cold-start 亦回 `stock 200`
- K3s rollout 暫態已自然收斂:前一輪 `BAD_PODS=2` 是新 AWOOOI pod rollout 時舊 pod terminating連續 6 次只讀觀察無非 Running/Completed podfinal cold-start `BAD_PODS 0`
- 110 textfile readback`awoooi_cold_start_monitor_up=1``pass=95``warn=1``blocked=0``last_exit_code=1``last_result{result="degraded"}=1``last_run_duration_seconds=132`
- `REMOTE_COMMAND_TIMEOUT_SECONDS=90 SSH_CONNECT_TIMEOUT=15 bash scripts/reboot-recovery/verify-cold-start-monitor-deploy.sh``COLD_START_MONITOR_DEPLOY_PARITY_OK`runtime state `monitor_up=1 warn=1 blocked=0 green=0 blocked_state=0`
- `REMOTE_COMMAND_TIMEOUT_SECONDS=90 SSH_CONNECT_TIMEOUT=15 bash scripts/reboot-recovery/full-stack-recovery-scorecard.sh``CORE_COLD_START_WARN_GATES=1``CORE_COLD_START_BLOCKED_GATES=0``CORE_COLD_START_DEPLOY_PARITY=1``CORE_REGISTRY_READY=1``DR_OFFSITE_EVIDENCE_READBACK=1``ESCROW_MISSING_COUNT=5``NEXT_STEP=complete_credential_escrow_review`
**仍維持 / 未完成**
- 目前唯一 cold-start WARN 是 MOMO daily data freshness`MOMO_DAILY_FRESHNESS 7|2026-06-24`,且 preflight 顯示 `PASS=19 WARN=6 BLOCKED=0`、Drive intake `0`、failed folder `0`、沒有比最後 clean import 更新的 source candidate。可宣稱「服務恢復、沒有新來源候選」不可宣稱「MOMO 業績資料已最新」。
- `ESCROW_MISSING_COUNT=5` 仍是真正 DR completion gate不得偽造 marker、不得把一般批准當成 credential escrow evidence。
- 110 control path 仍有 intermittent timeout evidenceinstaller 首次 `scp` timeout重試成功110 當下 load 約 `7-8`top 包含 `systemd``gitea`、StockPlatform Postgres、ClickHouse、Kafka、Docker。服務可用但不得宣稱 110 SSH 永久穩定。
**邊界**:未重啟主機,未 restart Docker / Nginx / K3s / DB / firewall未刪 pod未讀 secret value / token / `.env` / raw sessions / SQLite / auth未寫 credential escrow marker未使用 GitHub / `gh` / GitHub API未恢復 generic runner。
**下一步**:照 P0 主線處理唯一剩餘 cold-start WARNMOMO daily source freshness / source-arrival gateDR completion 另依 `complete_credential_escrow_review` 收 5 個 non-secret evidence。110 load / SSH timeout 留在 capacity/control-channel evidence不再回頭重開 runner 支線。
## 2026-07-01 — 21:05 backup / DR freshness 收斂與高頻備份保護
**照主線修正的問題**

View File

@@ -1,6 +1,6 @@
# AWOOOI 全棧冷啟動與主機重啟 SOP
> Version: v1.88
> Version: v1.89
> Last updated: 2026-07-01 Asia/Taipei
> Scope: 110 / 120 / 121 / 188 full-stack reboot recovery. 112 Kali is recorded as P3 optional and is not part of this recovery path.
@@ -18,7 +18,9 @@ v1.79 active owner response template rule同一輪 owner packet 產生後p
v1.80 / v1.81 credential escrow intake scorecard rule同一輪 owner response preflight 後,必須用 `scripts/reboot-recovery/post-reboot-credential-escrow-intake-scorecard.py --summary-file "$ARTIFACT_DIR/summary.txt" --owner-packet-file <owner-packets.json> --response-file <owner-response-template-or-candidate.json> --offsite-report-file <offsite-report.txt> --escrow-status-file <escrow-status.txt>` 收斂 DR escrow gate。scorecard 只讀 sanitized artifacts不得讀 secret value、不得寫 marker、不得送 owner request、不得開 runtime gate。placeholder readback 期望 `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`。若未來收到合格 redacted owner response 並由 preflight 回 `ready_for_independent_reviewer_acceptance`scorecard 應轉為 `STATUS=ready_for_independent_reviewer_acceptance`;即使 marker 尚未寫入,也只能進 `independent_reviewer_acceptance_then_marker_dry_run`,不得直接寫 marker 或宣稱 `DR_COMPLETE`
2026-07-01 21:05 latest live summarybackup / DR freshness 已收斂,但仍不可宣稱 full green 或 10 分鐘全自動恢復完成。188 `backup_from_110` 已受控重跑成功Harbor / Gitea / bitan backup 均 OK188 exporter 讀回 `backup_from_110 fresh=1`、Gitea private bundle `expected_repo_missing_count=0``failed_repo_count=0`。110 `awoooi_db` high-frequency backup 20:00 因 `too many connections for role "awoooi"` 失敗;本輪在 DB 舊 OR 查詢為 `0`、Postgres CPU 已低的條件下走 controlled short window產生 Restic snapshot `211a8948`,時間 `2026-07-01T20:58:20+08:00`tags `service:awoooi,freq:6h,timestamp:20260701_204344`tmp dump 已清除。正式保守調整為 `awoooi CONNECTION LIMIT 4`,保留 `statement_timeout=750ms``max_parallel_workers_per_gather=0``enable_seqscan=off`rollback 是 `ALTER ROLE awoooi CONNECTION LIMIT 2` 並保留同樣 role config。110 backup exporter 讀回 `awoooi_backup_job_fresh{job="awoooi_db"} 1``awoooi_backup_dr_phase{next_step="complete_credential_escrow_review"} 3``awoooi_backup_dr_credential_escrow_missing_count 5``full-stack-cold-start-check.sh --monitor-read-only --no-color --watch --interval 1 --max-attempts 1``PASS=93 WARN=3 BLOCKED=0``full-stack-recovery-scorecard.sh``CORE_COLD_START_WARN_GATES=3``CORE_COLD_START_BLOCKED_GATES=0``CORE_COLD_START_DEPLOY_PARITY=1``CORE_REGISTRY_READY=1``DR_OFFSITE_EVIDENCE_READBACK=1``NEXT_STEP=complete_credential_escrow_review`。Allowed declarationpublic routes / AWOOOI service / Gitea / Harbor registry / 188 backup-from-110 / 110 awoooi_db freshness 已恢復cold-start hard blockers `0`。Forbidden declarationfull green、10 分鐘全自動恢復完成、DR complete、credential escrow complete、MOMO data 最新、110 SSH 永久穩定。剩餘 WARN 是 MOMO current-month/source freshness warning 與 110 aggregate `backup-all` 上次 failed components。高頻全量 `pg_dump` 本輪耗時 `1152s` 並產生 `28G` dump後續 P0 必須建立專用 backup DB role / `AWOOOI_BACKUP_DATABASE_URL`,並把大型可重建 snapshot 表改成分層備份或 retention 後納入 full backup不得把 app role 放寬當長期唯一解法
2026-07-01 21:32 latest live summarycold-start 假 WARN 已收斂hard blockers 維持 `0`,但仍不可宣稱 full green 或 10 分鐘全自動恢復完成。`full-stack-cold-start-check.sh --monitor-read-only --no-color --watch --interval 1 --max-attempts 1` final artifact `/tmp/awoooi-cold-start-final-20260701-212632.log``PASS=95 WARN=1 BLOCKED=0`public routes / TLS 全部通過StockPlatform 21:22 左右的 `502` 已確認是 web/admin/edge 替換 warmup外部連續 5 次 `https://stock.wooo.work/``200`final cold-start 亦回 `stock 200`。K3s `BAD_PODS=2` 也是 rollout 暫態,連續 6 次只讀觀察已無非 Running/Completed podfinal `BAD_PODS 0`。MOMO current-month `0|0|-|-|-|-` 不再列為 WARN`momo-drive-token-source-recovery-preflight.sh` 會輸出 `MOMO_LATEST_IMPORT_CLEAN``MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE`cold-start 讀到 latest clean import 且 Drive 無更新 source candidate 時,判定 current-month sync not applicable。110 backup current health 也不再被舊 aggregate log 壓成 WARN`BACKUP_HEALTH_110 total=13 stale=0 missing_cron=0 missing_script=0 failed_count=5 config_failed=0 integrity_total=2 integrity_stale=0` 代表 current component freshness / critical config / integrity OK`failed_count=5` 保留為 INFO evidence等下一次 full `backup-all` 自然覆蓋。live 110 monitor 已同步hash `full-stack-cold-start-check.sh=d0711f75dfb1ee680442c9d6cf2191741f3b27605f347c9ef2a25a4fed6d40ac``momo-drive-token-source-recovery-preflight.sh=571d75e81c509683eb8a38fabbe81fc7822befe45206145f4fb4e865473f5254`110 textfile 讀回 `awoooi_cold_start_monitor_up=1``pass=95``warn=1``blocked=0``last_exit_code=1``last_result{result="degraded"}=1``verify-cold-start-monitor-deploy.sh``COLD_START_MONITOR_DEPLOY_PARITY_OK``full-stack-recovery-scorecard.sh``CORE_COLD_START_WARN_GATES=1``CORE_COLD_START_BLOCKED_GATES=0``CORE_COLD_START_DEPLOY_PARITY=1``CORE_REGISTRY_READY=1``DR_OFFSITE_EVIDENCE_READBACK=1``ESCROW_MISSING_COUNT=5``NEXT_STEP=complete_credential_escrow_review`。Allowed declarationpublic routes / AWOOOI service / Gitea / Harbor registry / 188 backup-from-110 / 110 awoooi_db freshness / K3s rollout / Stock public route 已恢復cold-start hard blockers `0`。Forbidden declarationfull green、10 分鐘全自動恢復完成、DR complete、credential escrow complete、MOMO data 最新、110 SSH 永久穩定。唯一 cold-start WARN 是 MOMO daily data freshness`MOMO_DAILY_FRESHNESS 7|2026-06-24`,且 Drive intake / failed folder 無新候選;必須走 source-arrival / formal import gate不可用假資料或手動 DB 寫入掩蓋
2026-07-01 21:05 previous live summarybackup / DR freshness 已收斂,但仍不可宣稱 full green 或 10 分鐘全自動恢復完成。188 `backup_from_110` 已受控重跑成功Harbor / Gitea / bitan backup 均 OK188 exporter 讀回 `backup_from_110 fresh=1`、Gitea private bundle `expected_repo_missing_count=0``failed_repo_count=0`。110 `awoooi_db` high-frequency backup 20:00 因 `too many connections for role "awoooi"` 失敗;本輪在 DB 舊 OR 查詢為 `0`、Postgres CPU 已低的條件下走 controlled short window產生 Restic snapshot `211a8948`,時間 `2026-07-01T20:58:20+08:00`tags `service:awoooi,freq:6h,timestamp:20260701_204344`tmp dump 已清除。正式保守調整為 `awoooi CONNECTION LIMIT 4`,保留 `statement_timeout=750ms``max_parallel_workers_per_gather=0``enable_seqscan=off`rollback 是 `ALTER ROLE awoooi CONNECTION LIMIT 2` 並保留同樣 role config。110 backup exporter 讀回 `awoooi_backup_job_fresh{job="awoooi_db"} 1``awoooi_backup_dr_phase{next_step="complete_credential_escrow_review"} 3``awoooi_backup_dr_credential_escrow_missing_count 5``full-stack-cold-start-check.sh --monitor-read-only --no-color --watch --interval 1 --max-attempts 1``PASS=93 WARN=3 BLOCKED=0``full-stack-recovery-scorecard.sh``CORE_COLD_START_WARN_GATES=3``CORE_COLD_START_BLOCKED_GATES=0``CORE_COLD_START_DEPLOY_PARITY=1``CORE_REGISTRY_READY=1``DR_OFFSITE_EVIDENCE_READBACK=1``NEXT_STEP=complete_credential_escrow_review`。Allowed declarationpublic routes / AWOOOI service / Gitea / Harbor registry / 188 backup-from-110 / 110 awoooi_db freshness 已恢復cold-start hard blockers `0`。Forbidden declarationfull green、10 分鐘全自動恢復完成、DR complete、credential escrow complete、MOMO data 最新、110 SSH 永久穩定。剩餘 WARN 是 MOMO current-month/source freshness warning 與 110 aggregate `backup-all` 上次 failed components。高頻全量 `pg_dump` 本輪耗時 `1152s` 並產生 `28G` dump後續 P0 必須建立專用 backup DB role / `AWOOOI_BACKUP_DATABASE_URL`,並把大型可重建 snapshot 表改成分層備份或 retention 後納入 full backup不得把 app role 放寬當長期唯一解法。
2026-07-01 19:32 latest live summary110 卡住的根因已確認並修復。主機 ping / SSH / Prometheus / Gitea / registry 均可達,但 `awoooi-startup-110.service``/usr/local/bin/awoooi-startup-110.sh` 被替換成 runner/CD lane fail-closed stub 而固定 `exit 75`,造成 post-reboot systemd degraded 與 cold-start warning。live stub hash 為 `55e1e87d44cf5b8cefb714a49d085b886697d856569ce9478537059d49129f88`repo 完整 startup script hash 為 `fcc67c7dde889b3cf8ffeca89cc5e58407fabc6f5a80554e39f3f1465f90b318`。修復方式固定使用 `scripts/reboot-recovery/repair-110-startup-script-stub.sh`:預設 `--verify` 只讀;`--apply` 只上傳 repo 完整 startup script、備份 live stub、解除 immutable、install 到 `/usr/local/bin/awoooi-startup-110.sh``systemctl daemon-reload`,並只 `reset-failed awoooi-startup-110.service``--start-service` 需另外明確指定,因為它會跑完整 startup checks。live apply 指令為 `BACKUP_SUFFIX=before-full-startup-restore-20260701-1928 bash scripts/reboot-recovery/repair-110-startup-script-stub.sh --apply`post-readback `remote_matches_expected=1``remote_is_runner_failclosed_stub=0`rollback backup 為 `/usr/local/bin/awoooi-startup-110.sh.before-full-startup-restore-20260701-1928`。之後清除 stale `systemd-ask-password-console.path` / `systemd-ask-password-wall.path` failed state110 已回 `systemctl is-system-running=running`、failed units `0`。最新 cold-start 讀回 `PASS=90 WARN=6 BLOCKED=0``FAILED_UNITS_110 0`110 startup stub / systemd degraded 不再是 blocker。禁止再把 live `/usr/local/bin/awoooi-startup-110.sh` 當 runner/CD lane opener 封成 stubrunner fail-closed enforcer 只能封 runner binary、runner unit、controlled opener artifact 或 upload opener source不得封 host startup recovery script。Allowed declaration110 不再卡在 startup stub / systemd degradedcold-start hard blockers `0`。Forbidden declarationfull green、10 分鐘全自動恢復已完成、DR complete、credential escrow complete、MOMO data 最新或 110 SSH 永久穩定;剩餘 warnings 仍需由 backup / DR escrow / alert 收斂處理。

View File

@@ -770,7 +770,15 @@ printf "%s\n" "$momo_drive_source_probe"
awk '/MOMO_GDRIVE_TOKEN_STAT / {split($2,a,":"); split($3,b,"="); exit !(a[1] == b[2] && a[3] <= 600)}' <<<"$out" && ok "188 momo Google Drive token ownership matches scheduler userns" || warn "188 momo Google Drive token ownership/writeback not confirmed"
grep -Fq "MOMO_IMPORT_CONFIG 當日業績匯入|即時業績_當日" <<<"$out" && ok "188 momo Drive import config points to expected daily-sales intake" || fail "188 momo Drive import config drifted from expected daily-sales intake"
awk '/MOMO_LATEST_IMPORT_JOB / {split($2,a,"|"); exit !(a[1] ~ /^[0-9]+$/ && a[2] == "completed" && a[6] == a[7] && a[8] == 0)}' <<<"$out" && ok "188 momo latest daily import job completed cleanly" || warn "188 momo latest daily import job not confirmed clean"
awk '/MOMO_MONTHLY_SYNC / {split($2,a,"|"); exit !(a[1] > 0 && a[1] == a[2] && a[3] == a[5] && a[4] == a[6])}' <<<"$out" && ok "188 momo current-month snapshot and realtime tables match" || warn "188 momo current-month snapshot/realtime sync not confirmed"
momo_latest_import_clean=$(awk '
$1 == "MOMO_LATEST_IMPORT_JOB" {
seen=1
split($2,a,"|")
if (a[1] ~ /^[0-9]+$/ && a[2] == "completed" && a[6] == a[7] && a[8] == 0) print 1;
else print 0;
}
END { if (!seen) print 0 }
' <<<"$out")
momo_source_stale_only=$(awk '
$1 == "MOMO_DRIVE_INTAKE_COUNT" {intake=$2+0}
$1 == "MOMO_DRIVE_FAILED_COUNT" {failed=$2+0}
@@ -780,19 +788,42 @@ printf "%s\n" "$momo_drive_source_probe"
if (intake == 0 && failed == 0 && global ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ && completed ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ && global <= completed) print 1;
else print 0;
}' <<<"$out")
momo_source_preflight_output=""
momo_source_preflight_summary=""
if [ "$momo_source_stale_only" != "1" ] && [ "$momo_latest_import_clean" = "1" ] && [ -x "$MOMO_SOURCE_PREFLIGHT_SCRIPT" ]; then
momo_source_preflight_output="$(
"$MOMO_SOURCE_PREFLIGHT_SCRIPT" \
--host ollama@192.168.0.188 \
--freshness-max-days 2 2>/dev/null || true
)"
momo_source_preflight_summary="$(awk '/^MOMO_DRIVE_TOKEN_SOURCE_PREFLIGHT / {line=$0} END {print line}' <<<"$momo_source_preflight_output")"
[ -n "$momo_source_preflight_summary" ] && echo "$momo_source_preflight_summary"
if awk '$1 == "MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE" {seen=1; ok=($2 == 1)} END {exit !(seen && ok)}' <<<"$momo_source_preflight_output"; then
momo_source_stale_only=1
fi
fi
if awk '/MOMO_MONTHLY_SYNC / {seen=1; split($2,a,"|"); ok=(a[1] > 0 && a[1] == a[2] && a[3] == a[5] && a[4] == a[6])} END {exit !(seen && ok)}' <<<"$out"; then
ok "188 momo current-month snapshot and realtime tables match"
elif [ "$momo_latest_import_clean" = "1" ] && [ "$momo_source_stale_only" = "1" ] && awk '/MOMO_MONTHLY_SYNC / {seen=1; split($2,a,"|"); ok=(a[1] == 0 && a[2] == 0)} END {exit !(seen && ok)}' <<<"$out"; then
ok "188 momo current-month sync not applicable; Drive has no newer source than last clean import"
else
warn "188 momo current-month snapshot/realtime sync not confirmed"
fi
if awk '/MOMO_DAILY_FRESHNESS / {split($2,a,"|"); exit !(a[1] ~ /^[0-9]+$/ && a[1] >= 0 && a[1] <= 2)}' <<<"$out"; then
ok "188 momo daily sales data fresh enough"
elif awk '/MOMO_DAILY_FRESHNESS / {split($2,a,"|"); exit !(a[1] ~ /^[0-9]+$/ && a[1] >= 3)}' <<<"$out"; then
if [ "$momo_source_stale_only" = "1" ]; then
warn "188 momo daily sales stale but Drive has no newer source candidate"
elif [ -x "$MOMO_SOURCE_PREFLIGHT_SCRIPT" ]; then
momo_source_preflight_summary="$(
"$MOMO_SOURCE_PREFLIGHT_SCRIPT" \
--host ollama@192.168.0.188 \
--freshness-max-days 2 2>/dev/null \
| awk '/^MOMO_DRIVE_TOKEN_SOURCE_PREFLIGHT / {line=$0} END {print line}' || true
)"
[ -n "$momo_source_preflight_summary" ] && echo "$momo_source_preflight_summary"
if [ -z "$momo_source_preflight_summary" ]; then
momo_source_preflight_output="$(
"$MOMO_SOURCE_PREFLIGHT_SCRIPT" \
--host ollama@192.168.0.188 \
--freshness-max-days 2 2>/dev/null || true
)"
momo_source_preflight_summary="$(awk '/^MOMO_DRIVE_TOKEN_SOURCE_PREFLIGHT / {line=$0} END {print line}' <<<"$momo_source_preflight_output")"
[ -n "$momo_source_preflight_summary" ] && echo "$momo_source_preflight_summary"
fi
if grep -q "BLOCKED=0" <<<"$momo_source_preflight_summary"; then
warn "188 momo daily sales stale but source preflight has no hard blocker"
elif awk '/MOMO_SOURCE_EMPTY_EVIDENCE_LINES / {exit !($2 > 0)}' <<<"$out"; then
@@ -844,7 +875,12 @@ fi
awk '/TEXTFILE_110 storage_health.prom age=/ {split($3,a,"="); exit !(a[2] < 300)}' <<<"$out" && ok "110 storage health exporter fresh" || warn "110 storage health exporter stale"
awk '/TEXTFILE_110 backup_health.prom age=/ {split($3,a,"="); exit !(a[2] < 900)}' <<<"$out" && ok "110 backup health exporter fresh" || warn "110 backup health exporter stale"
grep -q "STORAGE_HEALTH_110 root_readonly=0 current=0" <<<"$out" && ok "110 current boot storage health clean" || warn "110 storage health not clean"
grep -q "BACKUP_HEALTH_110 total=" <<<"$out" && awk '/BACKUP_HEALTH_110/ {split($3,a,"="); split($4,b,"="); split($5,c,"="); split($6,d,"="); split($7,e,"="); exit !((a[2]+b[2]+c[2]) == 0 && d[2] == 0 && e[2] == 0)}' <<<"$out" && ok "110 backup health has no stale expected jobs" || warn "110 latest aggregate/config backup had failed components; rerun backup-all after 120 recovers"
if grep -q "BACKUP_HEALTH_110 total=" <<<"$out" && awk '/BACKUP_HEALTH_110/ {split($3,a,"="); split($4,b,"="); split($5,c,"="); split($7,e,"="); exit !((a[2]+b[2]+c[2]+e[2]) == 0)}' <<<"$out"; then
ok "110 backup health has no stale expected jobs or critical config gaps"
awk '/BACKUP_HEALTH_110/ {split($6,a,"="); exit !(a[2] > 0)}' <<<"$out" && echo "INFO 110 latest aggregate backup-all still records failed_count but current component freshness is clean"
else
warn "110 backup health has stale expected jobs or critical config gaps"
fi
awk '/BACKUP_HEALTH_110/ {split($9,a,"="); exit !(a[2] == 0)}' <<<"$out" && ok "110 backup integrity and restore drill fresh" || warn "110 backup integrity or restore drill stale"
else
warn "110 schedule check unavailable"

View File

@@ -342,6 +342,8 @@ if [[ "$drive_intake_count" -eq 0 \
&& [[ "$drive_global_latest_date" < "$job_completed_date" || "$drive_global_latest_date" == "$job_completed_date" ]]; then
source_absent_without_newer_drive=1
fi
printf 'MOMO_LATEST_IMPORT_CLEAN %s\n' "$latest_job_clean"
printf 'MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE %s\n' "$source_absent_without_newer_drive"
monthly_sync="$(value_for DB_MONTHLY_SYNC)"
IFS='|' read -r sync_snapshot_count sync_monthly_count sync_dmin sync_dmax sync_mmin sync_mmax <<<"$monthly_sync"

View File

@@ -5,6 +5,9 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
COLD_START_CHECK = ROOT / "scripts" / "reboot-recovery" / "full-stack-cold-start-check.sh"
MOMO_SOURCE_PREFLIGHT = (
ROOT / "scripts" / "reboot-recovery" / "momo-drive-token-source-recovery-preflight.sh"
)
INSTALL_COLD_START = (
ROOT / "scripts" / "reboot-recovery" / "install-cold-start-monitor-110.sh"
)
@@ -49,6 +52,33 @@ def test_full_stack_cold_start_check_bounds_ssh_probes() -> None:
assert "SSH_110_RECOVERY_PACKAGE_NEXT_ACTION verify_or_preinstall_local_recovery_package_from_console_before_harbor_repair_retry" in text
def test_cold_start_momo_current_month_handles_no_new_source_without_false_warn() -> None:
text = COLD_START_CHECK.read_text(encoding="utf-8")
assert "momo_latest_import_clean" in text
assert "momo_source_stale_only" in text
assert "MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE" in text
assert "Drive has no newer source than last clean import" in text
assert "a[1] == 0 && a[2] == 0" in text
def test_momo_source_preflight_emits_machine_readable_no_new_source_evidence() -> None:
text = MOMO_SOURCE_PREFLIGHT.read_text(encoding="utf-8")
assert "MOMO_LATEST_IMPORT_CLEAN" in text
assert "MOMO_SOURCE_ABSENT_WITHOUT_NEWER_DRIVE" in text
assert "source_absent_without_newer_drive=1" in text
def test_cold_start_110_backup_splits_current_freshness_from_old_aggregate_failure() -> None:
text = COLD_START_CHECK.read_text(encoding="utf-8")
assert "critical config gaps" in text
assert "current component freshness is clean" in text
assert "split($6,a,\"=\"); exit !(a[2] > 0)" in text
assert "split($7,e,\"=\"); exit !((a[2]+b[2]+c[2]+e[2]) == 0)" in text
def test_recovery_scorecard_bounds_offsite_evidence_ssh() -> None:
text = RECOVERY_SCORECARD.read_text(encoding="utf-8")