fix(api): normalize priority work order source truth
All checks were successful
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) Successful in 9m37s
CD Pipeline / post-deploy-checks (push) Successful in 1m1s
All checks were successful
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) Successful in 9m37s
CD Pipeline / post-deploy-checks (push) Successful in 1m1s
This commit is contained in:
@@ -8,14 +8,18 @@ external SCM APIs.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from src.services.snapshot_paths import default_operations_dir
|
||||
|
||||
_DEFAULT_OPERATIONS_DIR = default_operations_dir(Path(__file__))
|
||||
_SNAPSHOT_FILE = "awoooi-priority-work-order-readback.snapshot.json"
|
||||
_SCHEMA_VERSION = "awoooi_priority_work_order_readback_v1"
|
||||
_SHA_RE = re.compile(r"^[0-9a-f]{40}$")
|
||||
|
||||
|
||||
def load_latest_awoooi_priority_work_order_readback(
|
||||
@@ -117,26 +121,49 @@ def _enrich_from_current_readbacks(payload: dict[str, Any]) -> None:
|
||||
|
||||
runtime_sha = str(
|
||||
workbench_summary.get("production_deploy_runtime_build_commit_sha") or ""
|
||||
)
|
||||
).strip().lower()
|
||||
runtime_short_sha = str(
|
||||
workbench_summary.get("production_deploy_runtime_build_commit_short_sha") or ""
|
||||
)
|
||||
).strip().lower()
|
||||
desired_short_sha = str(
|
||||
workbench_summary.get(
|
||||
"production_deploy_desired_main_api_image_tag_short_sha"
|
||||
)
|
||||
or ""
|
||||
)
|
||||
).strip().lower()
|
||||
current_head = _dict(payload.setdefault("current_head", {}))
|
||||
current_head["latest_verified_worktree_base_sha"] = runtime_short_sha
|
||||
current_head["latest_successful_deployed_source_sha"] = runtime_sha
|
||||
current_head["latest_successful_deploy_marker"] = (
|
||||
f"production desired image tag {desired_short_sha}"
|
||||
runtime_source_truth_available = _is_sha(runtime_sha)
|
||||
if runtime_source_truth_available:
|
||||
runtime_short_sha = runtime_short_sha or runtime_sha[:10]
|
||||
desired_short_sha = desired_short_sha or runtime_short_sha
|
||||
production_readback_id = f"production_readback:{desired_short_sha}"
|
||||
production_subject = f"production desired image tag {desired_short_sha}"
|
||||
|
||||
current_head["gitea_main_sha"] = runtime_sha
|
||||
current_head["latest_fetched_gitea_main_subject"] = production_subject
|
||||
current_head["latest_source_readiness_cd_run_id"] = production_readback_id
|
||||
current_head["latest_verified_worktree_base_sha"] = runtime_short_sha
|
||||
current_head["latest_successful_deployed_source_sha"] = runtime_sha
|
||||
current_head["latest_successful_deploy_marker"] = production_subject
|
||||
current_head["latest_source_readiness_cd_run_status"] = (
|
||||
"production_readback_verified"
|
||||
)
|
||||
current_head["latest_source_readiness_commit_sha"] = runtime_sha
|
||||
|
||||
state["updated_at"] = _taipei_now_iso()
|
||||
state["current_main_cd_run_id"] = production_readback_id
|
||||
state["current_main_cd_run_status"] = "production_readback_verified"
|
||||
state["current_main_latest_source_sha"] = runtime_sha
|
||||
state["latest_successful_deployed_source_sha"] = runtime_sha
|
||||
state["reboot_drill_preflight_source_status"] = "production_endpoint_ready"
|
||||
state["p0_004_template_copy_apply_gate_source_status"] = (
|
||||
"production_endpoint_ready"
|
||||
)
|
||||
|
||||
current_head["production_source_truth_available"] = runtime_source_truth_available
|
||||
current_head["stale_current_head_metadata_normalized"] = (
|
||||
runtime_source_truth_available
|
||||
)
|
||||
current_head["latest_source_readiness_cd_run_status"] = (
|
||||
"production_readback_verified"
|
||||
)
|
||||
current_head["latest_source_readiness_commit_sha"] = runtime_sha
|
||||
current_head["no_matching_runner_visible"] = False
|
||||
current_head["source_readiness_ci_fix_required"] = False
|
||||
|
||||
@@ -276,6 +303,74 @@ def _enrich_from_current_readbacks(payload: dict[str, Any]) -> None:
|
||||
"failed CD runs, and retired GitHub lanes must not reorder closed work."
|
||||
),
|
||||
]
|
||||
_set_rollups_and_summary(
|
||||
payload=payload,
|
||||
current_head=current_head,
|
||||
state=state,
|
||||
p0_004_ready=p0_004_ready,
|
||||
p0_006_event_gated=p0_006_event_gated,
|
||||
runtime_source_truth_available=runtime_source_truth_available,
|
||||
runtime_sha=runtime_sha,
|
||||
)
|
||||
|
||||
|
||||
def _set_rollups_and_summary(
|
||||
*,
|
||||
payload: dict[str, Any],
|
||||
current_head: dict[str, Any],
|
||||
state: dict[str, Any],
|
||||
p0_004_ready: bool,
|
||||
p0_006_event_gated: bool,
|
||||
runtime_source_truth_available: bool,
|
||||
runtime_sha: str,
|
||||
) -> None:
|
||||
completed = _list(payload.get("completed_in_priority_order"))
|
||||
in_progress = _list(payload.get("in_progress_or_blocked_in_priority_order"))
|
||||
latest_source_sha = (
|
||||
runtime_sha
|
||||
if runtime_source_truth_available
|
||||
else str(current_head.get("latest_successful_deployed_source_sha") or "")
|
||||
)
|
||||
active_blockers = _strings(state.get("active_p0_live_active_blockers"))
|
||||
active_gap_count = _int(state.get("active_p0_immediate_apply_gap_count"))
|
||||
|
||||
payload["rollups"] = {
|
||||
"completed_p0_count": len(completed),
|
||||
"in_progress_or_blocked_count": len(in_progress),
|
||||
"active_p0_immediate_apply_gap_count": active_gap_count,
|
||||
"active_p0_event_gated_by_fresh_reboot_window_only": p0_006_event_gated,
|
||||
"active_p0_live_active_blocker_count": len(active_blockers),
|
||||
"p0_004_runtime_readback_ready": p0_004_ready,
|
||||
"reboot_drill_preflight_runtime_readback_ready": (
|
||||
state.get("reboot_drill_preflight_runtime_readback_state") == "ready"
|
||||
),
|
||||
"production_source_truth_available": runtime_source_truth_available,
|
||||
"stale_current_head_metadata_normalized": runtime_source_truth_available,
|
||||
"stale_cd_runs_reopen_closed_work": False,
|
||||
"break_glass_reboot_drill_required": True,
|
||||
}
|
||||
payload["summary"] = {
|
||||
"status": str(payload.get("status") or ""),
|
||||
"active_p0_workplan_id": str(state.get("active_p0_workplan_id") or ""),
|
||||
"active_p0_state": str(state.get("active_p0_state") or ""),
|
||||
"active_p0_readiness_percent": _int(
|
||||
state.get("active_p0_readiness_percent")
|
||||
),
|
||||
"active_p0_live_active_blockers": active_blockers,
|
||||
"latest_successful_deployed_source_sha": latest_source_sha,
|
||||
"latest_successful_deployed_source_short_sha": latest_source_sha[:10],
|
||||
"latest_successful_deploy_marker": str(
|
||||
current_head.get("latest_successful_deploy_marker") or ""
|
||||
),
|
||||
"next_executable_mainline_workplan_id": str(
|
||||
state.get("next_executable_mainline_workplan_id") or ""
|
||||
),
|
||||
"next_executable_mainline_state": str(
|
||||
state.get("next_executable_mainline_state") or ""
|
||||
),
|
||||
"production_source_truth_available": runtime_source_truth_available,
|
||||
"stale_current_head_metadata_normalized": runtime_source_truth_available,
|
||||
}
|
||||
|
||||
|
||||
def _require_schema(payload: dict[str, Any], label: str) -> None:
|
||||
@@ -358,3 +453,11 @@ def _int(value: Any) -> int:
|
||||
|
||||
def _strings(value: Any) -> list[str]:
|
||||
return [str(item) for item in _list(value)]
|
||||
|
||||
|
||||
def _is_sha(value: str) -> bool:
|
||||
return bool(_SHA_RE.fullmatch(value))
|
||||
|
||||
|
||||
def _taipei_now_iso() -> str:
|
||||
return datetime.now(ZoneInfo("Asia/Taipei")).isoformat(timespec="seconds")
|
||||
|
||||
@@ -42,12 +42,12 @@ from src.services.gitea_workflow_runner_owner_attestation_request import (
|
||||
from src.services.p0_cicd_baseline_source_readiness import (
|
||||
load_latest_p0_cicd_baseline_source_readiness,
|
||||
)
|
||||
from src.services.reboot_auto_recovery_slo_scorecard import (
|
||||
load_latest_reboot_auto_recovery_slo_scorecard,
|
||||
)
|
||||
from src.services.reboot_auto_recovery_drill_preflight import (
|
||||
load_latest_reboot_auto_recovery_drill_preflight,
|
||||
)
|
||||
from src.services.reboot_auto_recovery_slo_scorecard import (
|
||||
load_latest_reboot_auto_recovery_slo_scorecard,
|
||||
)
|
||||
from src.services.runtime_surface_inventory import (
|
||||
load_latest_runtime_surface_inventory,
|
||||
)
|
||||
|
||||
@@ -74,6 +74,50 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot():
|
||||
assert "do not reboot" in data["next_execution_order"][0]
|
||||
|
||||
|
||||
def test_awoooi_priority_work_order_readback_normalizes_runtime_source_truth(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
runtime_sha = "b4dc407ce05c68a3908b993437a61b869d83810f"
|
||||
runtime_short_sha = runtime_sha[:10]
|
||||
monkeypatch.setenv("AWOOOI_BUILD_COMMIT_SHA", runtime_sha)
|
||||
monkeypatch.setenv("AWOOOI_DESIRED_API_IMAGE_TAG", runtime_sha)
|
||||
|
||||
payload = load_latest_awoooi_priority_work_order_readback()
|
||||
|
||||
current_head = payload["current_head"]
|
||||
state = payload["mainline_execution_state"]
|
||||
assert current_head["gitea_main_sha"] == runtime_sha
|
||||
assert current_head["latest_source_readiness_commit_sha"] == runtime_sha
|
||||
assert current_head["latest_source_readiness_cd_run_id"] == (
|
||||
f"production_readback:{runtime_short_sha}"
|
||||
)
|
||||
assert current_head["latest_fetched_gitea_main_subject"] == (
|
||||
f"production desired image tag {runtime_short_sha}"
|
||||
)
|
||||
assert current_head["stale_current_head_metadata_normalized"] is True
|
||||
assert state["current_main_latest_source_sha"] == runtime_sha
|
||||
assert state["latest_successful_deployed_source_sha"] == runtime_sha
|
||||
assert state["current_main_cd_run_status"] == "production_readback_verified"
|
||||
assert state["p0_004_template_copy_apply_gate_source_status"] == (
|
||||
"production_endpoint_ready"
|
||||
)
|
||||
assert state["reboot_drill_preflight_source_status"] == "production_endpoint_ready"
|
||||
assert payload["rollups"]["stale_current_head_metadata_normalized"] is True
|
||||
assert payload["summary"]["latest_successful_deployed_source_sha"] == runtime_sha
|
||||
|
||||
current_truth = json.dumps(
|
||||
{
|
||||
"current_head": current_head,
|
||||
"mainline_execution_state": state,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
)
|
||||
assert "3973" not in current_truth
|
||||
assert "49637ee7" not in current_truth
|
||||
assert "f426522" not in current_truth
|
||||
|
||||
|
||||
def test_awoooi_priority_work_order_readback_rejects_reordered_active_p0(tmp_path):
|
||||
operations_dir = tmp_path / "docs" / "operations"
|
||||
operations_dir.mkdir(parents=True)
|
||||
|
||||
@@ -50156,3 +50156,23 @@ production browser smoke:
|
||||
- 沒有讀 secret / token / `.env` / raw sessions / SQLite / auth,沒有寫 credential marker。
|
||||
- 沒有重啟主機,沒有 restart Docker / Nginx / K3s / DB / firewall。
|
||||
- 沒有使用 GitHub / gh / GitHub API / GitHub Actions。
|
||||
|
||||
## 2026-06-30 — 09:28 P0 priority work-order runtime source truth 正規化
|
||||
|
||||
**完成內容**:
|
||||
- 修正 `apps/api/src/services/awoooi_priority_work_order_readback.py`:當 Delivery Workbench 讀到合法 production runtime deploy SHA 時,將 `current_head` 與 `mainline_execution_state` 的 current main / CD / deployed source 欄位正規化為 `production_readback:<short_sha>`,不再讓舊 snapshot 的 `#3973`、`49637ee7` 或 `f426522` 混入目前主線進度。
|
||||
- 新增 `rollups` / `summary`,明確輸出 `production_source_truth_available`、`stale_current_head_metadata_normalized`、`stale_cd_runs_reopen_closed_work=false`、P0-006 fresh reboot event gate 與 P0-004 / reboot preflight readiness。
|
||||
- 補 `apps/api/tests/test_awoooi_priority_work_order_readback_api.py` regression:以 `AWOOOI_BUILD_COMMIT_SHA` / `AWOOOI_DESIRED_API_IMAGE_TAG` 模擬 production env,鎖住 priority readback 不再回吐舊 CD/run/source metadata。
|
||||
|
||||
**本地驗證結果**:
|
||||
- rebase 到 `a7e6de46a feat(delivery): expose p0 reboot drill readback` 後,`DATABASE_URL=postgresql+asyncpg://test:test@localhost:5432/test PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/test_awoooi_priority_work_order_readback_api.py apps/api/tests/test_delivery_closure_workbench_api.py ops/runner/test_cd_controlled_runtime_profile.py -q`:`35 passed`。
|
||||
- `PYTHONPATH=apps/api 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 apps/api/src/services/delivery_closure_workbench.py apps/api/tests/test_delivery_closure_workbench_api.py`:通過。
|
||||
- `PYTHONPATH=apps/api python3.11 -m ruff check apps/api/src/services/awoooi_priority_work_order_readback.py apps/api/tests/test_awoooi_priority_work_order_readback_api.py apps/api/src/services/delivery_closure_workbench.py apps/api/tests/test_delivery_closure_workbench_api.py`:通過。
|
||||
- `python3.11 ops/runner/guard-gitea-runner-pressure.py --root .`:通過,`auto_branch_events_on_110=0`、`generic_runner_labels=0`。
|
||||
- `node scripts/ci/check-gitea-step-env-secrets.js`:通過。
|
||||
- `git diff --check`:通過。
|
||||
|
||||
**仍維持**:
|
||||
- 沒有讀 secret / token / `.env` / raw sessions / SQLite / auth。
|
||||
- 沒有使用 GitHub / gh / GitHub API / GitHub Actions。
|
||||
- 沒有重啟主機,沒有 workflow_dispatch,沒有 host / Docker / K8s / DB / firewall runtime 寫入。
|
||||
|
||||
Reference in New Issue
Block a user