doctrine+dev: règle « app = surface SDK seule » + access-log par défaut

- rule_app-uses-sdk-surface-only : l'app se comporte comme si NextGraph était fini
  et sans défaut ; elle lit via `useShape` (scopé wallet virtuel, fourni par le
  polyfill), jamais via des internes (readModel/subscribeDoc) ni en raisonnant sur
  un problème NextGraph. Raison d'être du polyfill = le WALLET VIRTUEL (pas le hang
  ORM, qui n'est qu'un détail interne). Cible : `useShape` polyfill à la forme
  TanStack useQuery (data + isPending/isSuccess…), en anticipation de la mise à jour
  prévue de useShape par NextGraph — distingue nativement sync-en-cours de vide.
  Déviation actuelle notée : readEntities/subscribeDocs/bumpRead côté app.
- ngSession : access-log ON par défaut (le toggle opt-in était fragile), opt-out via
  localStorage festipod.debug.accessLog=0 ; ligne de diagnostic au démarrage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-07-09 22:36:29 +02:00
parent 4c80ada3de
commit 2295af610a
2 changed files with 60 additions and 11 deletions
@@ -0,0 +1,50 @@
---
type: rule
summary: L'app se comporte EXACTEMENT comme si NextGraph était fini et sans défaut — elle ne consomme QUE des surfaces SDK-shaped (`useShape`, `docs`, `inbox`…) et ne raisonne JAMAIS sur un problème courant de NextGraph (hang du fan-out ORM, cold-open, etc.). La raison d'être du polyfill est le WALLET VIRTUEL ; tout contournement interne (read-model union, subscribeDoc, open-repo…) vit DANS le polyfill, invisible à l'app.
---
# L'app n'utilise que la surface SDK — jamais les internes du polyfill
## La règle
L'app Festipod traite `@ng-eventually/client` comme un **SDK NextGraph fini et sans
défaut**. Concrètement :
1. **Lecture réactive = `useShape`** (la surface SDK-shaped, fournie par le polyfill,
**scopée au wallet virtuel**). L'app ne lit PAS via des internes du polyfill
(`readModel.readUnion`, `subscribeDoc`, un read-model maison…), et ne monte PAS sa
propre réactivité (re-run sur signal).
2. **L'app ne raisonne JAMAIS sur l'état courant de NextGraph** : pas de code ni de
commentaire du type « on fait X parce que le fan-out ORM hang / parce que la lecture
à froid rend 0 ». Ces problèmes n'existent pas du point de vue de l'app.
## La raison d'être du polyfill = le WALLET VIRTUEL
Le polyfill existe pour émuler le **wallet virtuel** (plusieurs identités sur un seul
wallet physique), que NextGraph ne fournit pas encore nativement. **Ce n'est PAS**
« parce que le fan-out ORM hang » — ça, c'est un simple **détail d'implémentation
interne** de la façon dont le polyfill livre un `useShape` fonctionnel. Tous les
contournements (read-model union à la place du fan-out ORM, `open-repo`, readiness
miroir de `readyPromise`, émulation de caps…) sont **internes au polyfill** et
n'apparaissent jamais dans l'app.
## Déviation actuelle (dette à corriger)
`src/shared/data/readEntities.ts` + `FestipodDataContext` lisent via
`readModel.readUnion` + `subscribeDocs` + `bumpRead`, avec un commentaire qui explique
que ça « remplace le fan-out `useShape` qui hang ». C'est la fuite exacte que cette
règle interdit.
**Cible** : le polyfill expose un `useShape` **réactif, scopé au wallet virtuel**, dont
la **forme suit TanStack `useQuery`**`{ data, isPending/isLoading, isSuccess, isError,
… }`**en anticipation de la mise à jour PRÉVUE de `useShape` par NextGraph** (qui va
adopter ce fonctionnement). Ce n'est donc pas une invention : c'est une API future de
NextGraph, émulée d'avance, qui s'aligne quand NextGraph la livre. Elle **distingue
nativement** `isPending` (sync en cours) de `isSuccess` + `data` vide (synchronisé,
réellement vide) — exactement le besoin. En interne, le hook encapsule readUnion sur
`subscribeDoc` + le scoping identité (invisible à l'app). L'app **supprime** sa
machinerie bespoke (`readEntities`/`subscribeDocs`/`bumpRead`) et lit via ce hook.
Le bug d'auto-seed (chronomètre 3 s) est un **symptôme** : avec `isSuccess`, l'auto-seed
décide « vide » seulement une fois la sync confirmée, au lieu de deviner un délai. Voir
[[rule_no-broker-polling]] et [[knowledge_nextgraph-stack]].