From 2bbbd458bcd9a7b5a74114fc605da0d6458f3416 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 Jul 2026 15:54:03 +0800 Subject: [PATCH] fix(priority): expose runtime readback freshness --- .../awoooi_priority_work_order_readback.py | 24 +++++++++++++++++++ ...awoooi_priority_work_order_readback_api.py | 14 +++++++++++ docs/LOGBOOK.md | 17 +++++++++++++ 3 files changed, 55 insertions(+) diff --git a/apps/api/src/services/awoooi_priority_work_order_readback.py b/apps/api/src/services/awoooi_priority_work_order_readback.py index a04e7d8d..978b6929 100644 --- a/apps/api/src/services/awoooi_priority_work_order_readback.py +++ b/apps/api/src/services/awoooi_priority_work_order_readback.py @@ -812,6 +812,7 @@ def load_latest_awoooi_priority_work_order_readback( _enrich_from_current_readbacks(payload) _require_mainline_consistency(payload, str(path)) _apply_commander_inserted_requirement_work_items(payload) + _mark_runtime_generated_at(payload) return payload @@ -960,6 +961,8 @@ def apply_controlled_cd_lane_live_metric_readback( active_blockers ) + _mark_runtime_generated_at(payload) + def apply_stockplatform_public_api_runtime_readback( payload: dict[str, Any], @@ -3329,6 +3332,27 @@ def _apply_commander_inserted_requirement_work_items( ) +def _mark_runtime_generated_at(payload: dict[str, Any]) -> None: + snapshot_generated_at = str( + payload.get("snapshot_generated_at") or payload.get("generated_at") or "" + ) + runtime_generated_at = _taipei_now_iso() + + if snapshot_generated_at: + payload["snapshot_generated_at"] = snapshot_generated_at + payload["generated_at"] = runtime_generated_at + payload["runtime_readback_generated_at"] = runtime_generated_at + + summary = _dict(payload.setdefault("summary", {})) + if snapshot_generated_at: + summary["snapshot_generated_at"] = snapshot_generated_at + summary["generated_at"] = runtime_generated_at + summary["runtime_readback_generated_at"] = runtime_generated_at + + rollups = _dict(payload.setdefault("rollups", {})) + rollups["runtime_readback_generated_at_present"] = True + + def _require_schema(payload: dict[str, Any], label: str) -> None: actual = payload.get("schema_version") if actual != _SCHEMA_VERSION: diff --git a/apps/api/tests/test_awoooi_priority_work_order_readback_api.py b/apps/api/tests/test_awoooi_priority_work_order_readback_api.py index ad1a8e4c..b5d4163d 100644 --- a/apps/api/tests/test_awoooi_priority_work_order_readback_api.py +++ b/apps/api/tests/test_awoooi_priority_work_order_readback_api.py @@ -43,6 +43,10 @@ def test_awoooi_priority_work_order_readback_loader_returns_mainline_order(): payload = load_latest_awoooi_priority_work_order_readback() assert payload["schema_version"] == "awoooi_priority_work_order_readback_v1" + assert payload["snapshot_generated_at"] == "2026-06-29T23:50:52+08:00" + assert payload["generated_at"] != payload["snapshot_generated_at"] + assert payload["generated_at"].endswith("+08:00") + assert payload["runtime_readback_generated_at"] == payload["generated_at"] assert payload["status"] == "p0_006_blocked_reboot_auto_recovery_slo_not_ready" assert payload["mainline_execution_state"]["active_p0_workplan_id"] == "P0-006" assert payload["mainline_execution_state"]["active_p0_state"] == ( @@ -248,6 +252,12 @@ def test_awoooi_priority_work_order_readback_loader_returns_mainline_order(): payload["summary"]["controlled_service_data_backup_readback_present"] is True ) + assert payload["summary"]["snapshot_generated_at"] == payload[ + "snapshot_generated_at" + ] + assert payload["summary"]["runtime_readback_generated_at"] == payload[ + "runtime_readback_generated_at" + ] assert payload["summary"]["controlled_service_data_backup_blocker_count"] == 4 assert payload["summary"][ "controlled_service_data_backup_next_safe_action" @@ -373,6 +383,10 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot( assert response.status_code == 200 data = response.json() + assert data["snapshot_generated_at"] == "2026-06-29T23:50:52+08:00" + assert data["generated_at"] != data["snapshot_generated_at"] + assert data["runtime_readback_generated_at"] == data["generated_at"] + assert data["summary"]["runtime_readback_generated_at"] == data["generated_at"] assert data["status"] == "p0_006_blocked_ai_loop_current_blocker_execution_queue" assert data["mainline_execution_state"]["active_p0_workplan_id"] == "P0-006" assert data["mainline_execution_state"]["active_p0_state"] == ( diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 90c9e551..2a4de30e 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -52953,3 +52953,20 @@ production browser smoke: - 沒有讀 secret / token / `.env` / raw sessions / SQLite / auth;沒有要求或收集 Windows 密碼。 - 沒有使用 GitHub / gh / GitHub API / GitHub Actions。 - 沒有重啟主機,沒有 service restart,沒有 VM power change,沒有 Windows policy apply,沒有 workflow_dispatch,沒有 DROP / TRUNCATE / restore / prune。 + +## 2026-07-02 — Priority work-order runtime generated_at freshness 修正 + +**完成內容**: +- `#4406` 已完成:`add790a47f` 的 controlled-runtime tests、API/Web image push、ArgoCD sync、API/Web/Worker rollout 與 production deploy readback 均成功;production scorecard 已讀回 `2026-07-02T15:08:44+08:00`、readiness `43`、active blockers `11`。 +- production `awoooi-priority-work-order-readback` 的 `summary` / `mainline_execution_state` 已是最新 runtime truth:`latest_successful_deployed_source_short_sha=add790a47f`、`windows99_management_readback_present=true`、`windows99_remote_execution_channel_ready=false`、`windows99_ssh_batch_status=permission_denied`、插入工作項 `55` 筆。 +- 修正 priority readback 的 top-level freshness:原始 snapshot 時間保留在 `snapshot_generated_at`,top-level `generated_at` 與 `runtime_readback_generated_at` 改為 runtime readback 生成時間,避免監控或人工只看 top-level `generated_at=2026-06-29T23:50:52+08:00` 誤判 production stale。 + +**本地驗證結果**: +- `DATABASE_URL=postgresql+asyncpg://test:test@localhost/test PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/test_awoooi_priority_work_order_readback_api.py -q -p no:cacheprovider`:`14 passed`。 +- `DATABASE_URL=postgresql+asyncpg://test:test@localhost/test PYTHONPATH=apps/api python3.11 -m pytest ops/runner/test_cd_controlled_runtime_profile.py scripts/reboot-recovery/tests/test_windows99_vmware_verify_collector.py scripts/reboot-recovery/tests/test_reboot_auto_recovery_slo_scorecard.py apps/api/tests/test_reboot_auto_recovery_slo_scorecard_api.py apps/api/tests/test_delivery_closure_workbench_api.py -q -p no:cacheprovider`:`70 passed`。 +- `python3.11 -m py_compile apps/api/src/services/awoooi_priority_work_order_readback.py apps/api/tests/test_awoooi_priority_work_order_readback_api.py`、`python3 ops/runner/guard-gitea-runner-pressure.py --root .`、`git diff --check`:通過。 + +**仍維持**: +- 沒有讀 secret / runner token / `.runner` 內容 / `.env` / raw sessions / SQLite / auth。 +- 沒有使用 GitHub / gh / GitHub API / GitHub Actions。 +- 沒有重啟主機,沒有 Docker / Nginx / K3s / DB / firewall restart,沒有 workflow_dispatch,沒有 DROP / TRUNCATE / restore / prune。