Created
July 10, 2026 08:22
-
-
Save danbri/02bcfc08f9486c274d4782071ce51ef9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Inconsistent schema representations for start2RefS2 in shexTest (JSON and Turtle say p1; ShExC, the test comment, and the test data say p2) | |
| Repository: shexSpec/shexTest, observed at commit 7d0cd92 (“fix typo in validation/#extends-closed-diamond_pass-bottom”). | |
| Affected test: start2RefS1-IstartS2 in validation/manifest.ttl (status mf:Proposed, traits sht:Import, sht:Start). | |
| Background | |
| Each schema in the suite is provided in three interchangeable representations that implementations may choose between: compact syntax (.shex), JSON (.json, ShExJ), and RDF (.ttl). The three files named start2RefS2.* are supposed to describe the same schema, and they do not. | |
| schemas/start2RefS2.shex says shape S2 requires predicate p2: | |
| start=@<http://a.example/S2> | |
| <http://a.example/S2> { | |
| <http://a.example/p2> . | |
| } | |
| schemas/start2RefS2.json says shape S2 requires predicate p1: | |
| { "@context": "http://www.w3.org/ns/shex.jsonld", | |
| "type": "Schema", | |
| "start": "http://a.example/S2", | |
| "shapes": [ | |
| { "type": "ShapeDecl", | |
| "id": "http://a.example/S2", | |
| "shapeExpr": { | |
| "type": "Shape", | |
| "expression": { | |
| "type": "TripleConstraint", | |
| "predicate": "http://a.example/p1" } } } ] } | |
| schemas/start2RefS2.ttl also says p1. | |
| Why p2 is the intended value | |
| The test start2RefS1-IstartS2 validates against schemas/start2RefS1-IstartS2.shex, which imports this schema (IMPORT <start2RefS2>) and references S2 from S1. Two independent pieces of evidence inside the suite agree with the .shex file: | |
| 1. The test’s own comment in validation/manifest.ttl spells the imported shape out as requiring p2: | |
| "I2 start=@<S1> <S1> { <p1> @<S2> } | <S2> { <p2> . } on { <s1> <p1> <n2> . <n2> <p2> \"X\" }" | |
| 2. The test data, validation/In1_Ip1_In2.In2_Ip2_LX.ttl, gives node n2 a p2 arc and no p1 arc: | |
| <http://a.example/n1> <http://a.example/p1> <http://a.example/n2> . | |
| <http://a.example/n2> <http://a.example/p2> "X" . | |
| The test is a sht:ValidationTest, i.e. the data is expected to conform. A triple constraint with no explicit cardinality requires exactly one matching arc, so: | |
| • With the .shex chain (S2 requires p2): node n2 has one p2 arc → conforms → test passes. ✔ | |
| • With the .json (or .ttl) chain (S2 requires p1): node n2 has zero p1 arcs → violates → test fails. ✘ | |
| Reproduction | |
| With any ShEx implementation that consumes the JSON representation and resolves imports: | |
| 1. Load schema schemas/start2RefS1-IstartS2.json (which imports start2RefS2, resolved to schemas/start2RefS2.json). | |
| 2. Validate node http://a.example/n1 against start shape http://a.example/S1 over the data file validation/In1_Ip1_In2.In2_Ip2_LX.ttl. | |
| 3. Result is non-conformant, contradicting the expected pass. Repeating with the .shex representations yields conformant. | |
| Suggested fix | |
| In schemas/start2RefS2.json and schemas/start2RefS2.ttl, change the predicate http://a.example/p1 to http://a.example/p2, matching start2RefS2.shex and the test’s comment and data. (The similarly named start2RefS2-IstartS1.* files are internally consistent and need no change.) “”” | |
| Human-readable (GitHub): | |
| • Mismatched JSON: https://github.com/shexSpec/shexTest/blob/main/schemas/start2RefS2.json ← says p1 | |
| • Canonical ShExC: https://github.com/shexSpec/shexTest/blob/main/schemas/start2RefS2.shex ← says p2 | |
| • Also-mismatched RDF twin: https://github.com/shexSpec/shexTest/blob/main/schemas/start2RefS2.ttl ← says p1 | |
| • Importing schema used by the failing test: https://github.com/shexSpec/shexTest/blob/main/schemas/start2RefS1-IstartS2.shex | |
| • Test data: https://github.com/shexSpec/shexTest/blob/main/validation/In1_Ip1_In2.In2_Ip2_LX.ttl | |
| • Manifest with the test entry (start2RefS1-IstartS2, search in page): https://github.com/shexSpec/shexTest/blob/main/validation/manifest.ttl |
Author
The alarming question for me is why my tests didn't catch this (or if I did, and it didn't propagate). Will look in a few mins...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Gpt 5.6 review of ^^^^:
Verdict
The ticket is technically correct, well evidenced, and should be filed. I would rate it:
At commit 7d0cd92, start2RefS2.shex constrains p2, while its ShExJ and ShExR/Turtle counterparts constrain p1. The discrepancy also remains on current main.
The intended value is overwhelmingly likely to be p2:
The proposed two-line semantic fix is therefore correct.
Important refinements
The link annotation:
Canonical ShExC
is technically questionable. The ShEx specification defines the language primarily in terms of ShExJ; conforming ShExC parses into a valid ShExJ document, while RDF representations must correspond to the RDF interpretation of ShExJ.
Use:
ShExC counterpart
or:
ShExC representation
The argument for p2 does not depend on declaring ShExC canonical.
The validation manifest explicitly names:
sht:schema <../schemas/start2RefS1-IstartS2.shex>
So a runner that follows that manifest literally and loads only the named ShExC file will pass.
The defect is more precisely:
Your current wording occasionally implies that every validation-test implementation is free to replace the manifest’s .shex URL with .json or .ttl. That may be true of particular harnesses, but it is not established by the validation entry itself.
This is too broad:
With any ShEx implementation that consumes the JSON representation and resolves imports
The import IRI is extensionless:
"imports": ["start2RefS2"]
and the corresponding ShExR form likewise imports .
The specification requires imports to be resolved and their returned representations interpreted as ShEx, but the mechanism by which an extensionless local import is mapped to .json, .ttl, or .shex is resolver or harness dependent.
Better:
With a ShEx implementation or test harness that loads the ShExJ representation and resolves the extensionless import to the corresponding start2RefS2.json file:
That is precise and defensible.
This is stronger than the present introductory claim that files with matching stems are “supposed” to be interchangeable. The repository states that directly:
<#start2RefS1-IstartS2> a sht:RepresentationTest ;
mf:status mf:Approved ;
sx:shex <start2RefS1-IstartS2.shex> ;
sx:json <start2RefS1-IstartS2.json> ;
sx:ttl <start2RefS1-IstartS2.ttl> .
That turns the report from “these look like twins” into “an approved test explicitly asserts equivalence, but its imported dependency makes them non-equivalent.”
Better title
start2RefS2 ShExJ and ShExR use p1, while ShExC and the validation fixture require p2
That is shorter, names the representations accurately, and states the likely correction without overloading the title with the affected parent test.
Suggested opening adjustment
The first two paragraphs could become:
The approved representation test start2RefS1-IstartS2 identifies its .shex, .json, and .ttl files as equivalent schema representations. Each imports the extensionless schema IRI start2RefS2, whose corresponding representation files are not equivalent: the ShExC form requires predicate p2, while the ShExJ and ShExR/Turtle forms require p1.
This changes the outcome of the positive validation fixture start2RefS1-IstartS2: the test data gives the referenced node a p2 arc and no p1 arc, matching the ShExC representation and the manifest comment.
Bottom line
The substantive diagnosis and fix are right. I would file it after making three changes:
Those changes remove the only plausible openings for a maintainer to quibble with an otherwise clear fixture bug.