feat: add typed tier assurance guardrails
This commit is contained in:
parent
3d0f614f49
commit
c65a2f1ff9
13 changed files with 727 additions and 7 deletions
|
|
@ -852,8 +852,171 @@ def _commitment_backed_concession(
|
|||
)
|
||||
|
||||
|
||||
def _assurance_claims(
|
||||
configuration: PricingConfiguration,
|
||||
_policy: BoundaryPolicy,
|
||||
_metrics: PricingMetrics,
|
||||
_baseline: PricingMetrics,
|
||||
) -> ConstraintResult:
|
||||
claims = configuration.model.assurance_claims
|
||||
if not claims:
|
||||
return ConstraintResult(
|
||||
id="assurance-claims",
|
||||
title="Tier assurance claims",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary="The tier makes no customer assurance claim.",
|
||||
reason="Silent tiers are unaffected by Tenancy Posture §11.",
|
||||
actual_value=0,
|
||||
threshold_value=0,
|
||||
unit="claims",
|
||||
)
|
||||
|
||||
violations: list[dict[str, str]] = []
|
||||
|
||||
def fail(claim_id: str, axis: str, section: str, reason: str) -> None:
|
||||
violations.append(
|
||||
{"claim_id": claim_id, "axis": axis, "section": section, "reason": reason}
|
||||
)
|
||||
|
||||
for claim in claims:
|
||||
levels = claim.minimum_levels
|
||||
wording = " ".join(claim.customer_wording.lower().split())
|
||||
if not levels:
|
||||
fail(claim.id, "all", "§11.1/§11.3", "claim has no typed minimum levels")
|
||||
if not claim.delivering_service.strip():
|
||||
fail(claim.id, "all", "§11.3", "delivering service is not named")
|
||||
if not claim.evidence_ref.strip():
|
||||
fail(claim.id, "all", "§11.3", "evidence reference is missing")
|
||||
|
||||
required_axis = {
|
||||
"isolation": "E",
|
||||
"availability": "V",
|
||||
"retention": "R",
|
||||
"performance": "P",
|
||||
}.get(claim.kind)
|
||||
if required_axis and required_axis not in levels:
|
||||
fail(
|
||||
claim.id,
|
||||
required_axis,
|
||||
"§11.1/§11.3",
|
||||
f"{claim.kind} claim does not record a {required_axis} minimum",
|
||||
)
|
||||
|
||||
if claim.kind == "isolation":
|
||||
if "cannot reach" in wording and levels.get("E", -1) < 4:
|
||||
fail(
|
||||
claim.id,
|
||||
"E",
|
||||
"§11.4",
|
||||
"'cannot reach' wording requires E4",
|
||||
)
|
||||
if levels.get("E", -1) >= 4 and levels.get("P", -1) < 3:
|
||||
fail(claim.id, "P", "§3.2", "E4 is reachable only at P3 or above")
|
||||
|
||||
if claim.kind == "retention":
|
||||
horizon = claim.maximum_erasure_horizon_days
|
||||
if horizon is None:
|
||||
fail(
|
||||
claim.id,
|
||||
"R",
|
||||
"§4.5.4/§11.1",
|
||||
"retention claim has no maximum erasure horizon",
|
||||
)
|
||||
if levels.get("P", -1) < 2 and not claim.provider_contract_ref:
|
||||
fail(
|
||||
claim.id,
|
||||
"P",
|
||||
"§4.5.4",
|
||||
"retention promise below P2 needs a provider contract that bounds the shared horizon",
|
||||
)
|
||||
deleted_is_gone = "deleted" in wording and (
|
||||
" is gone" in wording or " are gone" in wording or "permanently removed" in wording
|
||||
)
|
||||
horizon_disclosed = horizon is not None and str(horizon) in wording and "day" in wording
|
||||
if deleted_is_gone and levels.get("R", -1) < 4 and not horizon_disclosed:
|
||||
fail(
|
||||
claim.id,
|
||||
"R",
|
||||
"§11.4",
|
||||
"'deleted data is gone' requires R4 or the erasure horizon in customer wording",
|
||||
)
|
||||
regulatory_language = any(
|
||||
phrase in wording
|
||||
for phrase in ("regulator approved", "regulator-endorsed", "article 17 compliant")
|
||||
)
|
||||
if (
|
||||
levels.get("R", -1) >= 4
|
||||
and claim.erasure_mechanism == "key-destruction"
|
||||
and regulatory_language
|
||||
):
|
||||
fail(
|
||||
claim.id,
|
||||
"R/E",
|
||||
"§4.5/§11.4",
|
||||
"key-destruction wording may not imply regulatory endorsement",
|
||||
)
|
||||
|
||||
if claim.kind == "performance" and levels.get("P", -1) < 2:
|
||||
if not claim.resource_governor_ref:
|
||||
fail(
|
||||
claim.id,
|
||||
"P",
|
||||
"§8.3.1/§11.6",
|
||||
"performance-differentiated tier requires P2 or an enforceable resource governor",
|
||||
)
|
||||
|
||||
if claim.kind == "availability":
|
||||
if "zone" in wording and levels.get("V", -1) < 3:
|
||||
fail(claim.id, "V", "§11.4", "zone-loss wording requires V3")
|
||||
if ("region" in wording or "regional loss" in wording) and levels.get("V", -1) < 4:
|
||||
fail(claim.id, "V", "§11.4", "regional-loss wording requires V4")
|
||||
if "high availability" in wording and not any(
|
||||
term in wording for term in ("restart", "node", "zone", "region")
|
||||
):
|
||||
fail(
|
||||
claim.id,
|
||||
"V",
|
||||
"§11.4",
|
||||
"'high availability' must name the failure it survives",
|
||||
)
|
||||
|
||||
if violations:
|
||||
axes = ", ".join(sorted({item["axis"] for item in violations}))
|
||||
return ConstraintResult(
|
||||
id="assurance-claims",
|
||||
title="Tier assurance claims",
|
||||
severity="hard",
|
||||
status="fail",
|
||||
summary=f"Assurance claims violate typed minima on axis/axes {axes}.",
|
||||
reason="; ".join(
|
||||
f"{item['claim_id']} [{item['axis']} {item['section']}]: {item['reason']}"
|
||||
for item in violations
|
||||
),
|
||||
actual_value=len(violations),
|
||||
threshold_value=0,
|
||||
unit="violations",
|
||||
details={"violations": violations},
|
||||
suggested_action="Raise the typed minima, narrow the customer wording, or attach the required provider control.",
|
||||
)
|
||||
|
||||
return ConstraintResult(
|
||||
id="assurance-claims",
|
||||
title="Tier assurance claims",
|
||||
severity="hard",
|
||||
status="pass",
|
||||
summary=f"All {len(claims)} assurance claim(s) map to explicit framework minima.",
|
||||
reason="Customer wording, delivering service, evidence and coupled axis floors are recorded.",
|
||||
actual_value=len(claims),
|
||||
threshold_value=len(claims),
|
||||
unit="claims",
|
||||
details={"claim_ids": [claim.id for claim in claims]},
|
||||
)
|
||||
|
||||
|
||||
def default_constraints() -> tuple[BoundaryConstraint, ...]:
|
||||
return (
|
||||
BoundaryConstraint("assurance-claims", "Tier assurance claims", "hard", _assurance_claims),
|
||||
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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue