fix(api): expose stockplatform recovery control blocker
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 27s
CD Pipeline / build-and-deploy (push) Failing after 50m32s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-30 16:40:21 +08:00
parent 865a02d5b3
commit 55b625e957
5 changed files with 143 additions and 1 deletions

View File

@@ -52,6 +52,13 @@ def apply_stockplatform_public_api_runtime_readback(
runtime_blockers = _strings(runtime_readback.get("active_blockers"))
runtime_rollups = _dict(runtime_readback.get("rollups"))
runtime_readback_body = _dict(runtime_readback.get("readback"))
recovery_control_path = _dict(runtime_readback.get("recovery_control_path"))
recovery_control_path_status = str(
recovery_control_path.get("status") or "unknown"
)
recovery_control_path_blockers = _strings(
recovery_control_path.get("active_blockers")
)
state = _dict(payload.setdefault("mainline_execution_state", {}))
state["stockplatform_public_api_runtime_status"] = str(
@@ -64,6 +71,12 @@ def apply_stockplatform_public_api_runtime_readback(
state["stockplatform_public_api_live_drift_from_committed_scorecard"] = bool(
runtime_readback.get("live_drift_from_committed_scorecard") is True
)
state["stockplatform_public_api_recovery_control_path_status"] = (
recovery_control_path_status
)
state["stockplatform_public_api_recovery_control_path_active_blockers"] = (
recovery_control_path_blockers
)
for item in _list(payload.get("in_progress_or_blocked_in_priority_order")):
workplan = _dict(item)
@@ -90,6 +103,12 @@ def apply_stockplatform_public_api_runtime_readback(
evidence["stockplatform_ingestion_http_status"] = (
runtime_readback_body.get("ingestion_http_status")
)
evidence["stockplatform_recovery_control_path_status"] = (
recovery_control_path_status
)
evidence["stockplatform_recovery_control_path_active_blockers"] = (
recovery_control_path_blockers
)
if runtime_ready:
continue
@@ -124,6 +143,7 @@ def apply_stockplatform_public_api_runtime_readback(
existing_blockers
+ ["stockplatform_public_api_runtime_drift"]
+ runtime_blockers
+ recovery_control_path_blockers
)
state["active_p0_state"] = "blocked_stockplatform_public_api_runtime_drift"
state["next_executable_mainline_workplan_id"] = (
@@ -141,6 +161,12 @@ def apply_stockplatform_public_api_runtime_readback(
"freshness/ingestion are ok; fix runtime control-path evidence "
"before claiming the lane is only reboot-window gated."
),
(
"P0-006-STOCKPLATFORM-RECOVERY-CONTROL-PATH-RECEIPT: provide "
"target selector, check-mode/dry-run, rollback, post-apply "
"public API verifier, and KM/PlayBook/LOG writeback receipt before "
"any runtime apply."
),
(
"P0-006: keep reboot SLO timer live, but do not claim final SLO "
"closure while StockPlatform public API readback is blocked."
@@ -447,6 +473,18 @@ def _refresh_rollups_after_stockplatform_overlay(
state.get("stockplatform_public_api_live_drift_from_committed_scorecard")
is True
)
recovery_control_path_blockers = _strings(
state.get("stockplatform_public_api_recovery_control_path_active_blockers")
)
rollups["stockplatform_public_api_recovery_control_path_status"] = str(
state.get("stockplatform_public_api_recovery_control_path_status") or "unknown"
)
rollups["stockplatform_public_api_recovery_control_path_blocked"] = bool(
recovery_control_path_blockers
)
rollups["stockplatform_public_api_recovery_control_path_blocker_count"] = len(
recovery_control_path_blockers
)
rollups["active_p0_live_active_blocker_count"] = len(active_blockers)
rollups["active_p0_event_gated_by_fresh_reboot_window_only"] = (
rollups.get("active_p0_event_gated_by_fresh_reboot_window_only") is True
@@ -465,6 +503,12 @@ def _refresh_rollups_after_stockplatform_overlay(
state.get("stockplatform_public_api_live_drift_from_committed_scorecard")
is True
)
summary["stockplatform_public_api_recovery_control_path_status"] = str(
state.get("stockplatform_public_api_recovery_control_path_status") or "unknown"
)
summary["stockplatform_public_api_recovery_control_path_blockers"] = (
recovery_control_path_blockers
)
summary["next_executable_mainline_workplan_id"] = str(
state.get("next_executable_mainline_workplan_id") or ""
)

View File

@@ -90,6 +90,11 @@ def _build_payload(
ingestion_json=ingestion_json,
)
ready = all(checks.values())
recovery_control_path = _recovery_control_path_readback(runtime_ready=ready)
recovery_control_path_blockers = _strings(
recovery_control_path.get("active_blockers")
)
active_blockers = _unique_strings(active_blockers + recovery_control_path_blockers)
committed_freshness_ok = committed_stockplatform.get("freshness_status") == "ok"
committed_ingestion_ok = committed_stockplatform.get("ingestion_status") == "ok"
committed_ok = committed_freshness_ok and committed_ingestion_ok
@@ -139,6 +144,8 @@ def _build_payload(
"live_drift_from_committed_scorecard": (
live_drift_from_committed_scorecard
),
"recovery_control_path_status": recovery_control_path.get("status"),
"recovery_control_path_active_blockers": recovery_control_path_blockers,
},
"rollups": {
"runtime_ready": ready,
@@ -159,7 +166,16 @@ def _build_payload(
"live_drift_from_committed_scorecard": (
live_drift_from_committed_scorecard
),
"recovery_control_path_ready": (
recovery_control_path.get("status")
== "not_required_stockplatform_runtime_ready"
),
"recovery_control_path_blocked": bool(recovery_control_path_blockers),
"recovery_control_path_blocker_count": len(
recovery_control_path_blockers
),
},
"recovery_control_path": recovery_control_path,
"probes": probes,
"operation_boundaries": {
"read_only_public_https_probe": True,
@@ -179,6 +195,44 @@ def _build_payload(
}
def _recovery_control_path_readback(*, runtime_ready: bool) -> dict[str, Any]:
if runtime_ready:
return {
"status": "not_required_stockplatform_runtime_ready",
"active_blockers": [],
"safe_recovery_channels": [
"keep_monitoring_public_api_runtime_readback",
],
}
return {
"status": "blocked_recovery_control_path_receipt_missing",
"active_blockers": [
"stockplatform_recovery_control_path_receipt_missing",
"stockplatform_controlled_deploy_or_ssh_readback_required",
],
"safe_recovery_channels": [
"existing_stockplatform_manual_deploy_workflow_dispatch_with_runner_pressure_guard",
"bounded_ssh_or_runner_recovery_readback_without_docker_daemon_restart",
],
"forbidden_recovery_channels": [
"docker_daemon_restart",
"host_reboot",
"docker_prune_or_volume_restore",
"manual_database_rows_or_fake_freshness",
"restore_push_deploy_trigger_during_110_capacity_freeze",
"read_secret_or_raw_session_values",
],
"required_receipts": [
"target_selector",
"source_of_truth_diff_or_runtime_state_diff",
"check_mode_or_dry_run",
"rollback_command",
"post_apply_public_api_verifier",
"km_playbook_log_writeback_receipt",
],
}
def _active_blockers(
*,
api: dict[str, Any],