# [DEF:clean_release_facade:Module] # @TIER: STANDARD # @PURPOSE: Unified entry point for clean release operations. # @LAYER: Application from typing import List, Optional from backend.src.services.clean_release.repositories import ( CandidateRepository, ArtifactRepository, ManifestRepository, PolicyRepository, ComplianceRepository, ReportRepository, ApprovalRepository, PublicationRepository, AuditRepository ) from backend.src.services.clean_release.dto import ( CandidateDTO, ArtifactDTO, ManifestDTO, ComplianceRunDTO, ReportDTO, CandidateOverviewDTO ) from backend.src.services.clean_release.enums import CandidateStatus, RunStatus, ComplianceDecision from backend.src.models.clean_release import CleanPolicySnapshot, SourceRegistrySnapshot from backend.src.core.logger import belief_scope from backend.src.core.config_manager import ConfigManager class CleanReleaseFacade: """ @PURPOSE: Orchestrates repositories and services to provide a clean API for UI/CLI. """ def __init__( self, candidate_repo: CandidateRepository, artifact_repo: ArtifactRepository, manifest_repo: ManifestRepository, policy_repo: PolicyRepository, compliance_repo: ComplianceRepository, report_repo: ReportRepository, approval_repo: ApprovalRepository, publication_repo: PublicationRepository, audit_repo: AuditRepository, config_manager: ConfigManager ): self.candidate_repo = candidate_repo self.artifact_repo = artifact_repo self.manifest_repo = manifest_repo self.policy_repo = policy_repo self.compliance_repo = compliance_repo self.report_repo = report_repo self.approval_repo = approval_repo self.publication_repo = publication_repo self.audit_repo = audit_repo self.config_manager = config_manager def resolve_active_policy_snapshot(self) -> Optional[CleanPolicySnapshot]: """ @PURPOSE: Resolve the active policy snapshot based on ConfigManager. """ with belief_scope("CleanReleaseFacade.resolve_active_policy_snapshot"): config = self.config_manager.get_config() policy_id = config.settings.clean_release.active_policy_id if not policy_id: return None return self.policy_repo.get_policy_snapshot(policy_id) def resolve_active_registry_snapshot(self) -> Optional[SourceRegistrySnapshot]: """ @PURPOSE: Resolve the active registry snapshot based on ConfigManager. """ with belief_scope("CleanReleaseFacade.resolve_active_registry_snapshot"): config = self.config_manager.get_config() registry_id = config.settings.clean_release.active_registry_id if not registry_id: return None return self.policy_repo.get_registry_snapshot(registry_id) def get_candidate_overview(self, candidate_id: str) -> Optional[CandidateOverviewDTO]: """ @PURPOSE: Build a comprehensive overview for a candidate. """ with belief_scope("CleanReleaseFacade.get_candidate_overview"): candidate = self.candidate_repo.get_by_id(candidate_id) if not candidate: return None manifest = self.manifest_repo.get_latest_for_candidate(candidate_id) runs = self.compliance_repo.list_runs_by_candidate(candidate_id) latest_run = runs[-1] if runs else None report = None if latest_run: report = self.report_repo.get_by_run(latest_run.id) approval = self.approval_repo.get_latest_for_candidate(candidate_id) publication = self.publication_repo.get_latest_for_candidate(candidate_id) active_policy = self.resolve_active_policy_snapshot() active_registry = self.resolve_active_registry_snapshot() return CandidateOverviewDTO( candidate_id=candidate.id, version=candidate.version, source_snapshot_ref=candidate.source_snapshot_ref, status=CandidateStatus(candidate.status), latest_manifest_id=manifest.id if manifest else None, latest_manifest_digest=manifest.manifest_digest if manifest else None, latest_run_id=latest_run.id if latest_run else None, latest_run_status=RunStatus(latest_run.status) if latest_run else None, latest_report_id=report.id if report else None, latest_report_final_status=ComplianceDecision(report.final_status) if report else None, latest_policy_snapshot_id=active_policy.id if active_policy else None, latest_policy_version=active_policy.policy_version if active_policy else None, latest_registry_snapshot_id=active_registry.id if active_registry else None, latest_registry_version=active_registry.registry_version if active_registry else None, latest_approval_decision=approval.decision if approval else None, latest_publication_id=publication.id if publication else None, latest_publication_status=publication.status if publication else None ) def list_candidates(self) -> List[CandidateOverviewDTO]: """ @PURPOSE: List all candidates with their current status. """ with belief_scope("CleanReleaseFacade.list_candidates"): candidates = self.candidate_repo.list_all() return [self.get_candidate_overview(c.id) for c in candidates] # [/DEF:clean_release_facade:Module]