Preuve e2e (wallet frais, broker RÉEL rapide : 1er State 1-2 ms) : le private
store est synchronisé au login, la lecture du shim réussit à froid — le « fork sur
lag » que anti-fork compensait n'est PAS exhibé. Par le principe du polyfill
(compenser un gap RÉEL, jamais du poids mort), et par la règle no-polling :
- la version retry = polling (bannie) ;
- la version barrière `ensureRepoOpen(privateStore)` = CASSÉE (un store n'émet pas
de `State`, la barrière timeout systématiquement → CONTRAT 2 e2e échouait) ;
- le gap = non exhibé.
→ `ensureAccount` fait un `resolveAccount(id)` SIMPLE (une lecture, provision si 0).
`resolveAccountReliably`, `_forceOpenedSyncState` retirés ; `provisionRetry` gardé
optionnel @deprecated (ignoré) pour ne pas casser les 8 tests qui le passent.
`ensureRepoOpen`/`getSyncState` inchangés (chemin de lecture open-repo).
gate : tsc 0 ; bun test 116 ; test:e2e 39 passed, CONTRAT 2 VERT (« same account,
no second provisioning »). Le ~10s du re-resolve public est du scaling anchorless,
pas de la lenteur broker (broker mesuré à 1-2 ms).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le polling est un anti-pattern NextGraph (par abonnement). La résolution de compte
retentait ×8 la lecture du shim tant qu'elle rendait 0 (lag de sync) — c'est du
polling. Remplacé par la BARRIÈRE d'abonnement, déjà le mécanisme de open-repo :
- `resolveAccountReliably` : `await ensureRepoOpen(did🆖${privateStoreId})`
(subscribe + attendre le 1er State — le shim vit dans le graphe du private store),
PUIS lecture UNIQUE. Après la barrière, 0 ligne = compte réellement inexistant →
provision 1×, lignes présentes = réutilisé (garantie NO-FORK préservée). Plus de
boucle de re-lecture.
- timed-out (barrière expirée) : throw explicite, NE provisionne PAS (un provision
sur sync incomplète re-forkerait). Le « trop long » est un signal, pas un feu vert.
- fake ng sans doc_subscribe : ensureRepoOpen no-op → lecture immédiate (unit intact).
- `_forceOpenedSyncState` : helper test-only (underscore, non ré-exporté).
anti-fork.test.ts réécrit (5 tests : no-fork, neuf→1 provision, idempotence, fake
no-op, timed-out→throw) ; plus aucun test de comptage de retry.
gate : tsc propre ; bun test 117. e2e À RE-VALIDER quand le broker répond (dégradé
ce jour : crash Chromium post-connexion) — la barrière ensureRepoOpen est déjà
validée e2e (CONTRAT 3 + reconnexion) en broker sain. provisionRetry devient un
champ mort de StoreRegistryDeps (nettoyage ultérieur).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Les fix récents (anti-fork, open-repo, access-log) n'avaient AUCUN test de
comportement dans le domaine de la lib. Ajout de tests DÉTERMINISTES à base de `ng`
factice modélisant la condition d'échec (pas de broker réel — le harness e2e réel
réhydrate trop vite et ne reproduit pas ces cas).
- anti-fork.test.ts : fake avec lag de sync (0 lignes les K premières lectures du
record de compte, puis les vraies). Asserte le cœur du fix : compte retrouvé au
retry → réutilisé, 0 doc_create (pas de fork) ; compte réellement neuf → 1 seul
jeu de docs provisionné, budget de retry prouvé consommé ; idempotence de session ;
cas limite « trouvé à la dernière tentative ».
- open-repo.test.ts : fake où une requête ancrée rend vide tant que doc_subscribe
n'a pas ouvert le repo. Asserte subscribe-avant-read + idempotence (Set des repos
ouverts) + no-op si le ng n'a pas doc_subscribe.
- access-log.test.ts : off par défaut (silencieux), on via config ET via env
NG_EVENTUALLY_ACCESS_LOG, préfixe = identité active (suit setCurrentUser),
row-count sur READ. Restaure console.log/env fidèlement.
bun test : 91 → 117 pass, 0 fail. tsc --noEmit propre. src/ non touché.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>