Repository navigation
compliance: run SHACL for rule tests now that shaclgen translates rules (after linkml/linkml#3990) #39
Description
Status (2026-10-13): folded into linkml#3990 (fork #20): the three rule tests run SHACL, IMPLEMENTS where gen-shacl translates the rule and INCOMPLETE for invalid instances of rules it skips. The extra presence-implies-value compliance test is not included. Close when it merges.
What
The compliance suite skips SHACL in all three rules tests of tests/linkml/test_compliance/test_boolean_slot_compliance.py. So docs/generators/dashboard.md shows ❓ for SHACL under Precondition rules, Precondition combos and Value presence in rules.
shaclgen translates rules since linkml#3451 (boolean guard, exclusive value). linkml#3989 adds presence-implies-value, inheritance and open_world, and linkml#3990 adds the compositional translation. This calls for a test-only PR after linkml#3990.
Reproduction
uv run pytest tests/linkml/test_compliance/test_boolean_slot_compliance.py -rs -q \
-k "shacl and (test_preconditions or test_value_presence_in_rules)"SKIPPED [10] ...:2167: shaclgen does not support rules yet
SKIPPED [12] ...:2383: shaclgen does not support rules yet
SKIPPED [8] ...:2636: shaclgen does not support boolean expressions yet
This is what SHACL would decide at linkml#3990 (c89faac06), validating as check_data does (ShaclValidationPlugin, RDF from rdflib_dumper):
| Test / schema | Rule operators | sh:sparql |
SHACL vs expected |
|---|---|---|---|
test_preconditions |
any_of/none_of of equals_number |
0 | 6 valid agree; 4 invalid accepted |
combos if0then0 |
equals_number |
0 | 2 valid agree; 0-10 accepted |
combos no_preconditions, no_postconditions |
one side missing | 0 | 3 valid agree |
combos ifAthenB |
equals_string |
1 | AA rejected |
combos Disjunctive |
exactly_one_of of bounds |
0 | 11-1 accepted |
combos if1or2then3or4 |
any_of of equals_number |
0 | 11 accepted |
combos ifAorBthenCorD |
any_of of equals_string |
0 | 2 valid agree; AA accepted |
test_value_presence_in_rules (both multivalued) |
value_presence PRESENT→ABSENT, ABSENT→PRESENT |
2 | 8/8 agree |
main and linkml#3989 emit no sh:sparql for any of these. Minimal check, which prints invalid, valid, valid, invalid:
from linkml.validator import Validator
from linkml.validator.plugins.shacl_validation_plugin import ShaclValidationPlugin
presence = lambda slot, p: {"slot_conditions": {slot: {"value_presence": p}}}
schema = {
"id": "http://example.org/vp", "name": "vp", "default_prefix": "ex", "default_range": "string",
"prefixes": {"ex": "http://example.org/", "linkml": "https://w3id.org/linkml/"},
"imports": ["linkml:types"],
"classes": {"C": {"attributes": {"s1": {}, "s2": {}}, "rules": [
{"preconditions": presence("s1", "PRESENT"), "postconditions": presence("s2", "ABSENT")},
{"preconditions": presence("s1", "ABSENT"), "postconditions": presence("s2", "PRESENT")},
]}},
}
for inst in ({}, {"s1": "x"}, {"s2": "x"}, {"s1": "x", "s2": "x"}):
v = Validator(schema=schema, validation_plugins=[ShaclValidationPlugin(closed=True)])
print(inst, "valid" if not list(v.iter_results(inst, "C")) else "invalid")Harness behaviour
check_data validates nothing when expected_behavior is INCOMPLETE, NOT_APPLICABLE or FALSE_POSITIVE.
- Both precondition tests expect
INCOMPLETEfor every framework except JSON Schema and OWL. test_value_presence_in_rulesexpectsINCOMPLETEfor the invalid instances of every framework except JSON Schema.
Deleting the skips alone gives 30 passes, but only the 4 valid value_presence instances are actually validated. Setting SHACL to IMPLEMENTS in all three gives 22 passes and 8 failures: exactly the "accepted" cases above.
Plan
test_value_presence_in_rules: delete the skip; SHACLIMPLEMENTSfor all instances.test_preconditions_combos: delete the skip. SHACLIMPLEMENTSforifAthenBand every valid instance, andINCOMPLETEfor the invalid instances of rules shaclgen skips (equals_number,exactly_one_of, slot-levelany_of).test_preconditions: delete the skip. SHACLIMPLEMENTSfor valid instances, which guards against false positives, andINCOMPLETEfor invalid ones.- Add a presence-implies-value test across
CORE_FRAMEWORKS:- targets:
string, an enum without meanings, an enum with meanings; - instances: allowed, other, absent target, absent guard;
- a subclass instance, and
open_world; - expectations: SHACL
IMPLEMENTS, since all agree atc89faac06. A target whose range holds neither strings nor booleans makes shaclgen skip the rule with a warning, soINCOMPLETEthere.
- targets:
Notes
no_preconditions: the metamodel definespreconditionsas "an expression that must hold in order for the rule to be applicable to an instance", but not what an absent one means. The test expects valid, as JSON Schema decides: jsonschemagen emitsthenwithoutif, which "has no effect when "if" is absent" (JSON Schema 2019-09 §9.2.2.2). shaclgen skips such a rule, so the verdicts agree without SHACL enforcing anything.- Enum values with a
meaning:rdflib_dumperwrites them as that IRI, but the generated JSON-LD context leaves them literals, so valid JSON-LD data fails both the per-slotsh:inand the rule (gen-jsonld-context: enum values with a meaning stay literals unless the enum is @vocab-eligible, so data loaded through the context fails gen-shacl sh:in #40). This is pre-existing, and the harness doesn't exercise it. - Out of scope:
- lines 1439 (
test_class_boolean_with_expressions) and 1899 (test_slot_boolean_with_expressions): boolean expressions, feat(generators): translate class-level boolean expressions alike to SHACL and JSON Schema linkml/linkml#4028; - 2454 (
test_classification_rules):classification_rules; - 2556 (
test_union_of): skipped for every framework by@pytest.mark.skip.
- lines 1439 (
Acceptance
- No "does not support rules yet" / "boolean expressions yet" SHACL skip remains in the three rule tests.
uv run pytest tests/linkml/test_compliance/test_boolean_slot_compliance.py -k shaclpasses with the expectations above.- After
uv run pytest tests/linkml/test_compliance/ --with-output && uv run python scripts/generate_dashboard.py,docs/generators/dashboard.mdshows SHACL ✅ for Value presence in rules and⚠️ for Precondition rules / Precondition combos, instead of ❓.
Activity
[-]compliance: run SHACL for rule tests now that shaclgen translates rules (after #3990)[/-][+]compliance: run SHACL for rule tests now that shaclgen translates rules (after linkml/linkml#3990)[/+]