Commit Graph

4 Commits

Author SHA1 Message Date
Sylvain Duchesne f378c71739 docs: sept affirmations sur NextGraph requalifiées à la source
Lot F de la revue adverse. Chaque affirmation relue dans `nextgraph-rs` par symbole avant
d'être réécrite ; aucune ne s'est révélée exacte.

- `AddLink` / `RemoveLink` / `RepoLinkV0` étaient présentés comme **implémentés**. Leurs
  arms de vérificateur sont des `Ok(())`, là où celui d'`AddRepo` fait un vrai travail, et
  rien ne les construit. Le tableau dit désormais « déclaré, stubbé », et la conclusion qui
  en déduisait « le registre existe, seule la livraison manque » est corrigée : **les deux
  bouts** sont déclarés-et-stubbés.
- La table `inboxes` était dite « reconstruite vide à chaque session » — elle est
  repeuplée au chargement, et la clé privée d'inbox est persistée par repo. L'argument de
  sécurité qui s'appuyait dessus repose maintenant sur le bon motif : la table est **par
  vérificateur**, pas éphémère.
- La citation de « `doc_create` laisse `inbox: None` » pointait un constructeur réservé aux
  tests ; re-ciblée sur le chemin de production.
- `ExtObjectGet` était dit « le seul » primitif accessible à un non-membre et exigeant les
  clés : il y en a trois, et sa structure n'a aucun champ de clé.
- L'en-tête de `public-store.ts` était marqué **VERIFIED** alors qu'il repose sur un
  commentaire de doc, et la condition qu'il citait (« si les brokers pairs l'autorisent »)
  disparaissait de la conclusion. Requalifié en **pari**, condition rétablie.
- Deux sur-restrictions corrigées (ce qu'écrit le traitement d'un `ContactDetails`, et le
  prétendu « miroir 1:1 » de `NuriV0`, qui a dix champs).

**Sur la grammaire du ReadCap, une correction de MA correction.** J'avais écrit que la
forme `{target}:r:{cap}` était notre invention. Faux : le segment `r:` et son encodage sont
ceux d'amont, et l'auteur de NextGraph l'a énoncé. Ce qui est établi est plus étroit —
aucun parseur amont n'accepte aujourd'hui un NURI de repo qui le porte, et le segment est
produit comme valeur de champ. J'avais conclu d'une implémentation absente à ce que la
cible ferait, ce que la doctrine du projet interdit nommément. Seule « P1b remplace la
valeur, pas la forme » est corrigée, requalifiée en **pari**.

**Et la surface ne publie plus de type que personne n'utilise.** `export * from
"./model/types"` publiait huit types en bloc ; c'est une liste nommée de six. `ReadCap`
sort — aucune signature publiée ne le prend ni ne le rend, seules deux fonctions privées
de `inbox.ts` s'en servent — et `InboxScope` aussi. Un type n'est publié que si une
signature publiée l'utilise.

197 tests, 0 échec ; les trois typechecks propres ; `lint` sans erreur.
2026-08-10 12:09:20 +02:00
Sylvain Duchesne 0eb25286c8 refactor: renommer client → sdk, et fusionner les deux portes en une
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.
2026-08-07 11:16:57 +02:00
Sylvain Duchesne 0832338201 feat: un document en store public sert son ReadCap, une référence nue suffit
Le modèle amont est explicite dans `PublicRepoLinkV0` : le lien ne porte AUCUN
`read_cap`, et son commentaire dit pourquoi — *"The latest ReadCap of the branch
will be downloaded from the outerOverlay, if the peer brokers listed below allow
it […] the public site are served differently by brokers"*
(engine/net/src/types.rs:5098). La clé n'est pas remise par un émetteur : elle est
donnée par le réseau à qui la demande, parce que le broker a épinglé l'overlay
externe (`expose_outer`).

La bibliothèque refusait jusqu'ici la forme sans cap quel que soit le store. Sûr
dans le bon sens, mais une application ne pouvait pas exprimer « fais circuler, la
référence suffit » — le seul acte que le modèle rend gratuit — et son unique
contournement était de distribuer la clé, ce qui détruit la confidentialité
composable.

`emulated-verifier/public-store.ts` émule le mécanisme SANS toucher à la garde. La
possession reste l'unique critère : un document public est lisible non par exception
mais parce que son cap est *obtenable*. Chaque porte de lecture demande d'abord
(`readUnion`, `docs.sparqlQuery`, `ensureRepoOpen`, `documentInboxAddress`), puis le
chemin ordinaire s'applique.

Lire n'est pas écrire. Ce que le store sert est un droit de LECTURE :
`learnFromPublicStore` le classe à part et `assertMayWrite` refuse l'écriture
dessus. Sans cela une référence nue achetait une écriture, ce qu'aucun store amont
n'accorde.

Autres conséquences :

- `recordInPublicStore` (marquer + frapper) devient `markInPublicStore` (marquer).
  Frapper un second cap à côté de celui qu'on vient de télécharger donnerait deux
  clés différentes le jour où la constante devient un secret.
- `hasCap` quitte la porte polyfill : il se lisait « ai-je le droit de lire ceci ? »
  et un document public y répondait `false` jusqu'à ce qu'on demande son cap. Aucun
  appelant hors des tests.
- Les tests cross-user ne font plus traverser de cap par une variable JS : Bob
  n'obtient que la référence nue, comme une vraie application.

Écarts documentés plutôt que masqués : le pari sur un modèle DÉCLARÉ (`expose_outer`
est câblé à `false` côté client et `ExtTopicSyncReq` est `unimplemented!()`), la
découverte limitée à ce qu'on sait déjà nommer, `useShape` qui n'a pas d'await à
dépenser, et l'absence de `locator`.

179 tests unitaires, e2e 42/42 contre le broker en ligne.
2026-08-06 19:55:32 +02:00
Sylvain Duchesne 7672915bb9 docs: ce qu'un NURI transporte, et les quatre besoins d'un lien
Une discussion de conception a calé plusieurs fois sur une séparation supposée
entre « un NURI » et « un lien ». Elle n'existe pas, et l'avoir crue est ce qui a
fait livrer un `linkTo` faux sur trois points à la fois.

`NuriV0` porte exactement ce qu'un lien porte — `target`, `overlay`,
`access: Vec<NgAccessV0>`, `locator` — et `NgLinkV0` en est la forme structurée.
La vraie question n'est donc pas « NURI ou lien » mais ce qu'on met dans
`access` et `locator`. Nuance qui compte pour tout ce qui s'imprime : le TYPE a
tous les emplacements, la GRAMMAIRE de chaîne ne les expose pas tous.

`access` est une LISTE de formes d'accès (`ReadCap | Token | ExtRequest | Key |
Inbox | Topic`), donc une liste VIDE est un état légitime et courant : la
référence NOMME sa cible et n'accorde rien.

D'où les quatre besoins, chacun avec ce que la référence doit porter : nommer
(access vide), donner à lire (+ ReadCap, irréversible), faire trouver un
document public (overlay/locator, aucune clé), joindre depuis ailleurs
(locator, sans quoi un inconnu n'ouvre rien).

Trois confusions nommées parce que chacune a été faite ici : « sans clé » ne
veut pas dire « public » ; nommer n'est pas lire et c'est l'acte PAR DÉFAUT
(ce que notre test central prouve déjà) ; rien n'est vérifié à l'accès, donc
une référence ne peut pas être neutre en droits — ce qu'on y met EST
l'autorisation, et un lien diffusé ne se révoque pas.

Et la divergence la plus lourde, qui n'était consignée nulle part : publier
signifie ICI distribuer une clé, alors qu'en amont un document public est
lisible parce que son STORE l'est et que les brokers le servent. L'émulation
est trop stricte, pas inversée — elle sous-accorde — mais un consommateur ne
doit pas en conclure que publier est un acte de distribution de clé, ni
attendre quoi que ce soit de per-lecteur sur un document public.
2026-08-06 12:52:35 +02:00