Solid (user, app)-pair result sets
FROM NAMED restriction around whatever you type.Access control still applies to your query: it is evaluated only over the named graphs the pair may read. Wrap patterns in GRAPH ?g { … } to read across the authorized documents — a query against the default graph alone returns nothing here, because a Pod’s data lives in its per-document named graphs (and that is the fail-closed default).
The Pod — one named graph per document:
Session { agent, client }. Pick a pair on each side, run, and watch the result sets diverge.- …/profile/card— Public profile
- …/calendar/shared— Shared calendar
- …/notes/private— Private notes
1 graph invisible to this pair
- Private health data(indistinguishable from absent)
Why these graphs? 3 WAC/ACP grants matched
<#public> a acl:Authorization ; acl:accessTo <profile/card> ; acl:agentClass foaf:Agent ; # → auth:Public acl:mode acl:Read .
<#shared> a acl:Authorization ; acl:accessTo <calendar/shared> ; acl:agent <https://alice.pod.example/profile/card#me> , <https://bob.example/profile#me> ; acl:mode acl:Read .
<#notes> a acl:Authorization ; acl:accessTo <notes/private> ; acl:agent <https://alice.pod.example/profile/card#me> ; acl:mode acl:Read .
Run the query to see what this pair gets back.
- …/profile/card— Public profile
3 graphs invisible to this pair
- Shared calendar(indistinguishable from absent)
- Private health data(indistinguishable from absent)
- Private notes(indistinguishable from absent)
Why these graphs? 1 WAC/ACP grant matched
<#public> a acl:Authorization ; acl:accessTo <profile/card> ; acl:agentClass foaf:Agent ; # → auth:Public acl:mode acl:Read .
Run the query to see what this pair gets back.
Run the same SPARQL over the same Pod for two different (user, app) pairs and watch the answers diverge — the engine restricts each query to exactly the named graphs that pair is authorized to read, with the WAC/ACP grant that produced each result shown alongside.
How enforcement works & full caveat
In Solid your data lives in your Pod, and the rules for who may read what can depend not just on who is asking but on which application they ask from. sparq models a Pod as one named graph per document and reduces enforcement to a dataset restriction: for a Session { agent, client }, sparq-solid materializes exactly the named graphs that pair may read, then evaluates the query only over that authorized set via a FROM NAMED clause (its rewrite_for path). The default is fail-closed: absence of a grant is denial, and a non-authorized graph is indistinguishable from absent — an ungranted requester gets the empty set, so the Pod looks empty to it.
What is real, and what is precomputed. The restriction you see is real: the Pod is loaded into the sparq wasm engine in your tab with its named graphs preserved, and the same query is rewritten per pair — the differing result sets are the real engine doing the real graph-level restriction. What is precomputed is the access-control decision (which named graphs each pair may read): the WAC/ACP materialization runs natively / at build time, not in the browser, and ships here as fixtures (the rules behind each are shown in the “why these graphs?” panels, so nothing is hidden).
Most importantly, sparq-solid is a research track, not a Solid-server cutover. Per the project house rule (issue #55), security-critical paths run through vetted TypeScript in the production Solid server; sparq-solid is at most an authorization oracle, never the sole gate. It does not authenticate — it answers a graph-set question for an already-resolved (WebID, client) Session. This demo shows the graph-level access-control capability and semantics, not a certified production Solid deployment.
The live SPARQL REPLsparq-solid on GitHub Issue #55 — scope & house rule