Repository navigation
v1.2.0 — Stable numbers, and testing the gate itself
Three toolchains moved, and the numbers this manual documented as unstable are now stable. Re-verified by running them.
📄 SemOps-Manual-v1.2.0-A4.pdf — 88 pages, A4
📓 SemOps-Manual-v1.2.0-notebooks.zip — the three runnable notebooks
The unscoped count no longer drifts
Five identical runs now return 301 findings every time. Earlier editions reported "close to 300" with an observed range of 289–298, traced to STR-007 returning between 12 and 21 findings on identical input.
The cause was never the check. Several registry CONSTRUCTs bind two values per result — LOG-004's two inverses, LOG-006/007's domain and range, REA-001's two disjoint classes, STR-007's subject and object — while the merge step read one via Graph.value(), an arbitrary pick, and deduplicated on it. Values are sorted and joined now, and the report shows both instead of half the finding.
The engine modes agree
Chapter 7's table was 4/5/6/6 with LOG-001 double-reported and both reporting 5 Violations against native+sparql's 2. It is now 4/5/5/5 at identical severities. Only --engine native still differs, for a stated reason: it runs the SHACL shapes only, and QUA-004 exists solely as a SPARQL check.
The severity half needed more than a number change. This manual attributed the split to a pySHACL bug, following a long comment in the suite's own source. That was half right. pySHACL does ignore sh:severity where it was written — but it was written in the wrong place, inside each nested sh:sparql block rather than on the enclosing shape, where SHACL defines it. The native engine read it there anyway. Moving it made both engines agree.
The lesson is about shape authoring, not engine choice. If your gate fails on something you declared
Warning, check wheresh:severityis attached before blaming the engine.
New: Chapter 9 §9.8 — Testing the gate itself
From the sibling fixture repository that found the defects above. Its central practice answers a question the manual had left open — how do you know the gate still works?
- Assert check identifiers, not counts. A regression then reads as "
LOG-004no longer fires" rather than "expected 85, got 83". It also survives exactly the churn above: while totals moved between 289 and 298, the set of ids never did. - Keep a clean control producing no Violation and no Warning, so findings elsewhere are attributable to seeded errors rather than background noise.
- Mark each seeded fault with an
# ERROR:comment naming its check.
The motivating case: the suite has four times shipped a check that quietly matched nothing. A check that cannot fire is worse than no check, because it looks like coverage.
The extension took the same fix — but assessed it first
Version 0.11.0 adopted the severity correction and deleted a workaround built on the assumption that a strict engine ignoring misplaced sh:severity was an engine bug. Notably it did not adopt the suite's findings on trust: it assessed each against its own stack, concluding two did not apply and one applied in a different form.
Shared artefacts need propagation with independent assessment, not synchronisation. A fix that is right for one runtime is a hypothesis about the other.
Also
DAT-001can now detect an invalidxsd:boolean— the regex branch was unreachable, because rdflib rewrites the stored lexical form of an ill-typed boolean.STR-002andSTR-007no longer disagree about external vocabularies.- Chapter 14's "gaps that have closed" now lists seven.
- All three notebooks re-verified against suite 0.6.0 and shacl 0.1.9: zero errors.
Full changelog: v1.1.1...v1.2.0