diff --git a/apps/api/src/services/harbor_registry_controlled_recovery_receipt.py b/apps/api/src/services/harbor_registry_controlled_recovery_receipt.py index 1f1bfe2c7..bd74ce6c7 100644 --- a/apps/api/src/services/harbor_registry_controlled_recovery_receipt.py +++ b/apps/api/src/services/harbor_registry_controlled_recovery_receipt.py @@ -212,6 +212,12 @@ def validate_harbor_registry_controlled_recovery_receipt( "gitea_queue_cd_jobs_run_id_mismatch": gitea_queue[ "cd_run_jobs_run_id_mismatch" ], + "gitea_queue_normalized_classifier_field_count": gitea_queue[ + "normalized_classifier_field_count" + ], + "gitea_queue_normalized_classifier_field_ids": gitea_queue[ + "normalized_classifier_field_ids" + ], "deploy_marker_readback_seen": deploy_marker["receipt_seen"], "deploy_marker_verified": deploy_marker["deploy_marker_verified"], "deploy_marker_blocker_count": deploy_marker["blocker_count"], @@ -591,6 +597,9 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: "harbor_110_repair_jobs_unexpected_names": [], "harbor_110_repair_jobs_labels": [], "harbor_110_repair_jobs_runner_names": [], + "normalized_classifier_fields": [], + "normalized_classifier_field_count": 0, + "normalized_classifier_field_ids": [], "operation_boundary_violation": False, "blockers": [], "blocker_count": 0, @@ -653,6 +662,16 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: rollups.get("cd_run_jobs_run_id_mismatch") is True or readback.get("cd_run_jobs_run_id_mismatch") is True ) + cd_jobs_payload_classifier = str( + rollups.get("cd_run_jobs_payload_classifier") + or readback.get("cd_run_jobs_payload_classifier") + or "" + ) + harbor_jobs_payload_classifier = str( + rollups.get("harbor_110_repair_jobs_payload_classifier") + or readback.get("harbor_110_repair_jobs_payload_classifier") + or "" + ) boundary_violation = any( operation_boundaries.get(flag) is True for flag in ( @@ -675,6 +694,12 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: blocked=blocked, boundary_violation=boundary_violation, ) + normalized_classifier_fields = _gitea_queue_normalized_classifier_fields( + cd_jobs_payload_classifier=cd_jobs_payload_classifier, + harbor_jobs_payload_classifier=harbor_jobs_payload_classifier, + no_matching_label=no_matching_label, + blockers=blockers, + ) return { "receipt_seen": True, "schema_version": str(value.get("schema_version") or ""), @@ -692,11 +717,7 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: ), "current_cd_harbor_retrying_unavailable": current_cd_harbor_retrying, "cd_run_jobs_stale_or_mismatched": cd_jobs_stale, - "cd_run_jobs_payload_classifier": str( - rollups.get("cd_run_jobs_payload_classifier") - or readback.get("cd_run_jobs_payload_classifier") - or "" - ), + "cd_run_jobs_payload_classifier": cd_jobs_payload_classifier, "cd_run_jobs_head_sha_mismatch": cd_jobs_head_sha_mismatch, "cd_run_jobs_run_id_mismatch": cd_jobs_run_id_mismatch, "cd_run_jobs_expected_run_id": str( @@ -719,11 +740,7 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: "harbor_110_repair_blocked": blocked, "harbor_110_repair_jobs_stale_or_mismatched": jobs_stale, "harbor_110_repair_jobs_cross_workflow_mismatch": jobs_cross_workflow, - "harbor_110_repair_jobs_payload_classifier": str( - rollups.get("harbor_110_repair_jobs_payload_classifier") - or readback.get("harbor_110_repair_jobs_payload_classifier") - or "" - ), + "harbor_110_repair_jobs_payload_classifier": harbor_jobs_payload_classifier, "harbor_110_repair_jobs_expected_names": _strings( readback.get("harbor_110_repair_jobs_expected_names") ), @@ -736,6 +753,11 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: "harbor_110_repair_jobs_runner_names": _strings( readback.get("harbor_110_repair_jobs_runner_names") ), + "normalized_classifier_fields": normalized_classifier_fields, + "normalized_classifier_field_count": len(normalized_classifier_fields), + "normalized_classifier_field_ids": [ + item["field_id"] for item in normalized_classifier_fields + ], "operation_boundary_violation": boundary_violation, "blockers": blockers, "blocker_count": len(blockers), @@ -745,6 +767,48 @@ def _gitea_queue_readback(value: Any) -> dict[str, Any]: } +def _gitea_queue_normalized_classifier_fields( + *, + cd_jobs_payload_classifier: str, + harbor_jobs_payload_classifier: str, + no_matching_label: str, + blockers: list[str], +) -> list[dict[str, Any]]: + return [ + { + "field_id": "cd_run_jobs_payload_classifier", + "value": cd_jobs_payload_classifier, + "blockers": [ + item for item in blockers if item.startswith("gitea_queue_cd_jobs_") + ], + "metadata_only": True, + "raw_output_returned": False, + }, + { + "field_id": "harbor_110_repair_jobs_payload_classifier", + "value": harbor_jobs_payload_classifier, + "blockers": [ + item + for item in blockers + if item.startswith("gitea_queue_harbor_110_repair_jobs_") + ], + "metadata_only": True, + "raw_output_returned": False, + }, + { + "field_id": "latest_visible_harbor_110_repair_no_matching_runner_label", + "value": no_matching_label, + "blockers": [ + item + for item in blockers + if item == "gitea_queue_harbor_110_repair_no_matching_runner" + ], + "metadata_only": True, + "raw_output_returned": False, + }, + ] + + def _gitea_queue_blockers( *, no_matching_runner: bool, diff --git a/apps/api/tests/test_harbor_registry_controlled_recovery_receipt.py b/apps/api/tests/test_harbor_registry_controlled_recovery_receipt.py index c4eb293fb..1f8ffa91b 100644 --- a/apps/api/tests/test_harbor_registry_controlled_recovery_receipt.py +++ b/apps/api/tests/test_harbor_registry_controlled_recovery_receipt.py @@ -254,6 +254,25 @@ def test_harbor_recovery_receipt_surfaces_gitea_queue_blockers() -> None: assert queue["harbor_110_repair_no_matching_runner_label"] == "awoooi-host" assert queue["harbor_110_repair_jobs_stale_or_mismatched"] is True assert queue["harbor_110_repair_jobs_unexpected_names"] == ["ai-code-review"] + normalized = { + item["field_id"]: item for item in queue["normalized_classifier_fields"] + } + assert queue["normalized_classifier_field_count"] == 3 + assert queue["normalized_classifier_field_ids"] == [ + "cd_run_jobs_payload_classifier", + "harbor_110_repair_jobs_payload_classifier", + "latest_visible_harbor_110_repair_no_matching_runner_label", + ] + assert normalized[ + "latest_visible_harbor_110_repair_no_matching_runner_label" + ]["value"] == "awoooi-host" + assert normalized[ + "latest_visible_harbor_110_repair_no_matching_runner_label" + ]["blockers"] == ["gitea_queue_harbor_110_repair_no_matching_runner"] + assert all( + item["metadata_only"] is True and item["raw_output_returned"] is False + for item in normalized.values() + ) assert queue["raw_output_returned"] is False assert queue["top_visible_runs_returned"] is False assert payload["rollups"]["gitea_queue_blocker_count"] == 2 @@ -304,6 +323,19 @@ def test_harbor_recovery_receipt_surfaces_cross_workflow_queue_payload() -> None assert payload["rollups"]["gitea_queue_harbor_110_jobs_payload_classifier"] == ( "cd_workflow_jobs_returned_for_harbor_110_repair_run" ) + normalized = { + item["field_id"]: item + for item in payload["readback"]["gitea_actions_queue"][ + "normalized_classifier_fields" + ] + } + assert normalized["harbor_110_repair_jobs_payload_classifier"]["value"] == ( + "cd_workflow_jobs_returned_for_harbor_110_repair_run" + ) + assert normalized["harbor_110_repair_jobs_payload_classifier"]["blockers"] == [ + "gitea_queue_harbor_110_repair_jobs_cross_workflow_mismatch", + "gitea_queue_harbor_110_repair_jobs_stale_or_mismatched", + ] def test_harbor_recovery_receipt_surfaces_cd_jobs_payload_classifier() -> None: @@ -338,6 +370,22 @@ def test_harbor_recovery_receipt_surfaces_cd_jobs_payload_classifier() -> None: assert payload["rollups"]["gitea_queue_cd_jobs_payload_classifier"] == ( "cd_jobs_api_head_sha_mismatch_for_visible_cd_run" ) + assert payload["rollups"]["gitea_queue_normalized_classifier_field_count"] == 3 + assert payload["rollups"]["gitea_queue_normalized_classifier_field_ids"] == [ + "cd_run_jobs_payload_classifier", + "harbor_110_repair_jobs_payload_classifier", + "latest_visible_harbor_110_repair_no_matching_runner_label", + ] + normalized = { + item["field_id"]: item for item in queue["normalized_classifier_fields"] + } + assert normalized["cd_run_jobs_payload_classifier"]["value"] == ( + "cd_jobs_api_head_sha_mismatch_for_visible_cd_run" + ) + assert normalized["cd_run_jobs_payload_classifier"]["blockers"] == [ + "gitea_queue_cd_jobs_head_sha_mismatch", + "gitea_queue_cd_jobs_stale_or_mismatched", + ] def test_harbor_recovery_receipt_waits_for_deploy_marker_readback() -> None: