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.
This commit is contained in:
+6
-6
@@ -125,7 +125,7 @@ public/protected/private stores — on top of one shared wallet.
|
||||
account→document trust root, which is why every untrusted value that reaches its
|
||||
SPARQL is escaped (see SPARQL hardening below). It makes identity resolution
|
||||
cross-device: another device opening the same wallet reads the same pointer → the
|
||||
same doc-shim → the same accounts.
|
||||
same doc-shim → the same virtualUsers.
|
||||
- **Per-entity documents + per-scope index.** `createEntityDoc(id, scope)`
|
||||
makes a dedicated document for one entity (mirrors the target, where each entity
|
||||
is its own document/repo with a future inbox) and appends its NURI to the
|
||||
@@ -166,7 +166,7 @@ Virtual user (id)
|
||||
|
||||
So the 3 native stores (public/protected/private) are present, but emulated: each
|
||||
"store" is an index document
|
||||
(`AccountRecord.{docPublic,docProtected,docPrivate}`) that lists the NURIs of the
|
||||
(`VirtualUserRecord.{docPublic,docProtected,docPrivate}`) that lists the NURIs of the
|
||||
per-entity documents in that scope. It is not a physical native store.
|
||||
|
||||
Everything is physical in one place: the 3 index documents, every per-entity
|
||||
@@ -200,7 +200,7 @@ store-id:
|
||||
blocker, [`migration-guide.md`](./migration-guide.md)). At migration each scope
|
||||
resolves to the user's real per-scope store — the change is in this function,
|
||||
and the consumer application is unchanged.
|
||||
- **`walletInbox(id)` / `openDocumentInbox(doc)`** — an inbox BELONGS to someone. The
|
||||
- **`userInbox(id)` / `openDocumentInbox(doc)`** — an inbox BELONGS to someone. The
|
||||
first is a user's own inbox (where Links arrive), the second a DEDICATED inbox for
|
||||
one of its documents, opened on demand by its **owner only** (ownership read from the
|
||||
Store branches — a received cap is not ownership, and a recipient must not be able to
|
||||
@@ -489,7 +489,7 @@ emulates the inbox on the shared wallet:
|
||||
|
||||
### An inbox BELONGS to a virtual user (2026-07-30)
|
||||
|
||||
`storeRegistry.walletInbox(id)` resolves — creating on first sight — the inbox
|
||||
`storeRegistry.userInbox(id)` resolves — creating on first sight — the inbox
|
||||
document of one virtual user, recorded in the doc-shim under `shim:docInbox` and
|
||||
read by its own query (so an account written before this existed still resolves).
|
||||
The asymmetry that matters:
|
||||
@@ -596,7 +596,7 @@ specific document (the `anchor` arg) is governed by it — ungoverned docs (the
|
||||
mono-store default, no cap declared) flow through unchanged. This mirrors the target
|
||||
broker/verifier, which refuses a write without the document's write cap.
|
||||
|
||||
## Identity store (`shared-wallet/accounts.ts`)
|
||||
## Identity store (`shared-wallet/virtualUsers.ts`)
|
||||
|
||||
The real NextGraph login (redirect to the broker, opening the single shared
|
||||
wallet) is perceived as a technical access barrier (see the login
|
||||
@@ -614,7 +614,7 @@ identity id the consumer application relays to it:
|
||||
open underneath. The real logout lives elsewhere (hidden in the consumer
|
||||
application's settings/debug), because it forces a new redirect.
|
||||
- Framework-agnostic: no React, no DOM beyond an optional injected
|
||||
`AccountStorage` (a `window.localStorage`, a test fake, or `null` for SSR). The
|
||||
`VirtualUserStorage` (a `window.localStorage`, a test fake, or `null` for SSR). The
|
||||
React `Context`/`Provider` stays in the consumer application. `normalizeId`
|
||||
(case-insensitive, optional leading `@` stripped, trimmed) is the pure
|
||||
normalizer, reusable as the shim key normalizer.
|
||||
|
||||
Reference in New Issue
Block a user