feat: un dépôt est traité vingt secondes après, sans attendre son destinataire

Un dépôt attendait la prochaine connexion de son destinataire — potentiellement
des heures. Un vrai NextGraph aura un service qui traite les inbox en continu ;
il n'existe pas. On l'émule : après une écriture dans une inbox, une échéance
unique de vingt secondes draine l'inbox DE LA CIBLE.

C'est une usurpation d'identité, possible seulement parce qu'un portefeuille
partagé détient toutes les identités virtuelles. Elle est acceptable parce que
l'application n'apprend rien de faux : elle observe que les dépôts finissent par
converger, ce qui restera vrai avec un vrai service. Ce qui ne doit pas fuir,
c'est le mécanisme.

Trois gardes, tenues par du code et non par des consignes.

Rien n'atteint la surface publiée : les exports sont épinglés par un test, et
publier ceci reviendrait à publier un appel qui traite l'inbox d'autrui — après
quoi il ne resterait rien du modèle de confidentialité.

Le drainage agit avec un détenteur EXPLICITE, jamais l'identité ambiante. Le
propriétaire vient d'un enregistrement de routage (shim:inboxOwner), et cet
identifiant est passé à chaque étape. C'était le vrai danger : readLinks et
myInboxes demandent getCurrentUser() au moment où elles s'exécutent, donc un
drainage lancé pendant la session d'Alice aurait classé les capacités de Bob
chez elle. Le test l'épingle — après le drainage, Alice n'a aucune capacité sur
le document concerné, et les deux Links sont bien chez Bob, durablement.

Et les échecs remontent au journal d'accès au lieu de disparaître. Une boucle
différée qui avale ses erreurs, c'est la famille retirée en 8c8ade7 et e32b6d0.

Coalescence : une seule échéance en attente par cible, et deux drainages d'une
même inbox ne se chevauchent jamais — processInbox écrit ce qu'il applique.

Limite assumée : si la page disparaît avant l'échéance, le dépôt attend la
prochaine connexion. C'est le comportement honnête d'une émulation qui tient la
place d'un service absent.
This commit is contained in:
Sylvain Duchesne
2026-08-16 15:17:49 +02:00
parent 9e7aeef269
commit 07dfe68473
12 changed files with 1082 additions and 60 deletions
@@ -24,6 +24,7 @@ import { resetPublicStoreFetches } from "../emulated-verifier/public-store";
import { setAccessLog } from "./access-log";
import { inspectOutbox } from "./outbox-log";
import { startConnect } from "../emulated-verifier/connect";
import { cancelScheduledInboxProcessing } from "../emulated-verifier/inbox-processor";
import { resetSharedWalletSession, sharedWalletSession } from "./session";
/**
@@ -217,6 +218,10 @@ export function getConfig(): EventuallyConfig {
export function resetConfig(): void {
cfg = null;
currentUser = null;
// Any deferred inbox drain still waiting goes with it: it would fire into a library that
// no longer has an `ng` to read or write with, and report a failure about a session that
// no longer exists. See `emulated-verifier/inbox-processor.ts`.
cancelScheduledInboxProcessing();
// The hand-over goes with it, for the same reason: it is made of the config's injected
// `init`, so leaving it behind would let a revived barrier delegate to the PREVIOUS
// application's SDK.