fix(data): reset the read set + emulated caps on identity switch (isolation)
The shared-wallet stopgap keeps ONE React tree across a faux-logout + re-login under a different identifier (AccountContext.login only rewrites a localStorage id; AuthGate never remounts, no page reload). FestipodDataContext's by-need read set accumulates the current identity's scope docs and was never reset on identity change, so the PREVIOUS identity's PROTECTED docs (its participations) survived in the new identity's read set and leaked through the union read — the in-memory cap gate can't filter a doc it doesn't govern this session. Symptom: user B saw A's participation, and A's event surfaced on B's home (home = getUserEvents(currentUserId)). Treat every identifier change as a fresh session: a ref-guarded useEffect([username]) clears publicDocs/protectedDocs, resetCaps(), resetRegistryCache(), then bumps the read tick so the listing effect rebuilds the set bounded to the new identity. Isolation stays per-document/emulated; the reset only drops cross-identity carryover. Documented in knowledge_context-internals. Validated (@data, real broker): after an A→B switch, B does not participate and does not read A's participation; protected-isolation/read-filter/auth scenarios pass. tsc + build green; lib untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,12 @@ Un auto-seed se déclenche **uniquement hors production** (`process.env.NODE_ENV
|
||||
|
||||
`joinEvent`/`leaveEvent`/`updateEvent` **mutent directement** `ngEvent.participantCount` (`+1`/`-1`) — c'est un **cache** du nombre de `Participation`, pas une valeur recalculée. Il peut **désynchroniser** des objets `Participation` réels (ex. après un crash, un rejeu, ou la suppression partielle décrite dans [[caveat_participation-deletion]]). Ne pas s'y fier comme source de vérité du nombre de participants.
|
||||
|
||||
## Changement d'identité = session fraîche (isolation)
|
||||
|
||||
Le jeu de lecture par besoin (`publicDocs`/`protectedDocs`) **accumule** les docs de scope de l'identité courante (pour ne pas perdre un doc juste créé avant la re-liste). Or le stopgap wallet-partagé garde **un seul arbre React** au travers d'un faux-logout + re-login sous un **autre identifiant** (pas de rechargement — `AccountContext.login` ne fait que réécrire l'identifiant en localStorage, `AuthGate` ne remonte rien). Sans réinitialisation, **les docs PROTECTED de l'identité précédente (ses participations) survivent dans le jeu de lecture de la nouvelle identité et fuient** via la lecture union : le cap gate ne peut pas les filtrer quand le registre de caps (en mémoire) ne gouverne pas ce doc *cette* session (doc persisté d'un run antérieur, ou chargement frais où les caps sont vides). Symptôme observé : un utilisateur B voyait la participation de A (et l'événement de A apparaissait sur l'**accueil** de B, car l'accueil = `getUserEvents(currentUserId)`, cf. concept `app-architecture`).
|
||||
|
||||
**Règle** : traiter **tout changement d'identifiant** comme une session fraîche — un `useEffect([username])` (ref-gardé pour ne pas tirer au premier mount) vide `publicDocs`/`protectedDocs`, appelle `resetCaps()` + `resetRegistryCache()`, puis bump le read tick ; l'effet de listing reconstruit le jeu **borné à la nouvelle identité**. L'isolation reste par-document/émulée (concept `app-security`, [[knowledge_trust-model]]) ; ce reset ne fait que supprimer le report d'état inter-identités.
|
||||
|
||||
## Mutations no-op en mode local
|
||||
|
||||
En mode local/demo (`useLocalData`), `createEvent`/`joinEvent`/`leaveEvent`/`updateEvent` sont des **no-ops** (`console.log`, l'état ne change pas) — mais les écrans affichent quand même un **toast de succès** (« Tu participes »). UX potentiellement trompeuse : l'utilisateur croit s'être inscrit alors que rien n'a changé. Voir [[knowledge_data-modes]] pour le choix du provider selon le statut.
|
||||
|
||||
Reference in New Issue
Block a user