fix(client): durcir le cold-start du shim — ensureRepoOpen(anchor) avant lecture/écriture

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>
This commit is contained in:
Sylvain Duchesne
2026-07-13 15:06:30 +02:00
parent 078d675bbf
commit 3046ead08f
7 changed files with 473 additions and 6 deletions
+8 -6
View File
@@ -178,12 +178,14 @@ function makeLaggyFakeNg(opts: { lag?: number } = {}) {
.map((q) => ({ e: { value: q.o } }));
return { results: { bindings } };
});
// doc_subscribe: immediately push a State (the barrier) so ensureRepoOpen resolves.
const doc_subscribe = mock(async (..._a: unknown[]) => {
// Return an async-iterator-like the subscribe wrapper can consume; but the
// registry only needs `typeof doc_subscribe === "function"` for the reactive
// path. open-repo's subscribeDoc handles the actual shape; here it is unused
// (ensureAccount does not call ensureRepoOpen). Kept as a real fn.
// doc_subscribe: immediately push a State (the sync barrier) so `ensureRepoOpen`
// resolves at once. `resolveAccount`/`ensureAccount` now open the anchor repo
// (open-repo.ts) before reading/writing the shim (the cold-start heal); the real
// broker pushes `TabInfo` then a first `State` on subscribe, and open-repo awaits
// that `State`. Model it: invoke the callback with a `State` AppResponse so the
// barrier is reached synchronously (no 8s fallback → the retry tests stay fast).
const doc_subscribe = mock(async (_repo: unknown, _sid: unknown, cb: Function) => {
if (typeof cb === "function") cb({ V0: { State: {} } });
return () => {};
});
return {