@@ -1466,3 +1466,104 @@ def _create_guardrail_with_always_rule(
14661466 ),
14671467 ],
14681468 )
1469+
1470+
1471+ class TestMissingFieldPassesValidation :
1472+ """Test that rules referencing missing fields pass validation."""
1473+
1474+ def test_word_rule_missing_field_passes (
1475+ self , service : DeterministicGuardrailsService
1476+ ) -> None :
1477+ guardrail = DeterministicGuardrail (
1478+ id = "test-missing-field" ,
1479+ name = "Missing Field Guardrail" ,
1480+ description = "Test missing field" ,
1481+ enabled_for_evals = True ,
1482+ guardrail_type = "custom" ,
1483+ selector = GuardrailSelector (
1484+ scopes = [GuardrailScope .TOOL ], match_names = ["test" ]
1485+ ),
1486+ rules = [
1487+ WordRule (
1488+ rule_type = "word" ,
1489+ field_selector = SpecificFieldsSelector (
1490+ selector_type = "specific" ,
1491+ fields = [
1492+ FieldReference (path = "sentence2" , source = FieldSource .INPUT )
1493+ ],
1494+ ),
1495+ detects_violation = lambda s : len (s or "" ) > 0 ,
1496+ rule_description = "sentence2 is not empty" ,
1497+ ),
1498+ ],
1499+ )
1500+ result = service ._evaluate_deterministic_guardrail (
1501+ input_data = {"sentence1" : "hello" },
1502+ output_data = {},
1503+ guardrail = guardrail ,
1504+ )
1505+ assert result .result == GuardrailValidationResultType .PASSED
1506+
1507+ def test_number_rule_missing_field_passes (
1508+ self , service : DeterministicGuardrailsService
1509+ ) -> None :
1510+ guardrail = DeterministicGuardrail (
1511+ id = "test-missing-field" ,
1512+ name = "Missing Field Guardrail" ,
1513+ description = "Test missing field" ,
1514+ enabled_for_evals = True ,
1515+ guardrail_type = "custom" ,
1516+ selector = GuardrailSelector (
1517+ scopes = [GuardrailScope .TOOL ], match_names = ["test" ]
1518+ ),
1519+ rules = [
1520+ NumberRule (
1521+ rule_type = "number" ,
1522+ field_selector = SpecificFieldsSelector (
1523+ selector_type = "specific" ,
1524+ fields = [FieldReference (path = "age" , source = FieldSource .INPUT )],
1525+ ),
1526+ detects_violation = lambda n : n is not None and n < 0 ,
1527+ rule_description = "age is negative" ,
1528+ ),
1529+ ],
1530+ )
1531+ result = service ._evaluate_deterministic_guardrail (
1532+ input_data = {"name" : "test" },
1533+ output_data = {},
1534+ guardrail = guardrail ,
1535+ )
1536+ assert result .result == GuardrailValidationResultType .PASSED
1537+
1538+ def test_boolean_rule_missing_field_passes (
1539+ self , service : DeterministicGuardrailsService
1540+ ) -> None :
1541+ guardrail = DeterministicGuardrail (
1542+ id = "test-missing-field" ,
1543+ name = "Missing Field Guardrail" ,
1544+ description = "Test missing field" ,
1545+ enabled_for_evals = True ,
1546+ guardrail_type = "custom" ,
1547+ selector = GuardrailSelector (
1548+ scopes = [GuardrailScope .TOOL ], match_names = ["test" ]
1549+ ),
1550+ rules = [
1551+ BooleanRule (
1552+ rule_type = "boolean" ,
1553+ field_selector = SpecificFieldsSelector (
1554+ selector_type = "specific" ,
1555+ fields = [
1556+ FieldReference (path = "is_active" , source = FieldSource .INPUT )
1557+ ],
1558+ ),
1559+ detects_violation = lambda b : b is False ,
1560+ rule_description = "is_active is false" ,
1561+ ),
1562+ ],
1563+ )
1564+ result = service ._evaluate_deterministic_guardrail (
1565+ input_data = {"name" : "test" },
1566+ output_data = {},
1567+ guardrail = guardrail ,
1568+ )
1569+ assert result .result == GuardrailValidationResultType .PASSED
0 commit comments