La suite se ralentissait elle-même, de façon monotone. Chaque batterie crée ~11
identités virtuelles FRAÎCHES (`@alice-…`, `@owner-…`, `@recon-…`), chacune avec
ses trois documents de scope et son inbox, et toutes atterrissaient dans le MÊME
user physique — un wallet créé le 10 juillet et réutilisé depuis, que rien ne
nettoyait. Or une resynchronisation à froid est O(taille du user physique), ce
que la doc de cette bibliothèque énonce elle-même. D'où 250s il y a une semaine,
286s avant-hier, et une batterie qui a fini par dépasser les 20 minutes.
Les identités fraîches ne sont pas la faute : ce sont elles qui rendent une
batterie reproductible, une inbox stable accumulant sinon les dépôts des runs
précédents. La faute était de conserver le user physique qui les héberge.
Mesuré : 42/42 en **3,6 min** au lieu de 20+, synchro à froid la plus lente à
**30s** au lieu de 286s.
Le profil reste persistant À L'INTÉRIEUR d'une batterie — CONTRACT 1 et 2
testent précisément cela (reconnexion fidèle sur le même profil, absence de fork
de compte au travers).
Deux garde-fous pour que la prochaine dérive se voie :
- **Le budget appartient au runner**, qui échoue en nommant la cause probable.
Un `timeout` posé autour de la commande tuait le navigateur, et la suite
rapportait « Target page, context or browser has been closed » — un message
qui se lit comme un défaut applicatif, et que j'ai diagnostiqué deux fois de
travers avant de comparer les durées.
- **La synchro à froid remonte dans le résumé.** C'est le nombre qui a dérivé
pendant un mois sans que personne le regarde, parce qu'il n'apparaissait qu'au
détour de la ligne de détail d'une étape.
Défensif : loadShim/resolveAccount/ensureAccount ouvrent l'anchor (private-store-root)
avant de lire/écrire le compte shim, comme le fait déjà readScopeIndex. Robustesse
same-session si l'anchor est là-mais-pas-encore-souscrit.
NB (vérifié nextgraph-rs) : sur le login broker normal, le bootstrap charge le
private-store dans self.repos AVANT de rendre la session à JS → un wallet FRAIS
retourne 0 rows (pas RepoNotFound) et provisionne. Il n'existe AUCUN primitif JS
pour ouvrir un repo *inconnu* : ce heal n'est pas un remède à un store non
bootstrappé (limite NextGraph), juste une robustesse d'ouverture same-session.
Tests : cold-start-anchor.test.ts (rouge-avant/vert-après unit) ; harness e2e
repro-fresh-wallet (mint un wallet neuf par run — comble le trou "aucun test de
démarrage à froid sur wallet vierge"). Fakes anti-fork/watch-shape honorent
désormais la barrière first-State dont dépend le heal. e2e réel 42/42.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Défaut visé : sur une session verifier fraîche (reconnexion), la lecture ancrée
tape des repos pas encore ouverts dans self.repos → 0 ligne. Nouveau module
`open-repo.ts` : `ensureReposOpen`/`ensureRepoOpen` ouvrent/souscrivent un repo
via la primitive existante `subscribeDoc` (doc_subscribe) et attendent le push
d'état initial (borné, sans polling) AVANT la lecture ancrée. Câblé en amont de
`readUnion` (read-model) et `readScopeIndex` (store-registry). Idempotent par
session (Set des NURI ouverts + Map in-flight ; ré-ouverture si la session
injectée change). No-op si le `ng` injecté n'a pas doc_subscribe (fake unitaire).
État — NON MERGÉ, incomplet :
- AIDE le PROTECTED : la participation remonte au cold-start (mesuré app, timing
un peu bruité).
- N'ADRESSE PAS l'accueil PUBLIC : `readScopeIndex` de l'index public rend 0 même
côté écrivain même-session — le fix ouvre le repo mais l'index reste vide. Le
code d'index lib est prouvé scope-symétrique, donc la cause du public est
ailleurs (broker/store ou chemin app), À MESURER SOUS BROKER (actuellement
injoignable). Nécessité du fix elle-même non prouvée en e2e lib (broker down).
gate broker-indépendant : tsc --noEmit propre ; bun test 91 pass (worker).
Inclut le scaffolding e2e de repro reconnexion (broker/run/sdk-entry).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The polyfill had only fake-ng unit tests; real-broker behaviour (SPARQL graph
round-trip, doc_subscribe marshaling, inbox/index) was only ever exercised by
borrowing Festipod's harness. Add packages/client/e2e/ — a standalone Playwright
harness in the SDK's own domain: a minimal SDK page (configure() + the real
@ng-org/web ng, a window.__sdk bridge, zero Festipod domain) loaded in the broker
iframe on the real broker, authenticating with a DEDICATED wallet (name
ng-eventually-e2e, profile e2e/.playwright-profile-lib — gitignored, separate from
Festipod's). Runner: bun run e2e/run.ts (script test:e2e); not mixed into bun test.
Covers, against the real broker (23 checks, all green): docCreate; sparqlUpdate/
Query anchored default-graph round-trip; readUnion N-doc + per-doc tolerance + cap
gate; doc_subscribe initial+write+unsub and subscribeDocs per-doc isolation; inbox
post/read/watch + spoof guard; discovery submit/read/watchIndex + reserved-account
isolation; store-registry idempotency + bounded listMyEntityDocs + scope resolvers;
caps read-filter (in-memory, honestly scoped); IdentityStore.
Finding (reported, not a failure): on @ng-org/web 0.1.2-alpha.13 an anchored
INSERT DATA { GRAPH <plainNuri> {…} } DOES round-trip (no phantom graph) — several
lib comments assert the opposite; stale, to reconcile. Behaviour is unaffected (the
lib writes the always-safe no-GRAPH default-graph shape). bun test still 91 pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>