diff --git a/src/shared/data/entityWrites.ts b/src/shared/data/entityWrites.ts index caa606d..1556e79 100644 --- a/src/shared/data/entityWrites.ts +++ b/src/shared/data/entityWrites.ts @@ -94,13 +94,12 @@ export async function updateEntityField( const s = assertNuri(subject); const pred = `${FP}${field}`; const obj = renderTerm(term); - // NO explicit `GRAPH <${graphNuri}>` wrapper: anchored to `graphNuri`, both the - // DELETE and the INSERT target that repo's DEFAULT graph — the exact graph the - // anchored default-graph READ queries (read-model.ts readDoc). An explicit - // `GRAPH ` body writes into a NAMED graph the anchored read never - // sees, so the mutation would not round-trip (same fix as writeEntity / the - // lib's inbox.post). `assertNuri(graphNuri)` is still done implicitly by - // `docs.sparqlUpdate`'s anchor handling — validate `subject` here as it lands + // NO explicit `GRAPH <…>` wrapper: anchored to `graphNuri`, both the DELETE and + // the INSERT target that doc's anchored DEFAULT graph — the exact graph the + // anchored read queries. This no-GRAPH default-graph form is the CANONICAL SDK + // write shape (same as writeEntity / registration.ts); SDK graph details live in + // `@ng-eventually/client`, not here. `assertNuri(graphNuri)` is done implicitly + // by `docs.sparqlUpdate`'s anchor handling — validate `subject` here as it lands // in an IRI position. const del = `DELETE WHERE { <${s}> <${pred}> ?o }`; await docs.sparqlUpdate(sid, del, graphNuri); @@ -134,13 +133,11 @@ export async function writeEntity( if (obj === null) continue; triples.push(`<${FP}${field}> ${obj}`); } - // NO explicit `GRAPH <${g}>` wrapper: anchored to `graphNuri`, the write lands in - // that repo's DEFAULT graph — the exact graph the anchored default-graph READ - // queries (read-model.ts readDoc). An explicit `GRAPH ` body instead - // writes into a NAMED graph distinct from the repo's default graph, which the - // anchored default-graph read never sees (the old anchorless `GRAPH ?g` scan did, - // which is why it worked before the read switched to per-doc anchored). Same shape - // as the lib's inbox.post / entity writes: anchor scopes the write, no GRAPH clause. + // NO explicit `GRAPH <…>` wrapper: anchored to `graphNuri`, the write lands in + // that doc's anchored DEFAULT graph — the exact graph the anchored read queries. + // This is the CANONICAL SDK write shape (anchor scopes the write, no GRAPH clause; + // same as updateEntityField / registration.ts); SDK graph details live in + // `@ng-eventually/client`, not here. const update = ` INSERT DATA { <${assertNuri(subject)}> ${triples.join(' ;\n ')} . diff --git a/src/shared/data/registration.ts b/src/shared/data/registration.ts index c4d95c8..f8dbfd5 100644 --- a/src/shared/data/registration.ts +++ b/src/shared/data/registration.ts @@ -331,12 +331,11 @@ async function countParticipations( ): Promise { const evL = escapeLiteral(eventId); const usL = escapeLiteral(userId); - // NO explicit `GRAPH <${graphNuri}>` wrapper: participations are written by - // `writeEntity` into the anchored DEFAULT graph (one doc per entity), so this - // count MUST read that same default graph — anchored to `graphNuri`, with no - // `GRAPH` clause. An explicit `GRAPH ` body reads a NAMED graph the - // writes never land in → always 0 (the graph-mismatch bug — same fix as - // writeEntity/updateEntityField and the lib's read-model/inbox). + // NO explicit `GRAPH <…>` wrapper: participations are written by `writeEntity` + // into the anchored DEFAULT graph (one doc per entity), so this count reads that + // same anchored default graph — anchored to `graphNuri`, no `GRAPH` clause. This + // is the CANONICAL SDK read/write shape (write and read the same anchored default + // graph); SDK graph details live in `@ng-eventually/client`, not here. const query = ` SELECT (COUNT(DISTINCT ?s) AS ?n) WHERE { ?s a <${P.partType}> ; @@ -420,12 +419,12 @@ export async function deleteParticipation( const usIri = escapeIri(userId); const evL = escapeLiteral(eventId); const usL = escapeLiteral(userId); - // NO explicit `GRAPH <${graphNuri}>` wrapper: participations live in the - // anchored DEFAULT graph (writeEntity), so the sweep must DELETE from that same - // default graph — anchored to `graphNuri`, no `GRAPH` clause. Deleting from an - // explicit `GRAPH ` named graph would no-op (the triples aren't - // there), silently leaving the participation → the F2 resurrection. Same fix as - // countParticipations / writeEntity. + // NO explicit `GRAPH <…>` wrapper: participations live in the anchored DEFAULT + // graph (writeEntity), so the sweep DELETEs from that same anchored default + // graph — anchored to `graphNuri`, no `GRAPH` clause. Write, read and delete all + // use the one CANONICAL anchored-default-graph shape so they stay consistent (a + // mismatched target here would no-op the delete → the F2 resurrection). SDK graph + // details live in `@ng-eventually/client`, not here. const sweep = ` DELETE { ?s ?p ?o } WHERE { @@ -478,11 +477,10 @@ export async function insertNotification( const payloadTriple = notif.payload ? `\n <${P.payload}> "${escapeLiteral(notif.payload)}" ;` : ''; - // NO explicit `GRAPH <${graphNuri}>` wrapper: anchored to `graphNuri`, the - // INSERT lands in that repo's DEFAULT graph — consistent with every other - // per-entity write (writeEntity / updateEntity / the lib's inbox.post). An - // explicit `GRAPH ` body targets a phantom named graph that no - // anchored default-graph read ever sees (graph-mismatch bug). + // NO explicit `GRAPH <…>` wrapper: anchored to `graphNuri`, the INSERT lands in + // that doc's anchored DEFAULT graph — the CANONICAL SDK write shape, consistent + // with every other per-entity write (writeEntity / updateEntityField). SDK graph + // details live in `@ng-eventually/client`, not here. const update = ` INSERT DATA { <${assertNuri(subject)}> a <${NOTIF_TYPE_IRI}> ;