from __future__ import annotations from dataclasses import dataclass from typing import Any @dataclass(frozen=True) class GateDecision: passed: bool error_code: str | None = None error_message: str | None = None def evaluate_step_gate(step_key: str, payload: dict[str, Any]) -> GateDecision: if payload.get("success") is False: return GateDecision( passed=False, error_code=str(payload.get("error_code") or "step_reported_failure"), error_message=str(payload.get("error") or "Step returned success=false"), ) if step_key == "demand_classify" and payload.get("failed_batches"): return GateDecision(False, "classification_failed_batches", "Classification has failed batches") if step_key in {"demand_grade", "demand_expand", "video_discovery"}: failed = int(payload.get("failed", payload.get("failed_count", 0)) or 0) if failed > 0: return GateDecision( False, "business_failures", f"{step_key} reported {failed} failed item(s)", ) if step_key == "aigc_write_record": if payload.get("effect_recorded") is not True or not payload.get("payload_hash"): return GateDecision( False, "aigc_record_incomplete", "AIGC publish payload/hash was not durably recorded", ) failed_batches = int(payload.get("failed_batch_count", 0) or 0) if failed_batches > 0: return GateDecision( False, "aigc_publish_failed", f"AIGC publish reported {failed_batches} failed batch(es)", ) return GateDecision(True)