Second tour adverse sur le lot C. Six trouvailles, dont trois sur ce que je venais de
livrer.
**Le correctif de `createEntityDoc` reproduisait le défaut qu'il annonçait avoir fermé.**
Il levait sur la PREMIÈRE écriture de registre en échec. Or :
- lever sur le listing sautait l'écriture de la clé — détruisant le chemin de
récupération que le commentaire d'à côté décrit explicitement (« la clé doit rester
récupérable même si le listing a échoué »), et laissant le document orphelin ;
- lever sur la clé laissait le document LISTÉ sans clé — précisément l'état « se lit vide
pour toujours » que je prétendais empêcher, en pire, puisque l'appelant n'a même plus
sa référence.
Les deux écritures sont désormais tentées, ce qui atterrit reste, et l'échec est rapporté
après en nommant la moitié manquante.
**Le refus de `share` reposait sur une valeur qui confond absence et ignorance.**
`resolveAccount` avale toute erreur de lecture et rend `null`, si bien qu'un incident
réseau faisait répondre « personne ne s'est connecté sous ce nom » à propos de quelqu'un
qui existe. `lookupAccount` propage désormais l'erreur ; `resolveAccount` reste la forme
tolérante que tous les autres appelants veulent.
**J'avais livré ce comportement sans un seul test.** `test/app-surface.test.ts` en ajoute
huit, tous sur ce qu'un APPELANT voit : `ensureIdentity` rend l'identité, un appel de
placement avant connexion nomme l'erreur, le placement agit comme l'utilisateur connecté,
`share` refuse un nom inventé mais laisse remonter une panne, et une création à moitié
écrite échoue en disant quelle moitié — dont le cas « le listing a échoué, la clé est
quand même là ».
En écrivant ces tests j'ai refait dans leur faux la faute que cette revue a corrigée
ailleurs : ignorer le sujet dans la requête de compte, ce qui rendait le dossier d'un
autre utilisateur. Deux des huit échouaient pour cette raison, sans rapport avec le code.
**Et la documentation contredisait le code livré dans le même commit** : le README
enseignait encore `createEntityDoc(me, "protected")` — en JS la portée devient `"alice"` —
et le contrat déclarait `Nuri` là où le code et la feuille disent `NuriLike`.
197 tests unitaires, e2e 40/40 et applicatif 12/12.
L'objectif acté était deux appels spécifiques au polyfill, voire un. Il en publiait
quatre. Chacun des trois de trop était une raison que la BIBLIOTHÈQUE a, pas un besoin
qu'une application a :
- **`configureStoreRegistry`** existait parce qu'il y a deux internes à câbler — le SDK
injecté d'un côté, la session de l'autre. Vu de l'appelant, les deux disent « voici ce
qu'il te faut pour tourner ». Replié dans `configure`, qui prend désormais
`getSession` / `normalizeId` / `pointerGuard`.
- **`setCurrentUser`** n'a plus lieu d'être publié depuis que le portail d'accès est
passé dans le polyfill : c'est lui qui pose l'identité. Et une application qui nomme
sa propre identité est exactement le geste qui inverse le modèle — il ne doit pas
exister d'appel publié vers lequel se tourner. Le harnais e2e, lui, joue plusieurs
identités sur une même page ; il y accède par le chemin interne, ce qu'un harnais a
le droit de faire et une application non.
- **`connectedUser`** est maintenant attendu DANS `ensureIdentity`. Ce n'était pas une
commodité : la suite applicative avait montré qu'une app devait l'attendre elle-même,
sinon une note qu'on venait de lui partager se lisait comme illisible. J'avais traité
le symptôme dans l'app d'exemple ; le défaut était côté bibliothèque. En amont, ouvrir
la session EST la connexion — aucune application n'attend un second appel.
Reste donc `configure({ … })`, plus `await ensureIdentity()` dont le site d'appel
survit à la migration : une application attendra toujours une session avant de rendre.
Le test étendu hier a fait son travail : les deux contrôles de contrat sont passés au
rouge sur `configureStoreRegistry`, `connectedUser` et `StoreRegistryDeps` dès que la
surface a bougé.
180 tests unitaires, e2e 40/40 (3,4 min) et applicatif 10/10 (0,8 min).
Deux mouvements de surface, aucun changement de comportement.
**`packages/client` → `packages/sdk`, `@ng-eventually/client` → `@ng-eventually/sdk`.**
« client » ne disait rien : ce paquet EST le SDK que l'application appelle, et c'est
tout ce qu'elle appelle. L'ancien nom reste comme mot-clé de recherche dans
`docs/source-layout-by-fate.md` et le tableau des paquets du README.
**Une seule entrée.** L'entrée `./polyfill` disparaît ; ses symboles applicatifs —
`configure`, `configureStoreRegistry`, `setCurrentUser`, `connectedUser` et leurs types
— vivent dans un bloc `POLYFILL-ERA` de `src/index.ts`.
Ce que la seconde porte portait mérite d'être nommé avant d'être retiré : *ce qu'on
importe de ce chemin est exactement ce qu'on supprimera à la migration*. Une seule
porte perd ce signal — rien à la ligne d'import ne distingue `configure`, qui part, de
`docs`, que le vrai SDK remplace sur place. Trois choses le portent désormais : le bloc
lui-même, l'inventaire d'exports de `docs/api-contract.md` (épinglé par
`test/vocabulary.test.ts`, donc il ne peut pas rancir en silence), et le contrôle de
vocabulaire sur les noms publiés.
**Six symboles quittent la surface au passage**, et la fusion est ce qui a rendu le
choix visible plutôt qu'hérité :
- `getConfig` / `getStoreRegistryDeps` — câblage interne, atteint par
`shared-wallet/bootstrap` ;
- `resetConfig` / `resetStoreRegistry` / `resetCaps` — remises à zéro de test, atteintes
par leur chemin interne, ce qui est leur raison d'être ;
- le `share` direct — `inbox.share` a toujours été la même fonction, et la publier deux
fois brouillait la frontière qu'elle servait à marquer.
Corrections d'affirmations fausses trouvées en chemin : le contrat annonçait `isNuri` /
`hasReadCap` sur la porte SDK alors qu'ils ne sont plus exportés depuis le passage au
permissif en entrée (`NuriLike` validé à la porte) ; le README du paquet documentait
`capFor`, `shareCap`, `getCaps` et `publishRepoLink`, dont aucun n'existe ; et le README
de l'app d'exemple affirmait que la suite e2e la pilote, ce qui reste à faire.
179 tests unitaires, typecheck bibliothèque / exemple / harnais, e2e 42/42 contre le
broker en ligne — mesuré une fois après le renommage, une fois après la fusion.