Skip to content

Commit ea0b1a3

Browse files
Merge pull request #19 from ksumit-nitp/feature/add-guardrail-cutoff-validation
Add validation for guardrail cutoff signs
2 parents c871add + 9707f4d commit ea0b1a3

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

eppo_metrics_sync/eppo_metrics_sync.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from eppo_metrics_sync.validation import (
77
unique_names,
88
valid_fact_references,
9-
metric_aggregation_is_valid
9+
metric_aggregation_is_valid,
10+
valid_guardrail_cutoff_signs
1011
)
1112

1213
from eppo_metrics_sync.dbt_model_parser import DbtModelParser
@@ -110,6 +111,7 @@ def validate(self):
110111
unique_names(self)
111112
valid_fact_references(self)
112113
metric_aggregation_is_valid(self)
114+
valid_guardrail_cutoff_signs(self)
113115

114116
if self.validation_errors:
115117
error_count = len(self.validation_errors)

eppo_metrics_sync/validation.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,33 @@ def metric_aggregation_is_valid(payload):
8787
)
8888

8989

90+
def valid_guardrail_cutoff_signs(payload):
91+
facts = dict()
92+
for fact_source in payload.fact_sources:
93+
for fact in fact_source['facts']:
94+
facts[fact['name']] = fact
95+
96+
for m in payload.metrics:
97+
numerator_fact_name = m['numerator']['fact_name']
98+
if is_guardrail_cutoff_exist(m) and numerator_fact_name in facts and 'desired_change' in facts[numerator_fact_name]:
99+
error = is_valid_guardrail_cutoff_sign(m, facts[numerator_fact_name])
100+
if error:
101+
payload.validation_errors.append(
102+
f"{m['name']} is having invalid guardrail_cutoff sign: {error}"
103+
)
104+
105+
106+
def is_valid_guardrail_cutoff_sign(metric, numerator_fact):
107+
if numerator_fact['desired_change'] == 'decrease' and metric['guardrail_cutoff'] < 0:
108+
return f"guardrail_cutoff value should be positive"
109+
elif numerator_fact['desired_change'] == 'increase' and metric['guardrail_cutoff'] > 0:
110+
return f"guardrail_cutoff value should be negative"
111+
112+
113+
def is_guardrail_cutoff_exist(metric):
114+
return 'is_guardrail' in metric and metric['is_guardrail'] and 'guardrail_cutoff' in metric
115+
116+
90117
def distinct_advanced_aggregation_parameter_set(
91118
aggregation,
92119
operation,

tests/test_validation.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ def test_unique_fact_names():
3939
eppo_metrics_sync.validate()
4040

4141

42+
def test_valid_guardrail_cutoff_signs():
43+
eppo_metrics_sync = EppoMetricsSync(directory=None)
44+
eppo_metrics_sync.load_eppo_yaml(
45+
path=test_yaml_dir + "/invalid_guardrail_cutoff_sign.yaml")
46+
47+
with pytest.raises(ValueError, match="Total Upgrades to Paid Plan is having invalid guardrail_cutoff sign: "
48+
"guardrail_cutoff value should be negative"):
49+
eppo_metrics_sync.validate()
50+
51+
4252
"""def test_unique_fact_property_names():
4353
4454
eppo_metrics_sync = EppoMetricsSync(directory = None)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fact_sources:
2+
- name: upgrades_table
3+
sql: select * from upgrades
4+
timestamp_column: ts
5+
entities:
6+
- entity_name: user
7+
column: user_id
8+
facts:
9+
- name: upgrades
10+
desired_change: increase
11+
metrics:
12+
- name: Total Upgrades to Paid Plan
13+
entity: User
14+
is_guardrail: true
15+
guardrail_cutoff: 1
16+
numerator:
17+
fact_name: upgrades
18+
operation: sum

0 commit comments

Comments
 (0)