///|
/// Deployment decision that combines provider health with compatibility. This
/// is intentionally pure so release automation can use it in CI without
/// network access or process-global state.
pub(all) struct DeploymentDecision {
allowed : Bool
health : ProviderHealth
compatibility : CompatibilityReport?
reason : String
} derive(Debug)
///|
pub fn deployment_check(
previous : Provider?,
next : Provider,
policy : ProviderPolicy,
) -> DeploymentDecision {
let health = next.health_check(policy)
let compatibility = previous.map(old => compare_providers(old, next))
let compatibility_ok = match compatibility {
Some(report) => report.is_safe()
None => true
}
let allowed = health.is_ready() &&
health.policy.is_compliant() &&
compatibility_ok
let reason = if !health.is_ready() {
"provider health check failed"
} else if !health.policy.is_compliant() {
"provider deployment policy failed"
} else if !compatibility_ok {
"provider compatibility review failed"
} else {
"provider is safe to deploy"
}
{ allowed, health, compatibility, reason }
}
///|
pub fn DeploymentDecision::summary(self : DeploymentDecision) -> String {
(if self.allowed { "allowed" } else { "blocked" }) + ": " + self.reason
}
///|
pub fn DeploymentDecision::is_release_ready(self : DeploymentDecision) -> Bool {
self.allowed && !self.requires_manual_review()
}
///|
pub fn DeploymentDecision::health_status(self : DeploymentDecision) -> String {
self.health.status_text()
}
///|
pub fn DeploymentDecision::requires_manual_review(
self : DeploymentDecision,
) -> Bool {
match self.compatibility {
Some(report) => report.requires_replay() || self.health.has_warnings()
None => self.health.has_warnings()
}
}
///|
pub fn ProviderHealth::has_warnings(self : ProviderHealth) -> Bool {
self.audit.has_warnings() || self.policy.violation_count() > 0
}