fix(client): résolution de compte barrière-autoritative — fin du fork à la reconnexion
Bug: à la reconnexion, resolveAccount lisait le shim depuis le store-root (did🆖${privateStoreId}), NON abonnable → pas de barrière first-State → un "0 rows" à froid est ambigu → le retry (resolveAccountReliably/provisionRetry) échoue → nouveau compte provisionné → FORK → données du compte invisibles. Cause NextGraph (vérifiée nextgraph-rs): "trouvable-sans-lookup" (store-root) et "abonnable" (did:ng:o:<RepoID aléatoire>) sont DISJOINTS — pas de doc à la fois devinable et attendable → une résolution shim purement barrière est impossible. Fix (indirection pointeur → doc-shim abonnable): - Les AccountRecord migrent dans un doc-shim doc_create'd (did:ng:o:..., a une barrière). - Un pointeur écrit-une-fois dans le store-root (<shim:root> <shim:shimDoc> <docShim>) le nomme. resolveShimDoc lit le pointeur → ensureRepoOpen(docShim) [barrière] → lecture de compte AUTORITATIVE (cold 0 = absent pour de vrai). Retry de compte SUPPRIMÉ. - Micro-garde résiduel (pointerGuard, ex-provisionRetry) sur le SEUL triple pointeur écrit-une-fois; ne peut jamais forker un compte; fork de pointeur réconcilié au doc-shim canonique (lexicographiquement-min), sans perte. - Migration: migrateLegacyRecords copie (pas déplace) les comptes de l'ancien store-root vers le doc-shim avant toute conclusion "absent"; idempotent; wallet neuf → no-op. Tests: unit 128/128, e2e réel 42/42 (CONTRACT 2 = non-fork du compte à la reconnexion), red-before/green-after prouvé. Docs: nextgraph-current-state (antagonisme + indirection), simulation, migration-guide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+16
-6
@@ -98,12 +98,22 @@ public/protected/private stores — on top of one shared wallet.
|
||||
`docs.docCreate` primitive. The `scope` (`public|protected|private`) is a
|
||||
logical attribute tracked here, not a physical store.
|
||||
- **The `sharedWalletShim`** is the mapping `account → its 3 scope-document
|
||||
NURIs`, persisted as RDF in the shared wallet's private store (the anchor,
|
||||
always known from the session: `RegistrySession.privateStoreId`). That makes
|
||||
identity resolution cross-device: another device opening the same wallet reads
|
||||
the same shim and finds the same accounts. It is the account→document trust root,
|
||||
which is why every untrusted value that reaches its SPARQL is escaped (see
|
||||
SPARQL hardening below).
|
||||
NURIs`. It is persisted as RDF, but **not directly in the store-root graph** — it
|
||||
lives in a subscribable **doc-shim** reached through a write-once **pointer** in the
|
||||
store-root, an indirection forced by a NextGraph fact: "findable-without-lookup"
|
||||
(store-root) and "subscribable / cold-read-authoritative" (`did:ng:o:` repo with a
|
||||
first-`State` barrier) are DISJOINT. The pointer (findable) names the doc-shim
|
||||
(authoritative); resolution reads the pointer from the store-root, opens the doc-shim
|
||||
through its barrier, and reads the account authoritatively — so a fresh reconnecting
|
||||
session never mistakes sync-lag for "account absent" (which would provision a FORK).
|
||||
Full rationale — including why the old account-level retry (`provisionRetry`) is
|
||||
removed and how legacy store-root records are migrated forward — is in
|
||||
[`nextgraph-current-state.md`](./nextgraph-current-state.md) §§ *Findable vs
|
||||
subscribable* / *The pointer → doc-shim indirection*. This map is the
|
||||
account→document trust root, which is why every untrusted value that reaches its
|
||||
SPARQL is escaped (see SPARQL hardening below). It makes identity resolution
|
||||
cross-device: another device opening the same wallet reads the same pointer → the
|
||||
same doc-shim → the same accounts.
|
||||
- **Per-entity documents + per-scope index.** `createEntityDoc(id, scope)`
|
||||
makes a dedicated document for one entity (mirrors the target, where each entity
|
||||
is its own document/repo with a future inbox) and appends its NURI to the
|
||||
|
||||
Reference in New Issue
Block a user