Files
adaptive-pricing/adaptive_pricing_core/governance.py

175 lines
5.6 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from decimal import Decimal
from typing import Any, Literal
GovernanceDecision = Literal["proceed", "approval_required", "blocked"]
RecommendationType = Literal["research", "simulation", "model_change", "execution"]
RecommendationPriority = Literal["high", "medium", "low"]
RiskSeverity = Literal["low", "medium", "high"]
HealthStatus = Literal["pass", "warn", "fail"]
def _decimal(value: Decimal | str | int | float | None, default: str = "0") -> Decimal:
if value in (None, ""):
return Decimal(default)
return Decimal(str(value))
@dataclass(frozen=True)
class GovernancePolicy:
policy_id: str
max_self_serve_discount_pct: Decimal = Decimal("10")
max_customer_visible_price_increase_pct: Decimal = Decimal("15")
max_active_experiments: int = 2
max_concurrent_candidate_rollouts: int = 1
require_approval_for_candidate_rollout: bool = True
require_approval_for_approximate_provider_mapping: bool = True
block_unsupported_provider_artifacts: bool = True
drift_blocks_execution: bool = True
require_approval_for_price_change: bool = True
require_customer_notice_for_price_increase: bool = True
customer_notice_days: int = 30
grandfather_existing_customers: bool = True
customer_visible_tuning_enabled: bool = False
customer_visible_tuning_requires_active_model: bool = True
communication_owner_role: str = "operator"
default_approver_role: str = "operator"
metadata: dict[str, Any] = field(default_factory=dict)
@dataclass(frozen=True)
class ApprovalRequirement:
id: str
title: str
approver_role: str
reason: str
blocking: bool = True
@dataclass(frozen=True)
class GovernanceRisk:
id: str
severity: RiskSeverity
summary: str
mitigation: str
@dataclass(frozen=True)
class SupportingObservation:
id: str
title: str
summary: str
source_ref: str
value: str | None = None
@dataclass(frozen=True)
class GovernanceAssessment:
decision: GovernanceDecision
summary: str
approvals: tuple[ApprovalRequirement, ...]
risks: tuple[GovernanceRisk, ...]
supporting_observations: tuple[SupportingObservation, ...]
notes: tuple[str, ...] = ()
@dataclass(frozen=True)
class SellerRecommendation:
id: str
recommendation_type: RecommendationType
priority: RecommendationPriority
title: str
rationale: str
suggested_action: str
confidence: Decimal
governance: GovernanceAssessment
risks: tuple[GovernanceRisk, ...]
supporting_observations: tuple[SupportingObservation, ...]
related_model_ids: tuple[str, ...] = ()
related_profile_ids: tuple[str, ...] = ()
notes: tuple[str, ...] = ()
@dataclass(frozen=True)
class HealthCheck:
id: str
title: str
status: HealthStatus
summary: str
value: str | None = None
threshold: str | None = None
suggested_action: str | None = None
@dataclass(frozen=True)
class SafeTuningParameter:
key: str
label: str
description: str
data_type: str
default_value: str | None = None
min_value: str | None = None
max_value: str | None = None
customer_visible: bool = True
@dataclass(frozen=True)
class SafeTuningExample:
id: str
title: str
outcome: str
summary: str
customer_message: str
visible_to_customer: bool
tradeoffs: tuple[str, ...]
@dataclass(frozen=True)
class SafeTuningContract:
model_id: str
model_name: str
mode: str
customer_visible: bool
tunable_parameters: tuple[SafeTuningParameter, ...]
tradeoff_lexicon: dict[str, str]
examples: tuple[SafeTuningExample, ...]
notes: tuple[str, ...] = ()
def governance_policy_from_dict(raw: dict[str, Any]) -> GovernancePolicy:
return GovernancePolicy(
policy_id=raw.get("policy_id", "default-governance-policy"),
max_self_serve_discount_pct=_decimal(raw.get("max_self_serve_discount_pct"), "10"),
max_customer_visible_price_increase_pct=_decimal(
raw.get("max_customer_visible_price_increase_pct"),
"15",
),
max_active_experiments=int(raw.get("max_active_experiments", 2)),
max_concurrent_candidate_rollouts=int(raw.get("max_concurrent_candidate_rollouts", 1)),
require_approval_for_candidate_rollout=bool(
raw.get("require_approval_for_candidate_rollout", True)
),
require_approval_for_approximate_provider_mapping=bool(
raw.get("require_approval_for_approximate_provider_mapping", True)
),
block_unsupported_provider_artifacts=bool(
raw.get("block_unsupported_provider_artifacts", True)
),
drift_blocks_execution=bool(raw.get("drift_blocks_execution", True)),
require_approval_for_price_change=bool(raw.get("require_approval_for_price_change", True)),
require_customer_notice_for_price_increase=bool(
raw.get("require_customer_notice_for_price_increase", True)
),
customer_notice_days=int(raw.get("customer_notice_days", 30)),
grandfather_existing_customers=bool(raw.get("grandfather_existing_customers", True)),
customer_visible_tuning_enabled=bool(raw.get("customer_visible_tuning_enabled", False)),
customer_visible_tuning_requires_active_model=bool(
raw.get("customer_visible_tuning_requires_active_model", True)
),
communication_owner_role=raw.get("communication_owner_role", "operator"),
default_approver_role=raw.get("default_approver_role", "operator"),
metadata=dict(raw.get("metadata", {})),
)