fix(reboot): surface vmx relink dry-run evidence gate
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 2m14s
CD Pipeline / build-and-deploy (push) Has started running
CD Pipeline / post-deploy-checks (push) Has been cancelled
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 1s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 40s

This commit is contained in:
Your Name
2026-07-03 13:13:13 +08:00
parent 558b9e916e
commit bcaf6c3a26
5 changed files with 352 additions and 43 deletions

View File

@@ -3475,6 +3475,40 @@ def _enrich_from_current_readbacks(
windows99_vmx_source_locator_readback.get("candidate_confirmation_required")
is True
)
state[
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run"
] = bool(
windows99_vmx_source_locator_readback.get(
"human_confirmation_required_for_dry_run"
)
is True
)
state[
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required"
] = bool(
windows99_vmx_source_locator_readback.get(
"verified_source_or_identity_evidence_required"
)
is True
)
state["windows99_vmx_source_locator_controlled_relink_dry_run_ready"] = bool(
windows99_vmx_source_locator_readback.get(
"controlled_relink_dry_run_ready"
)
is True
)
state["windows99_vmx_source_locator_controlled_relink_dry_run_blocker"] = str(
windows99_vmx_source_locator_readback.get(
"controlled_relink_dry_run_blocker"
)
or ""
)
locator_relink_plan = _dict(
windows99_vmx_source_locator_readback.get("controlled_relink_dry_run_plan")
)
state["windows99_vmx_source_locator_relink_dry_run_plan_id"] = str(
locator_relink_plan.get("plan_id") or ""
)
state["windows99_vmx_source_locator_candidate_source_count_known"] = bool(
windows99_vmx_source_locator_readback.get("candidate_source_count_known")
is True
@@ -3891,6 +3925,29 @@ def _enrich_from_current_readbacks(
evidence["windows99_vmx_source_locator_candidate_confirmation_required"] = state[
"windows99_vmx_source_locator_candidate_confirmation_required"
]
evidence[
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run"
] = state[
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run"
]
evidence[
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required"
] = state[
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required"
]
evidence[
"windows99_vmx_source_locator_controlled_relink_dry_run_ready"
] = state[
"windows99_vmx_source_locator_controlled_relink_dry_run_ready"
]
evidence[
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker"
] = state[
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker"
]
evidence["windows99_vmx_source_locator_relink_dry_run_plan_id"] = state[
"windows99_vmx_source_locator_relink_dry_run_plan_id"
]
evidence["windows99_vmx_source_locator_candidate_source_count_known"] = state[
"windows99_vmx_source_locator_candidate_source_count_known"
]
@@ -4683,6 +4740,31 @@ def _set_rollups_and_summary(
state.get("windows99_vmx_source_locator_candidate_confirmation_required")
is True
),
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run": (
state.get(
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run"
)
is True
),
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required": (
state.get(
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required"
)
is True
),
"windows99_vmx_source_locator_controlled_relink_dry_run_ready": (
state.get("windows99_vmx_source_locator_controlled_relink_dry_run_ready")
is True
),
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker": str(
state.get(
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker"
)
or ""
),
"windows99_vmx_source_locator_relink_dry_run_plan_id": str(
state.get("windows99_vmx_source_locator_relink_dry_run_plan_id") or ""
),
"windows99_vmx_source_locator_candidate_source_count_known": (
state.get("windows99_vmx_source_locator_candidate_source_count_known")
is True
@@ -5005,6 +5087,31 @@ def _set_rollups_and_summary(
state.get("windows99_vmx_source_locator_candidate_confirmation_required")
is True
),
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run": (
state.get(
"windows99_vmx_source_locator_human_confirmation_required_for_dry_run"
)
is True
),
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required": (
state.get(
"windows99_vmx_source_locator_verified_source_or_identity_evidence_required"
)
is True
),
"windows99_vmx_source_locator_controlled_relink_dry_run_ready": (
state.get("windows99_vmx_source_locator_controlled_relink_dry_run_ready")
is True
),
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker": str(
state.get(
"windows99_vmx_source_locator_controlled_relink_dry_run_blocker"
)
or ""
),
"windows99_vmx_source_locator_relink_dry_run_plan_id": str(
state.get("windows99_vmx_source_locator_relink_dry_run_plan_id") or ""
),
"windows99_vmx_source_locator_candidate_source_count_known": (
state.get("windows99_vmx_source_locator_candidate_source_count_known")
is True

View File

@@ -156,10 +156,131 @@ def build_windows99_vmx_source_locator_readback(
and set(receipt_aliases).issubset(set(target_aliases or receipt_aliases))
)
receipt_locate_status = str(receipt.get("locate_status") or "")
expected_vmx_path_present_count = (
_int(receipt.get("expected_vmx_path_present_count"))
if receipt_applies
else None
)
candidate_source_count = (
_int(receipt.get("candidate_source_count")) if receipt_applies else None
)
candidate_source_fingerprint_count = (
_int(receipt.get("candidate_source_fingerprint_count"), 0)
if receipt_applies
else None
)
alias_hint_candidate_count = (
_int(receipt.get("alias_hint_candidate_count"), 0)
if receipt_applies
else None
)
unassigned_ubuntu_candidate_count = (
_int(receipt.get("unassigned_ubuntu_candidate_count"), 0)
if receipt_applies
else None
)
identity_target_hint_count = (
_int(receipt.get("identity_target_hint_count"), 0)
if receipt_applies
else None
)
identity_unassigned_ubuntu_candidate_count = (
_int(receipt.get("identity_unassigned_ubuntu_candidate_count"), 0)
if receipt_applies
else None
)
candidate_confirmation_required = bool(
receipt_applies and "requires_confirmation" in receipt_locate_status
)
controlled_relink_dry_run_ready = bool(
receipt_applies and receipt.get("controlled_relink_dry_run_ready") is True
)
verified_source_or_identity_evidence_required = bool(
receipt_applies
and candidate_confirmation_required
and not controlled_relink_dry_run_ready
)
controlled_relink_dry_run_blocker = ""
if receipt_applies:
status = "collector_readback_single_identity_candidate_confirmation_required"
next_step = "confirm_single_unassigned_ubuntu_candidate_before_scoped_relink_dry_run"
safe_next_step = str(receipt.get("safe_next_step") or safe_next_step)
if controlled_relink_dry_run_ready:
status = "collector_readback_scoped_relink_dry_run_ready"
next_step = "run_scoped_relink_dry_run_no_windows_or_vm_write"
safe_next_step = (
"run_scoped_relink_dry_run_no_windows_or_vm_write_then_post_verifier"
)
elif verified_source_or_identity_evidence_required:
status = "collector_readback_verified_source_required_before_relink_dry_run"
next_step = (
"provide_verified_vmx_source_or_identity_evidence_then_"
"scoped_relink_dry_run"
)
safe_next_step = (
"provide_existing_vmx_source_or_verified_backup_path_then_build_"
"scoped_relink_dry_run_no_write"
)
controlled_relink_dry_run_blocker = (
"verified_vmx_source_or_identity_evidence_missing"
)
else:
status = "collector_readback_no_scoped_relink_candidate"
next_step = "provide_existing_vmx_source_or_backup_path"
safe_next_step = (
"provide_existing_vmx_source_or_verified_backup_path_then_rerun_"
"locator_check_mode_no_write"
)
controlled_relink_dry_run_blocker = "scoped_relink_candidate_not_verified"
relink_dry_run_plan = {
"plan_id": f"windows99-vmx-source-relink-dry-run-{','.join(missing_aliases) or 'none'}",
"mode": "dry_run_no_windows_or_vm_write",
"ready": controlled_relink_dry_run_ready,
"blocker": controlled_relink_dry_run_blocker,
"target_selector": {
"host_alias": "99",
"vm_aliases": target_aliases,
"missing_vmx_aliases": missing_aliases,
"candidate_requires_verified_identity": (
verified_source_or_identity_evidence_required
),
},
"source_diff": {
"expected_vmx_path_count": expected_vmx_path_count,
"expected_vmx_path_present_count": expected_vmx_path_present_count,
"candidate_source_count": candidate_source_count,
"candidate_source_fingerprint_count": (
candidate_source_fingerprint_count
),
"alias_hint_candidate_count": alias_hint_candidate_count,
"identity_target_hint_count": identity_target_hint_count,
"identity_unassigned_ubuntu_candidate_count": (
identity_unassigned_ubuntu_candidate_count
),
"raw_path_output": False,
"path_fingerprint_only": True,
"bounded_identity_metadata_only": bool(
receipt_applies
and receipt.get("bounded_identity_metadata_only") is True
),
},
"rollback_ref": "rollback://awoooi/windows99-vmx-source-relink-dry-run",
"post_verifier": [
"bash scripts/reboot-recovery/collect-windows99-vmware-verify.sh --collect",
"GET /api/v1/agents/reboot-auto-recovery-slo-scorecard",
"GET /api/v1/agents/windows99-vmx-source-repair-package",
"GET /api/v1/agents/windows99-vmx-source-locator-readback",
],
"km_writeback_ref": str(receipt.get("km_writeback_ref") or "")
if receipt_applies
else "",
"playbook_trust_writeback_ref": str(
receipt.get("playbook_trust_writeback_ref") or ""
)
if receipt_applies
else "",
"apply_allowed_by_this_plan": False,
"remote_write_performed": False,
"vm_power_change_performed": False,
}
return {
"schema_version": _SCHEMA_VERSION,
@@ -199,47 +320,28 @@ def build_windows99_vmx_source_locator_readback(
),
"remote_locator_mode": "in_memory_stdin_scriptblock",
"expected_vmx_path_count": expected_vmx_path_count,
"expected_vmx_path_present_count": (
_int(receipt.get("expected_vmx_path_present_count"))
if receipt_applies
else None
),
"candidate_source_count": (
_int(receipt.get("candidate_source_count")) if receipt_applies else None
),
"expected_vmx_path_present_count": expected_vmx_path_present_count,
"candidate_source_count": candidate_source_count,
"candidate_source_count_known": bool(receipt_applies),
"candidate_source_fingerprint_count": (
_int(receipt.get("candidate_source_fingerprint_count"), 0)
if receipt_applies
else None
),
"alias_hint_candidate_count": (
_int(receipt.get("alias_hint_candidate_count"), 0)
if receipt_applies
else None
),
"unassigned_ubuntu_candidate_count": (
_int(receipt.get("unassigned_ubuntu_candidate_count"), 0)
if receipt_applies
else None
),
"candidate_source_fingerprint_count": candidate_source_fingerprint_count,
"alias_hint_candidate_count": alias_hint_candidate_count,
"unassigned_ubuntu_candidate_count": unassigned_ubuntu_candidate_count,
"identity_metadata_read": bool(
receipt_applies and receipt.get("identity_metadata_read") is True
),
"identity_target_hint_count": (
_int(receipt.get("identity_target_hint_count"), 0)
if receipt_applies
else None
),
"identity_target_hint_count": identity_target_hint_count,
"identity_unassigned_ubuntu_candidate_count": (
_int(receipt.get("identity_unassigned_ubuntu_candidate_count"), 0)
if receipt_applies
else None
identity_unassigned_ubuntu_candidate_count
),
"locate_status": receipt_locate_status if receipt_applies else "",
"candidate_confirmation_required": bool(
receipt_applies and "requires_confirmation" in receipt_locate_status
"candidate_confirmation_required": candidate_confirmation_required,
"human_confirmation_required_for_dry_run": False,
"verified_source_or_identity_evidence_required": (
verified_source_or_identity_evidence_required
),
"controlled_relink_dry_run_ready": controlled_relink_dry_run_ready,
"controlled_relink_dry_run_blocker": controlled_relink_dry_run_blocker,
"controlled_relink_dry_run_plan": relink_dry_run_plan,
"public_lan_topology_redacted": True,
"redacted_public_display_only": True,
"raw_path_output": False,