Skip to content

Reconcile, and GET asks for N-Triples then Turtle - #71

Merged
namedgraph merged 2 commits into
mainfrom
feat/reconcile
Oct 29, 2026
Merged

namedgraph merged 2 commits into
mainfrom
feat/reconcile

Conversation

@namedgraph

@namedgraph namedgraph commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Why

The XML serialization's executor has a core Reconcile that matches names such as a place of birth, a home, an employer or a school against Wikidata. This PR puts the same operation into the spec and the Python implementation, so the two serializations keep the same catalog (§5).

What

  • formal-semantics.md §4.7 Reconciliation specifies Reconcile as a query effect, URI × Literal × Maybe Literal × Maybe Literal → Result:
    • It speaks the W3C Entity Reconciliation Service API to any endpoint; Wikidata's is one of them.
    • The manifest's identifierSpace resolves the candidate ids to URIs.
    • The query goes as the protocol's queries form field, with an optional type id and limit.
    • The Result binds entity, name, description (when the service gives one), score (xsd:decimal) and match (xsd:boolean), best first.
    • Errors: a manifest without an identifier space, or a response that isn't JSON, raises ValueError; a non-2xx answer propagates as transport, as for GET.
  • Python:
    • operations/reconcile.py, a READ operation.
    • ReconciliationClient in client.py, with the same constructor as the other clients.
  • Docs: the README catalog, the planner's prompts/system.md with a runnable example, and an Unreleased CHANGELOG entry.

Tests

  • tests/unit/test_reconcile.py (7) covers:
    • rows with their ids resolved;
    • the type and limit sent with the query;
    • JSON arguments;
    • an empty result;
    • a missing identifier space;
    • type checks;
    • that the operation reads.
  • tests/http_stub.py answers the protocol offline, as it answers SPARQL: a manifest for a JSON GET, and no candidates for a POST of queries. test_system_prompt routes a reconciliation POST to that default handler.
  • The suite passes with uv run --with pytest python -m pytest tests -m "not network": 1120 passed.
  • Live against Wikidata: "Aarhus University" restricted to universities (Q3918) returns Q924265, score 100, match true.

Also: GET asks for N-Triples, then Turtle

GET now ranks the RDF media types it accepts: application/n-triples, text/turtle;q=0.9, application/ld+json;q=0.8, application/rdf+xml;q=0.7.

  • The bug: unranked, a server choosing among equals picked freely, and Wikidata picked RDF/XML.
  • Why that fails: Wikidata writes its rdf:nodeIDs as hashes, and most of them start with a digit. RDF/XML requires XML NCNames, which can't, so rdflib refused every Wikidata entity: rdf:nodeID value is not a valid NCName. The same blank nodes are fine in N-Triples and Turtle.
  • Upstream: reported as T252731 in 2020 and declined in favour of T244341, which is still open. w3c/rdf-xml#127 proposes relaxing the RDF/XML grammar.
  • What it unlocks: Reconcile followed by GET of the chosen ?entity now works in Python, as it already did in the Java executor (Jena is lenient).
  • Checks: a new test in tests/unit/test_get.py covers the header, and a live GET of http://www.wikidata.org/entity/Q25319 returns 7060 statements, coordinates included. The suite passes: 1121.

🤖 Generated with Claude Code

@namedgraph namedgraph changed the title Reconcile: a name's candidate entities from a reconciliation service, as a Result Reconcile, and GET asks for N-Triples then Turtle Oct 29, 2026
namedgraph and others added 2 commits October 29, 2026 13:57
… as a Result

formal-semantics.md §4.7. A core operation over the W3C Entity Reconciliation
Service API, so any service is an endpoint and Wikidata's is one of them: the
manifest's identifierSpace resolves the candidate ids to URIs, the query goes
as the queries form field with an optional type id and limit, and the Result
binds entity, name, description, score and match per candidate, best first.

The XML serialization's executor has it too; this keeps the two
serializations' catalogs the same.

The offline stub answers the protocol as it answers SPARQL: a manifest for a
JSON GET, no candidates for a POST of queries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The RDF media types a GET accepts are ranked by quality value, in
MEDIA_TYPES' order. Unranked, a server choosing among equals picked freely,
and Wikidata picked RDF/XML: its rdf:nodeIDs are hashes that start with a
digit, not the XML NCNames RDF/XML requires, and rdflib refused every entity
(Wikimedia T252731, declined in 2020 in favour of T244341, still open). The
same blank nodes are fine in N-Triples and Turtle. A GET of a Wikidata entity
now reads it, so a Reconcile candidate's description is a GET away.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@namedgraph
namedgraph merged commit cf72c3d into main Oct 29, 2026
12 checks passed
@namedgraph
namedgraph deleted the feat/reconcile branch October 29, 2026 13:07
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