Skip to content

Instantly share code, notes, and snippets.

@danbri
Created July 10, 2026 08:22
Show Gist options
  • Select an option

  • Save danbri/02bcfc08f9486c274d4782071ce51ef9 to your computer and use it in GitHub Desktop.

Select an option

Save danbri/02bcfc08f9486c274d4782071ce51ef9 to your computer and use it in GitHub Desktop.
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
@danbri

danbri commented Jul 10, 2026

Copy link
Copy Markdown
Author

Gpt 5.6 review of ^^^^:

Verdict

The ticket is technically correct, well evidenced, and should be filed. I would rate it:

  • Correctness: 9.5/10
  • Diagnostic quality: 9/10
  • Issue-writing quality: 8/10
  • Severity: small patch, moderate interoperability/test-suite impact

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 validation manifest describes imported S2 as { . }, points to the relevant data, and marks the entry as a positive sht:ValidationTest.
  • The data gives n1 →p1→ n2 and n2 →p2→ "X".
  • The importing ShExC schema follows exactly that structure.
  • Most decisively, the suite has an approved representation test explicitly grouping the .shex, .json, and .ttl forms of start2RefS1-IstartS2 as representations of the same schema.

The proposed two-line semantic fix is therefore correct.

Important refinements

  1. Do not call the ShExC file “canonical”

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.

  1. Distinguish the representation-test defect from the validation-manifest defect

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:

  1. The approved representation test is internally inconsistent.
  2. Validation using the ShExJ or ShExR representation and its corresponding imported representation produces a result different from the ShExC route.
  3. Toolchains that convert, substitute, compare, or preferentially consume those representations can fail the intended positive case.

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.

  1. Replace “any ShEx implementation”

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.

  1. Lead with the approved representation test

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:

  1. Replace “Canonical ShExC.”
  2. Qualify the import-resolution reproduction.
  3. Add the approved sht:RepresentationTest entry as the primary evidence.

Those changes remove the only plausible openings for a maintainer to quibble with an otherwise clear fixture bug.

@ericPxKanda

Copy link
Copy Markdown

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