fix(client): anchored default-graph writes for inbox + scope index

Inbox deposits and the per-(account,scope) index append were written into an
explicit GRAPH <plainNuri> named graph, which the real broker stores separately
from the repo's default graph (repo_graph_name with overlay suffix) — so an
anchored default-graph read (read-model.readDoc) never saw them and deposits
did not round-trip. Drop the GRAPH wrapper: the anchor scopes the write to the
repo's default graph, matching the read. Mocks updated accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-07-06 12:45:11 +02:00
parent c85c635f63
commit d39b12885a
5 changed files with 73 additions and 24 deletions
+15 -9
View File
@@ -124,13 +124,18 @@ export async function post(targetInbox: Nuri, opts: PostOptions): Promise<void>
const fromTriple =
from == null ? "" : ` ;\n <${P.from}> "${escapeLiteral(from)}"`;
// NO explicit `GRAPH <…>` wrapper: the real broker stores each repo's triples
// under repo_graph_name(repo_id, overlay_id) — the doc NURI WITH an overlay
// suffix, not the plain NURI. An `INSERT DATA { GRAPH <plainNuri> {…} }`
// therefore targets a phantom graph and does NOT round-trip. The only
// verified-working shape is the anchored DEFAULT graph (no GRAPH clause):
// `sparqlUpdate(sid, update, targetInbox)` scopes the write to that repo's
// default graph (same shape as read-model.ts readDoc/readUnion).
const update = `
INSERT DATA {
GRAPH <${targetInbox}> {
<${subject}> a <${P.type}> ;
<${subject}> a <${P.type}> ;
<${P.payload}> "${payloadLiteral}" ;
<${P.ts}> "${ts}"${fromTriple} .
}
}`;
await sparqlUpdate(sid, update, targetInbox);
}
@@ -145,14 +150,15 @@ export async function post(targetInbox: Nuri, opts: PostOptions): Promise<void>
*/
export async function read(targetInbox: Nuri): Promise<Deposit[]> {
const sid = await sessionId();
// NO explicit `GRAPH <…>` clause — read the anchored DEFAULT graph (see the
// note in `post`). The anchor (`targetInbox`) scopes the query to that repo's
// default graph, exactly where `post` writes.
const query = `
SELECT ?payload ?ts ?from WHERE {
GRAPH <${targetInbox}> {
?d a <${P.type}> ;
<${P.payload}> ?payload ;
<${P.ts}> ?ts .
OPTIONAL { ?d <${P.from}> ?from }
}
?d a <${P.type}> ;
<${P.payload}> ?payload ;
<${P.ts}> ?ts .
OPTIONAL { ?d <${P.from}> ?from }
}`;
const result = await sparqlQuery(sid, query, undefined, targetInbox);
const deposits: Deposit[] = [];