generated from coulomb/repo-seed
Implement boundary engine and close WP-0004
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
from .boundary_engine import (
|
||||
BoundaryPolicy,
|
||||
CommitmentTerms,
|
||||
ConstraintResult,
|
||||
PricingConfiguration,
|
||||
ValidationResult,
|
||||
default_commitment_terms,
|
||||
validate_pricing_configuration,
|
||||
)
|
||||
from .pricing_models import (
|
||||
ChargeComponent,
|
||||
Commitment,
|
||||
@@ -10,12 +19,19 @@ from .pricing_models import (
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"BoundaryPolicy",
|
||||
"ChargeComponent",
|
||||
"Commitment",
|
||||
"CommitmentTerms",
|
||||
"ConstraintResult",
|
||||
"PricingModel",
|
||||
"PricingModelStatus",
|
||||
"PricingConfiguration",
|
||||
"TunableParameter",
|
||||
"ValidationResult",
|
||||
"default_commitment_terms",
|
||||
"load_pricing_models",
|
||||
"validate_pricing_configuration",
|
||||
"validate_pricing_catalog",
|
||||
"validate_pricing_model",
|
||||
]
|
||||
|
||||
937
adaptive_pricing_core/boundary_engine.py
Normal file
937
adaptive_pricing_core/boundary_engine.py
Normal file
@@ -0,0 +1,937 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from typing import Any, Callable, Literal
|
||||
|
||||
from .pricing_models import PricingModel
|
||||
|
||||
ConstraintSeverity = Literal["hard", "soft"]
|
||||
ConstraintStatus = Literal["pass", "fail", "review"]
|
||||
ValidationDecision = Literal["accepted", "requires_approval", "rejected"]
|
||||
ConstraintEvaluator = Callable[
|
||||
["PricingConfiguration", "BoundaryPolicy", "PricingMetrics", "PricingMetrics"],
|
||||
"ConstraintResult",
|
||||
]
|
||||
|
||||
TWOPLACES = Decimal("0.01")
|
||||
PCTPLACES = Decimal("0.1")
|
||||
|
||||
|
||||
def _money(value: Decimal) -> Decimal:
|
||||
return value.quantize(TWOPLACES, rounding=ROUND_HALF_UP)
|
||||
|
||||
|
||||
def _percent(value: Decimal) -> Decimal:
|
||||
return value.quantize(PCTPLACES, rounding=ROUND_HALF_UP)
|
||||
|
||||
|
||||
def _decimal(value: Decimal | str | int | float | None) -> Decimal:
|
||||
if value in (None, ""):
|
||||
return Decimal("0")
|
||||
return Decimal(str(value))
|
||||
|
||||
|
||||
def _recurring_non_usage_component_revenue(model: PricingModel) -> Decimal:
|
||||
total = Decimal("0")
|
||||
for component in model.charge_components:
|
||||
if component.kind in {"access", "usage", "setup"}:
|
||||
continue
|
||||
if component.amount is None:
|
||||
continue
|
||||
if component.cadence == "one_time":
|
||||
continue
|
||||
total += component.amount
|
||||
return total
|
||||
|
||||
|
||||
def _access_fee_amount(model: PricingModel) -> Decimal:
|
||||
for component in model.charge_components:
|
||||
if component.kind == "access" and component.amount is not None:
|
||||
return component.amount
|
||||
return model.access_fee_amount
|
||||
|
||||
|
||||
def _usage_component(model: PricingModel):
|
||||
return next((component for component in model.charge_components if component.kind == "usage"), None)
|
||||
|
||||
|
||||
def _tunable_default(model: PricingModel, key: str) -> Decimal | None:
|
||||
parameter = next((item for item in model.tunable_parameters if item.key == key), None)
|
||||
if not parameter or parameter.default_value in (None, ""):
|
||||
return None
|
||||
return Decimal(str(parameter.default_value))
|
||||
|
||||
|
||||
def _default_included_units(model: PricingModel) -> Decimal:
|
||||
usage = _usage_component(model)
|
||||
if usage and usage.included_units is not None:
|
||||
return usage.included_units
|
||||
value = _tunable_default(model, "included_tokens")
|
||||
return value if value is not None else Decimal("0")
|
||||
|
||||
|
||||
def _default_usage_unit_price(model: PricingModel) -> Decimal:
|
||||
usage = _usage_component(model)
|
||||
if usage and usage.unit_price is not None:
|
||||
return usage.unit_price
|
||||
value = _tunable_default(model, "overage_unit_price")
|
||||
return value if value is not None else Decimal("0")
|
||||
|
||||
|
||||
def _months_from_commitment(value: Decimal, unit: str | None) -> int:
|
||||
normalized = (unit or "month").lower()
|
||||
if normalized in {"month", "months"}:
|
||||
return int(value)
|
||||
if normalized in {"year", "years"}:
|
||||
return int(value * Decimal("12"))
|
||||
return int(value)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CommitmentTerms:
|
||||
contract_duration_months: int | None = None
|
||||
minimum_monthly_turnover: Decimal = Decimal("0")
|
||||
prepaid_amount: Decimal = Decimal("0")
|
||||
guaranteed_platform_fee: Decimal = Decimal("0")
|
||||
customer_funded_onboarding: Decimal = Decimal("0")
|
||||
reduced_cancellation_flexibility: bool = False
|
||||
|
||||
|
||||
def default_commitment_terms(model: PricingModel) -> CommitmentTerms:
|
||||
contract_duration = None
|
||||
minimum_turnover = Decimal("0")
|
||||
prepaid_amount = Decimal("0")
|
||||
guaranteed_platform_fee = Decimal("0")
|
||||
|
||||
for commitment in model.commitments:
|
||||
raw_value = _decimal(commitment.value)
|
||||
if commitment.kind == "contract_duration":
|
||||
contract_duration = _months_from_commitment(raw_value, commitment.unit)
|
||||
elif commitment.kind in {"minimum_turnover", "minimum_monthly_turnover"}:
|
||||
minimum_turnover = raw_value
|
||||
elif commitment.kind in {"guaranteed_platform_fee", "minimum_platform_fee"}:
|
||||
guaranteed_platform_fee = raw_value
|
||||
elif commitment.kind == "prepayment" and (commitment.unit or "").lower() in {"eur", "usd"}:
|
||||
prepaid_amount = raw_value
|
||||
|
||||
tunable_contract_duration = _tunable_default(model, "contract_duration_months")
|
||||
if contract_duration is None and tunable_contract_duration is not None:
|
||||
contract_duration = int(tunable_contract_duration)
|
||||
|
||||
return CommitmentTerms(
|
||||
contract_duration_months=contract_duration,
|
||||
minimum_monthly_turnover=minimum_turnover,
|
||||
prepaid_amount=prepaid_amount,
|
||||
guaranteed_platform_fee=guaranteed_platform_fee,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PricingConfiguration:
|
||||
model: PricingModel
|
||||
segment: str | None = None
|
||||
expected_usage_units: Decimal = Decimal("0")
|
||||
expected_usage_variance_pct: Decimal = Decimal("0")
|
||||
allocated_fixed_cost: Decimal = Decimal("0")
|
||||
direct_cost_amount: Decimal = Decimal("0")
|
||||
unit_cost: Decimal = Decimal("0")
|
||||
support_cost: Decimal = Decimal("0")
|
||||
onboarding_cost: Decimal = Decimal("0")
|
||||
risk_cost: Decimal = Decimal("0")
|
||||
payment_fee_fixed: Decimal = Decimal("0")
|
||||
payment_fee_rate_pct: Decimal = Decimal("0")
|
||||
access_fee_amount: Decimal | None = None
|
||||
included_units: Decimal | None = None
|
||||
usage_unit_price: Decimal | None = None
|
||||
discount_amount: Decimal = Decimal("0")
|
||||
commitment_terms: CommitmentTerms = field(default_factory=CommitmentTerms)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BoundaryPolicy:
|
||||
minimum_margin_pct: Decimal = Decimal("0")
|
||||
target_margin_pct: Decimal = Decimal("15")
|
||||
max_payment_fee_pct: Decimal = Decimal("10")
|
||||
max_expected_usage_variance_pct: Decimal = Decimal("50")
|
||||
approval_discount_pct: Decimal = Decimal("10")
|
||||
max_discount_pct: Decimal = Decimal("25")
|
||||
minimum_contract_duration_for_discount_months: int = 3
|
||||
minimum_turnover_multiple_for_discount: Decimal = Decimal("1")
|
||||
minimum_prepayment_months_for_discount: Decimal = Decimal("1")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PricingMetrics:
|
||||
currency: str
|
||||
monthly_revenue: Decimal
|
||||
effective_monthly_revenue: Decimal
|
||||
payment_fees: Decimal
|
||||
payment_fee_pct: Decimal
|
||||
allocated_fixed_cost: Decimal
|
||||
direct_cost_amount: Decimal
|
||||
variable_usage_cost: Decimal
|
||||
support_cost: Decimal
|
||||
onboarding_cost: Decimal
|
||||
customer_funded_onboarding: Decimal
|
||||
risk_cost: Decimal
|
||||
total_monthly_cost: Decimal
|
||||
monthly_margin: Decimal
|
||||
margin_pct: Decimal
|
||||
cost_floor_revenue: Decimal
|
||||
minimum_margin_revenue: Decimal
|
||||
target_margin_revenue: Decimal
|
||||
expected_usage_units: Decimal
|
||||
included_units: Decimal
|
||||
billable_usage_units: Decimal
|
||||
unit_cost: Decimal
|
||||
usage_unit_price: Decimal
|
||||
access_fee_amount: Decimal
|
||||
contract_duration_months: int
|
||||
minimum_monthly_turnover: Decimal
|
||||
prepaid_amount: Decimal
|
||||
guaranteed_platform_fee: Decimal
|
||||
concession_value: Decimal
|
||||
concession_pct: Decimal
|
||||
baseline_monthly_revenue: Decimal
|
||||
baseline_margin: Decimal
|
||||
baseline_margin_pct: Decimal
|
||||
meaningful_commitment_signals: tuple[str, ...]
|
||||
reduced_cancellation_flexibility: bool
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ConstraintResult:
|
||||
id: str
|
||||
title: str
|
||||
severity: ConstraintSeverity
|
||||
status: ConstraintStatus
|
||||
summary: str
|
||||
reason: str
|
||||
actual_value: Decimal | str | int | None = None
|
||||
threshold_value: Decimal | str | int | None = None
|
||||
unit: str | None = None
|
||||
details: dict[str, Any] = field(default_factory=dict)
|
||||
suggested_action: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BoundaryConstraint:
|
||||
id: str
|
||||
title: str
|
||||
severity: ConstraintSeverity
|
||||
evaluator: ConstraintEvaluator
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ValidationResult:
|
||||
model_id: str
|
||||
model_name: str
|
||||
decision: ValidationDecision
|
||||
valid: bool
|
||||
requires_approval: bool
|
||||
summary: str
|
||||
configuration: dict[str, Any]
|
||||
metrics: PricingMetrics
|
||||
policy: BoundaryPolicy
|
||||
constraints: tuple[ConstraintResult, ...]
|
||||
|
||||
|
||||
def _required_revenue(cost: Decimal, margin_pct: Decimal) -> Decimal:
|
||||
if margin_pct >= Decimal("100"):
|
||||
return Decimal("Infinity")
|
||||
ratio = Decimal("1") - (margin_pct / Decimal("100"))
|
||||
if ratio <= Decimal("0"):
|
||||
return Decimal("Infinity")
|
||||
return _money(cost / ratio)
|
||||
|
||||
|
||||
def _meaningful_commitment_signals(
|
||||
metrics: PricingMetrics,
|
||||
baseline_metrics: PricingMetrics,
|
||||
policy: BoundaryPolicy,
|
||||
) -> tuple[str, ...]:
|
||||
signals: list[str] = []
|
||||
|
||||
if metrics.minimum_monthly_turnover >= (
|
||||
metrics.monthly_revenue * policy.minimum_turnover_multiple_for_discount
|
||||
) and metrics.minimum_monthly_turnover > Decimal("0"):
|
||||
signals.append("minimum_monthly_turnover")
|
||||
|
||||
if metrics.prepaid_amount >= (
|
||||
metrics.monthly_revenue * policy.minimum_prepayment_months_for_discount
|
||||
) and metrics.prepaid_amount > Decimal("0"):
|
||||
signals.append("prepayment")
|
||||
|
||||
if metrics.guaranteed_platform_fee >= metrics.monthly_revenue and metrics.guaranteed_platform_fee > Decimal("0"):
|
||||
signals.append("guaranteed_platform_fee")
|
||||
|
||||
if metrics.customer_funded_onboarding >= metrics.onboarding_cost and metrics.onboarding_cost > Decimal("0"):
|
||||
signals.append("customer_funded_onboarding")
|
||||
|
||||
if (
|
||||
metrics.contract_duration_months >= policy.minimum_contract_duration_for_discount_months
|
||||
and metrics.contract_duration_months > baseline_metrics.contract_duration_months
|
||||
):
|
||||
signals.append("longer_contract_duration")
|
||||
|
||||
if metrics.reduced_cancellation_flexibility:
|
||||
signals.append("reduced_cancellation_flexibility")
|
||||
|
||||
return tuple(signals)
|
||||
|
||||
|
||||
def _build_metrics(
|
||||
configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
*,
|
||||
baseline_metrics: PricingMetrics | None = None,
|
||||
) -> PricingMetrics:
|
||||
model = configuration.model
|
||||
defaults = default_commitment_terms(model)
|
||||
|
||||
access_fee_amount = configuration.access_fee_amount
|
||||
if access_fee_amount is None:
|
||||
access_fee_amount = _access_fee_amount(model)
|
||||
|
||||
included_units = configuration.included_units
|
||||
if included_units is None:
|
||||
included_units = _default_included_units(model)
|
||||
|
||||
usage_unit_price = configuration.usage_unit_price
|
||||
if usage_unit_price is None:
|
||||
usage_unit_price = _default_usage_unit_price(model)
|
||||
|
||||
contract_duration_months = configuration.commitment_terms.contract_duration_months
|
||||
if contract_duration_months is None:
|
||||
contract_duration_months = defaults.contract_duration_months or 1
|
||||
|
||||
minimum_monthly_turnover = (
|
||||
configuration.commitment_terms.minimum_monthly_turnover
|
||||
if configuration.commitment_terms.minimum_monthly_turnover > Decimal("0")
|
||||
else defaults.minimum_monthly_turnover
|
||||
)
|
||||
prepaid_amount = (
|
||||
configuration.commitment_terms.prepaid_amount
|
||||
if configuration.commitment_terms.prepaid_amount > Decimal("0")
|
||||
else defaults.prepaid_amount
|
||||
)
|
||||
guaranteed_platform_fee = (
|
||||
configuration.commitment_terms.guaranteed_platform_fee
|
||||
if configuration.commitment_terms.guaranteed_platform_fee > Decimal("0")
|
||||
else defaults.guaranteed_platform_fee
|
||||
)
|
||||
customer_funded_onboarding = configuration.commitment_terms.customer_funded_onboarding
|
||||
reduced_cancellation_flexibility = configuration.commitment_terms.reduced_cancellation_flexibility
|
||||
|
||||
expected_usage_units = _decimal(configuration.expected_usage_units)
|
||||
billable_usage_units = max(expected_usage_units - included_units, Decimal("0"))
|
||||
|
||||
recurring_revenue = (
|
||||
access_fee_amount
|
||||
+ _recurring_non_usage_component_revenue(model)
|
||||
+ (usage_unit_price * billable_usage_units)
|
||||
- configuration.discount_amount
|
||||
)
|
||||
monthly_revenue = _money(max(recurring_revenue, Decimal("0")))
|
||||
effective_monthly_revenue = _money(
|
||||
max(monthly_revenue, minimum_monthly_turnover, guaranteed_platform_fee)
|
||||
)
|
||||
|
||||
payment_fees = _money(
|
||||
configuration.payment_fee_fixed
|
||||
+ (effective_monthly_revenue * configuration.payment_fee_rate_pct / Decimal("100"))
|
||||
)
|
||||
if effective_monthly_revenue > Decimal("0"):
|
||||
payment_fee_pct = _percent(
|
||||
(payment_fees / effective_monthly_revenue) * Decimal("100")
|
||||
)
|
||||
else:
|
||||
payment_fee_pct = Decimal("100.0") if payment_fees > Decimal("0") else Decimal("0.0")
|
||||
|
||||
variable_usage_cost = _money(expected_usage_units * configuration.unit_cost)
|
||||
residual_onboarding_cost = max(
|
||||
configuration.onboarding_cost - customer_funded_onboarding,
|
||||
Decimal("0"),
|
||||
)
|
||||
total_monthly_cost = _money(
|
||||
configuration.allocated_fixed_cost
|
||||
+ configuration.direct_cost_amount
|
||||
+ variable_usage_cost
|
||||
+ configuration.support_cost
|
||||
+ residual_onboarding_cost
|
||||
+ configuration.risk_cost
|
||||
+ payment_fees
|
||||
)
|
||||
monthly_margin = _money(effective_monthly_revenue - total_monthly_cost)
|
||||
if effective_monthly_revenue > Decimal("0"):
|
||||
margin_pct = _percent((monthly_margin / effective_monthly_revenue) * Decimal("100"))
|
||||
else:
|
||||
margin_pct = Decimal("-100.0") if total_monthly_cost > Decimal("0") else Decimal("0.0")
|
||||
|
||||
cost_floor_revenue = _money(total_monthly_cost)
|
||||
minimum_margin_revenue = _required_revenue(total_monthly_cost, policy.minimum_margin_pct)
|
||||
target_margin_revenue = _required_revenue(total_monthly_cost, policy.target_margin_pct)
|
||||
|
||||
baseline_revenue = Decimal("0")
|
||||
baseline_margin = Decimal("0")
|
||||
baseline_margin_pct = Decimal("0.0")
|
||||
concession_value = Decimal("0")
|
||||
concession_pct = Decimal("0.0")
|
||||
meaningful_commitment_signals: tuple[str, ...] = ()
|
||||
baseline_contract_duration = contract_duration_months
|
||||
|
||||
if baseline_metrics is not None:
|
||||
baseline_revenue = baseline_metrics.effective_monthly_revenue
|
||||
baseline_margin = baseline_metrics.monthly_margin
|
||||
baseline_margin_pct = baseline_metrics.margin_pct
|
||||
concession_value = _money(max(baseline_metrics.monthly_margin - monthly_margin, Decimal("0")))
|
||||
if baseline_metrics.effective_monthly_revenue > Decimal("0"):
|
||||
concession_pct = _percent(
|
||||
(concession_value / baseline_metrics.effective_monthly_revenue) * Decimal("100")
|
||||
)
|
||||
else:
|
||||
concession_pct = Decimal("0.0")
|
||||
baseline_contract_duration = baseline_metrics.contract_duration_months
|
||||
|
||||
probe_baseline = baseline_metrics
|
||||
if probe_baseline is None:
|
||||
probe_baseline = PricingMetrics(
|
||||
currency=model.currency,
|
||||
monthly_revenue=monthly_revenue,
|
||||
effective_monthly_revenue=effective_monthly_revenue,
|
||||
payment_fees=payment_fees,
|
||||
payment_fee_pct=payment_fee_pct,
|
||||
allocated_fixed_cost=_money(configuration.allocated_fixed_cost),
|
||||
direct_cost_amount=_money(configuration.direct_cost_amount),
|
||||
variable_usage_cost=variable_usage_cost,
|
||||
support_cost=_money(configuration.support_cost),
|
||||
onboarding_cost=_money(configuration.onboarding_cost),
|
||||
customer_funded_onboarding=_money(customer_funded_onboarding),
|
||||
risk_cost=_money(configuration.risk_cost),
|
||||
total_monthly_cost=total_monthly_cost,
|
||||
monthly_margin=monthly_margin,
|
||||
margin_pct=margin_pct,
|
||||
cost_floor_revenue=cost_floor_revenue,
|
||||
minimum_margin_revenue=minimum_margin_revenue,
|
||||
target_margin_revenue=target_margin_revenue,
|
||||
expected_usage_units=expected_usage_units,
|
||||
included_units=included_units,
|
||||
billable_usage_units=billable_usage_units,
|
||||
unit_cost=configuration.unit_cost,
|
||||
usage_unit_price=usage_unit_price,
|
||||
access_fee_amount=access_fee_amount,
|
||||
contract_duration_months=baseline_contract_duration,
|
||||
minimum_monthly_turnover=minimum_monthly_turnover,
|
||||
prepaid_amount=prepaid_amount,
|
||||
guaranteed_platform_fee=guaranteed_platform_fee,
|
||||
concession_value=Decimal("0"),
|
||||
concession_pct=Decimal("0.0"),
|
||||
baseline_monthly_revenue=effective_monthly_revenue,
|
||||
baseline_margin=monthly_margin,
|
||||
baseline_margin_pct=margin_pct,
|
||||
meaningful_commitment_signals=(),
|
||||
reduced_cancellation_flexibility=reduced_cancellation_flexibility,
|
||||
)
|
||||
|
||||
meaningful_commitment_signals = _meaningful_commitment_signals(
|
||||
PricingMetrics(
|
||||
currency=model.currency,
|
||||
monthly_revenue=monthly_revenue,
|
||||
effective_monthly_revenue=effective_monthly_revenue,
|
||||
payment_fees=payment_fees,
|
||||
payment_fee_pct=payment_fee_pct,
|
||||
allocated_fixed_cost=_money(configuration.allocated_fixed_cost),
|
||||
direct_cost_amount=_money(configuration.direct_cost_amount),
|
||||
variable_usage_cost=variable_usage_cost,
|
||||
support_cost=_money(configuration.support_cost),
|
||||
onboarding_cost=_money(configuration.onboarding_cost),
|
||||
customer_funded_onboarding=_money(customer_funded_onboarding),
|
||||
risk_cost=_money(configuration.risk_cost),
|
||||
total_monthly_cost=total_monthly_cost,
|
||||
monthly_margin=monthly_margin,
|
||||
margin_pct=margin_pct,
|
||||
cost_floor_revenue=cost_floor_revenue,
|
||||
minimum_margin_revenue=minimum_margin_revenue,
|
||||
target_margin_revenue=target_margin_revenue,
|
||||
expected_usage_units=expected_usage_units,
|
||||
included_units=included_units,
|
||||
billable_usage_units=billable_usage_units,
|
||||
unit_cost=configuration.unit_cost,
|
||||
usage_unit_price=usage_unit_price,
|
||||
access_fee_amount=access_fee_amount,
|
||||
contract_duration_months=contract_duration_months,
|
||||
minimum_monthly_turnover=minimum_monthly_turnover,
|
||||
prepaid_amount=prepaid_amount,
|
||||
guaranteed_platform_fee=guaranteed_platform_fee,
|
||||
concession_value=concession_value,
|
||||
concession_pct=concession_pct,
|
||||
baseline_monthly_revenue=baseline_revenue,
|
||||
baseline_margin=baseline_margin,
|
||||
baseline_margin_pct=baseline_margin_pct,
|
||||
meaningful_commitment_signals=(),
|
||||
reduced_cancellation_flexibility=reduced_cancellation_flexibility,
|
||||
),
|
||||
probe_baseline,
|
||||
policy,
|
||||
)
|
||||
|
||||
return PricingMetrics(
|
||||
currency=model.currency,
|
||||
monthly_revenue=monthly_revenue,
|
||||
effective_monthly_revenue=effective_monthly_revenue,
|
||||
payment_fees=payment_fees,
|
||||
payment_fee_pct=payment_fee_pct,
|
||||
allocated_fixed_cost=_money(configuration.allocated_fixed_cost),
|
||||
direct_cost_amount=_money(configuration.direct_cost_amount),
|
||||
variable_usage_cost=variable_usage_cost,
|
||||
support_cost=_money(configuration.support_cost),
|
||||
onboarding_cost=_money(configuration.onboarding_cost),
|
||||
customer_funded_onboarding=_money(customer_funded_onboarding),
|
||||
risk_cost=_money(configuration.risk_cost),
|
||||
total_monthly_cost=total_monthly_cost,
|
||||
monthly_margin=monthly_margin,
|
||||
margin_pct=margin_pct,
|
||||
cost_floor_revenue=cost_floor_revenue,
|
||||
minimum_margin_revenue=minimum_margin_revenue,
|
||||
target_margin_revenue=target_margin_revenue,
|
||||
expected_usage_units=expected_usage_units,
|
||||
included_units=included_units,
|
||||
billable_usage_units=billable_usage_units,
|
||||
unit_cost=configuration.unit_cost,
|
||||
usage_unit_price=usage_unit_price,
|
||||
access_fee_amount=access_fee_amount,
|
||||
contract_duration_months=contract_duration_months,
|
||||
minimum_monthly_turnover=minimum_monthly_turnover,
|
||||
prepaid_amount=prepaid_amount,
|
||||
guaranteed_platform_fee=guaranteed_platform_fee,
|
||||
concession_value=concession_value,
|
||||
concession_pct=concession_pct,
|
||||
baseline_monthly_revenue=_money(baseline_revenue),
|
||||
baseline_margin=_money(baseline_margin),
|
||||
baseline_margin_pct=baseline_margin_pct,
|
||||
meaningful_commitment_signals=meaningful_commitment_signals,
|
||||
reduced_cancellation_flexibility=reduced_cancellation_flexibility,
|
||||
)
|
||||
|
||||
|
||||
def _baseline_configuration(configuration: PricingConfiguration) -> PricingConfiguration:
|
||||
return PricingConfiguration(
|
||||
model=configuration.model,
|
||||
segment=configuration.segment,
|
||||
expected_usage_units=configuration.expected_usage_units,
|
||||
expected_usage_variance_pct=configuration.expected_usage_variance_pct,
|
||||
allocated_fixed_cost=configuration.allocated_fixed_cost,
|
||||
direct_cost_amount=configuration.direct_cost_amount,
|
||||
unit_cost=configuration.unit_cost,
|
||||
support_cost=configuration.support_cost,
|
||||
onboarding_cost=configuration.onboarding_cost,
|
||||
risk_cost=configuration.risk_cost,
|
||||
payment_fee_fixed=configuration.payment_fee_fixed,
|
||||
payment_fee_rate_pct=configuration.payment_fee_rate_pct,
|
||||
commitment_terms=default_commitment_terms(configuration.model),
|
||||
)
|
||||
|
||||
|
||||
def _segment_eligibility(
|
||||
configuration: PricingConfiguration,
|
||||
_policy: BoundaryPolicy,
|
||||
_metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if not configuration.segment or not configuration.model.eligibility:
|
||||
return ConstraintResult(
|
||||
id="segment-eligibility",
|
||||
title="Segment eligibility",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary="Segment eligibility not restrictive for this evaluation.",
|
||||
reason="No customer segment was supplied or the model declares no eligibility list.",
|
||||
)
|
||||
|
||||
if configuration.segment in configuration.model.eligibility:
|
||||
return ConstraintResult(
|
||||
id="segment-eligibility",
|
||||
title="Segment eligibility",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Segment '{configuration.segment}' is eligible.",
|
||||
reason="The supplied customer segment is listed in the model eligibility rules.",
|
||||
actual_value=configuration.segment,
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="segment-eligibility",
|
||||
title="Segment eligibility",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Segment '{configuration.segment}' is not eligible for this model.",
|
||||
reason="The model declares an explicit eligibility list and the supplied segment is outside it.",
|
||||
actual_value=configuration.segment,
|
||||
details={"eligible_segments": list(configuration.model.eligibility)},
|
||||
suggested_action="Choose an eligible segment or use a different pricing model.",
|
||||
)
|
||||
|
||||
|
||||
def _usage_variance_limit(
|
||||
configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
_metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
actual = _percent(configuration.expected_usage_variance_pct)
|
||||
if actual <= policy.max_expected_usage_variance_pct:
|
||||
return ConstraintResult(
|
||||
id="usage-variance-limit",
|
||||
title="Usage variance limit",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Expected usage variance {actual}% is within the allowed range.",
|
||||
reason="The scenario stays inside the configured usage-variance guardrail.",
|
||||
actual_value=actual,
|
||||
threshold_value=policy.max_expected_usage_variance_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="usage-variance-limit",
|
||||
title="Usage variance limit",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Expected usage variance {actual}% exceeds the allowed {policy.max_expected_usage_variance_pct}%.",
|
||||
reason="High-variance usage invalidates the pricing configuration until the seller widens the guardrail or changes the package.",
|
||||
actual_value=actual,
|
||||
threshold_value=policy.max_expected_usage_variance_pct,
|
||||
unit="percent",
|
||||
suggested_action="Reduce exposure to volatile usage or tighten the included-usage assumptions.",
|
||||
)
|
||||
|
||||
|
||||
def _payment_fee_limit(
|
||||
_configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.payment_fee_pct <= policy.max_payment_fee_pct:
|
||||
return ConstraintResult(
|
||||
id="payment-fee-limit",
|
||||
title="Payment fee limit",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Payment fees consume {metrics.payment_fee_pct}% of revenue, within policy.",
|
||||
reason="Payment-provider fees remain inside the configured coverage ceiling.",
|
||||
actual_value=metrics.payment_fee_pct,
|
||||
threshold_value=policy.max_payment_fee_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="payment-fee-limit",
|
||||
title="Payment fee limit",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Payment fees consume {metrics.payment_fee_pct}% of revenue, above the {policy.max_payment_fee_pct}% ceiling.",
|
||||
reason="The pricing configuration leaves too little contribution margin after provider fees.",
|
||||
actual_value=metrics.payment_fee_pct,
|
||||
threshold_value=policy.max_payment_fee_pct,
|
||||
unit="percent",
|
||||
suggested_action="Increase revenue, reduce fee burden, or change the collection method.",
|
||||
)
|
||||
|
||||
|
||||
def _cost_floor_coverage(
|
||||
_configuration: PricingConfiguration,
|
||||
_policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.monthly_margin >= Decimal("0"):
|
||||
return ConstraintResult(
|
||||
id="cost-floor-coverage",
|
||||
title="Cost floor coverage",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Monthly revenue clears the cost floor by {metrics.monthly_margin} {metrics.currency}.",
|
||||
reason="Expected revenue covers allocated fixed cost, variable cost, and payment fees.",
|
||||
actual_value=metrics.monthly_margin,
|
||||
threshold_value=Decimal("0.00"),
|
||||
unit=metrics.currency,
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="cost-floor-coverage",
|
||||
title="Cost floor coverage",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Monthly revenue misses the cost floor by {abs(metrics.monthly_margin)} {metrics.currency}.",
|
||||
reason=f"At least {metrics.cost_floor_revenue} {metrics.currency} monthly revenue is required to break even under these assumptions.",
|
||||
actual_value=metrics.monthly_margin,
|
||||
threshold_value=Decimal("0.00"),
|
||||
unit=metrics.currency,
|
||||
suggested_action="Raise price, lower cost, or add stronger commitments before offering this configuration.",
|
||||
)
|
||||
|
||||
|
||||
def _minimum_margin(
|
||||
_configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.margin_pct >= policy.minimum_margin_pct:
|
||||
return ConstraintResult(
|
||||
id="minimum-margin",
|
||||
title="Minimum margin",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Margin {metrics.margin_pct}% satisfies the hard minimum.",
|
||||
reason="The configuration meets the seller's minimum margin boundary.",
|
||||
actual_value=metrics.margin_pct,
|
||||
threshold_value=policy.minimum_margin_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="minimum-margin",
|
||||
title="Minimum margin",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Margin {metrics.margin_pct}% is below the hard minimum of {policy.minimum_margin_pct}%.",
|
||||
reason=f"At least {metrics.minimum_margin_revenue} {metrics.currency} monthly revenue is required to satisfy the minimum margin boundary.",
|
||||
actual_value=metrics.margin_pct,
|
||||
threshold_value=policy.minimum_margin_pct,
|
||||
unit="percent",
|
||||
suggested_action="Increase price, reduce costs, or add commitment-backed protection.",
|
||||
)
|
||||
|
||||
|
||||
def _target_margin_approval(
|
||||
_configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.margin_pct >= policy.target_margin_pct:
|
||||
return ConstraintResult(
|
||||
id="target-margin-approval",
|
||||
title="Target margin approval threshold",
|
||||
severity="soft",
|
||||
status="pass",
|
||||
summary=f"Margin {metrics.margin_pct}% satisfies the target margin threshold.",
|
||||
reason="No sales or pricing approval is required on margin grounds.",
|
||||
actual_value=metrics.margin_pct,
|
||||
threshold_value=policy.target_margin_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="target-margin-approval",
|
||||
title="Target margin approval threshold",
|
||||
severity="soft",
|
||||
status="review",
|
||||
summary=f"Margin {metrics.margin_pct}% is below the target threshold of {policy.target_margin_pct}%.",
|
||||
reason=f"The configuration is economically viable but falls short of the seller's preferred target margin of {policy.target_margin_pct}%.",
|
||||
actual_value=metrics.margin_pct,
|
||||
threshold_value=policy.target_margin_pct,
|
||||
unit="percent",
|
||||
suggested_action="Route through approval or improve economics before release.",
|
||||
)
|
||||
|
||||
|
||||
def _discount_exposure_limit(
|
||||
_configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.concession_pct <= policy.max_discount_pct:
|
||||
return ConstraintResult(
|
||||
id="discount-exposure-limit",
|
||||
title="Discount exposure limit",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"Economic concession {metrics.concession_pct}% stays inside the hard discount ceiling.",
|
||||
reason="The configuration does not exceed the seller's maximum discount exposure.",
|
||||
actual_value=metrics.concession_pct,
|
||||
threshold_value=policy.max_discount_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="discount-exposure-limit",
|
||||
title="Discount exposure limit",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Economic concession {metrics.concession_pct}% exceeds the hard discount ceiling of {policy.max_discount_pct}%.",
|
||||
reason="The proposed economics reduce seller value too far relative to the model baseline.",
|
||||
actual_value=metrics.concession_pct,
|
||||
threshold_value=policy.max_discount_pct,
|
||||
unit="percent",
|
||||
suggested_action="Reduce the concession or offset it with a materially stronger commitment structure.",
|
||||
)
|
||||
|
||||
|
||||
def _discount_approval_threshold(
|
||||
_configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.concession_pct <= policy.approval_discount_pct:
|
||||
return ConstraintResult(
|
||||
id="discount-approval-threshold",
|
||||
title="Discount approval threshold",
|
||||
severity="soft",
|
||||
status="pass",
|
||||
summary=f"Economic concession {metrics.concession_pct}% is inside the self-serve threshold.",
|
||||
reason="No extra approval is needed for discount exposure.",
|
||||
actual_value=metrics.concession_pct,
|
||||
threshold_value=policy.approval_discount_pct,
|
||||
unit="percent",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="discount-approval-threshold",
|
||||
title="Discount approval threshold",
|
||||
severity="soft",
|
||||
status="review",
|
||||
summary=f"Economic concession {metrics.concession_pct}% exceeds the self-serve threshold of {policy.approval_discount_pct}%.",
|
||||
reason="The configuration may still be acceptable, but it now requires seller approval instead of self-serve acceptance.",
|
||||
actual_value=metrics.concession_pct,
|
||||
threshold_value=policy.approval_discount_pct,
|
||||
unit="percent",
|
||||
suggested_action="Escalate for approval or reduce the concession magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def _commitment_backed_concession(
|
||||
_configuration: PricingConfiguration,
|
||||
_policy: BoundaryPolicy,
|
||||
metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
if metrics.concession_value <= Decimal("0"):
|
||||
return ConstraintResult(
|
||||
id="commitment-backed-concession",
|
||||
title="Commitment-backed concession",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary="No economic concession was introduced relative to the model baseline.",
|
||||
reason="The configuration does not weaken seller economics versus the baseline assumptions.",
|
||||
actual_value=metrics.concession_value,
|
||||
threshold_value=Decimal("0.00"),
|
||||
unit=metrics.currency,
|
||||
)
|
||||
|
||||
if metrics.meaningful_commitment_signals:
|
||||
return ConstraintResult(
|
||||
id="commitment-backed-concession",
|
||||
title="Commitment-backed concession",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary="The economic concession is backed by explicit commitments.",
|
||||
reason="The configuration introduces weaker unit economics, but it also adds meaningful seller protections.",
|
||||
actual_value=metrics.concession_value,
|
||||
threshold_value=Decimal("0.00"),
|
||||
unit=metrics.currency,
|
||||
details={"signals": list(metrics.meaningful_commitment_signals)},
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="commitment-backed-concession",
|
||||
title="Commitment-backed concession",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary="The configuration introduces weaker seller economics without an offsetting commitment.",
|
||||
reason="Discounts and improved customer unit economics must be tied to enforceable or economically meaningful commitments.",
|
||||
actual_value=metrics.concession_value,
|
||||
threshold_value=Decimal("0.00"),
|
||||
unit=metrics.currency,
|
||||
suggested_action="Add minimum turnover, prepayment, guaranteed fees, or a materially longer contract before offering this concession.",
|
||||
)
|
||||
|
||||
|
||||
def default_constraints() -> tuple[BoundaryConstraint, ...]:
|
||||
return (
|
||||
BoundaryConstraint("segment-eligibility", "Segment eligibility", "hard", _segment_eligibility),
|
||||
BoundaryConstraint("usage-variance-limit", "Usage variance limit", "hard", _usage_variance_limit),
|
||||
BoundaryConstraint("payment-fee-limit", "Payment fee limit", "hard", _payment_fee_limit),
|
||||
BoundaryConstraint("cost-floor-coverage", "Cost floor coverage", "hard", _cost_floor_coverage),
|
||||
BoundaryConstraint("minimum-margin", "Minimum margin", "hard", _minimum_margin),
|
||||
BoundaryConstraint("target-margin-approval", "Target margin approval threshold", "soft", _target_margin_approval),
|
||||
BoundaryConstraint("discount-exposure-limit", "Discount exposure limit", "hard", _discount_exposure_limit),
|
||||
BoundaryConstraint("discount-approval-threshold", "Discount approval threshold", "soft", _discount_approval_threshold),
|
||||
BoundaryConstraint("commitment-backed-concession", "Commitment-backed concession", "hard", _commitment_backed_concession),
|
||||
)
|
||||
|
||||
|
||||
def _configuration_view(configuration: PricingConfiguration, metrics: PricingMetrics) -> dict[str, Any]:
|
||||
return {
|
||||
"segment": configuration.segment,
|
||||
"currency": metrics.currency,
|
||||
"access_fee_amount": metrics.access_fee_amount,
|
||||
"included_units": metrics.included_units,
|
||||
"usage_unit_price": metrics.usage_unit_price,
|
||||
"expected_usage_units": metrics.expected_usage_units,
|
||||
"expected_usage_variance_pct": _percent(configuration.expected_usage_variance_pct),
|
||||
"allocated_fixed_cost": metrics.allocated_fixed_cost,
|
||||
"direct_cost_amount": metrics.direct_cost_amount,
|
||||
"unit_cost": metrics.unit_cost,
|
||||
"support_cost": metrics.support_cost,
|
||||
"onboarding_cost": metrics.onboarding_cost,
|
||||
"risk_cost": metrics.risk_cost,
|
||||
"payment_fee_fixed": _money(configuration.payment_fee_fixed),
|
||||
"payment_fee_rate_pct": _percent(configuration.payment_fee_rate_pct),
|
||||
"discount_amount": _money(configuration.discount_amount),
|
||||
"commitment_terms": {
|
||||
"contract_duration_months": metrics.contract_duration_months,
|
||||
"minimum_monthly_turnover": metrics.minimum_monthly_turnover,
|
||||
"prepaid_amount": metrics.prepaid_amount,
|
||||
"guaranteed_platform_fee": metrics.guaranteed_platform_fee,
|
||||
"customer_funded_onboarding": metrics.customer_funded_onboarding,
|
||||
"reduced_cancellation_flexibility": metrics.reduced_cancellation_flexibility,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def validate_pricing_configuration(
|
||||
configuration: PricingConfiguration,
|
||||
policy: BoundaryPolicy,
|
||||
constraints: tuple[BoundaryConstraint, ...] | None = None,
|
||||
) -> ValidationResult:
|
||||
baseline_metrics = _build_metrics(_baseline_configuration(configuration), policy)
|
||||
metrics = _build_metrics(configuration, policy, baseline_metrics=baseline_metrics)
|
||||
|
||||
results = tuple(
|
||||
constraint.evaluator(configuration, policy, metrics, baseline_metrics)
|
||||
for constraint in (constraints or default_constraints())
|
||||
)
|
||||
|
||||
hard_failures = [result for result in results if result.status == "fail" and result.severity == "hard"]
|
||||
soft_reviews = [result for result in results if result.status == "review"]
|
||||
valid = not hard_failures
|
||||
requires_approval = valid and bool(soft_reviews)
|
||||
|
||||
if hard_failures:
|
||||
decision: ValidationDecision = "rejected"
|
||||
summary = "Rejected: " + ", ".join(result.title for result in hard_failures) + "."
|
||||
elif soft_reviews:
|
||||
decision = "requires_approval"
|
||||
summary = "Approval required: " + ", ".join(result.title for result in soft_reviews) + "."
|
||||
else:
|
||||
decision = "accepted"
|
||||
summary = "Accepted: all boundary constraints passed."
|
||||
|
||||
return ValidationResult(
|
||||
model_id=configuration.model.id,
|
||||
model_name=configuration.model.name,
|
||||
decision=decision,
|
||||
valid=valid,
|
||||
requires_approval=requires_approval,
|
||||
summary=summary,
|
||||
configuration=_configuration_view(configuration, metrics),
|
||||
metrics=metrics,
|
||||
policy=policy,
|
||||
constraints=results,
|
||||
)
|
||||
78
docs/BoundaryValidation.md
Normal file
78
docs/BoundaryValidation.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Boundary Validation
|
||||
|
||||
Status: implementation-facing MVP for `ADAPTIVE-WP-0004`.
|
||||
|
||||
## Purpose
|
||||
|
||||
This document describes the first explicit boundary engine now available in
|
||||
`adaptive_pricing_core.boundary_engine`.
|
||||
|
||||
The engine turns pricing-policy intent into inspectable validation outcomes
|
||||
instead of leaving viability checks implicit in dashboard review.
|
||||
|
||||
## Inputs
|
||||
|
||||
The validator accepts:
|
||||
|
||||
- a canonical `PricingModel`
|
||||
- a `PricingConfiguration` describing expected usage, fee assumptions, cost
|
||||
allocation, optional price overrides, and commitment terms
|
||||
- a `BoundaryPolicy` defining hard and soft limits
|
||||
|
||||
## Constraint Types
|
||||
|
||||
Current MVP constraints cover:
|
||||
|
||||
- segment eligibility
|
||||
- expected usage variance limit
|
||||
- payment fee ceiling
|
||||
- cost-floor coverage
|
||||
- minimum margin
|
||||
- target-margin approval threshold
|
||||
- discount exposure ceiling
|
||||
- discount approval threshold
|
||||
- commitment-backed concession enforcement
|
||||
|
||||
Hard constraints reject a configuration. Soft constraints mark it as valid only
|
||||
with approval.
|
||||
|
||||
## Commitment Logic
|
||||
|
||||
The engine treats a concession as any configuration that weakens seller
|
||||
economics relative to the model baseline under the same scenario assumptions.
|
||||
|
||||
A concession is considered meaningfully backed only when at least one of these
|
||||
protections is present:
|
||||
|
||||
- minimum monthly turnover at or above modeled monthly revenue
|
||||
- prepayment covering at least one modeled month
|
||||
- guaranteed platform fee at or above modeled monthly revenue
|
||||
- customer-funded onboarding that neutralizes onboarding cost
|
||||
- materially longer contract duration
|
||||
- reduced cancellation flexibility
|
||||
|
||||
## Outputs
|
||||
|
||||
Validation returns a `ValidationResult` with:
|
||||
|
||||
- `decision`: `accepted`, `requires_approval`, or `rejected`
|
||||
- `valid` and `requires_approval`
|
||||
- a human-readable summary
|
||||
- machine-readable configuration snapshot
|
||||
- machine-readable economics metrics
|
||||
- per-constraint results with reasons, thresholds, and suggested actions
|
||||
|
||||
## Coulomb Adapter
|
||||
|
||||
The Coulomb observatory exposes this engine through
|
||||
`observatory.boundary.build_boundary_validation()`.
|
||||
|
||||
That adapter currently uses:
|
||||
|
||||
- observed per-period payment fee rate
|
||||
- observed AI usage cost
|
||||
- observed per-member infrastructure cost allocation
|
||||
- conservative default policy thresholds
|
||||
|
||||
This is intentionally an MVP policy surface. Later milestones can replace these
|
||||
defaults with seller-managed governance data and richer LTV-aware constraints.
|
||||
@@ -20,6 +20,7 @@ from .load import (
|
||||
load_value_range,
|
||||
)
|
||||
from .allocation import build_cost_allocation
|
||||
from .boundary import build_boundary_validation
|
||||
from .credits import build_credit_summary, load_credit_wallets
|
||||
from .membership_analytics import build_membership_analytics
|
||||
from .pricing_context import build_cost_floor, build_market_price_view, build_value_range_view
|
||||
@@ -93,6 +94,7 @@ def build_dashboard_payload(data_dir: Path | None = None, period: str | None = N
|
||||
cost_allocation = build_cost_allocation(snapshot, usage_records)
|
||||
ai_cost_per_member = usage_summary["cost_per_active_user_eur"]
|
||||
simulations = build_pricing_simulations(snapshot, models, ai_cost_per_member)
|
||||
boundary_validation = build_boundary_validation(snapshot, models, usage_records)
|
||||
credit_wallets = load_credit_wallets(root)
|
||||
credit_summary = build_credit_summary(
|
||||
credit_wallets,
|
||||
@@ -125,6 +127,7 @@ def build_dashboard_payload(data_dir: Path | None = None, period: str | None = N
|
||||
"usage": usage_summary,
|
||||
"cost_allocation": cost_allocation,
|
||||
"pricing_simulations": simulations,
|
||||
"boundary_validation": boundary_validation,
|
||||
"credit_wallets": credit_summary,
|
||||
"recommendations": recommendations,
|
||||
"infrastructure": {
|
||||
|
||||
105
projects/coulomb-pricing/observatory/boundary.py
Normal file
105
projects/coulomb-pricing/observatory/boundary.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
from .models import EconomicsSnapshot, PricingModel
|
||||
|
||||
from ._repo_root import ensure_repo_root_on_syspath
|
||||
|
||||
ensure_repo_root_on_syspath()
|
||||
|
||||
from adaptive_pricing_core.boundary_engine import ( # noqa: E402
|
||||
BoundaryPolicy,
|
||||
PricingConfiguration,
|
||||
validate_pricing_configuration,
|
||||
)
|
||||
|
||||
|
||||
def _usage_unit_cost(records: list[dict[str, Any]], period: str) -> Decimal:
|
||||
period_rows = [row for row in records if row.get("period") == period]
|
||||
total_tokens = sum(Decimal(str(row.get("tokens", "0"))) for row in period_rows)
|
||||
total_cost = sum(Decimal(str(row.get("cost_eur", "0"))) for row in period_rows)
|
||||
if total_tokens <= Decimal("0"):
|
||||
return Decimal("0")
|
||||
return total_cost / total_tokens
|
||||
|
||||
|
||||
def _total_usage_units(records: list[dict[str, Any]], period: str) -> Decimal:
|
||||
return sum(Decimal(str(row.get("tokens", "0"))) for row in records if row.get("period") == period)
|
||||
|
||||
|
||||
def build_boundary_policy(snapshot: EconomicsSnapshot) -> BoundaryPolicy:
|
||||
return BoundaryPolicy(
|
||||
minimum_margin_pct=Decimal("0"),
|
||||
target_margin_pct=Decimal("15"),
|
||||
max_payment_fee_pct=Decimal("10"),
|
||||
max_expected_usage_variance_pct=Decimal("50"),
|
||||
approval_discount_pct=Decimal("10"),
|
||||
max_discount_pct=Decimal("25"),
|
||||
minimum_contract_duration_for_discount_months=3,
|
||||
minimum_turnover_multiple_for_discount=Decimal("1"),
|
||||
minimum_prepayment_months_for_discount=Decimal("1"),
|
||||
)
|
||||
|
||||
|
||||
def build_boundary_validation(
|
||||
snapshot: EconomicsSnapshot,
|
||||
models: list[PricingModel],
|
||||
usage_records: list[dict[str, Any]],
|
||||
segment: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
fee_rate_pct = Decimal("0")
|
||||
if snapshot.monthly_revenue > Decimal("0"):
|
||||
fee_rate_pct = (
|
||||
snapshot.monthly_payment_processing_cost / snapshot.monthly_revenue
|
||||
) * Decimal("100")
|
||||
|
||||
unit_cost = _usage_unit_cost(usage_records, snapshot.period)
|
||||
usage_units = _total_usage_units(usage_records, snapshot.period)
|
||||
direct_usage_cost = sum(
|
||||
Decimal(str(row.get("cost_eur", "0")))
|
||||
for row in usage_records
|
||||
if row.get("period") == snapshot.period
|
||||
)
|
||||
allocated_fixed_cost = (
|
||||
snapshot.monthly_infrastructure_cost / snapshot.active_members
|
||||
if snapshot.active_members
|
||||
else snapshot.monthly_infrastructure_cost
|
||||
)
|
||||
|
||||
policy = build_boundary_policy(snapshot)
|
||||
model_results = []
|
||||
for model in models:
|
||||
has_usage_component = any(component.kind == "usage" for component in model.charge_components)
|
||||
configuration = PricingConfiguration(
|
||||
model=model,
|
||||
segment=segment or (model.eligibility[0] if model.eligibility else None),
|
||||
expected_usage_units=usage_units if has_usage_component else Decimal("0"),
|
||||
expected_usage_variance_pct=Decimal("25"),
|
||||
allocated_fixed_cost=allocated_fixed_cost,
|
||||
direct_cost_amount=Decimal("0") if has_usage_component else direct_usage_cost,
|
||||
unit_cost=unit_cost if has_usage_component else Decimal("0"),
|
||||
payment_fee_rate_pct=fee_rate_pct,
|
||||
)
|
||||
model_results.append(validate_pricing_configuration(configuration, policy))
|
||||
|
||||
return {
|
||||
"period": snapshot.period,
|
||||
"policy": policy,
|
||||
"assumptions": {
|
||||
"segment": segment or "model-default-eligibility",
|
||||
"observed_usage_units": usage_units,
|
||||
"observed_usage_unit_cost": unit_cost,
|
||||
"direct_usage_cost_for_flat_models": direct_usage_cost,
|
||||
"allocated_fixed_cost_per_member": allocated_fixed_cost,
|
||||
"payment_fee_rate_pct": fee_rate_pct,
|
||||
"expected_usage_variance_pct": Decimal("25"),
|
||||
},
|
||||
"model_results": model_results,
|
||||
"notes": [
|
||||
"This MVP policy uses current observatory economics and conservative defaults rather than a seller-specific governance file.",
|
||||
"Self-serve discounts above 10% require approval; discounts above 25% are rejected.",
|
||||
"Term-only concessions require at least a 3-month contract to count as meaningful commitment support.",
|
||||
],
|
||||
}
|
||||
@@ -24,9 +24,15 @@ def test_dashboard_payload_contains_live_ledger_totals() -> None:
|
||||
assert payload["membership_analytics"]["active_members"] == 1
|
||||
assert payload["usage"]["record_count"] == 1
|
||||
assert len(payload["pricing_simulations"]["scenarios"]) == 3
|
||||
assert len(payload["boundary_validation"]["model_results"]) == 3
|
||||
assert payload["boundary_validation"]["policy"]["target_margin_pct"] == "15"
|
||||
assert any(
|
||||
result["decision"] == "rejected"
|
||||
for result in payload["boundary_validation"]["model_results"]
|
||||
)
|
||||
assert payload["recommendations"]
|
||||
|
||||
|
||||
def test_payload_json_is_valid() -> None:
|
||||
parsed = json.loads(payload_json(DATA_DIR, "2026-06"))
|
||||
assert Decimal(parsed["payments"][0]["fees_amount"]) == Decimal("0.44")
|
||||
assert Decimal(parsed["payments"][0]["fees_amount"]) == Decimal("0.44")
|
||||
|
||||
168
projects/coulomb-pricing/tests/test_boundary_engine.py
Normal file
168
projects/coulomb-pricing/tests/test_boundary_engine.py
Normal file
@@ -0,0 +1,168 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
|
||||
from adaptive_pricing_core.boundary_engine import (
|
||||
BoundaryPolicy,
|
||||
CommitmentTerms,
|
||||
PricingConfiguration,
|
||||
validate_pricing_configuration,
|
||||
)
|
||||
from observatory.load import load_pricing_models
|
||||
|
||||
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
|
||||
|
||||
|
||||
def _model(model_id: str):
|
||||
return next(item for item in load_pricing_models(DATA_DIR) if item.id == model_id)
|
||||
|
||||
|
||||
def test_commitment_backed_discount_is_accepted_when_economics_stay_strong() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("membership-plus-overage"),
|
||||
segment="coulomb-social-members",
|
||||
expected_usage_units=Decimal("100200"),
|
||||
expected_usage_variance_pct=Decimal("25"),
|
||||
allocated_fixed_cost=Decimal("2.00"),
|
||||
unit_cost=Decimal("0.00000125"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
usage_unit_price=Decimal("0.0015"),
|
||||
commitment_terms=CommitmentTerms(
|
||||
contract_duration_months=6,
|
||||
minimum_monthly_turnover=Decimal("9.30"),
|
||||
),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "accepted"
|
||||
assert result.valid is True
|
||||
assert result.requires_approval is False
|
||||
commitment_result = next(
|
||||
item for item in result.constraints if item.id == "commitment-backed-concession"
|
||||
)
|
||||
assert commitment_result.status == "pass"
|
||||
assert "minimum_monthly_turnover" in commitment_result.details["signals"]
|
||||
|
||||
|
||||
def test_discount_without_commitment_is_rejected() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("membership-plus-overage"),
|
||||
segment="coulomb-social-members",
|
||||
expected_usage_units=Decimal("100200"),
|
||||
expected_usage_variance_pct=Decimal("25"),
|
||||
allocated_fixed_cost=Decimal("2.00"),
|
||||
unit_cost=Decimal("0.00000125"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
usage_unit_price=Decimal("0.0015"),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "rejected"
|
||||
assert result.valid is False
|
||||
failing_ids = {
|
||||
item.id for item in result.constraints if item.status == "fail" and item.severity == "hard"
|
||||
}
|
||||
assert "commitment-backed-concession" in failing_ids
|
||||
|
||||
|
||||
def test_weak_commitment_trade_is_rejected() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("membership-plus-overage"),
|
||||
segment="coulomb-social-members",
|
||||
expected_usage_units=Decimal("100200"),
|
||||
expected_usage_variance_pct=Decimal("25"),
|
||||
allocated_fixed_cost=Decimal("2.00"),
|
||||
unit_cost=Decimal("0.00000125"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
usage_unit_price=Decimal("0.0015"),
|
||||
commitment_terms=CommitmentTerms(
|
||||
contract_duration_months=2,
|
||||
minimum_monthly_turnover=Decimal("9.00"),
|
||||
),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "rejected"
|
||||
commitment_result = next(
|
||||
item for item in result.constraints if item.id == "commitment-backed-concession"
|
||||
)
|
||||
assert commitment_result.status == "fail"
|
||||
|
||||
|
||||
def test_large_but_supported_concession_requires_approval() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("flat-899-eur-monthly"),
|
||||
segment="coulomb-social-members",
|
||||
allocated_fixed_cost=Decimal("1.00"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
access_fee_amount=Decimal("7.50"),
|
||||
commitment_terms=CommitmentTerms(
|
||||
contract_duration_months=6,
|
||||
minimum_monthly_turnover=Decimal("8.00"),
|
||||
),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "requires_approval"
|
||||
assert result.valid is True
|
||||
assert result.requires_approval is True
|
||||
review_ids = {item.id for item in result.constraints if item.status == "review"}
|
||||
assert "discount-approval-threshold" in review_ids
|
||||
|
||||
|
||||
def test_zero_usage_flat_configuration_can_pass() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("flat-899-eur-monthly"),
|
||||
segment="coulomb-social-members",
|
||||
expected_usage_units=Decimal("0"),
|
||||
expected_usage_variance_pct=Decimal("0"),
|
||||
allocated_fixed_cost=Decimal("3.00"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "accepted"
|
||||
assert result.metrics.billable_usage_units == Decimal("0")
|
||||
|
||||
|
||||
def test_high_fee_configuration_is_rejected() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("flat-899-eur-monthly"),
|
||||
segment="coulomb-social-members",
|
||||
allocated_fixed_cost=Decimal("1.00"),
|
||||
payment_fee_rate_pct=Decimal("30"),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "rejected"
|
||||
payment_fee_result = next(item for item in result.constraints if item.id == "payment-fee-limit")
|
||||
assert payment_fee_result.status == "fail"
|
||||
|
||||
|
||||
def test_unprofitable_configuration_is_rejected() -> None:
|
||||
result = validate_pricing_configuration(
|
||||
PricingConfiguration(
|
||||
model=_model("flat-899-eur-monthly"),
|
||||
segment="coulomb-social-members",
|
||||
allocated_fixed_cost=Decimal("10.00"),
|
||||
payment_fee_rate_pct=Decimal("5"),
|
||||
),
|
||||
BoundaryPolicy(),
|
||||
)
|
||||
|
||||
assert result.decision == "rejected"
|
||||
assert result.metrics.monthly_margin < Decimal("0")
|
||||
assert any(item.id == "cost-floor-coverage" and item.status == "fail" for item in result.constraints)
|
||||
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "Boundary engine and explainable validation"
|
||||
domain: financials
|
||||
repo: adaptive-pricing
|
||||
status: backlog
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: helix-forge
|
||||
created: "2026-07-02"
|
||||
@@ -21,7 +21,7 @@ engine with inspectable outcomes.
|
||||
|
||||
```task
|
||||
id: ADAPTIVE-WP-0004-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "180ea896-4e89-4256-b1ba-0d72e4d49dcd"
|
||||
```
|
||||
@@ -34,7 +34,7 @@ eligibility, and approval thresholds.
|
||||
|
||||
```task
|
||||
id: ADAPTIVE-WP-0004-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "16c96dc5-45fc-4cca-9f71-d3b8d797f28f"
|
||||
```
|
||||
@@ -46,7 +46,7 @@ pass/fail results, violated constraints, and structured reasons.
|
||||
|
||||
```task
|
||||
id: ADAPTIVE-WP-0004-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "adaa7751-b1b9-4d9e-a708-4caaf6a4801d"
|
||||
```
|
||||
@@ -59,7 +59,7 @@ usage assumptions.
|
||||
|
||||
```task
|
||||
id: ADAPTIVE-WP-0004-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "96a1f2d4-518f-4e4f-8227-43bac08ff615"
|
||||
```
|
||||
@@ -72,7 +72,7 @@ unprofitable configurations.
|
||||
|
||||
```task
|
||||
id: ADAPTIVE-WP-0004-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "0a771125-cc2b-4339-b210-ac834562516f"
|
||||
```
|
||||
@@ -81,4 +81,3 @@ Exit when pricing configurations can be validated against explicit constraints
|
||||
with machine-readable and human-readable explanations.
|
||||
|
||||
Dependencies: `ADAPTIVE-WP-0003`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user