Files
Sylvain Duchesne 3547967d37 chore(client): retirer la migration legacy + alléger les logs d'accès
- Migration des comptes legacy supprimée (migrateLegacyRecords + garde migratedInto
  + call-sites). Un wallet pré-fix (records store-root, pas de pointeur) provisionne
  simplement un doc-shim frais; contenu legacy ignoré (voulu, données = dev). La
  résolution barrière-autoritative + anti-fork (resolvePointer/ensureRepoOpen/
  canonicalDoc/ensureInFlight/pointerGuard) est inchangée.
- Logs d'accès SDK préfixés [polyfill] + NURI tronqué via shortNuri() (retire
  did:ng:o: et :v:…, garde 8 chars) → moins verbeux.
  Ex: [polyfill] [user1] READ vDlwbZio… (resolvePointer) → 1 triple-rows

Tests: bun test unit 126/0. Docs (nextgraph-current-state/simulation/migration-guide)
mis à jour (migration legacy retirée du modèle décrit).

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

5.1 KiB

Migration guide — when real NextGraph matures

The whole point of this library: the consumer application already writes SDK-shaped code, so when NextGraph ships cross-wallet reads, capabilities and inboxes, only this lib changes. The consumer application's code does not change. This is the checklist.

Guiding invariant

Every emulated piece has a 1:1 image in the real infra. Migration = swap the emulation for the real primitive, remove the scaffold. If a piece of the emulation has no clear target image, that is a drift signal (see simulation.md).

Checklist

1. Emulated ReadCaps → real capabilities

Translate the per-document CapRegistry (caps.ts) into real NextGraph caps: the broker/verifier enforces them, and useShape already returns only authorized documents. The directed grantRead(doc, granteeId) maps to a native per-document ReadCap issued to that identity. The read filter (read-filter.ts) and the write guard (ng-proxy.ts sparql_update override) are then dead code — remove them. The access unit is already the document (@graph), matching the native per-repo cap model, so this is a data step, not a reshape.

2. Place documents in real native stores

Today docCreate(..., undefined) writes every document into the shared wallet's private store, and the public|protected|private scope is a logical label in the shim (see the two-axes section in simulation.md).

  • doc_create cannot target a non-private native store today — verified: StoreRepo is not JS-constructible from the SDK, so there is no way to pass a public/protected store as the create destination (docCreate's trailing store arg is left undefined → private store). The private store works only because it opens without RepoNotFound.
  • When the SDK lets you construct/target a native store, the migration adds a getNativeStore(scope)-style resolver returning the real store to pass as the docCreate destination, so the logical scope label becomes a real store placement. (No such helper exists yet — it is blocked on the SDK gap above.)
  • At that point store-registry.ts maps (account, scope) to the user's real store NURI instead of a document in the shared wallet; the per-scope index document (the store-container emulation) is replaced by the store itself. The surface facing the consumer application (createEntityDoc, listEntityDocs, resolvers) is designed to survive that swap unchanged.

3. Drop the resolver / shim

The sharedWalletShim (account → 3 scope-document NURIs, held in a subscribable doc-shim reached via a write-once pointer in the store-root — see nextgraph-current-state.md § The pointer → doc-shim indirection) has no target equivalent — the target has no central directory. Remove it entirely: store-registry.ts, configureStoreRegistry, the pointer + doc-shim resolution, and the pointerGuard dep. Cross-wallet reads replace the fan-out; per-user wallets replace the shared one.

4. Real inbox → drop the in-lib read emulation

Replace the emulated inbox.ts deposit (docs.sparqlUpdate into a shared-wallet document) with the native inbox_post_link (proposed/future). On the read side the recipient's own verifier unseals each queued sealed message and applies it inline when it processes its inbox — there is no separate curator to build; the in-lib read emulation simply goes away (see the deferred global-index note in the top-level README and decisions/discovery-model.md). The single global index replaces the cross-account fan-out.

5. Retire the identity store → real per-user login

Remove accounts.ts (the IdentityStore that persists the identity id in localStorage) and the app-level "Connexion" screen. The technical broker gate becomes the real per-user login (see decisions/shared-wallet-login-flow.md). The flow shape ("broker redirect → app") does not change.

6. Drop the isolation scaffold

isolation.ts (application-visibility scaffold) disappears against a different piece of infra than the caps: real per-account wallets, and the relationship concept the consumer application owns. Distinct axis from ReadCaps — remove independently.

7. Remove the build alias — the client becomes the real SDK

The consumer application imports @ng-org/web / @ng-org/orm resolved to this lib via a build alias during the polyfill period. Removing the alias makes those imports resolve to the real SDK — the ng/useShape/inbox surface is SDK-identical, so no consumer code changes. The one non-SDK call — configure(...) / @ng-eventually/client/polyfill — is deleted. The lib itself disappears.

What does not change

The consumer application's code. Shapes, screens, the acts of granting access, entity→scope mapping, the relationship graph — all injected, all untouched. Migration is entirely inside this library plus removing the alias + the bootstrap call. That asymmetry — a mature SDK face outward, all compensation inward — is the library's reason to exist.