fix(alerts): enforce caliber ruling R5-supp (period linkage)

deviation_engine: link kpi_value_id on deviation/trend alert rows; skip when period not attributable or kpi_values row missing; dedupe key now (entity_id,kpi_id,kpi_value_id,alert_type)

deviation_push: same-source R1/R5 guards, no-period request writes nothing

tests: add test_alert_caliber_r5_residual_20260919 (13 cases incl. negative controls); adapt r1r4/r5 fixtures to the supplemental ruling
This commit is contained in:
Hermes CI Fix
2026-09-19 11:12:31 +08:00
parent 5a99ed87e0
commit 8c5853f64b
5 changed files with 497 additions and 91 deletions
@@ -158,10 +158,13 @@ class TestR1DemoEntityExcluded:
import app.utils.deviation_engine as de
_demo_and_active(db)
create_test_kpi(db, kpi_code="DEMO_REVENUE", kpi_name="演示收入",
entity_id=6, unit="%", threshold_red=RED_EXPR)
create_test_kpi(db, kpi_code="F_REVENUE", kpi_name="营业收入",
entity_id=1, unit="%", threshold_red=RED_EXPR)
k_demo = create_test_kpi(db, kpi_code="DEMO_REVENUE", kpi_name="演示收入",
entity_id=6, unit="%", threshold_red=RED_EXPR)
k_real = create_test_kpi(db, kpi_code="F_REVENUE", kpi_name="营业收入",
entity_id=1, unit="%", threshold_red=RED_EXPR)
# R5-补1(2026-09-19):差异预警须落 kpi_value_id 关联,故夹具补该期间的 kpi_values 行
#(否则按补1 跳过不入库,本用例将观察不到「遍历范围」这一被测口径)
_kpi_value(db, k_real, "2026-08", 14.45, entity_id=1)
# 让所有 KPI 都「差异触发」,只观察遍历范围(不依赖预算数据形态)
monkeypatch.setattr(de, "build_deviation_alert",
lambda db_s, kpi, period, *a, **kw: {