Skip to content

[mirror] fix: JSON-LD collection syntax can silently duplicate shared RDF lists - #2

Open
jdsika wants to merge 1 commit into
mainfrom
confirm/jsonld-shared-list
Open

jdsika wants to merge 1 commit into
mainfrom
confirm/jsonld-shared-list

Conversation

@jdsika

@jdsika jdsika commented Sep 14, 2026

Copy link
Copy Markdown

Mirror of RDFLib#3543 — tracking only. Do not merge.

Upstream PR: RDFLib#3543

Why this PR exists

Every fix this organisation depends on is written as a self-contained, single-commit
upstream contribution rather than a local patch, so that a fork is only needed for as
long as its contributions are unmerged.

That convention has one weakness: an upstream PR is easy to lose track of, because it
lives in someone else's repository and closes on someone else's schedule. This mirrored PR
is the counterweight — an open PR in our own fork for every contribution still pending
upstream, so the set of things we are carrying is visible from our own repository list.

It is closed when the upstream PR is merged or rejected, not before.

Contents

A single commit, identical in content to the upstream PR head:

confirm/jsonld-shared-list -> main

Where it is used

Not yet consumed: the pipeline pins released rdflib==7.6.0. Same defect class as the merged RDFLib#3504 (Turtle), which diffable-rdf 0.0.2 had to work around.

Converter.to_collection walked an rdf:List chain checking only that each cell
carries one rdf:first/rdf:rest pair and that the chain is acyclic. It did not
check how many statements point into the chain.

The @list form inlines the whole chain at a single reference and writes its
cells nowhere else, so when a cell is referenced from more than one place each
referring list rendered the shared cells again. The round trip then gained
triples:

    _:tail rdf:first "b" ; rdf:rest rdf:nil .
    _:head rdf:first "a" ; rdf:rest _:tail .
    ex:s1  ex:p _:head .
    ex:s2  ex:p _:tail .            # second reference into the chain

serialized as two independent @list values, one per referring subject, so the
tail was emitted twice: 6 triples in, 8 out, not isomorphic.

This is the same defect class as RDFLib#3504, which fixed TurtleSerializer and
LongTurtleSerializer by counting statements that point into the chain. The
JSON-LD converter has its own chain walk and was not covered by that fix, so
it gets the same check: a cell that is the object of more than one statement
is not rendered as a list, and the chain is written out with explicit
rdf:first/rdf:rest instead.

An empty chain still renders as "@list": [], which is rdf:nil rather than a
list structure, so nothing is lost there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant