test(e2e): le parcours d'un primo-arrivant, et un harnais qui échoue au lieu de se pendre
Aucun parcours n'avait jamais marché le chemin d'un nouvel arrivant : tous pré-injectaient l'identifiant dans l'URL, ce qui fait résoudre l'identité sans jamais afficher la barrière. La suite était verte par-dessus un lien de téléchargement pointant sur un fichier que personne ne servait — et le serveur de test répondait la page HTML de l'application pour tout chemin inconnu, donc un fichier manquant ne POUVAIT pas échouer. Le nouveau parcours part d'un profil vide : barrière, téléchargement réel, import dans l'application portefeuille, saisie de l'identifiant, remise au broker, retour dans l'iframe. Il vérifie neuf points, dont celui qui compte — l'identifiant a survécu et l'identité rapportée est celle qui a été saisie. Le harnais, lui, se pendait au lieu d'échouer. Cause observée : le tuyau devtools de Chromium lâche et Playwright n'émet ni close ni disconnected, si bien que la suite bloquait dans son propre nettoyage sans imprimer ni résumé ni l'échec déjà en route. Toutes les attentes sont désormais bornées et nomment ce qu'elles attendaient ; vérifié en cassant délibérément une attente, et observé en conditions réelles — trois minutes et « gave up waiting for: alice to sign in » là où j'ai tué trois exécutions d'une heure ce matin. Deux exécutions simultanées ne se détruisent plus : verrou atomique sur le profil, et récupération d'un navigateur laissé par une exécution tuée. Le marqueur devient .user-consumed — il n'a jamais attesté d'une disponibilité, seulement qu'un lot avait déjà pris l'utilisateur de ce profil. Au passage, la destruction du profil dépendait du marqueur, écrit en FIN de lot : une exécution tuée avant laissait un profil que la suivante réutilisait, et héritait de sa casse. Elle dépend maintenant du profil. La suite applicative reste non mesurée sur cette machine : un conteneur en boucle de redémarrage recycle son interface réseau, et sept exécutions sur dix échouent sur le transport. Trois sont passées 21/21.
This commit is contained in:
@@ -14,13 +14,15 @@ They must stay apart, and the reason is not tidiness.
|
||||
|
||||
## Why they cannot be one call
|
||||
|
||||
`init()` hands the page over synchronously when the page is top-level, so nothing placed after it runs. The `barrier` must therefore appear **before** `init()`.
|
||||
`init()` starts the broker redirect as its first statement when the page is top-level, so anything the barrier needs to show must already be in place. The `barrier` must therefore appear **before** `init()`.
|
||||
|
||||
But an identity cannot connect before `init()` either: connecting reaches the application's session thunk, which only `init()`'s own callback resolves. Await the whole of sign-in before `init()` and it deadlocks; call it after and the `barrier` never appears.
|
||||
|
||||
The way out is that only *half* of it has that dependency. Settling is awaited by this package's `init()` wrapper before it delegates; connecting stays in the published call, awaited where a session exists.
|
||||
|
||||
**The ordering invariant is carried by the composition, not by a documented call order** — which is why an application must call this package's `init`, not the one it injected. A note telling callers to order two calls correctly is not a mechanism.
|
||||
**The invariant is carried by the composition from `init()` onwards** — which is why an application must call this package's `init`, not the one it injected: calling it settles the identity whether or not the published call has run.
|
||||
|
||||
It does **not** cover calling the published sign-in strictly first and awaiting it: the connection work it adds waits for a session only `init()` resolves, so it deadlocks in silence. Half an invariant carried by a mechanism, half still owed to the caller — and the half still owed fails silently, which is the worst kind.
|
||||
|
||||
## The failure this cost
|
||||
|
||||
|
||||
Reference in New Issue
Block a user