feat(platform): close AI expense value loop
Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
This commit is contained in:
155
server/tests/test_agent_asset_release_recall.py
Normal file
155
server/tests/test_agent_asset_release_recall.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from app.services.agent_asset_release_guard import ReleaseEvaluationInput
|
||||
from app.services.agent_asset_release_policy import (
|
||||
ReleaseGuardPolicy,
|
||||
evaluate_release,
|
||||
)
|
||||
from app.services.agent_asset_release_recall import estimate_release_recall
|
||||
|
||||
|
||||
def test_recall_uses_random_stratum_to_estimate_full_negative_population() -> None:
|
||||
result = estimate_release_recall(
|
||||
true_positive_count=90,
|
||||
disagreement_false_negative_count=2,
|
||||
random_negative_population_count=800,
|
||||
random_reviewed_count=80,
|
||||
random_false_negative_count=1,
|
||||
)
|
||||
|
||||
assert result.estimated_false_negative_count == 12.0
|
||||
assert result.recall == pytest.approx(90 / 102, abs=1e-6)
|
||||
assert result.recall_lower_bound is not None
|
||||
assert result.recall_lower_bound < result.recall
|
||||
assert result.false_negative_upper_bound is not None
|
||||
assert result.false_negative_upper_bound > result.estimated_false_negative_count
|
||||
assert result.method == "stratified_random_audit_wilson_upper_bound"
|
||||
|
||||
|
||||
def test_recall_is_exact_when_no_random_negative_stratum_exists() -> None:
|
||||
result = estimate_release_recall(
|
||||
true_positive_count=18,
|
||||
disagreement_false_negative_count=2,
|
||||
random_negative_population_count=0,
|
||||
random_reviewed_count=0,
|
||||
random_false_negative_count=0,
|
||||
)
|
||||
|
||||
assert result.recall == 0.9
|
||||
assert result.recall_lower_bound == 0.9
|
||||
assert result.estimated_false_negative_count == 2.0
|
||||
|
||||
|
||||
def test_recall_remains_unavailable_before_random_audit_evidence_exists() -> None:
|
||||
result = estimate_release_recall(
|
||||
true_positive_count=10,
|
||||
disagreement_false_negative_count=0,
|
||||
random_negative_population_count=25,
|
||||
random_reviewed_count=0,
|
||||
random_false_negative_count=0,
|
||||
)
|
||||
|
||||
assert result.recall is None
|
||||
assert result.recall_lower_bound is None
|
||||
assert result.estimated_false_negative_count is None
|
||||
|
||||
|
||||
def test_zero_true_positives_with_confirmed_miss_has_zero_recall() -> None:
|
||||
result = estimate_release_recall(
|
||||
true_positive_count=0,
|
||||
disagreement_false_negative_count=1,
|
||||
random_negative_population_count=0,
|
||||
random_reviewed_count=0,
|
||||
random_false_negative_count=0,
|
||||
)
|
||||
|
||||
assert result.recall == 0.0
|
||||
assert result.recall_lower_bound == 0.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs",
|
||||
[
|
||||
{"random_reviewed_count": 3, "random_negative_population_count": 2},
|
||||
{"random_false_negative_count": 2, "random_reviewed_count": 1},
|
||||
{"true_positive_count": -1},
|
||||
{"confidence_level": 0.92},
|
||||
],
|
||||
)
|
||||
def test_recall_rejects_inconsistent_evidence(kwargs: dict[str, int | float]) -> None:
|
||||
values: dict[str, int | float] = {
|
||||
"true_positive_count": 1,
|
||||
"disagreement_false_negative_count": 0,
|
||||
"random_negative_population_count": 2,
|
||||
"random_reviewed_count": 1,
|
||||
"random_false_negative_count": 0,
|
||||
"confidence_level": 0.95,
|
||||
}
|
||||
values.update(kwargs)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
estimate_release_recall(**values) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_release_gate_collects_without_blind_negative_ground_truth() -> None:
|
||||
result = evaluate_release(
|
||||
"shadow",
|
||||
ReleaseEvaluationInput(
|
||||
total=20,
|
||||
failure_count=0,
|
||||
precision=1.0,
|
||||
details={
|
||||
"metric_source": "release_runtime_telemetry",
|
||||
"negative_ground_truth_status": "insufficient_random_negative_reviews",
|
||||
"recall_lower_bound": None,
|
||||
},
|
||||
),
|
||||
ReleaseGuardPolicy(shadow_min_samples=1).to_dict(),
|
||||
)
|
||||
|
||||
assert result["status"] == "collecting"
|
||||
assert result["reasons"] == ["insufficient_random_negative_reviews"]
|
||||
|
||||
|
||||
def test_release_gate_uses_recall_confidence_lower_bound_not_point_estimate() -> None:
|
||||
policy = ReleaseGuardPolicy(shadow_min_samples=1, min_recall=0.95).to_dict()
|
||||
result = evaluate_release(
|
||||
"shadow",
|
||||
ReleaseEvaluationInput(
|
||||
total=20,
|
||||
failure_count=0,
|
||||
precision=1.0,
|
||||
details={
|
||||
"metric_source": "release_runtime_telemetry",
|
||||
"negative_ground_truth_status": "available_stratified_random_audit",
|
||||
"recall": 0.98,
|
||||
"recall_lower_bound": 0.9,
|
||||
},
|
||||
),
|
||||
policy,
|
||||
)
|
||||
|
||||
assert result["status"] == "failed"
|
||||
assert "recall_lower_bound_below_threshold" in result["reasons"]
|
||||
|
||||
|
||||
def test_release_gate_passes_when_precision_recall_and_samples_are_sufficient() -> None:
|
||||
result = evaluate_release(
|
||||
"shadow",
|
||||
ReleaseEvaluationInput(
|
||||
total=20,
|
||||
failure_count=0,
|
||||
precision=0.99,
|
||||
details={
|
||||
"metric_source": "release_runtime_telemetry",
|
||||
"negative_ground_truth_status": "available_stratified_random_audit",
|
||||
"recall": 0.98,
|
||||
"recall_lower_bound": 0.96,
|
||||
},
|
||||
),
|
||||
ReleaseGuardPolicy(shadow_min_samples=20, min_recall=0.95).to_dict(),
|
||||
)
|
||||
|
||||
assert result["status"] == "passed"
|
||||
Reference in New Issue
Block a user