Skip to content

Commit d0a7316

Browse files
committed
fix(gen-shacl): enforce operator exactness, nested-slot parity, numeric bounds
Resolve the adversarial-audit findings on the rule-converter stack. Every fix carries regression tests; 18 of the 19 new tests fail on the pre-fix source (the 19th locks in already-correct zero-member has_member semantics that had no coverage). - Operator exactness (audit A1/B2/C2): named patterns and the compositional fallback now require their conditions to set EXACTLY the operators they translate. A new _set_operator_fields helper enumerates the constraint-bearing fields actually set on a condition or class expression (metadata excluded; scalars never judged by truthiness, so minimum_value: 0 still counts). Previously a condition mixing a recognized operator with an unrecognized one (equals_string + pattern), expression-level any_of/all_of/none_of/exactly_one_of, co-set equals_string + equals_string_in, or value_presence: ABSENT combined with a bound was partially translated, silently dropping conjuncts and producing demonstrated false positives. All such rules are now skipped (skip, never mis-translate). - Boolean-guard range gate (audit A2): the boolean-guard pattern only dispatches when the target slot's induced range is boolean. An equals_string "true" postcondition on a string-range slot previously hijacked the boolean comparison and flagged conforming data; it now dispatches to presence-implies-value, which compares the string. - Nested inner-slot parity (audit B1/C1): _member_conditions resolves the container slot in the induced context of the outer class, requires its range to be a class, and resolves inner slot URIs and enum values against that range class. Previously inner slots resolved against the OUTER class: a slot_usage slot_uri override on the member class made sh:path and the SPARQL body diverge (constraint silently never fired), and an inner slot name colliding with an outer slot_usage override queried a predicate members never carry, making has_member's FILTER NOT EXISTS vacuously true (false positives on conforming data). The _resolve_member_enum_ref special case is subsumed by passing the range class to _resolve_enum_value_ref. - Numeric bound gate (audit B3/C3): _sparql_number returns None for anything but int / finite float (bool excluded), and callers skip the rule. The metamodel range of minimum_value/maximum_value is Anything: a string bound produced unparsable SPARQL that poisoned the entire shapes graph at validation time, and a YAML date parsed as arithmetic (2020-01-01 = 2018), silently never firing. Docstring corrected. - elseconditions warning (audit B4): rules with an else branch now log a warning that only the forward direction is enforced, consistent with the bidirectional/open_world warnings. - Test hygiene: the vacuous "<Manual> not in query" assertion now checks the full IRI form; new zero-member has_member end-to-end test. Signed-off-by: Carlo van Driesten <carlo.van-driesten@vdl.digital>
1 parent 15c4d0d commit d0a7316

2 files changed

Lines changed: 1009 additions & 87 deletions

File tree

0 commit comments

Comments
 (0)