Files
ng-eventually/docs/decisions/private-store-nuri-scope.md
Sylvain Duchesne 737729c9ce refactor: le paquet s'appelle polyfill, « SDK » désigne celui de NextGraph
Le nom @ng-eventually/sdk entrait en collision avec le SDK de NextGraph, dont
ce paquet est justement un polyfill. Impossible d'écrire « le SDK » sans lever
l'ambiguïté à chaque phrase — et le contrat publié, lu par une application,
était le pire endroit pour laisser traîner ça.

packages/sdk → packages/polyfill, @ng-eventually/sdk → @ng-eventually/polyfill,
contract_sdk-surface → contract_polyfill-surface, e2e/sdk-entry.ts →
e2e/polyfill-entry.ts, docs/sdk-reference.md → docs/polyfill-reference.md.

Les occurrences de « SDK » qui désignent celui de NextGraph restent intactes,
y compris les chemins dans nextgraph-rs (sdk/js/orm, sdk/js/web). Le tri s'est
fait occurrence par occurrence, pas par substitution.

Le contrat énonce désormais son identité en une phrase : « This package is a
polyfill of NextGraph's SDK. »
2026-08-10 17:14:25 +02:00

3.1 KiB

ADR — Use a store NURI as the useShape scope AND @graph

Date: 2026-03-17 · Status: Accepted (partially superseded — see below). Historical decision, ported into this lib because the insight still governs how the shim opens repos. Original context: the consuming app.

Partially superseded (2026-07-03). The private-store-only scope was replaced for shareable domain entities: they are now scoped AND written to the protected store (did:ng:${protected_store_id}), verified to open without RepoNotFound. The central insight of this ADR still holds and now applies to both stores: you must open the repo via the store's NURI or you get RepoNotFound. (How it is opened has since changed — see the note under Decision.)

Context

Loading test data updated the in-memory ORM signals (immediate UI) but produced RepoNotFound on doc_create and orm_frontend_update. Data vanished on reload because the SPARQL writes never reached the broker: the verifier's self.repos HashMap did not contain the store's repo → resolve_target() failed.

Options considered

A — did:ng:i scope + doc_create for @graph

did:ng:i is documented as a subscription scope; doc_create returns a real NURI. Against: did:ng:i goes through NuriTargetV0::UserSite, which does NOT open individual repos; doc_create calls resolve_target(PrivateStore), which requires the repo already in self.repos → fails; needs complex retry/timing.

B — the store NURI as scope AND @graph (chosen)

Exact copy of the working expense-tracker-rdf example: orm_start_graph with the store's NURI opens the repo in self.repos; subsequent orm_frontend_update finds it. Simple, no retry. Against: slightly less flexible than did:ng:i (scoped to one store); requires passing the session down to the ORM hook.

C — did:ng:i scope + reuse an existing entity's @graph

Works for users who already have data. Against: fails for empty wallets (no entity to reuse) → falls back to doc_create and the same RepoNotFound.

Decision

Option B: use the store NURI as both the useShape scope AND the write @graph, exactly like expense-tracker-rdf. This is why this lib's shim opens the store repo before writing, and why did:ng:i must never be used as a scope (it breaks writes with RepoNotFound). See the scope rule in ../simulation.md.

The decision stands; the mechanism named in it has been replaced. Opening was orm_start_graph when this was written. It is now ensureRepoOpendoc_subscribe plus a wait for the first State (packages/polyfill/src/emulated-verifier/open-repo.ts:167) — after orm_start_graph was found to hang on a fan-out (subscribe.ts:28,181). What must be read here is the invariant "open the repo, by its store NURI, before writing", not the call that used to implement it.

Consequences

  • Positive: immediate writes after connect (no retry); persistence across reload; aligned with the official examples.
  • Risk: if NextGraph changes the store's open behaviour, this breaks.