feat(governance): 補齊 release decision 維護窗口保留
All checks were successful
Code Review / ai-code-review (push) Successful in 15s
CD Pipeline / tests (push) Successful in 1m29s
CD Pipeline / build-and-deploy (push) Successful in 4m48s
CD Pipeline / post-deploy-checks (push) Successful in 1m34s

This commit is contained in:
Your Name
2026-06-14 11:11:25 +08:00
parent e2c868fd9c
commit 1ae67f1fa2
12 changed files with 174 additions and 17 deletions

View File

@@ -48,6 +48,7 @@ def load_latest_ai_agent_result_capture_release_decision_hold(
_require_owner_decision_holds(payload, label)
_require_verifier_decision_holds(payload, label)
_require_rollback_decision_holds(payload, label)
_require_maintenance_window_decision_holds(payload, label)
_require_live_apply_decision_holds(payload, label)
_require_blocked_transitions(payload, label)
_require_actions(payload, label)
@@ -219,6 +220,22 @@ def _require_rollback_decision_holds(payload: dict[str, Any], label: str) -> Non
_require_valid_status(item, label, f"rollback decision hold {item_id}")
def _require_maintenance_window_decision_holds(payload: dict[str, Any], label: str) -> None:
items = payload.get("maintenance_window_decision_holds") or []
_require_ids(items, "hold_id", _expected_ids("maintenance_window_decision_hold"), label, "maintenance window decision holds")
for item in items:
item_id = item.get("hold_id")
if item.get("hold_mode") != "maintenance_window_decision_hold":
raise ValueError(f"{label}: maintenance window decision hold {item_id} mode is invalid")
if item.get("maintenance_window_required") is not True:
raise ValueError(f"{label}: maintenance window decision hold {item_id} must require maintenance window")
if item.get("maintenance_window_approved") is not False or item.get("live_apply_release_passed") is not False:
raise ValueError(f"{label}: maintenance window decision hold {item_id} must stay unapproved and unpassed")
_require_valid_status(item, label, f"maintenance window decision hold {item_id}")
if not item.get("maintenance_summary"):
raise ValueError(f"{label}: maintenance window decision hold {item_id}.maintenance_summary is required")
def _require_live_apply_decision_holds(payload: dict[str, Any], label: str) -> None:
items = payload.get("live_apply_decision_holds") or []
_require_ids(items, "hold_id", _expected_ids("live_apply_decision_hold"), label, "live apply decision holds")
@@ -286,6 +303,7 @@ def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
"owner_decision_hold_count": len(payload.get("owner_decision_holds") or []),
"verifier_decision_hold_count": len(payload.get("verifier_decision_holds") or []),
"rollback_decision_hold_count": len(payload.get("rollback_decision_holds") or []),
"maintenance_window_decision_hold_count": len(payload.get("maintenance_window_decision_holds") or []),
"live_apply_decision_hold_count": len(payload.get("live_apply_decision_holds") or []),
"blocked_decision_transition_count": len(payload.get("blocked_decision_transitions") or []),
"operator_action_count": len(payload.get("operator_actions") or []),