Files
ng-eventually/docs/decisions/private-store-nuri-scope.md
T
Sylvain Duchesne bea9f51d91 docs: own the current-NextGraph-state knowledge + boundary (lib side)
This library presents a mature-NextGraph SDK face to consumers while
compensating for the current SDK's gaps via a shared-wallet simulation. It
therefore OWNS all current-state + simulation knowledge — moved here out of the
Festipod app repo, which must treat this library as a finished SDK.

New docs/:
- nextgraph-current-state.md — what the current SDK/broker do and don't expose
  (5 store types, document=repo, per-document ReadCap, inbox not exposed, iframe
  RPC proxy, mono-user/no-global-data, wallet import constraint). Keeps the
  nextgraph-rs source pointers.
- simulation.md — how the lib emulates the mature behaviour on one shared wallet
  (shim, store!=document two axes, docCreate→private store, RepoNotFound scope
  rule, @ng-org double-proxy DataCloneError, emulated ReadCap/inbox/curator).
- decisions/ — the current-SDK ADRs (private-store-nuri-scope, sparql-delete,
  shared-wallet-login, discovery mechanism).
- fork-inbox-fallback.md — the Rust-patch/self-host route not taken.
- migration-guide.md — the checklist for when real NextGraph matures.

README: boundary framing from the lib's side + docs/ index; replaced the stale
"scaffold/stubbed" status with the actually-implemented mechanisms per source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 23:23:23 +02:00

2.6 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 (orm_start_graph) or you get RepoNotFound.

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 a store repo via orm_start_graph before writing, and why did:ng:i must never be used as a scope (it breaks writes with RepoNotFound). See the orm_start_graph scope rule in ../simulation.md.

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.