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:
@@ -29,7 +29,7 @@ import {
|
||||
docs,
|
||||
subscribeDoc,
|
||||
subscribeDocs,
|
||||
readModel,
|
||||
readUnion,
|
||||
inbox,
|
||||
storeRegistry,
|
||||
useShape as libUseShape,
|
||||
@@ -39,11 +39,11 @@ import {
|
||||
// application must not — but through the internal path, never the published entry.
|
||||
// `storeRegistry` above is the app-facing slice; these are the shim internals.
|
||||
import * as registryInternals from "../src/shared-wallet/account-registry";
|
||||
import * as accounts from "../src/shared-wallet/accounts";
|
||||
import * as virtualUsers from "../src/shared-wallet/virtual-users";
|
||||
import { isNuri } from "@ng-eventually/client";
|
||||
import type { Nuri, ShapeObservable, ShapeQuery } from "@ng-eventually/client";
|
||||
|
||||
const { IdentityStore } = accounts;
|
||||
const { IdentityStore } = virtualUsers;
|
||||
|
||||
/**
|
||||
* The Playwright boundary. Every NURI reaching this harness crosses the bridge as
|
||||
@@ -131,7 +131,7 @@ configureStoreRegistry({
|
||||
|
||||
const state: { status: string; error?: string } = { status: "connecting" };
|
||||
|
||||
// Identity store over the iframe's localStorage (the real AccountStorage).
|
||||
// Identity store over the iframe's localStorage (the real VirtualUserStorage).
|
||||
const identity = new IdentityStore(
|
||||
typeof window !== "undefined" && window.localStorage ? window.localStorage : null,
|
||||
);
|
||||
@@ -293,7 +293,7 @@ const identity = new IdentityStore(
|
||||
docNuris.push(d);
|
||||
}
|
||||
const toRead: Nuri[] = includeBad ? [...docNuris, "did:ng:o:definitely-not-a-real-doc-xyz"] : docNuris;
|
||||
const subjects = await readModel.readUnion(toRead);
|
||||
const subjects = await readUnion(toRead);
|
||||
return { docNuris, subjectCount: subjects.length, subjects };
|
||||
},
|
||||
/**
|
||||
@@ -309,9 +309,9 @@ const identity = new IdentityStore(
|
||||
setCurrentUser("owner-O");
|
||||
getCaps().open(doc, "protected");
|
||||
setCurrentUser("someone-else");
|
||||
const asStranger = await readModel.readUnion([doc]);
|
||||
const asStranger = await readUnion([doc]);
|
||||
setCurrentUser("owner-O");
|
||||
const asOwner = await readModel.readUnion([doc]);
|
||||
const asOwner = await readUnion([doc]);
|
||||
resetCaps();
|
||||
setCurrentUser(null);
|
||||
return { strangerCount: asStranger.length, ownerCount: asOwner.length };
|
||||
@@ -382,9 +382,9 @@ const identity = new IdentityStore(
|
||||
async inboxPostRead(id: string, payloadA: unknown, payloadB: unknown) {
|
||||
// The target must be that user's OWN inbox, not an arbitrary document: you may
|
||||
// deposit into anyone's, you may only read your own. Establishing the identity
|
||||
// FIRST is what makes `walletInbox` resolve (and file) that user's inbox.
|
||||
// FIRST is what makes `userInbox` resolve (and file) that user's inbox.
|
||||
setCurrentUser(id);
|
||||
const target = await storeRegistry.walletInbox(id);
|
||||
const target = await storeRegistry.userInbox(id);
|
||||
await inbox.post(target, { payload: payloadA, from: null, ts: 1000 });
|
||||
await inbox.post(target, { payload: payloadB, from: null, ts: 2000 });
|
||||
const deposits = await inbox.read(target);
|
||||
@@ -398,7 +398,7 @@ const identity = new IdentityStore(
|
||||
// Watching an inbox is READING it continuously, so the watcher stays connected
|
||||
// for the whole probe — including across `inboxWatchDeposit`.
|
||||
setCurrentUser(id);
|
||||
const target = await storeRegistry.walletInbox(id);
|
||||
const target = await storeRegistry.userInbox(id);
|
||||
const rec = { fires: 0, lastLen: -1, unsub: () => {}, target };
|
||||
(window as any).__sdk._inboxWatch = rec;
|
||||
rec.unsub = inbox.watch(target, (deposits) => {
|
||||
@@ -556,7 +556,7 @@ const identity = new IdentityStore(
|
||||
} catch (e: any) {
|
||||
rawRowCount = -2; // threw (e.g. RepoNotFound / InvalidNuri)
|
||||
}
|
||||
const subjects = await readModel.readUnion(listed.length ? listed : [asNuri(entityNuri)]);
|
||||
const subjects = await readUnion(listed.length ? listed : [asNuri(entityNuri)]);
|
||||
const markers: string[] = [];
|
||||
for (const subj of subjects) {
|
||||
for (const vals of Object.values(subj.props)) {
|
||||
@@ -840,7 +840,7 @@ const identity = new IdentityStore(
|
||||
setCurrentUser(ownerId);
|
||||
const deposits = await inbox.read(ownerInbox);
|
||||
// The address is machinery: it must not surface among the document's properties.
|
||||
const subjects = await readModel.readUnion([doc]);
|
||||
const subjects = await readUnion([doc]);
|
||||
const props = Object.keys(subjects[0]?.props ?? {});
|
||||
setCurrentUser(null);
|
||||
return {
|
||||
@@ -859,7 +859,7 @@ const identity = new IdentityStore(
|
||||
// the recipient's durable Links would grow run after run on a persistent wallet,
|
||||
// making every later `connectedUser()` re-apply a longer and longer history.
|
||||
setCurrentUser(friendId);
|
||||
const friendInbox = await storeRegistry.walletInbox(friendId);
|
||||
const friendInbox = await storeRegistry.userInbox(friendId);
|
||||
|
||||
setCurrentUser("owner-O");
|
||||
const doc = await docs.docCreate(s.session_id, "Graph", "data:graph", "store", undefined);
|
||||
|
||||
Reference in New Issue
Block a user