test(@multibrowser): le compteur converge AUSSI côté inscrit B (Q4) + caveat polling

Q4 — le scénario réactif ne vérifiait la convergence de participantCount que du
POV du PROPRIÉTAIRE A. Ajout des assertions symétriques côté INSCRIT B : après que
B rejoint, B voit le compteur passer à 1 réactivement (sans reload) ; après
désinscription, il revient à 0 côté B. Le doc public mis à jour par A (seul
matérialiseur) se propage via le broker jusqu'au doc_subscribe de B. Ferme « A et
B ont-ils tous les deux le compteur incrémenté ? » — oui. Vert wallet frais (16 steps).

Doctrine : nouveau caveat bdd-testing/caveat_poll-broker-reads — asserter les
lectures broker en POLLING borné (lag de sync ~1s), jamais en one-shot ; vaut pour
les lectures à froid (reconnexion) et la propagation réactive (compteur
cross-navigateur). Consolide la doc-debt des features touchées cette session.

Non couvert (suivi) : observateur TIERS (découverte publique, flaky).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-07-08 14:09:21 +02:00
parent c07150cb27
commit 517045c257
2 changed files with 41 additions and 0 deletions
@@ -0,0 +1,36 @@
---
type: caveat
summary: Les lectures @data/@multibrowser contre le broker réel convergent avec un lag de sync (~s) — asserter en POLLING borné, jamais en lecture unique ; une lecture one-shot course la fenêtre de sync/réactivité et flake. Vaut pour les lectures à froid (reconnexion) ET la propagation réactive (compteur cross-navigateur).
last_checked: 2026-07-08
---
# Asserter les lectures broker en polling, pas en one-shot
Contre le **broker réel** (@data, @multibrowser), une donnée écrite n'est pas
lisible **instantanément** par un lecteur : il y a un **lag de sync** (le CRDT du
doc doit se propager/s'ouvrir avant qu'une lecture ancrée le rende). Mesuré : une
donnée fraîche se lit typiquement en **~1 s**, parfois après la 1ʳᵉ tentative.
**Piège** : une assertion qui lit **une seule fois**, tout de suite, **course
cette fenêtre** et échoue de façon **flaky** — alors que le comportement applicatif
est correct (l'UI réelle est **réactive** : `doc_subscribe` fait converger l'écran
en quelques secondes). Un test qui lit one-shot mesure le lag, pas le bug.
**Règle** : asserter en **POLLING borné** (re-lire en boucle jusqu'à ~10-15 s max)
la condition attendue. C'est ce que fait déjà la matérialisation côté steps ; toute
NOUVELLE assertion de lecture doit suivre le même pattern.
Deux familles concernées, toutes deux vérifiées :
- **Lecture à froid / reconnexion** — une session verifier fraîche (page fraîche,
nouveau login) relit ses propres docs après ouverture de repo ; la 1ʳᵉ lecture
peut rendre 0, la suivante les données. Voir `event/reconnexion-meme-identite`
(les 3 `Then` de la page fraîche pollent) et `event/steps/data/reconnexion.steps.ts`.
- **Propagation réactive cross-navigateur** — un compteur écrit par le propriétaire
se propage au `doc_subscribe` d'un autre navigateur ; asserter « passe à {int}
sans reload » en attendant la convergence. Voir le scénario réactif de
`event/e2e-multibrowser.feature` (POV A **et** B).
Ce caveat porte sur **comment écrire les assertions** contre le broker — pas sur
les internes NextGraph (lag/sync/ouverture de repo), qui vivent dans le repo
`@ng-eventually/client`. Voir aussi [[caveat_wallet-bloat-hang]] (autre source de
flakiness @data : le profil gonflé qui fait hanger les requêtes ancrées).
@@ -72,11 +72,16 @@ Fonctionnalité: Validation e2e multi-navigateurs des nouvelles features (T02.f)
Quand le navigateur "B" s'inscrit à l'événement "Apéro réactif"
Alors sans recharger, le compteur de participants réactif dans "A" pour "Apéro réactif" passe à 1
Et le navigateur "A" affiche un participant "inconnu" pour "Apéro réactif"
# Convergence symétrique côté inscrit : B voit aussi le compteur à 1 réactivement
# (le doc public de l'événement mis à jour par A se propage via le broker vers B).
Et sans recharger, le compteur de participants réactif dans "B" pour "Apéro réactif" passe à 1
# Option B symétrique : B se désinscrit → A (propriétaire) matérialise le
# marqueur "leave" depuis l'inbox et RECALCULE participantCount sur SON PROPRE
# doc → le compteur repasse à 0 côté A, SANS reload ni action de A.
Quand le navigateur "B" se désinscrit de l'événement "Apéro réactif"
Alors sans recharger, le compteur de participants réactif dans "A" pour "Apéro réactif" passe à 0
# Convergence symétrique côté inscrit après désinscription : B voit aussi 0.
Et sans recharger, le compteur de participants réactif dans "B" pour "Apéro réactif" passe à 0
Scénario: Un navigateur découvre l'événement public publié dans l'autre
Étant donné un navigateur "A" avec le wallet partagé