refactor(comments): retirer les raisonnements sur l'état de NextGraph du code app
Application de la règle qu'on vient de durcir : l'app IGNORE entièrement l'état d'implémentation de NextGraph. Le CODE était légitime — `inbox.readSynced` est une surface SDK exportée ; ce sont les JUSTIFICATIONS qui fautaient, en expliquant les choix par des internes du cœur. Réécrit en termes de CONTRAT : - registration.ts / FestipodDataContext : « barrier-gated read, le repo d'inbox n'est pas encore ouvert dans le verifier, un read ancré renverrait 0 » devient « `read` rend ce qui est connu localement maintenant, `readSynced` rend une fois les dépôts synchronisés visibles ; ce site a besoin du second parce qu'il lit depuis une session froide ». - ngBootstrap : « le verifier sérialise les créations » devient « `docCreate` est un aller-retour qui ne recouvre pas le suivant, donc le coût du seed croît LINÉAIREMENT avec le nombre de documents ». Le ~2s mesuré est conservé, mais explicitement comme une observation, pas comme un contrat. - entityWrites : description de lecture périmée (ORM fan-out, ngSet couplé au scope) remplacée par la vue réactive. La distinction read/readSynced vit désormais là où elle est légitime : knowledge_sdk-surface, avec le critère de choix (`read` dans une session qui observe déjà l'inbox, `readSynced` dès que la justesse dépend d'une session froide voyant le dépôt d'une autre identité). knowledge_context-internals cesse d'expliquer le fix par `ensureRepoOpen`/premier `State` et pointe le contrat. Laissé tel quel : `src/shared/support/hooks.ts` et les steps e2e — le harness de test connaît légitimement la plomberie ; la règle vise l'app. Et le « no cross-account fan-out » de FestipodDataContext, qui décrit le périmètre de l'app et non NextGraph. tsc : 0 erreur. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GbGgNEHRejVKoREvFuDFg
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
type: knowledge
|
||||
summary: Internal pitfalls of FestipodDataContext — currentUserId = a stable principal derived from the identifier, TWO id spaces joined through the normalized identifier (resolveParticipantUser / USER_PRINCIPAL_PREFIX), OPT-IN auto-seed (FESTIPOD_AUTO_SEED, OFF by default), Option-B derived participantCount (reliable at the owner's connection through a barrier-gated inbox read; single source = event.participantCount), session reset on identity change (overlay + caps), useShapeQuery instrumentation (spinner + timing) + identity-first logs, mutations that are no-ops in local mode despite the toast
|
||||
summary: Internal pitfalls of FestipodDataContext — currentUserId = a stable principal derived from the identifier, TWO id spaces joined through the normalized identifier (resolveParticipantUser / USER_PRINCIPAL_PREFIX), OPT-IN auto-seed (FESTIPOD_AUTO_SEED, OFF by default), Option-B derived participantCount (reliable at the owner's connection because it reads under the synced-view contract; single source = event.participantCount), session reset on identity change (overlay + caps), useShapeQuery instrumentation (spinner + timing) + identity-first logs, mutations that are no-ops in local mode despite the toast
|
||||
last_checked: 2026-07-27
|
||||
---
|
||||
|
||||
@@ -52,7 +52,7 @@ When it is enabled, the auto-seed fires if events AND users are both empty — *
|
||||
|
||||
## `participantCount` — derived and owned by the owner (Option B)
|
||||
|
||||
> ✅ **CORRECTED (2026-07-13).** The requirement is **"reliable at the owner's NEXT CONNECTION"** (the creator processes their inbox when they connect), NOT a live real-time cross-user notification. The bug was: the owner-materializer materialized **too early** (before the participant's deposit had synced) → read `active=0` → wrote 0 → **memoized that 0** → never re-processed. Fix: (1) a **barrier-gated inbox read** — `inbox.readSynced` (= `ensureRepoOpen(doc)` waits for the first `State`, THEN `read`, like `discovery.readIndex`) instead of `inbox.read`, so an already-synced deposit IS seen on connection; (2) the materializer fires **directly on connection** (`[ready, ownedKey]`), no longer only on a push; (3) `materializedCountRef` no longer locks in a premature 0 (its sole role = loop guard: only write when the derived value changes); (4) **the single source of the NUMBER = `event.participantCount`** (the `participantCount: 1` literal in `CreateEventScreen` is removed → it starts at 0; the display no longer computes a local number). Kept GREEN (on a fresh profile) by `event/e2e-multibrowser.feature` « Le compteur converge chez le propriétaire à sa prochaine connexion » (un-`@wip`'d). No polling ([[rule_no-broker-polling]]).
|
||||
> ✅ **CORRECTED (2026-07-13).** The requirement is **"reliable at the owner's NEXT CONNECTION"** (the creator processes their inbox when they connect), NOT a live real-time cross-user notification. The bug was: the owner-materializer materialized **too early** (before the participant's deposit had synced) → read `active=0` → wrote 0 → **memoized that 0** → never re-processed. Fix: (1) read under the **synced-view contract** — `inbox.readSynced` instead of `inbox.read`, so a deposit already synced by another identity IS seen from a cold session (the two differ by contract, see [[knowledge_sdk-surface]]); (2) the materializer fires **directly on connection** (`[ready, ownedKey]`), no longer only on a push; (3) `materializedCountRef` no longer locks in a premature 0 (its sole role = loop guard: only write when the derived value changes); (4) **the single source of the NUMBER = `event.participantCount`** (the `participantCount: 1` literal in `CreateEventScreen` is removed → it starts at 0; the display no longer computes a local number). Kept GREEN (on a fresh profile) by `event/e2e-multibrowser.feature` « Le compteur converge chez le propriétaire à sa prochaine connexion » (un-`@wip`'d). No polling ([[rule_no-broker-polling]]).
|
||||
|
||||
**Since Option B (2026-07-07)**: `participantCount` is no longer mutated in place by the participant. The flow is inbox-deposit → owner-materialization:
|
||||
- `joinEvent`/`leaveEvent` **no longer** write `participantCount` on the event's doc (that would be an isolation violation — the participant writing someone else's doc; NextGraph writes are membership-bound, with no append). The participant only writes their **own** participation doc (protected), then **deposits** a marker into the event's inbox (`depositRegistration` on join, `depositLeave` on leave, `src/shared/data/registration.ts`).
|
||||
|
||||
@@ -47,7 +47,7 @@ May assume: the SDK owns NURI construction and placement. May not assume: that t
|
||||
|
||||
## Inbox — delivery to an identity
|
||||
|
||||
**`inbox.post(targetInbox, { payload, from?, ts? })`** deposits into a document's inbox. `from` omitted defaults to the current identity; **`from: null` is an explicit anonymous deposit**, and naming another identity is rejected as a spoof. **`inbox.read(targetInbox)`** returns every `Deposit` (`{ from, payload, ts }`) sorted by ascending `ts`. **`inbox.watch(targetInbox, onDeposits)`** fires once on the initial state and again on every change; it returns an unsubscribe. **`inbox.readSynced`** is the read that waits for the document to be current. `inbox.materialize` is an alias of `read`.
|
||||
**`inbox.post(targetInbox, { payload, from?, ts? })`** deposits into a document's inbox. `from` omitted defaults to the current identity; **`from: null` is an explicit anonymous deposit**, and naming another identity is rejected as a spoof. **`inbox.read(targetInbox)`** returns every `Deposit` (`{ from, payload, ts }`) sorted by ascending `ts`. **`inbox.watch(targetInbox, onDeposits)`** fires once on the initial state and again on every change; it returns an unsubscribe. **`inbox.readSynced`** is the same read under a stronger contract: it returns once the deposits synced to that inbox are visible, where `read` returns what is known locally right now. **Choose by need, not by habit**: `read` inside a session already watching the inbox, `readSynced` whenever correctness depends on a cold session seeing another identity's deposit. `inbox.materialize` is an alias of `read`.
|
||||
|
||||
May assume:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user