fix: la suite n'était pas hermétique, et deux tests ne pouvaient pas échouer
Second tour adverse sur le lot D. Trois trouvailles, et une erreur de diagnostic de ma part qui vaut d'être consignée. **La suite verte dépendait de l'ordre des fichiers.** `bun test isolation-active public-store` donnait 5 échecs quand chaque fichier seul était vert — donc un checkout de CI avec un autre ordre d'inodes livrait rouge. Deux causes distinctes : - le travail de connexion, lancé sans être attendu par `setCurrentUser`, débordait d'un fichier sur le suivant et armait l'émulation. `connectedUser` abandonne désormais dès que l'identité pour laquelle il a démarré n'est plus connectée — ce qui est de toute façon la bonne sémantique : en amont une session appartient à un utilisateur, et changer d'utilisateur est une autre session ; - et surtout **mon propre test de store public exposait le cap d'un document que personne ne détient** — un état que la bibliothèque ne produit jamais. Il ne passait que tant que l'émulation était désarmée. Alice crée sa note avant de l'exposer, maintenant. Balayage des 21 paires de fichiers : plus aucune ne pollue. **Le contrôle symétrique ajouté hier ne pouvait pas échouer.** « La liste d'Alice ne contient pas la note de Bob » lisait un rendu ANTÉRIEUR à l'écriture de Bob : l'attente de `showScope` était satisfaite au premier sondage par le marqueur déjà à l'écran, sans synchroniser quoi que ce soit. Alice écrit désormais une note APRÈS celle de Bob — `writeNote` attend son apparition, donc ce qui suit est un rendu qui post-date. Et le `.catch` qui avalait le délai d'attente est retiré : une liste qui ne se stabilise jamais est un échec à voir, pas une dégradation à absorber. **Le test anti-fork prouvait « pas le premier », pas « le canonique ».** Son minimum lexicographique était aussi le DERNIER élément, si bien qu'un choix positionnel — la faute exacte que ce test existe pour attraper — restait vert. Le minimum est déplacé au milieu ; vérifié par mutation, « prendre le dernier » le fait rougir. **Mon erreur de diagnostic.** J'ai cru trouver, sous la trouvaille d'ordre, une fuite entre utilisateurs — les caps d'Alice classés chez Bob — et je l'ai « reproduite ». Le repro était faux : son faux `ng` ignorait le sujet dans la requête d'inbox, donc l'inbox de Bob résolvait vers celle d'Alice. Une fois le faux corrigé, la fuite ne se reproduit plus, ni avec ni sans correctif. Le danger reste réel en lecture du code — trois chemins classent des caps plusieurs `await` après la garde qui les autorisait — donc `caps.holderKey`/`learnFor` le ferment par construction, mais les commentaires disent maintenant ce que c'est : un risque fermé, pas un défaut observé. 189 tests unitaires, e2e 40/40 et applicatif 12/12.
This commit is contained in:
@@ -403,6 +403,10 @@ async function assertOwnInbox(targetInbox: Nuri, op: string): Promise<void> {
|
||||
export async function read(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
const targetInbox = toNuri(targetInboxLike, "inbox.read");
|
||||
await assertOwnInbox(targetInbox, "read");
|
||||
// WHO this read belongs to, captured with the guard that authorised it — see the note
|
||||
// beside the filing below, and `caps.holderKey`.
|
||||
const owner = getCurrentUser();
|
||||
const ownerKey = getCaps().holderKey();
|
||||
const sid = await sessionId();
|
||||
// NOTE: cold-start repo opening is done by the COLD DIRECT readers that need it
|
||||
// (a cold reader that opens the repo before reading), NOT here — `inbox.watch`
|
||||
@@ -444,10 +448,19 @@ export async function read(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
// view that was empty for want of that cap re-read instead of staying stale.
|
||||
const delivered: Deposit[] = [];
|
||||
const links: ReadCap[] = [];
|
||||
// The ownership guard ran at entry; the filing happens several awaits later, and filing
|
||||
// resolves WHO is holding at that moment. So an application switching identity in the
|
||||
// gap could have this inbox's caps land in the NEW holder's ring. A hazard read off the
|
||||
// code, not a leak anyone reproduced — see `caps.holderKey`.
|
||||
//
|
||||
// Abandoning is the faithful answer: upstream an inbox is processed by ITS owner's
|
||||
// verifier, and switching user is another session. Nothing is lost — an inbox is not
|
||||
// consumed by reading, so the next connection under the right identity files them.
|
||||
const stillOwner = getCurrentUser() === owner;
|
||||
for (const d of deposits) {
|
||||
const cap = capOfPayload(d.payload);
|
||||
if (cap) {
|
||||
getCaps().learn(cap);
|
||||
if (stillOwner) getCaps().learnFor(ownerKey, cap);
|
||||
links.push(cap);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user