From 42dbfd0c346cabde29472f62baa2224dabd28eff Mon Sep 17 00:00:00 2001 From: Sylvain Duchesne Date: Mon, 27 Jul 2026 12:07:06 +0200 Subject: [PATCH] =?UTF-8?q?docs(concept):=20mod=C3=A8le=20d'inscription=20?= =?UTF-8?q?recal=C3=A9=20+=20l'inbox=20NextGraph=20suit=20aussi=20les=20ma?= =?UTF-8?q?nques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le brief inscriptions est réécrit sur le modèle reposé par le PO : tout est clés et URLs, sans notion d'appartenance. Le participant crée une Participation chiffrée, dépose son did (URI sans ReadCap) dans l'inbox de l'événement ; le créateur traite l'inbox automatiquement, déduplique sans pouvoir lire, et range la référence dans un Set porté par l'événement ; compteur = Set.size ; seules les connexions détiennent la clé et reconnaissent la personne. La dédup s'appuie sur un fait vérifié dans nextgraph-rs : l'overlay (segment `:v:` d'un NURI) est STORE-scopé, jamais document-scopé. Deux Participations d'une même personne portent donc le même `:v:`. Contrepartie actée dans le brief : ce `:v:` est un pseudonyme stable et permanent — c'est le MÊME bit d'information qui permet de dédupliquer sans lire et de tracer d'un événement à l'autre ; on ne peut pas garder l'un sans l'autre. Retiré du brief : le trilemme et la piste de dédup par vérification de signature. Ils reposaient sur une notion de membership importée de l'état courant du source Rust, où elle est un échafaudage inerte — erreur de méthode désormais consignée en règle. Règles : - rule_capture-nextgraph-findings (nouvelle) — toute connaissance établie sur le fonctionnement réel de NextGraph se consigne AU MOMENT de la découverte dans la doc du polyfill ; distinguer VÉRIFIÉ d'INFÉRÉ ; ne jamais déduire la forme cible de l'état courant du source. - rule_file-nextgraph-bugs → rule_nextgraph-inbox — l'inbox reçoit désormais DEUX familles : les dysfonctionnements ET les manques dont on a besoin. Une fiche de manque dit ce que le polyfill émule en attendant et ce qu'il faudra en RETIRER quand ça atterrit en amont : l'inbox devient un suivi de l'avancement de NextGraph, pas un simple bug-tracker. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_014GbGgNEHRejVKoREvFuDFg --- .project/concepts/data-layer/_overview.md | 8 +- .../brief_2026-07-20_attendance-set-model.md | 94 +++++++++++-------- .../rule_capture-nextgraph-findings.md | 33 +++++++ .../data-layer/rule_file-nextgraph-bugs.md | 23 ----- .../data-layer/rule_nextgraph-inbox.md | 42 +++++++++ 5 files changed, 137 insertions(+), 63 deletions(-) create mode 100644 .project/concepts/data-layer/rule_capture-nextgraph-findings.md delete mode 100644 .project/concepts/data-layer/rule_file-nextgraph-bugs.md create mode 100644 .project/concepts/data-layer/rule_nextgraph-inbox.md diff --git a/.project/concepts/data-layer/_overview.md b/.project/concepts/data-layer/_overview.md index 24751b0..2cb45b7 100644 --- a/.project/concepts/data-layer/_overview.md +++ b/.project/concepts/data-layer/_overview.md @@ -2,7 +2,7 @@ type: _overview summary: Comment Festipod persiste ses données via le SDK @ng-eventually/client — entités stockées comme documents par scope, écriture SPARQL directe + lecture par modèle union, stack SHEX, modes connected/demo, seed triggers: - keywords: [nextgraph, "@ng-eventually", union, readUnion, readEntities, SHEX, shape, scope, "@graph", NURI, sparql, seed, wallet, FestipodData, ngSession, ngGraph, bootstrap, document, entité, déconnexion, reconnexion, durabilité, outbox, SerializationError] + keywords: [nextgraph, "@ng-eventually", polyfill, union, readUnion, readEntities, SHEX, shape, scope, "@graph", NURI, overlay, ReadCap, WriteCap, cap-less, sparql, seed, wallet, FestipodData, ngSession, ngGraph, bootstrap, document, entité, déconnexion, reconnexion, durabilité, outbox, SerializationError] paths: ["src/shared/shapes/**", "src/shared/data/readEntities.ts", "src/shared/data/entityWrites.ts", "src/shared/context/NextGraphContext.tsx", "src/shared/context/FestipodDataContext.tsx", "src/shared/utils/ng*", "src/shared/data/seedData.ts"] --- @@ -23,6 +23,12 @@ Comment Festipod **persiste ses données** via NextGraph (P2P, local-first, chif ## Règles d'écriture - [[rule_document-per-entity]] — chaque entité = **son propre document** (par scope), jamais au niveau du store ; c'est ce qui rend l'isolation par-document du SDK possible +- [[rule_app-uses-sdk-surface-only]] — l'app se comporte comme si NextGraph était fini ; tout contournement vit dans le polyfill + +## Ce qui sort de ce repo (deux destinations, ne pas les confondre) + +- [[rule_capture-nextgraph-findings]] — une **connaissance** établie sur le fonctionnement réel de NextGraph → doc de référence du **polyfill**, au moment de la découverte +- [[rule_nextgraph-inbox]] — un **dysfonctionnement** de NextGraph, ou un **manque** dont on a besoin et qu'on émule en attendant → fiche dans `orm-tests/INBOX/`, qui suit l'avancement amont et dit quoi retirer du polyfill ## Pièges (lire avant de toucher aux suppressions / aux champs d'event) diff --git a/.project/concepts/data-layer/brief_2026-07-20_attendance-set-model.md b/.project/concepts/data-layer/brief_2026-07-20_attendance-set-model.md index 779228d..5d994df 100644 --- a/.project/concepts/data-layer/brief_2026-07-20_attendance-set-model.md +++ b/.project/concepts/data-layer/brief_2026-07-20_attendance-set-model.md @@ -1,62 +1,78 @@ --- type: brief -summary: Réaligner les inscriptions sur la vision initiale — objet participation auto-possédé (vérité) + Set curé cap-less sur l'événement + cap scellé aux connexions → compteur = refs distinctes, anonyme par défaut, personne ne désinscrit autrui. Supersede en partie l'Option-B (compteur muté + userId dans l'inbox). Dépend de l'alignement caps du polyfill. +summary: Modèle cible des inscriptions — le participant crée une Participation chiffrée et dépose son did (URI sans ReadCap) dans l'inbox de l'événement ; le créateur traite l'inbox automatiquement, déduplique sur l'overlay (store-scopé) sans pouvoir lire, et range la référence dans un Set porté par l'événement ; compteur = Set.size ; seules les connexions détiennent la clé et reconnaissent la personne. Supersede l'Option-B (compteur muté + userId en clair dans l'inbox). --- -# Brief (2026-07-20) — inscriptions par Set (objet-vérité + Set curé cap-less) +# Brief (2026-07-20, révisé 2026-07-27) — inscriptions par Set -## Pourquoi +## Le modèle -L'implémentation actuelle (Option-B, [[brief_2026-07-06_reactive-reads-and-attendance]]) dérive un `participantCount` **muté-en-place** depuis des marqueurs d'inbox qui portent le **`userId` en clair** → (1) compteur **falsifiable** (marqueurs non authentifiés), (2) **fuite d'identité** au créateur, indépendamment de toute connexion. La **vision initiale**, retrouvée : **présence anonyme par défaut**, seul un **connecté (= ami)** voit l'identité. Faisabilité : **seules les références cap-less sont confirmées** (cf. polyfill `docs/readcap-and-nuri-model.md`) ; le **compteur** repose encore sur des inconnues (keyless-fetch, dédup-vérifiée — voir Tensions). Ne pas surestimer. +Posé par le PO le 2026-07-27. Tout est **clés et URLs** — pas de rôle, pas d'appartenance, pas de liste d'autorisation. -## Modèle cible +1. Le participant crée un objet **Participation** — **chiffré**, dans son store *protected* — décrivant son inscription. +2. Il dépose dans l'**inbox de l'événement** le **did** de cet objet : l'URI **sans ReadCap**. +3. Le **créateur** de l'événement traite son inbox **automatiquement**, dès qu'il est en ligne. +4. Il **ne peut pas lire** la Participation, donc il **ignore l'identité** du participant — mais il a de quoi **dédupliquer** (voir ci-dessous). +5. Il range une **référence** à la Participation dans un **Set** porté par le document de l'événement. +6. N'importe qui lit **`Set.size`** → le nombre de participants. +7. Une personne **connectée** au participant détient la clé, **déchiffre** la Participation et **reconnaît** la personne. *(Traité dans un 2e temps.)* -- **Objet participation = la vérité**, auto-possédé (protected), mis à jour/supprimé par le **seul inscrit** → **personne ne désinscrit autrui**. -- **Set sur l'événement** (doc du créateur — lui seul l'écrit) de **références cap-less** aux participations. Le créateur **ajoute** (sur nudge d'inbox) et **nettoie** les périmées. -- **Compteur = nombre de références distinctes** (`Set.size`) — plus de compteur muté séparé. -- **Identité** résolue **seulement** par les détenteurs du cap = les **connexions** (à qui l'inscrit a scellé le cap-porteur) → anonyme au public **et** au créateur non-ami. -- **Désinscription** = l'inscrit supprime son objet **ET** dépose un **nudge « retire la réf X »** chez le créateur — car une suppression n'est **PAS** détectable sans clé (**VÉRIFIÉ P0, Q2** : broker append-only, tombstone chiffré). Le créateur retire la réf du Set sur le nudge (forgeable = accepté, hors-scope sécurité). Les connexions (qui ont le cap) peuvent aussi filtrer en relisant l'objet. -- **Validation d'existence — CONFIRMÉ (P0, Q1)** : les lectures broker ne sont pas cap-gatées → le créateur peut vérifier que l'objet **existe** (fetch des blocs chiffrés) avant d'ajouter → un join forgé **sans objet réel** est **rejeté**. *Nuances* : (a) marche avec l'overlay **inner** (ou outer exposé) — une **sonde e2e** confirmera lequel la réf porte ; (b) existence ≠ **dédup** (#3) et ≠ inviolabilité totale (référencer un objet réel *quelconque* passe la vérif). +Trois propriétés en découlent, et ce sont elles qu'on cherchait : **présence anonyme par défaut** (le créateur lui-même ne voit pas qui) ; **personne ne désinscrit autrui** (l'objet est auto-possédé) ; **aucun `userId` en clair** ne circule. -## Ce qui change vs l'actuel +## Sur quoi ça repose — faits établis dans NextGraph -- **Retirer le `userId`** des marqueurs d'inbox → ne garder qu'un **nudge + référence cap-less**. -- **Compter par références distinctes**, pas par `userId`. -- `event.participantCount` muté-en-place **disparaît** au profit de `Set.size`. -- La **résolution d'identité** passe par la **lecture de l'objet** (cap), pas par le marqueur. +Vérifiés par lecture de `nextgraph-rs`. Le détail et les pointeurs vivent côté polyfill (`docs/readcap-and-nuri-model.md`) — cf. [[rule_capture-nextgraph-findings]]. -## Ce qui reste valable +| Fait | Statut | Ce qu'il permet ici | +|---|---|---| +| Un NURI cap-less (`did:ng:o:{repo}:v:{overlay}`, sans `:k:`) **nomme sans donner à lire** | VÉRIFIÉ | Le did déposé dans l'inbox référence sans divulguer | +| L'**overlay** (`:v:`) est **store-scopé**, jamais document-scopé | VÉRIFIÉ | **La clé de dédup** — voir section suivante | +| Sans la clé, les blocs restent **du ciphertext** | VÉRIFIÉ | Le créateur ne peut vraiment pas lire | +| L'existence d'un objet est **vérifiable sans clé** (protocole `Ext`, sans identité ni contrôle) | VÉRIFIÉ | *Optionnel* : valider qu'un did pointe sur un objet réel avant de l'ajouter | +| Une **suppression** n'est **PAS** détectable sans la clé (append-only, tombstone chiffré) | VÉRIFIÉ | La désinscription ne peut pas être *observée* — voir points ouverts | -- La **lecture réactive** + le **reconnect-lifecycle** (lire le Set réactivement, ré-armer à la reconnexion). -- Le **fix identité** déjà livré (résoudre participation→profil via la clé). +## La dédup : sur quoi exactement -## Tensions fondamentales (revue adverse — 2026-07-20) +**Hypothèse de travail — à confirmer par le PO.** Le mécanisme que j'identifie derrière « il a normalement assez d'informations pour dédupliquer » : -Un adversaire a réfuté les deux promesses phares. **Distinction clé** (le polyfill vise la *forme*, pas la *sécurité* — cf. son objectif) : les attaques par **forge** (compteur gonflé, `from:null`) relèvent de l'insécurité **acceptée** de l'émulation ; **mais** le trilemme ci-dessous est un problème de **MODÈLE** qui **survit au vrai crypto** — ce sont donc de vraies questions de conception, pas des nitpicks d'émulation. Sous les primitifs NextGraph, **anonyme + compté-juste (dédupliqué) + inviolable** ne tiennent PAS ensemble : +Le segment `:v:` d'un NURI ne vient **pas du document** mais de **son store** (`ProtectedStore(id) → outer(id)`). Or une personne a **un seul** store protected. Donc **toutes ses Participations portent le même `:v:`**, quel que soit le nombre d'objets qu'elle crée. Le créateur déduplique là-dessus : deux références de même `:v:` dans le Set d'un même événement = la même personne. **Sans jamais savoir qui.** -1. **« Inviolable » est faux.** Le fetch keyless (INFÉRÉ, absent de `caps.ts` : `canRead(doc,null)→false`) ne prouve que l'**existence** d'un NURI, jamais une participation **valide, distincte, de cet événement** — un attaquant référence n'importe quel NURI existant → compteur gonflé. Sans keyless-fetch, retour au nudge (`inbox.post` accepte `from:null`) → forge comme Option-B. -2. **Anonymat ⊥ inviolabilité (overlay).** Valider l'existence exige l'**overlay** ; overlay = `outer(store_id)`, **un seul store protected par identité** → stable sur TOUS les événements → un créateur voyant `:v:{overlay}` sur N événements **corrèle** « même participant partout » sans lire l'identité (**pseudonyme de traçage**). *Mitigation candidate : chaque participation dans son propre repo/store → overlay par-participation.* -3. **Dédup : base VÉRIFIÉE (`nextgraph-rs`), mais GATÉE sur la vérification.** Le fond était juste : les **commits SONT signés** par un `UserId` (clé technique **≠ le profil**), donc un id technique de dédup **existe** — pas besoin de pseudonyme applicatif. MAIS deux gaps : (a) **vérifier** la signature exige d'être **membre du repo** (`member_pubkey`) — le créateur n'est pas membre du store du participant, et le store-partagé-en-écriture n'existe pas ; (b) le **dépôt d'inbox n'est PAS authentifié** (sealed box anonyme ; un `from` nommé = clé de **profil** → fuite). → dédup-par-signature-vérifiée **pas directement atteignable** dans le flux actuel. **Piste** : participations dans un **store PAR-ÉVÉNEMENT** vérifiable par le créateur → le digest d'auteur (par-overlay, donc par-store) = un **pseudonyme par-événement** → dédup + **pas** de corrélation cross-événement + anonyme-profil. Reste à résoudre « le créateur peut vérifier » (membership). *(Le digest par-user redevient corrélable pour un membre disposant de la members map sur un store stable par-user → d'où l'intérêt du store par-événement.)* -4. **Leave-par-détection-de-suppression : IMPOSSIBLE keyless — VÉRIFIÉ (P0, Q2).** Broker append-only, tombstone chiffré → sans clé on voit « une activité », pas « une suppression ». **Résolu** par un **nudge de leave** (voir Modèle cible), pas une détection automatique de réf pendante. +Conséquence de conception : le Set est **indexé par `:v:`** — au plus une référence par `:v:`. `Set.size` = nombre de `:v:` distincts = nombre de personnes distinctes. -De plus (revue caps polyfill) : dans l'**émulation actuelle sans crypto**, le contenu est en **clair** dans le wallet partagé (`sparqlQuery` bypass le filtre) → l'anonymat « cap-less ne peut pas lire » **n'est même pas applicable** tant que le polyfill ne fournit pas soit du vrai crypto, soit une projection read-model masquée. +### La contrepartie, à connaître avant de la découvrir plus tard -**Ce qui tient (validé par l'adversaire)** : l'objet auto-possédé **tue le griefing** de la désinscription forgée d'autrui, et **retire la fuite** du userId-dans-le-marqueur. Vrais gains — mais ils n'exigent pas tout le pivot. +Ce `:v:` est un **pseudonyme stable et permanent de la personne**, présent dans **toute** référence cap-less vers **n'importe lequel** de ses documents protected. Il ne dit pas *qui* (`BLAKE3(store_id)` n'est pas inversible), mais c'est un **handle constant**, le même partout et pour toujours. + +- Un créateur organisant plusieurs événements voit « le même `:v:` revient » → **corrélation de présence** d'un événement à l'autre. +- Si quelqu'un apprend un jour, par un seul recoupement, que `:v:X` = Marie, **toutes** les participations de Marie deviennent liables **rétroactivement**. + +**Le point structurel** : c'est **le même bit d'information** qui permet de dédupliquer sans lire et qui permet de tracer. On ne peut pas garder l'un en supprimant l'autre — sauf à changer le **découpage en stores**, ce qui déplace le curseur sans faire disparaître l'arbitrage. Ce n'est pas un défaut de l'émulation : la propriété survit au vrai NextGraph. + +## Ce qui change vs l'implémentation actuelle (Option-B) + +L'existant ([[brief_2026-07-06_reactive-reads-and-attendance]]) dérive un `participantCount` **muté en place** depuis des marqueurs d'inbox portant le **`userId` en clair**. + +- **Retirer le `userId`** des dépôts d'inbox → ne reste que le **did cap-less**. +- **Compter des références distinctes** (par `:v:`), plus des `userId`. +- **`event.participantCount` muté disparaît** au profit de `Set.size`. +- La **résolution d'identité** passe par la **lecture de l'objet** (donc par la clé), plus par le marqueur. + +Ce qui reste valable tel quel : la **lecture réactive** et le **ré-armement à la reconnexion** ; le **fix d'espaces d'id** déjà livré. + +## Points ouverts + +- **Désinscription.** Supprimer son objet ne suffit pas : sans clé, le créateur ne peut pas *observer* la suppression (VÉRIFIÉ). Il faut donc un **acte explicite** — un second dépôt d'inbox « retire la référence X ». Forgeable (n'importe qui peut le déposer), ce qui est **hors périmètre sécurité** mais mérite d'être acté. Cf. [[caveat_participation-deletion]] : la désinscription doit rester **autoritative**. +- **Créateur hors-ligne.** Le Set ne bouge pas tant qu'il n'a pas traité son inbox. Accepté en V1 ; un service curateur est la sortie éventuelle. +- **Validation d'existence.** Le créateur *peut* vérifier qu'un did pointe sur un objet réel avant de l'ajouter (protocole `Ext`). **Pas requis** par le modèle — à ranger comme durcissement optionnel, pas comme prérequis. +- **Reconnaissance par les connexions** (étape 7) — explicitement remise à un 2e temps : comment la clé est scellée aux connexions, et ce qu'il advient d'une connexion rompue. ## Dépendances -- **Bloquant** : l'**émulation caps du polyfill** alignée — réfs cap-less + possession, **ET** (pour la dédup #3) **WriteCap=membership + stores par-événement à signature vérifiable**. Ces deux derniers **ne sont pas encore façonnés** par le brief polyfill → son **scope doit s'élargir**, sinon les deux briefs **ne composent pas** (constat adverse). Brief polyfill `2026-07-20-caps-emulation-alignment`. -- **Parké** : la **terminologie identité** (wallet/user/profil) — détermine « à quelle identité on scelle ». -- **INFÉRÉ** : le **fetch keyless** (existence sans lire) — à confirmer pour la version forte. +- **Bloquant** : l'**émulation caps du polyfill**. Aujourd'hui `caps.ts` modélise une **ACL** (set de principals par document) là où le réel est **possession de clé**, et le contenu reste lisible en clair (`sparqlQuery`, `inbox.read` contournent le filtre). Tant que ce n'est pas corrigé, coder l'anonymat côté Festipod produirait du code qui **prétend** isoler sans isoler. Brief polyfill `2026-07-20-caps-emulation-alignment`, lot P1. +- **Parké** : la **terminologie identité** (wallet / user / profil) — cf. `.project/to-discuss.md`. -## Statut : direction cible, PAS un pivot immédiat +## Statut : direction cible validée, mise en œuvre gatée -Vu les tensions ci-dessus, **ne pas retirer Option-B** tant que : (a) le **trilemme** n'est pas tranché (que sacrifie-t-on, ou quelle mitigation — pseudonyme par-événement signé ?) ; (b) l'**émulation caps du polyfill** est alignée (sinon l'anonymat n'est pas applicable) ; (c) la **terminologie identité** est clarifiée ; (d) le **fetch keyless** est **vérifié** (spike P0). Les fixes contenus déjà faits (id-space) restent ; le reconnect-lifecycle reste utile quel que soit le modèle. +Le modèle est **tranché** (PO, 2026-07-27) et ses fondations sont **vérifiées**. Ce qui reste gaté, c'est la **mise en œuvre** : elle attend le lot P1 du polyfill. **Ne pas retirer l'Option-B** d'ici là. -## Questions ouvertes - -- **Owner hors-ligne** : le Set ne bouge pas tant que le créateur n'a pas matérialisé (accepté V1 ; futur service curateur). -- **Dédup** : « une participation = un objet par user par événement » à garantir (sinon un user avec 2 objets = compté 2×). -- **Anonymat-hôte** : par défaut le créateur ne détient pas le cap (sauf ami) → il ne voit pas l'identité. Cohérent avec l'arbitrage discuté. - -Liens : [[brief_2026-07-06_reactive-reads-and-attendance]] (superseded en partie), [[caveat_participation-deletion]], app-security ([[brief_2026-05-18_authorization-matrix]], [[knowledge_trust-model]]), polyfill `readcap-and-nuri-model.md` + brief caps. +Liens : [[brief_2026-07-06_reactive-reads-and-attendance]] (superseded), [[caveat_participation-deletion]], [[rule_capture-nextgraph-findings]], [[rule_document-per-entity]], app-security ([[brief_2026-05-18_authorization-matrix]], [[knowledge_trust-model]]), polyfill `readcap-and-nuri-model.md` + `docs/vision.md`. diff --git a/.project/concepts/data-layer/rule_capture-nextgraph-findings.md b/.project/concepts/data-layer/rule_capture-nextgraph-findings.md new file mode 100644 index 0000000..d88ae25 --- /dev/null +++ b/.project/concepts/data-layer/rule_capture-nextgraph-findings.md @@ -0,0 +1,33 @@ +--- +type: rule +summary: Toute connaissance importante établie sur le fonctionnement RÉEL de NextGraph (mécanisme du cœur/broker/verifier, sémantique d'un primitif, propriété de forme) → la consigner AU MOMENT de la découverte dans la doc de référence du polyfill `../../nextgraph/ng-eventually-js/docs/`, jamais dans le repo Festipod ; distinguer VÉRIFIÉ d'INFÉRÉ, et ne jamais déduire la forme CIBLE de l'état COURANT du source +--- + +# Règle : consigner toute connaissance NextGraph au moment où on l'établit + +Quand une enquête établit un **fait important sur le fonctionnement réel de NextGraph** — le mécanisme d'un primitif, la sémantique d'une structure, une propriété de forme (« l'overlay est *store*-scopé, jamais document-scopé »), une garde d'accès, ce qu'une opération exige ou n'exige pas — **écris-le tout de suite** dans la documentation de référence du polyfill : + +`../../nextgraph/ng-eventually-js/docs/` (depuis la racine de ce repo) — typiquement la fiche de référence du sujet (modèle de caps/NURI, état courant, référence SDK). + +**Jamais dans le repo Festipod.** `AGENTS.md` l'interdit explicitement : la doctrine Festipod décrit *comment Festipod utilise le SDK*, pas l'état de NextGraph. Cf. [[rule_app-uses-sdk-surface-only]]. + +## Au moment de la découverte — pas à la fin + +Le « je consignerai en fin de session » ne marche pas : le contexte est compacté avant, et le fait est perdu. Ces connaissances coûtent **très cher** à établir (plusieurs enquêtes d'agents dans le source Rust, souvent contradictoires avant convergence) et sont **invérifiables de mémoire** — une seconde session repaiera le prix fort pour la même réponse, ou pire, se contentera d'une intuition fausse. + +## Le piège central : état courant ≠ forme cible + +**Ne jamais lire l'état courant de `nextgraph-rs` pour en DÉDUIRE la forme cible.** Le source contient de l'**échafaudage inachevé** qui ressemble à du modèle : on peut y lire des types d'appartenance et de permissions qui sont **inertes au runtime** (jamais appelés hors tests unitaires, structures construites vides). En déduire un primitif « membership » et le façonner dans le polyfill, c'est y graver une forme qui n'existera pas — exactement le mode d'échec que le polyfill existe pour empêcher. + +Le source sert à **vérifier un mécanisme existant**, jamais à **inférer une intention**. L'intention se demande au concepteur de NextGraph. + +## Forme de la note + +- **Distinguer VÉRIFIÉ** (chemin lu de bout en bout, ou mieux : observé à l'exécution) d'**INFÉRÉ** (déduit, non tracé). Un fait porteur non marqué se transforme silencieusement en certitude. +- **Pointer des symboles**, pas des numéros de ligne (volatils) — et dater la note. +- Écrire aussi la **conséquence** du fait, pas seulement le fait : c'est elle qu'on relira. +- Un fait qui **contredit** une note existante → corriger la note, ne pas empiler. + +## Règle sœur + +Celle-ci vise la **connaissance** — ce qui *est* ; [[rule_nextgraph-inbox]] vise ce qu'il faut **remonter ou attendre** — les dysfonctionnements et les manques (→ `../../nextgraph/orm-tests/INBOX/`). Une même enquête produit souvent les deux : ranger chaque moitié à sa place. Cf. [[knowledge_nextgraph-stack]]. diff --git a/.project/concepts/data-layer/rule_file-nextgraph-bugs.md b/.project/concepts/data-layer/rule_file-nextgraph-bugs.md deleted file mode 100644 index 7fcd853..0000000 --- a/.project/concepts/data-layer/rule_file-nextgraph-bugs.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: rule -summary: Tout dysfonctionnement de NextGraph lui-même (cœur/broker/verifier ou primitif SDK qui se comporte mal — PAS un bug app ni un câblage polyfill) → créer un rapport .md dans le bug-inbox NextGraph partagé `../../nextgraph/orm-tests/INBOX/` ---- - -# Règle : consigner tout dysfonctionnement NextGraph dans le bug-inbox partagé - -Quand tu identifies un **dysfonctionnement de NextGraph lui-même** — le cœur/broker/verifier, ou un primitif SDK (`doc_subscribe`, `sparql_update`, socket, reconnexion, ouverture de repo…) qui se comporte mal — **crée un rapport `.md`** dans le bug-inbox NextGraph partagé : - -`../../nextgraph/orm-tests/INBOX/` (depuis la racine de ce repo) — le repo frère `nextgraph/orm-tests` (tests d'intégration ORM contre un vrai broker, avec `tests/standalone/` pour les repros). - -## Ce qui QUALIFIE (et ce qui ne qualifie pas) - -- **Oui** : un primitif NextGraph a le mauvais comportement — socket qui meurt (`SerializationError`), pas de reconnexion automatique, `doc_subscribe` qui ne délivre pas / est lent, cold-open de repo lent, écriture non durable côté broker. -- **Non** : un bug de l'**app** (effet React mal câblé, gating d'un effet) ou un **câblage du polyfill** (mauvais NURI, souscription non ré-armée). Ceux-là se corrigent **chez nous** — ils ne vont PAS dans l'inbox NextGraph. La distinction est cruciale : d'abord prouver que c'est le primitif qui faute (idéalement par un test), pas notre intégration. Cf. [[rule_app-uses-sdk-surface-only]]. - -## Format du rapport - -Nom : `YYYY-MM-DD-.md`. Contenu : symptôme, **preuve verbatim** (logs / mesures), repro (idéalement un script standalone — `orm-tests/tests/standalone/`), attendu vs observé, pointeurs source (marqués « à re-vérifier » si non revérifiés), sévérité + statut. Un post-mortem plus complet peut vivre côté polyfill/Festipod ; l'inbox reçoit le **rapport actionnable pour les mainteneurs NextGraph**. - -## Pourquoi - -Séparer proprement « bug NextGraph » (remonte à l'upstream via ce bug-inbox) de « à corriger chez nous » (app/polyfill), et ne **rien perdre** : chaque dysfonctionnement identifié laisse une trace triable. Cf. [[knowledge_nextgraph-stack]]. diff --git a/.project/concepts/data-layer/rule_nextgraph-inbox.md b/.project/concepts/data-layer/rule_nextgraph-inbox.md new file mode 100644 index 0000000..bf5a926 --- /dev/null +++ b/.project/concepts/data-layer/rule_nextgraph-inbox.md @@ -0,0 +1,42 @@ +--- +type: rule +summary: L'inbox NextGraph partagée `../../nextgraph/orm-tests/INBOX/` reçoit DEUX familles de fiches — les dysfonctionnements (un primitif se comporte mal) ET les manques (un primitif dont on a besoin, pas encore implémenté, qu'on émule dans le polyfill en attendant). Elle sert de suivi de l'avancement de NextGraph : quand un manque est comblé en amont, sa fiche dit quoi RETIRER du polyfill. +--- + +# Règle : l'inbox NextGraph reçoit les dysfonctionnements ET les manques + +L'inbox NextGraph partagée est `../../nextgraph/orm-tests/INBOX/` (depuis la racine de ce repo) — dans le repo frère `nextgraph/orm-tests`, qui héberge les tests d'intégration ORM contre un vrai broker (`tests/standalone/` pour les repros). + +Elle n'est **pas** qu'un bug-tracker. Elle a **deux entrées** et **une boucle de sortie**. + +## Entrée 1 — les dysfonctionnements + +Un primitif NextGraph existe mais **se comporte mal** : socket qui meurt (`SerializationError`), pas de reconnexion automatique, `doc_subscribe` qui ne délivre pas ou tarde, cold-open de repo lent, écriture non durable côté broker, panique atteignable. + +## Entrée 2 — les manques dont on a besoin + +Un primitif **n'est pas encore implémenté** (ou n'est qu'un échafaudage inerte) alors que notre modèle en dépend. Le déposer aussi, avec les trois informations qui font sa valeur : + +- **ce dont on a besoin** et pourquoi — le modèle qui en dépend ; +- **ce que le polyfill fait en attendant** — l'émulation qui bouche le trou ; +- **ce qu'il faudra retirer** du polyfill le jour où ça atterrit en amont. + +C'est ce troisième point qui transforme la fiche en **ticket de nettoyage**. Sans lui, l'émulation survit à sa raison d'être et le polyfill se met à diverger de la cible — exactement ce qu'il existe pour éviter. + +## Ce qui ne qualifie PAS + +Un bug de l'**app** (effet React mal câblé, gating d'un effet) ou un **câblage du polyfill** (mauvais NURI, souscription non ré-armée). Ceux-là se corrigent **chez nous**. La distinction est cruciale : d'abord prouver que c'est le primitif qui faute — idéalement par un test — pas notre intégration. Cf. [[rule_app-uses-sdk-surface-only]]. + +## La boucle : l'inbox suit l'avancement de NextGraph + +Les fiches ne partent pas seulement vers l'amont, elles se **relisent** : ensemble, elles disent où en est NextGraph par rapport à ce dont Festipod a besoin. Quand une fiche se résout en amont, la mise à jour du polyfill suit — souvent en **retirant** de l'émulation devenue inutile, pas en ajoutant du code. + +## Format de la fiche + +Nom : `YYYY-MM-DD-.md`. Contenu : nature (**dysfonctionnement** ou **manque**), symptôme ou besoin, **preuve verbatim** (logs, mesures, pointeurs source marqués « à re-vérifier »), repro quand c'est un dysfonctionnement (idéalement un standalone dans `orm-tests/tests/standalone/`), attendu vs observé, et — pour un manque — le **contournement polyfill** et **ce qu'il faudra retirer**. Sévérité + statut. + +L'inbox reçoit le **rapport actionnable pour les mainteneurs NextGraph** ; un post-mortem plus long peut vivre côté polyfill. + +## Règle sœur + +Celle-ci vise ce qu'il faut **remonter ou attendre** ; [[rule_capture-nextgraph-findings]] vise la **connaissance** établie sur le fonctionnement réel (→ doc de référence du polyfill). Une même enquête produit souvent les deux : ranger chaque moitié à sa place. Cf. [[knowledge_nextgraph-stack]].