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:
@@ -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[] = [];
|
||||
|
||||
@@ -422,9 +422,12 @@ export async function createEntityDoc(username: string, scope: Scope): Promise<N
|
||||
try {
|
||||
await sparqlUpdate(
|
||||
s.sessionId,
|
||||
// indexDoc is a NURI in IRI position → assertNuri; entityNuri is a NURI
|
||||
// stored as a literal → escapeLiteral.
|
||||
`INSERT DATA { GRAPH <${assertNuri(indexDoc)}> { <${INDEX_SUBJECT}> <${P.contains}> "${escapeLiteral(entityNuri)}" } }`,
|
||||
// NO explicit `GRAPH <…>` wrapper: the real broker stores each repo's
|
||||
// triples under repo_graph_name(repo_id, overlay_id), not the plain NURI,
|
||||
// so an INSERT into `GRAPH <plainNuri>` targets a phantom graph and does
|
||||
// NOT round-trip. Write the anchored DEFAULT graph instead (the `indexDoc`
|
||||
// anchor scopes it). entityNuri is a NURI stored as a literal → escapeLiteral.
|
||||
`INSERT DATA { <${INDEX_SUBJECT}> <${P.contains}> "${escapeLiteral(entityNuri)}" }`,
|
||||
indexDoc,
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -440,7 +443,9 @@ async function readScopeIndex(indexDoc: Nuri): Promise<Nuri[]> {
|
||||
try {
|
||||
const res = await sparqlQuery(
|
||||
s.sessionId,
|
||||
`SELECT ?e WHERE { GRAPH <${assertNuri(indexDoc)}> { <${INDEX_SUBJECT}> <${P.contains}> ?e } }`,
|
||||
// NO explicit `GRAPH <…>` clause — read the anchored DEFAULT graph (see
|
||||
// the note in createEntityDoc). The `indexDoc` anchor scopes the query.
|
||||
`SELECT ?e WHERE { <${INDEX_SUBJECT}> <${P.contains}> ?e }`,
|
||||
undefined,
|
||||
indexDoc,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user