Commit Graph

7 Commits

Author SHA1 Message Date
Sylvain Duchesne b62bfe1e63 refactor: ouvrir une inbox est un acte de registre, et deux invariants rendus explicites
`openDocumentInbox` passe du shim aux registres de branche. Ce qu'il fait est de
la comptabilité du verifier : vérifier la propriété, enregistrer la moitié
lecture sur la branche User, publier l'adresse. Seule la création du document
support relève du shim, et elle est appelée, pas hébergée. En amont l'acte
équivalent est générer une paire de clés et commiter `AddInboxCap`.

Deux risques de migration signalés par le contrat interne, transformés en
invariants vérifiés plutôt que supposés :

- **Le couple `(document, inbox)`** est un littéral RDF séparé par une espace là
  où l'amont a une structure typée (`AddInboxCapV0 { repo_id, overlay, priv_key }`).
  L'espace est sûr parce qu'un NURI n'en contient pas — alphabet base64url et
  segments `:` — mais c'était une propriété implicite. `encodeInboxCap` la
  vérifie désormais : un découpage erroné classerait une inbox sous un document
  tronqué et perdrait les dépôts sans erreur, la classe de panne que ce chemin a
  déjà payée une fois.
- **Le namespace réservé** garantit qu'aucun identifiant utilisateur ne peut s'y
  loger — sauf que `normalizeId` est injecté par le consommateur et que le
  défaut de la bibliothèque ne fait que trimmer. Une collision ne serait pas
  cosmétique : un utilisateur se retrouverait sur un compte d'infrastructure, à
  lire et écrire des documents qui ne sont pas les siens. Vérifié à la
  normalisation, avec un test qui simule un `normalizeId` hostile.

160 tests unitaires, typecheck src/test/e2e vert, e2e 40/40 contre le broker.
2026-08-04 15:02:29 +02:00
Sylvain Duchesne 107f9d1633 refactor(vocabulary): les noms publiés parlent la langue de la cible, et un test le tient
La correction de nomenclature du 2026-07-30 — en amont un *wallet* n'est qu'un
trousseau, ce qui possède des stores est un **user** (un *site*) — s'était faite
à la main. `walletInbox` y a échappé et a vécu des semaines, en faisant des
dégâts : le nom rendait « une inbox par wallet » évident, masquant qu'un user en
a **deux** en amont (repos de store public et protected, les deux seuls
`AddInboxCap` du moteur). Une discipline appliquée à la main en oublie un ; un
test non.

D'où `test/vocabulary.test.ts` : tout nom publié est bâti sur des mots que la
CIBLE emploie — vérifiés dans `nextgraph-rs` — ou porte un marqueur disant
POURQUOI il n'existe qu'ici (`virtual`, `physical`, `shim`, `emulated`,
`polyfill`), ce qui dit aussi quand il disparaît. Un échec n'est pas « renommer
pour faire passer le test », c'est une question : la cible a-t-elle un mot pour
ça ? la chose n'existe-t-elle qu'ici ? le mot est-il vraiment de la glue ?

Ce que le test a trouvé, et les réponses :

- `walletInbox` → `userInbox`, avec l'écart de cardinalité écrit noir sur blanc
  plutôt que caché par le nom.
- `accounts` / `AccountRecord` / `AccountStorage` → `virtualUsers` /
  `VirtualUserRecord` / `VirtualUserStorage`, module `accounts.ts` →
  `virtual-users.ts`. « account » n'est pas de la cible : c'est notre mot pour
  l'utilisateur virtuel, et le marqueur le dit désormais.
- `readModel` → la fonction `readUnion`, exposée directement. « model » n'était
  ni de la cible ni de la glue, et le namespace ne tenait qu'une fonction.
- Le reste était du vocabulaire légitime à déclarer (`subject`, `base`,
  `schema`, `connected`, le modèle réactif de l'ORM).

Corrigé au passage, sur signalement du contrat interne : l'en-tête d'`open-repo`
justifiait son correctif par un mécanisme que le source contredit. Un repo absent
de `self.repos` lève bien `RepoNotFound`
(`engine/verifier/src/request_processor.rs:264,269`). Les 0 lignes observées
viennent d'ailleurs — `Verifier::load` repeuple `self.repos` depuis le stockage
sur un profil persistant (`verifier.rs:535-560`), et notre propre `readDoc`
attrape toute erreur et rend `[]`. Le correctif est bon, le diagnostic écrit à
côté ne l'était pas.

159 tests unitaires, typecheck src/test/e2e vert, e2e 40/40 contre le broker.
2026-08-04 14:35:01 +02:00
Sylvain Duchesne e01a8dbab1 refactor(layout): séparer les registres de branche du shim
`store-registry.ts` portait deux destins dans un seul fichier de 1379 lignes.
`emulated-verifier/branch-registers.ts` prend les compartiments durables —
registre de caps de branche Store (`AddRepo`), registre de Links de branche User
(`AddLink`), enregistrements d'inbox (`AddInboxCap`), adresses de branche Header
— chacun nommant son mécanisme natif. Ils émulent la comptabilité du VERIFIER et
survivent conceptuellement : à la migration le natif les reprend, seule notre
représentation RDF disparaît.

`shared-wallet/account-registry.ts` garde le shim proprement dit — indirection
pointeur → doc-shim, résolution et provisionnement des comptes, cache. Aucun
pendant amont, s'évapore en entier.

Les imports croisés entre les deux sont délibérés et visibles : un registre a
besoin du shim pour savoir À QUI il est, le shim classe la structure d'un user au
moment où il le résout. Tout l'usage est en corps de fonction, donc le cycle de
modules est inerte à l'évaluation.

157 tests unitaires, typecheck src/test/e2e vert, e2e 40/40 contre le broker.
2026-08-04 14:09:06 +02:00
Sylvain Duchesne 36c0148750 refactor(layout): extraire le magasin d'injection vers shared-wallet/bootstrap
L'entrée publique `/polyfill` portait le magasin d'injection (le `ng` injecté,
les dépendances du registre, QUI est connecté, le singleton `CapRegistry`). Tout
module interne l'importait donc pour atteindre la config — ce qui faisait de
l'entrée une dépendance du code qu'elle publie, avec les cycles
`polyfill` <-> `connect` et `polyfill` <-> `inbox`.

Le magasin rejoint `shared-wallet/` : rien n'est injecté en amont, l'app importe
le SDK et « qui suis-je » est la session — il n'y a pas de relais d'utilisateur
courant parce qu'un wallet a exactement un user. Ce module est la forme de cette
absence, il s'évapore en entier à la migration.

L'entrée ne fait plus que ré-exporter. Plus aucun module interne n'importe
`polyfill`.
2026-08-04 13:51:56 +02:00
Sylvain Duchesne 0b37d17c2f docs: reprendre les citations après le rangement, et retirer le membre login fabriqué
Les deux contrats et la doctrine portent des centaines de citations `file:line`
vers `src/`. Le rangement par destin les périmait en bloc — 208 reprises (45
chemins `src/x.ts`, 163 mentions nues). Sans ça la réorganisation pourrissait
l'instrument même qui tient la discipline qu'elle sert.

Et un défaut relevé par le contrat interne, vérifié : `ng-proxy` fabriquait un
membre `login`. `@ng-org/web` n'expose aucune méthode de ce nom — zéro
occurrence dans les déclarations installées comme dans `sdk/js/lib-wasm/src/lib.rs`
— mais le proxy répondait une fonction au lieu d'`undefined`, laquelle plantait
à l'appel. C'était le seul endroit où ce wrapper ajoutait à la surface du SDK,
contre son propre en-tête.

157 tests unitaires, typecheck src/test/e2e vert.
2026-08-04 12:56:02 +02:00
Sylvain Duchesne cd096de2b0 refactor(layout): les portes non gardées en un seul module, mintCap chez le verifier
Trois extractions que le rangement par destin a rendues évidentes :

- `subscribePhysicalDoc` et `ensurePhysicalRepoOpen` rejoignent
  `shared-wallet/physical.ts`, qui devient l'API non gardée de la machinerie
  en un seul endroit — ce que sa propre doctrine réclamait (« des fonctions
  séparées, jamais des exemptions »). Elles vivaient jusqu'ici à côté de leurs
  jumelles gardées, à un import près d'être atteintes par erreur. Les deux
  cœurs sont désormais exportés sous un nom `Unguarded`, pour cet unique
  importateur.
- `mintCap` et sa valeur de remplacement quittent `model/nuri.ts` pour
  `emulated-verifier/caps.ts`. `model/` transcrit le vocabulaire d'adressage de
  la cible ; frapper une clé n'en fait pas partie — en amont le moteur frappe à
  la création du repo, et ensuite on cherche un cap dans ce qu'on détient ou on
  le reçoit. Sa présence dans le module modèle contredisait l'en-tête de ce
  module et logeait la seule valeur inventée de l'émulation dans le fichier qui
  se dit vocabulaire vérifié.

Un cycle est apparu au passage (`open-repo` ↔ `physical`) : résolu en faisant
appeler à `open-repo` le cœur non gardé plutôt que la porte de la machinerie.

157 tests unitaires, typecheck src/test/e2e vert.
2026-08-04 12:49:59 +02:00
Sylvain Duchesne 88914f50ae refactor(layout): ranger les modules par destin à la migration
Les 25 modules étaient à plat, nommés d'après ce qu'ils font mécaniquement
(`store-registry`, `read-model`, `reach`, `caps`). Rien dans l'arborescence ne
disait lesquels DEVIENDRONT le vrai SDK, lesquels tiennent lieu du travail que
le verifier fera nativement, et lesquels n'existent que parce qu'un wallet est
partagé — trois destins sans rapport.

Quatre dossiers, les deux fichiers d'entrée restant à la racine pour que
l'`exports` du paquet et le code du consommateur ne bougent pas :

- `model/` — le modèle d'adressage de la cible, transcrit : vocabulaire pur,
  pas d'I/O. Survit comme connaissance.
- `surface/` — ce que l'app touche, chaque symbole ayant un pendant cible
  documenté. Supprimé quand l'alias bascule ; le code de l'app est inchangé.
- `emulated-verifier/` — les doublures de ce que le verifier fait nativement :
  possession, dépôt des caps, frontière, non-livraison, traitement des inbox,
  registres de branche, ouverture de repo. **C'est le dossier où diverger du
  modèle est possible.** Le préfixe `emulated-` porte le sens : tient lieu de,
  jamais est — cette bibliothèque ne réside dans aucune couche de la cible,
  elle les référence.
- `shared-wallet/` — n'existe que parce qu'un wallet héberge toutes les
  identités. Aucun pendant, rien sur quoi s'aligner ; sa seule loi est de
  rester invisible depuis `surface/`. S'évapore, remplacé par rien.

`store-registry-api.ts` devient `surface/placement.ts` : il faisait déjà à la
main ce que la frontière de dossier fait structurellement — c'est la meilleure
preuve interne du bien-fondé de ce rangement.

Ce commit ne fait que déplacer et recâbler les imports (src, test, e2e). Les
scissions des modules à cheval suivent.

157 tests unitaires, typecheck src/test/e2e vert.
2026-08-04 12:46:44 +02:00