# What works for me — Cahier des charges (v9)

> **Version 9 — 6 juillet 2026 à 14h47.** Mise à jour de session (pivot V2.0). Ajout depuis la v8 :
> **Nouveau §19 — V2.0 : pipeline 100 % IA (décidé les 04–06/07/2026, EN CONSTRUCTION).** La prochaine version du site test, nommée **V2.0** partout, **abandonne totalement le moteur local Regex** (retrait du « Choix du moteur » des Réglages, du toggle Regex/IA et des deux jeux étanches) : tout le traitement passe par un **pipeline en 5 étapes**, chacune une **commande lancée à la main par Elena via Claude Code** sur son ordinateur (aucun moteur branché en ligne), chacune adossée à une **page de schéma publiée** (`/app/extraction-schema` · `/derived-metrics` · `/correlation-schema` · `/insight-ranking` · `/insight-generation`), plus un **registre transverse des croyances utilisateur** (`/user-beliefs`). Le §19 consolide tout ce qui a été validé : les **5 commandes** (Extract User Data · Run Recap Table · Run All Correlations · Find Insights · Run Insights Requested) avec leurs modèles ; la **structure des catégories & KPI canoniques** (consolidation : Énergie/Douleur/Brouillard mental absorbés dans Symptômes, Humeur = Bonne|Pas bonne, Fadi/Didi, Sport vs Mouvements) ; le **moteur de sollicitation à 3 niveaux** (fixes · piloté par les analyses · questions conditionnelles) ; le **Récap V2.0** (4 familles d'agrégation, « n oui / jours déclarés », % Fadi) ; le **moteur de corrélations à 2 couches** (dépistage Pearson · extraction de règles support/confiance/lift) avec ses **5 piliers de validité tous tenus** et le **carnet d'hypothèses** (candidate → prospectif → confirmée) ; l'**architecture à étages** (fichiers dérivés séparés du store) ; le **planning de construction en 9 étapes**. Les sections V1 (§6, §8–§10, §18.6) restent valables pour la démo **actuellement en prod** ; le §19 décrit la cible V2.0. Reprise du statut v8 ci-dessous.
>
> **Version 8 — 3 juillet 2026 à 05h51.** Mise à jour de session (cœur du moteur). Ajouts depuis la v7 :
> **Vocabulaire appétit** — « Envie de manger », « Faim », « Pas faim », « Satiété » = **4 valeurs canoniques de la catégorie Symptômes** (jamais Humeur/Alimentation) ; moteur local `appetiteSignal` (négation = état réel) + jeu IA retagué (23 signaux) + règles gravées dans `store.vocabRules` (§6.2, §18.6). **Corrélations automatiques : Douleur, Symptômes et Brouillard mental SÉPARÉS** — une corrélation relie un déclencheur à UN type précis (clé `flag::trigger`, cartes « Tes douleurs… » / « Tes symptômes… » / « Ton brouillard mental… ») ; les anciennes cartes fusionnées deviennent obsolètes (§9.3). **Analyses ciblées (raccourcis)** — nouveau §9.8 : section discrète de l'écran Corrélations auto ; chaque raccourci compare deux catégories en **séries agrégées** puis **valeur × valeur**, filtres stricts Symptômes(satiété)/Symptômes(envie de manger), verdicts honnêtes (r, n, « données insuffisantes ») ; liste de 6 maintenue à la main (jamais écrasée) ; **[ROADMAP] moteur de suggestion additif**. **Boucle de curation (React v2, solution temporaire)** — popin « Réagir au traitement fait de l'Entrée saisie » : entrée rappelée, donnée extraite + 👍/👎 (vue IA seulement), signaux frères, catégories multi-sélectionnables = vraie scission, champ valeur, « dire au modèle » ; chaque réaction = donnée (`store.feedback`) rejouée après réanalyse et injectée au prochain Run IA (§8.2, §18.6). **Deux jeux de données étanches Regex/IA + Run IA** (§8.1, §9.1, §10.1, §18.6) : toggles « Données sources » sur Données/Corrélations auto/manuelles (Regex à gauche, IA à droite), jeu IA figé à la date du dernier Run (manuel, incrémental), premier Run IA exécuté le 02/07 sur les 88 entrées. Reprise du statut v7 ci-dessous.
>
> **Version 7 — 2 juillet 2026 à 16h19.** Mise au net de session. Ajout depuis la v6 :
> **Écran Réglages — les 4 parties racine (I. Design · II. Moteur · III. Gestion des données personnelles · IV. Informations légales) deviennent repliables et FERMÉES par défaut** (`<details class="set-part-block">`, titre en `<summary>` + chevron). L'écran s'ouvre en vue compacte. L'état ouvert/fermé de chaque partie est **conservé le temps de la session** (`S.partsOpen`, écouteur `toggle` en capture) pour survivre aux re-renders déclenchés par un réglage interne, mais **repart replié** au prochain lancement (non persisté). Détail en §12. Reprise du statut v6 ci-dessous.
>
> **Version 6 — 30 juin 2026 à 11h05.** Mise au net de session. Ajouts depuis la v5c :
> **Mantra projet** en pied de la barre d'onglets (FR « Comparaison n'est pas raison. Test & Learn. » / EN « Comparison is not proof. Test & Learn. », clé i18n `footerMantra`). **Moteur d'extraction commutable** (Réglages → II. Moteur → « Choix du moteur », fonction `fn2`) : **local** (défaut, sur l'appareil) ou **IA/LLM** (conçu, pas encore branché → repli local + note « non connecté ») ; aiguilleur `extractEntry()`. **Moteur local enrichi** : correspondance **mot-entier** (corrige les faux positifs type « bu »→« bureau », plus d'« Alimentation » hallucinée), **rôles SOMMEIL** (coucher/réveil/durée), **ÉNERGIE notée 1→5**, **libellés contextuels** (« Coucher à 22h », « 8h de sommeil », « Glycémie 110 mg/dl »). **Réanalyse** : bouton **« Tout réanalyser »** + migration automatique unique (réversible via `_sigBak`) — le **texte des entrées n'est jamais modifié**, seule la couche dérivée est régénérée. **Refonte du Récap (Données)** : ordre Sommeil / Alimentation / Activité / Social / Énergie / Douleur / Brouillard mental / Climat ; **Humeur & Stress retirés du récap** ; sommeil en **h:mm**, énergie en **/5** et alimentation en **prises/jour** (1 décimale, **arrondi au plafond**), douleur & brouillard en **fréquence** (non / occasionnel / fréquent / quotidien), climat = tendance dominante ; règle « calculer à partir de l'existant, même 1 seule donnée ». **« Par catégorie »** affiche les **libellés contextuels**. **Nouveau §18 — Modèle cible « valeurs plates » & extraction IA** (validé en conception ; **remplace** la piste « champs typés par catégorie »), dont **§18.5 : anonymisation obligatoire comme condition de branchement du moteur IA, dès la démo**. Reprise du statut v5c ci-dessous.
>
> **Version 5c — 27 juin 2026 à 19h20.** Mise au net de session. Ajouts depuis la v5b :
> **Langage canonique (Ubiquitous Language)** — suggestions de facteurs **typées** catégorie/valeur (chips différenciés), `verdict`→`band` (Force), `tag`→`category` (UI + code + i18n) ; glossaire `app-ios/glossaire.md` (§17). **Liste des valeurs** (Réglages → Moteur) — éditer / supprimer / ajouter / **fusionner par glisser-déposer** (souris + tactile) ; base d'alias `valueAliases` + `valuesExtra` (§4) + **normalisation à la saisie** (« Sucré »→« Sucre ») ; numériques exclus (§6.5). **Journal** — picto **« masquer le contenu »** (floute texte/photos, chips visibles) ; **raccourcis rapides retirés**. **Données** — « Par catégorie » **replié par défaut**. **Mon compte** — section **« Comment ça marche »**. **Corrélations manuelles** — sous-titre « Corrélation n'est pas causalité » ; chaque carte porte « **Corrélation observée le {date}, sur les données du … au …** » ; « Association observée »→« Corrélation observée » (auto + manuel). **Catégorie « Social »** (👥) + valeurs-graines « Quality Family Time » / « Network pro ». Reprise du statut v5b ci-dessous.
>
> **Version 5b — 27 juin 2026 à 08h56.** Mise au net de session. Ajouts depuis la v5 :
> **Corrélations manuelles** — le méga-menu de suggestions **reste affiché tant que le curseur est dans un champ** (ouverture au focus / clic / frappe ; sélectionner une suggestion garde le focus ET le menu ouvert ; fermeture seulement quand le focus quitte tous les champs, ou via Échap) ; **filtrage à la frappe** ; comportement documenté (§10.1, §16). **Réglages** — titres de sous-sections **toujours en noir** même si la fonction dedans est inactive (le gris ne porte que sur le contenu) ; « Boutons des corrélations » → **« Boutons »** ; note « les fonctions en gris… » **retirée** ; **tous les styles de Réglages forkés sous `.settings-screen`** (isolation totale, retouchables sans impact ailleurs) ; titres de groupe agrandis (≈ 1,2 rem). Reprise du statut v5 ci-dessous.
>
> **Version 5 — 27 juin 2026 à 00h06.** Mise au net de session. Ajout depuis la v4 :
> **réorganisation complète de l'écran Réglages en 4 grandes parties** (I. Design · II. Moteur · III. Gestion des données personnelles · IV. Informations légales), avec sous-groupes et sections repliables, et la **matrice « Choix du moteur » éclatée en sections « Fonctions » par étape** ; ajout de la sous-section **« Applications à connecter »** (Apple Santé, Google Fit, Oura, Fitbit, Withings, Dexcom, **Localisation & météo**) ; tag **« Climat »** (renommé) ; **« Charger des exemples » retiré** des Réglages. Reprise du statut v4 ci-dessous.
>
> **Statut v4 (26 juin 2026 à 22h55).** Mise au net de session. Ajouts depuis la v3 :
> (1) **Réglages → Choix du moteur** : nouvelle fonction *Analyse du ton de la voix*
> (manuel/local indisponibles ; via IA = analyse du son de la voix pour détecter l'humeur —
> stress, énervement, joie, etc.) ; (2) nouvelle partie **Réglages → Corrélations →
> Sources médicales** (sous-parties « URL d'API » et « Jeux de données » ; toggles, champs
> URL / import de fichier, recherche marketplace, « Ajouter une source » toujours visible)
> — **cosmétique**, en vue de la future version IA.
>
> **Statut du document.** Spécification complète et faisant autorité de l'application
> *What works for me* (journal de santé conversationnel + exploration de corrélations).
> Cette v4 consolide tout ce qui a été décidé, **y compris des fonctions pas encore
> présentes dans la démo web**. Elle remplace les versions précédentes
> (`cahier-des-charges.md`, `cahier-des-charges-v2.md`, `cahier-des-charges-v3.md`).
>
> **Public visé : Claude.** Ce document est écrit pour être implémenté par un agent
> Claude. Il est donc explicite sur les modèles de données, les algorithmes (avec
> formules), les comportements écran par écran, et les critères d'acceptation. Quand une
> fonction est « décidée mais pas encore codée », elle est marquée **[ROADMAP]** avec le
> détail d'implémentation attendu.

---

## 1. Objet & vision

**What works for me** est *« le journal de santé à qui tu parles »* (EN : *the health
journal you talk to*). L'utilisateur note son vécu de santé en **langage naturel**, sans
formulaire. L'app **structure** automatiquement chaque note (tags + valeurs), la
**range** par thème, et **explore des corrélations** entre facteurs (alimentation, météo,
sommeil…) et symptômes (douleur, brouillard mental…).

Promesse : obtenir des données de santé exploitables *sans remplir un seul formulaire*.

Garde-fou permanent : l'app **n'établit pas de diagnostic** et rappelle systématiquement
que **corrélation n'est pas causalité**. Les associations sont statistiques.

### Cibles de plateforme
- **Démo web (existant)** : PWA mobile-first, vanilla JS + PHP/OVH, local-first. Sert à
  valider les flux et le design. URL : `https://w.shoette.com/app/`.
- **App native iOS (cible)** : à développer. La démo web est la référence fonctionnelle.

---

## 2. Principes UX transverses

- **Mobile-first**, aéré, monochrome par thème (turquoise par défaut, corail en option).
- **Local-first** : tout est écrit en local puis synchronisé ; doit fonctionner hors-ligne.
- **Saisie zéro-friction** : texte libre, dictée vocale, photo. Pas de champs obligatoires.
- **Bilingue FR/EN**, bascule instantanée de toute l'interface.
- **Accessibilité** : taille de texte Normal / Grand (+12 %).
- **Polices** : display = *Space Grotesk* ; corps = *Inter*.
- **Navigation** : barre d'onglets bas (5 entrées) + accès *Mon compte* via le nom en
  haut à droite.

### Barre d'onglets (5)
`Journal` · `Données` · `Corrélations automatiques` · `Corrélations manuelles` · `Réglages`
Libellés **complets** (pas d'abréviation), sur 2 lignes si besoin, icône à côté du texte,
fins séparateurs verticaux entre items (non bord-à-bord). Repli sous 600 px : icône
au-dessus du texte.

---

## 3. Architecture technique

### Démo web (état actuel)
- **Front** : un seul fichier `app.js` (vanilla JS, IIFE), rendu par concaténation de
  chaînes HTML réinjectées dans `#app`. CSS unique `styles.css` (variables par thème).
- **Back** : `api.php` minimal sur hébergement mutualisé OVH. Comptes dans
  `data/store_<id>.json`. Mots de passe hashés bcrypt (`password_hash`). Actions :
  `signup`, `login`, `load`, `save`.
- **Persistance** : `localStorage` (clé `wwfm_store_<token>`) + sync serveur asynchrone
  via `persistStore()`. Session dans `wwfm_session`.
- **Déploiement** : FTP (lftp) vers `/w/app` sur le cluster OVH.

### Cible production / iOS [ROADMAP]
- Base de données (PostgreSQL ou SQLite) au lieu des fichiers JSON.
- Sessions signées (JWT ou session durcie), chiffrement at-rest des données de santé.
- Dictée vocale native, notifications push (Service Worker côté web, APNs côté iOS).
- Le schéma JSON ci-dessous est directement mappable sur un schéma relationnel.

---

## 4. Modèle de données (schéma du `store`)

Le `store` d'un compte est un objet JSON. `normStore()` garantit les valeurs par défaut.

```jsonc
{
  "profile": {
    "lang": "fr",                // 'fr' | 'en'
    "theme": "turquoise",        // 'turquoise' | 'coral'
    "textsize": "normal",        // 'normal' | 'large'
    "password": "…",             // EN CLAIR (démo test uniquement) — voir §12
    "createdAt": 1750000000000,  // ms ; défaut = date de la 1re entrée, sinon now()
    "sex": "F",                  // 'M' | 'F' | 'O' (sexe à la naissance) ; pour standards métaboliques
    "birthdate": "1990-05-12"    // 'YYYY-MM-DD'
  },
  "entries": [
    {
      "id": "e_xxx",
      "createdAt": 1750000000000,
      "text": "Dîner fromage, mains raides ce matin, temps humide",
      "photo": null,             // dataURL JPEG redimensionné, ou null
      "signals": [               // tags structurés (voir §6)
        { "category": "food", "label": "Fromage", "value": "Fromage", "confidence": 0.74 }
      ],
      "editedAt": 1750000500000  // présent SI l'entrée a été éditée après création
    }
  ],
  "correlations": {              // dictionnaire persistant des corrélations AUTO (clé = trigger)
    "fromage": {
      "key": "fromage", "label": "Fromage",
      "incidents": 4, "days": 5, "band": "moderate", "ratio": 0.8,
      "observedAt": 1750000000000, "windowDays": 3,
      "current": true,           // présent dans le dernier run
      "pinned": false,           // épinglé par l'utilisateur (toujours affiché)
      "hidden": false            // masqué par l'utilisateur
    }
  },
  "corrWindow": 3,               // fenêtre d'analyse auto : 1 | 3 | 7 (jours)
  "recapDays": 7,                // fenêtre du Récap Données : 7 | 14 | 30
  "corrBtnStyle": "icons",       // 'icons' | 'iconstext' (boutons pin/masquer)
  "manual": {                    // corrélations manuelles (voir §10)
    "factors": ["heure du coucher", "qualité de la nuit"],
    "saved": [                   // liste PERSISTANTE des analyses lancées, dédupliquée par facteurs
      {
        "key": "heure du coucher | qualité de la nuit", // facteurs normalisés (minuscules) + triés
        "mode": "pair",          // 'pair' (2 facteurs) | 'multi' (3+)
        "pair": {  },            // OU "multi": { } selon le mode (détails §10.3)
        "pinned": false,         // épinglée par l'utilisateur (tri en tête)
        "hidden": false,         // masquée (bascule dans l'archive)
        "createdAt": 1750000000000
      }
    ]
  },
  "valueAliases": {              // base de VALEURS GROUPÉES (§6.5) : "categorie::valeurLower" -> valeur principale
    "food::sucré": "Sucre"       //   ex. « Sucré » résout (rétroactif + futur) vers « Sucre »
  },
  "valuesExtra": {               // valeurs textuelles ajoutées manuellement par catégorie (pas encore dans les entrées)
    "food": ["Miel"]
  },
  "lastAnalysisAt": 1750000000000, // dernier run de l'analyse auto
  "insights": []                 // legacy (ne plus utiliser ; remplacé par correlations)
}
```

**Champs hors `store`** (identité de compte, non transplantés à l'import) :
`token` (= id de compte), `email`, et copie session de lang/theme/textsize.

---

## 5. Authentification

- Écran d'accueil : logo, tagline, e-mail + mot de passe, bascule **Créer un compte /
  Se connecter**.
- `signup` / `login` via `api.php` ; **repli local** (`localSignup`/`localLogin`) si le
  réseau échoue.
- À l'inscription **et** à la connexion, le mot de passe saisi est **capturé** et rangé
  dans `profile.password` (pour l'affichage en clair dans *Mon compte*, voir §9.6 et §12).
- Validation : e-mail + mot de passe requis. Messages d'erreur i18n
  (`errMissing`/`errExists`/`errNouser`/`errBadpass`).

---

## 6. Taxonomie & moteur d'attribution de tags

### 6.1 Catégories (13)
| clé | emoji | FR | EN | rôle corrélation auto |
|---|---|---|---|---|
| `sleep` | 😴 | Sommeil | Sleep | — |
| `food` | 🍽️ | Alimentation | Food | **trigger** |
| `mood` | 🙂 | Humeur | Mood | — |
| `energy` | ⚡️ | Énergie | Energy | — |
| `pain` | 🩹 | Douleur | Pain | **symptôme (flag)** |
| `stress` | 🌀 | Stress | Stress | — |
| `symptom` | 🌡️ | Symptômes | Symptoms | **symptôme (flag)** |
| `brain_fog` | 🌫️ | Brouillard mental | Brain fog | **symptôme (flag)** |
| `meds` | 💊 | Médicaments | Medication | — |
| `activity` | 🏃 | Activité | Activity | — |
| `social` | 👥 | Social | Social | — |  *(ajoutée le 27/06/2026)*
| `measure` | 📊 | Mesures | Measurements | — |
| `environment` | ⛅️ | Climat | Climate | **trigger** |  *(clé `environment` inchangée)*
| `other` | 📝 | Divers | Other | — |

`RECAP_KEYS` (ordre du Récap Données) : `sleep, food, mood, energy, pain, stress,
brain_fog, environment`.

**Valeurs « graines »** (`CAT_SEED_VALUES`) : valeurs fournies par l'app pour certaines
catégories, visibles dans la Liste des valeurs (§6.5) même sans entrée — actuellement
`social` → « Quality Family Time », « Network pro ».

### 6.2 Moteur de tags (existant, 100 % client)
- `structureEntry(text)` met le texte en minuscules, teste des **listes de mots-clés**
  codées en dur par catégorie. Premier mot-clé trouvé → tag de la catégorie.
- Extraction de **valeurs numériques** : sommeil (`Xh`), tension (`120/80 mmHg`),
  glycémie (`mg/dl`, `g/l`), poids (`kg`), pouls (`bpm`).
- Si rien ne matche → tag `other`. Détection de **négation** simple (pas/peu/sans/no/bad…)
  pour qualifier sommeil/humeur/énergie en « plutôt difficile » vs « noté ».
- Latence nulle, coût zéro (aucun appel réseau, aucun token).

**Améliorations v6 (30/06/2026) — moteur local :**
- **Correspondance MOT-ENTIER** (`kwHit`) : un mot-clé ne matche que s'il est bordé de non-lettres → corrige les faux positifs de sous-chaîne (« bu » dans « bureau », « dos » dans « adossé »…). Fini l'« Alimentation » fantôme.
- **Sommeil typé** (`sleepSignals`) : détection de **rôles** — `coucher` / `réveil` (heures d'horloge, gère minuit) et `durée` (déclarée). Un nombre n'est interprété **que** s'il y a un indice de rôle dans le texte (sinon laissé brut, sans inventer) → « 22h » n'est plus lu comme « 22 h de sommeil ».
- **Énergie notée 1→5** (`energyLevel`) : 1 épuisé · 2 fatigué · 3 correct · 4 en forme · 5 pleine forme (négation prise en compte).
- **Libellés contextuels** (`text` du signal, affiché dans les puces + « Par catégorie ») : « Coucher à 22h », « 8h de sommeil », « Glycémie 110 mg/dl », « Tension 12/8 », « Poids … kg ».
- **Vocabulaire appétit (03/07/2026)** : `appetiteSignal(lc)` extrait une des **4 valeurs canoniques** de la catégorie Symptômes — « Envie de manger », « Faim », « Pas faim », « Satiété » (ordre de test : satiété > pas faim > envie > faim ; la négation « pas faim » est un état réel, pas un mot-clé ignoré). Ces règles vivent aussi dans `store.vocabRules` pour les futurs Runs IA.
- **Moteur commutable** : réglage `store.extractEngine` (`local` défaut / `llm` / `manual`), piloté par la matrice « Choix du moteur » (`fn2`) ; aiguilleur `extractEntry(text)`. `llm` non branché → repli `structureEntry` + note ; `manual` → aucune extraction auto.
- **Réanalyse** : `reanalyzeAll()` (bouton « Tout réanalyser ») + `maybeMigrate()` (réanalyse auto unique au changement de moteur, `store.engineBuild`). Les anciens signaux sont archivés dans `entry._sigBak` (réversible) ; **le texte de l'entrée n'est jamais touché**.

### 6.3 [ROADMAP] Apprentissage des re-qualifications (`userRules`)
Quand l'utilisateur corrige/ajoute un tag sur une entrée, **mémoriser la règle** pour les
saisies futures.
- Stocker `profile.userRules = { "<mot/expression>": ["food","symptom"], ... }`.
- `structureEntry` consulte `userRules` **en priorité** sur les listes génériques.
- Prévoir résolution de conflits (règle utilisateur > règle générique) et une action
  « réappliquer mes règles aux entrées passées ».
- **Sans token** (déterministe). C'est l'évolution attendue par l'utilisatrice (ex :
  « soif » → Alimentation **et** Symptôme).

### 6.4 [ROADMAP] Classification LLM (option hybride)
Appel à l'API Anthropic (Claude) pour classer les entrées : compréhension du langage
naturel, multilinguisme, négations, contexte. Mode **hybride** : règles locales d'abord,
LLM en repli si confiance basse. Coût : latence ~300–800 ms + ~50–150 tokens d'input par
entrée. Implique d'envoyer des données de santé à un tiers → **point de gouvernance à
trancher** (consentement, anonymisation).

### 6.5 Liste des valeurs (édition, fusion, alias) — Réglages → II. Moteur
Sous *Listes de catégories* (cf. §12), une section **« Liste des valeurs »** expose les
**valeurs** textuelles (hors nombres/mesures) détectées dans les entrées, **groupées par
catégorie**, avec un compteur d'occurrences. Contrairement aux catégories (figées), les
valeurs sont **éditables** :
- **Éditer** (renommer) : re-tague rétroactivement toutes les entrées portant cette valeur,
  et enregistre un **alias** ancien→nouveau.
- **Supprimer** : retire **tout le signal** des entrées concernées (l'entrée est conservée),
  après **confirmation** (compteur d'entrées affecté) ; nettoie aussi les alias liés.
- **Ajouter** : crée une valeur (stockée dans `valuesExtra`), disponible comme cible de fusion.
- **Fusionner par glisser-déposer** (souris **et** tactile, via *pointer events*) : glisser
  une valeur **sur** une autre (même catégorie) → fusion ; **la valeur reçue est conservée**.
  Toutes les entrées de la valeur glissée sont retaguées vers la valeur reçue.
- **Base de valeurs groupées** (`store.valueAliases`, clé `categorie::valeurLower`) : chaîne
  d'alias résolue (anti-cycle). **Le moteur de tags applique cette normalisation à la saisie**
  (`structureEntry`) : écrire « Sucré » → tag **« Sucre »** (la valeur principale).

---

## 7. Écran Journal

### 7.1 Ajouter une entrée
- Zone de saisie en haut (textarea), placeholder d'exemple.
- **Texte libre** + **dictée vocale** (Web Speech API en démo ; native en iOS) +
  **photo** (redimensionnée ≤ 1000 px, JPEG qualité 0.7).
- _(Retiré le 27/06/2026 : les **raccourcis rapides** sous la zone — Ma nuit / Mon repas /
  Une douleur / Mon humeur — ont été supprimés ; clés i18n `quick1-4`/`qs1-4` dormantes.)_
- À l'envoi : entrée **horodatée**, **catégorisée** (`structureEntry`), **sauvegardée**, toast
  de confirmation.

### 7.2 Entrées sollicitées (pull)
Section **au milieu de l'écran**, entre la saisie libre (7.1) et le journal (7.3) : les
**saisies sollicitées par l'app** (« pull »), par opposition à la saisie libre spontanée.

- **Présentation** : encart **sans fond**, simple **bordure fine** (`--c-100`), badge
  « **Proposé par l'app** » + titre « **Entrées sollicitées** ». Le haut de page (saisie
  libre + sollicitations) reste **neutre/blanc** ; la démarcation visuelle se fait par le
  **fond teinté de la section « Ton journal »** en dessous (voir §7.3).
- **Toujours visible** : la section est **affichée en permanence**, même lorsqu'aucune
  sollicitation n'est en attente — dans ce cas elle conserve son en-tête et affiche le
  message « *Aucune sollicitation en attente pour le moment.* ». *(Comportement et message
  validés.)*
- **Encarts pré-renseignés**, à compléter (ou non) puis envoyer. Deux types :
  - **Question ouverte** : champ texte pré-rempli (ex. « J'ai mangé … ») + boutons
    **Envoyer** / **Ignorer**.
  - **Oui / Non** : boutons **Oui** / **Non** + **Ignorer**.
- **Effet** : répondre **crée une vraie entrée de journal** (horodatée, **auto-taguée** via
  `structureEntry`), puis l'encart disparaît ; *Ignorer* le retire sans saisie.
- **Règles de déclenchement** (quelles sollicitations, et quand) : consignées dans
  **Réglages → Entrées sollicitées / « Pull Input »** (voir §12).
- **[ROADMAP]** Le **moteur de déclenchement** (évaluation des conditions + notification
  *push*) n'est pas encore actif : en démo, les sollicitations d'exemple restent affichées
  jusqu'à réponse ou *Ignorer*. Le **mode de déclenchement** (à la main / local / IA) est
  exposé dans **Réglages → « Choix du moteur »**, ligne *moteur de sollicitation d'entrées*
  (voir §12).

### 7.3 Consulter le journal
- Liste anti-chronologique. Fenêtre par défaut : **dernières 24 h** ; bouton
  *Afficher plus* (+24 h par clic).
- **Recherche** textuelle temps réel (texte + catégories).
- **Filtres** : plage de dates, catégorie, tranche horaire (double slider).
  Icône filtre **colorée** (fond plein) quand un filtre est actif.
- **Masquer le contenu** : picto (œil) à côté du titre « Ton journal » qui **floute le texte
  et les photos** des entrées — les **chips** (catégories/valeurs) restent visibles. But :
  montrer les _data_ à quelqu'un **sans** le détail écrit. Bascule de session (non persistée).
- **Fond teinté dédié** : la section « Ton journal » (titre + recherche/filtres + liste)
  a un **fond de couleur propre, dédié par thème** (`--journal-bg` : turquoise `#CDE7E8`,
  corail `#FAD8D8`) ; **les cartes d'entrées restent blanches** et ressortent dessus. But :
  démarquer nettement le **journal (passé)** du **haut de page** (saisie + sollicitations).

### 7.4 Éditer / supprimer une entrée
- Bouton crayon ✏️ discret sur chaque carte → **bottom sheet** d'édition.
- Permet : modifier le **texte**, **ajouter/retirer des tags**, **supprimer** l'entrée.
- À l'enregistrement : `editedAt = now`, signaux recalculés depuis le nouveau texte (ou
  conservés si édités manuellement). Badge « modifiée » sur la carte.
- **Effet sur l'analyse (retenue)** : une entrée éditée après le dernier run est marquée ;
  l'écran *Corrélations automatiques* affiche une **bannière** invitant à relancer, et le
  prochain run **réintègre** la version à jour (les infos issues de la v1 obsolète ne sont
  plus comptées).

---

## 8. Écran Données

### 8.1 Récap (panneau compact)
- **Panneau de synthèse teinté** (fond `--c-50`, en-tête `--c-100`), visuellement
  **distinct** des listes détaillées qui suivent. Lignes condensées, emoji inline,
  valeurs en pastilles blanches.
- Titre « Récap » + période dynamique « {n} derniers jours ».
- Deux vues commutables (segmented control) : **Valeurs santé** / **Complétude du suivi**.
  - *Valeurs* : valeur par dimension (détail v6 ci-dessous) ou **« informations absentes »**
    (style dédié : pastille pointillée estompée) si aucune donnée.
  - *Complétude* : pastille score 1/2/3 (Insuffisant / Intermédiaire / Suffisant).
- **Fenêtre paramétrable** : défaut **7 jours** ; choix **7 / 14 / 30** dans Réglages.
  Les seuils de complétude (`score3 = ⌈0,7·win⌉`, `score2 = ⌈0,35·win⌉`) et de fréquence
  (quotidien `⌈0,8·win⌉`, fréquent `⌈0,4·win⌉`) sont **proportionnels** à la fenêtre.

**Contenu du Récap — spec validée v6 (30/06/2026).** S'applique **quel que soit le moteur**
(local ou IA) ; seule la *fiabilité* des données diffère — assumé, c'est le rôle de la vue
*Complétude*. Règle générale : **calculer à partir de ce qui existe** (même une seule donnée
sur la fenêtre est restituée). Pour les moyennes calculées : **1 décimale, arrondie au
plafond** (vers le haut). Ordre des lignes (Humeur & Stress **retirés** du récap) :

1. **Sommeil** — *moyenne d'heures de sommeil par nuit*, en **h:mm** (pas en décimal) = Σ(durée des nuits) ÷ **nuits avec info**. La durée d'une nuit est **déclarée** (« dormi 8h ») **ou calculée** (réveil − coucher de la veille ; gère minuit ; la déclarée l'emporte).
2. **Alimentation** — *prises par jour* = nb de prises ÷ **jours avec info** (1 décimale, plafond).
3. **Activité** — *nombre de fois* sur la période (compte total).
4. **Social** — *nombre de fois* sur la période (compte total).
5. **Énergie** — *moyenne /5* : chaque jour donne un score 1→5 (moyenne des indices du jour), puis moyenne des jours (1 décimale, plafond).
6. **Douleur** — **fréquence** : `non` (0 j) / `occasionnel` (1-2 j) / `fréquent` (3-5 j) / `quotidien` (6-7 j) — proportionnel à la fenêtre.
7. **Brouillard mental** — **fréquence** (même barème).
8. **Climat** — température + humidité moyennes si chiffres disponibles ; sinon **tendance dominante** (ex. « Humide (4/7 j) »).

### 8.2 Par catégorie
- Liste complète regroupée par catégorie, **une catégorie par ligne** (pas en grille).
- Chaque bloc dépliable liste les valeurs extraites + horodatage. **Tous repliés par
  défaut** (depuis 27/06/2026 ; auparavant `sleep/food/pain` ouverts).
- **v6 (moteur local)** : les valeurs s'affichent avec leur **libellé contextuel** (« Coucher à 22h », « 8h de sommeil », « Glycémie 110 mg/dl ») plutôt qu'un nombre nu. En **moteur IA**, c'est l'IA qui détermine ce qu'elle inclut.
- **Liste à hauteur fixe** (~5 lignes, **identique pour toutes** les catégories) avec
  **scroll vertical interne**. **Chargement progressif** : **40 lignes** affichées au
  départ (on scrolle dans la boîte pour les parcourir), puis lien **« Voir plus »** (+20),
  puis bouton **« Afficher plus »** (+20 par clic) jusqu'à épuisement. La hauteur de la
  boîte ne change jamais ; seul le contenu défilable grandit. La position de scroll est
  préservée lors d'un chargement supplémentaire. (Compteur d'en-tête = total réel.)

---

## 9. Écran Corrélations automatiques

(Renommé depuis « Corrélations ».)

### 9.1 Fonctionnement
- Pas de mise à jour automatique : bouton **Mettre à jour** lance `runAnalysis()`.
- Affiche les associations trouvées + date du dernier run.
- Bannière **stale** si des entrées ont `editedAt > lastAnalysisAt`.

### 9.2 Fenêtre d'analyse (sélecteur sous la tagline)
- **24 h / 3 jours / 1 semaine** = délai cause→effet recherché entre un trigger et un
  symptôme. Changer la fenêtre **relance** l'analyse. (Pas de ligne d'explication sous le
  sélecteur.)

### 9.3 Algorithme `computeInsights(windowDays)`
- Portée : **14 derniers jours** d'entrées. *(Voir [ROADMAP] §9.7 : option tout
  l'historique.)*
- Agrégation **par jour** — **flags SÉPARÉS (03/07/2026)** : chaque jour porte un flag PAR TYPE (`pain`, `symptom`, `brain_fog`, suivis indépendamment). Une corrélation relie un trigger à UN type (clé `flag::trigger`) ; l'UI l'énonce (« Tes douleurs… », « Tes symptômes… », « Ton brouillard mental… »). Les valeurs de `food` et `environment` sont des *triggers*.
- Un trigger de jour J co-occure si un *flag* existe à J, J+1, … J+(windowDays−1)
  (fenêtre glissante).
- Retenir les triggers avec **≥ 2 co-occurrences**. Bande : `weak` (<4), `moderate`
  (4–5), `strong` (≥6). `ratio = co-occurrences / jours-avec-trigger`. Max **6**, triées
  par occurrences.

### 9.4 Dictionnaire persistant & cycle de vie
- `runAnalysis()` fusionne les résultats frais dans `store.correlations` (clé = trigger) :
  met à jour data + `observedAt = now` + `windowDays` + `current = true`, **en
  conservant** `pinned`/`hidden`. Les clés absentes du run passent `current = false`.
- **Affichées** (liste principale) : `!hidden && (current || pinned)`, triées
  (épinglées d'abord, puis par occurrences).
- **Archivées** (section dépliable « Afficher les corrélations obsolètes (N) ») :
  `hidden || (!current && !pinned)`.

### 9.5 Carte de corrélation
- Énoncé : « Tes douleurs/symptômes reviennent souvent les jours où tu notes : « {x} ». »
- Bande de force + barre de ratio + texte d'occurrences.
- **Ligne de date normée** (remplace l'ancien caveat) : « Corrélation observée le {date},
  sur les données {des 24 h / des 3 jours / de la semaine} précédentes. » Date + fenêtre
  = celles de la dernière observation (une obsolète garde sa fenêtre d'origine).
  La **même ligne figure désormais sur les cartes manuelles** (§10.4) : date du Run +
  **plage des jours réellement analysés** (« du {premier} au {dernier} »).
- **Actions en pictogrammes discrets** à droite de la ligne de date :
  - 📌 **Épingler / Désépingler** : reste affichée en permanence, **sans échéance**.
  - 🚫 **Masquer / Réafficher** : bascule dans l'archive.
  - Style réglable : **Pictogrammes** (défaut) ou **Pictogrammes et texte** (Réglages).

### 9.6 Tags d'état
`Épinglée` (plein), `Obsolète` (gris), `Masquée` (pointillé) selon l'état.

### 9.7 [ROADMAP] Portée « tout l'historique »
Ajouter une option (réglage ou sélecteur) pour analyser **toutes les données** au lieu des
14 derniers jours. Impact : plus de patterns mais aussi associations plus anciennes.
Implémentation : paramétrer le `since` de `computeInsights` (et idéalement exposer le choix
à l'utilisateur).

---

### 9.8 Analyses ciblées (raccourcis) — 03/07/2026
- Section **discrète** (repliable, fermée tant qu'aucun résultat) sous le bouton « Mettre à jour ».
- Un raccourci = une paire de catégories, avec **filtre de valeurs** optionnel pour Symptômes
  (`satiete` / `envie` : on n'agrège QUE ces informations, jamais tous les symptômes).
- Chaque lancement (manuel, bouton-chip) compare : **(1) séries agrégées** — énergie = niveau
  moyen /5, sommeil = durée de nuit (h), douleur/symptômes/brouillard = présence 0/1 sur les
  jours avec entrée, alimentation/activité/social = compte par jour ; **(2) valeur × valeur** —
  présence quotidienne de chaque valeur de A contre chaque valeur de B (valeurs vues ≥ 2 jours).
- **Verdicts honnêtes** : r de Pearson + n jours communs ; corrélation si |r| ≥ 0,35 (forte ≥ 0,6) ;
  « données insuffisantes » si n < 3 ; les paires non corrélées sont comptées, pas cachées.
- Respecte la **source Regex/IA** de l'écran ; résultats **persistés** (`store.shortcutResults`),
  datés et sourcés ; caveat « association ≠ preuve » sur chaque carte.
- **Liste maintenue à la main** (`store.shortcuts`, 6 raccourcis au 03/07 : Énergie×Alimentation ·
  Douleur×Alimentation · Satiété×Activité · Envie×Activité · Satiété×Sommeil · Envie×Sommeil),
  semée une fois, **jamais écrasée**.
- **[ROADMAP] Moteur de suggestion** : un moteur déclenchera l'ajout de « raccourcis de
  génération d'analyses ciblées pertinentes » — **additif uniquement** (ne retire ni ne modifie
  jamais les raccourcis posés à la main).

## 10. Écran Corrélations manuelles

Génération **on demand** d'analyses choisies par l'utilisateur.

### 10.1 Saisie des facteurs
- **N facteurs** (min 2) en **texte libre** ; boutons *+ Ajouter un facteur* / × retirer.
- **Méga-menu de suggestions** : panneau **sous le champ** (pas à droite), pleine largeur,
  **4 colonnes** desktop / 2 mobile. Source : presets (heure du coucher, heure du dîner,
  heure du réveil, qualité de la nuit). Un **facteur** est soit une **catégorie**
  (ex. « Alimentation »), soit une **valeur** (ex. « Sucre ») : la liste mêle les **noms de
  catégories** et les **valeurs** extraites des entrées passées, chaque suggestion portant
  son type (`manualVocab()` renvoie `{label, kind:'category'|'value'}`). Voir §17 (vocabulaire).
  - **Chips différenciés par type** : une suggestion **catégorie** a un fond **plus intense**
    qu'une **valeur** (`.mf-sug--category` = `--c-200` vs base `.mf-sug` = `--c-50`).
  - **Filtrage à la frappe** : à chaque caractère ajouté/retiré, la liste se restreint aux
    suggestions contenant le texte saisi (sous-chaîne, insensible à la casse).
  - **Reste affiché tant que le curseur est dans un champ de facteur** : ouverture au
    **focus**, au **clic** et à la **frappe** ; **sélectionner une suggestion** remplit le
    champ, **garde le focus ET le menu ouvert** (re-filtré sur la nouvelle valeur) ;
    fermeture **uniquement** quand le focus quitte **tous** les champs de facteur, ou via
    **Échap**. Passer d'un champ à l'autre **ne ferme pas** le menu (il se repositionne sous
    le champ actif).
  - **Clic sur une suggestion** = remplit le champ correspondant (`data-idx`).
- Bouton **Run**.

### 10.2 Construction des séries `factorDaily(factor)`
- Match : une entrée concerne un facteur si son texte/ses signaux contiennent un mot
  (>2 lettres) du facteur.
- Valeur quotidienne : si facteur « horaire » (heure/coucher/réveil/dîner…), extraire
  l'heure du texte (`23h`, `23:30`) sinon l'heure de `createdAt`. Sinon : 1er nombre d'un
  signal puis du texte ; à défaut, **nombre d'occurrences** du jour. Agrégat = moyenne.

### 10.3 Calcul & affichage
- **2 facteurs** : Pearson sur jours communs → **nuage de points** + force.
- **3+ facteurs** : **un seul résultat global** (jamais la liste des paires). Matrice de
  corrélation k×k puis **valeur propre dominante** λ₁ (power iteration) →
  `force = clamp((λ₁−1)/(k−1), 0, 1)`. Affichage : carte unique « f1 × f2 × f3 » +
  **graphique multi-courbes** (une ligne normalisée par facteur).
- **Force + note + pastille (toujours)** _(code : champ `band`, badge `.band-dot`)_ :
  - 🟢 **Vert** — *Corrélation forte* (|r| ou force ≥ 0,6)
  - 🟡 **Jaune** — *Corrélation possible* (≥ 0,35)
  - 🔴 **Rouge** — *Pas de corrélation claire* (< 0,35, < 3 jours communs, ou variance nulle)
  - Note rédigée : « Coefficient r = {r} sur {n} jours communs. {sens} » ou
    « Schéma commun aux {k} facteurs : force {s}/100, sur {n} jours communs. » + rappel
    « association observée, pas une preuve de cause à effet ».
- **Graphiques neutres** : le nuage de points et le multi-courbes utilisent une palette
  **gris/noir** (fond, axes, points, courbes — variables `--chart-*`) **indépendante du
  thème** — rendu volontairement sobre/professionnel, **identique** en turquoise comme en
  corail.

### 10.4 Sauvegarde, épingler & masquer
- Chaque **Run** enregistre le résultat dans `store.manual.saved` (liste **persistante**),
  **dédupliquée par facteurs** (clé = facteurs en minuscules, triés) : relancer la même
  combinaison **met à jour** la carte existante en conservant son épinglage/masquage.
- Chaque carte porte un **pied épingler / masquer** identique à l'écran auto (§9.5) :
  📌 **épingler** (tri en tête, tag « Épinglée ») et 🚫 **masquer** (bascule dans la section
  dépliable **« Afficher les corrélations masquées (N) »**, avec réaffichage). Style des
  boutons réglable (Pictogrammes / Pictogrammes et texte, cf. §12).
- Tri des visibles : épinglées d'abord, puis par date de calcul décroissante.
- **Ligne de date** (comme l'écran auto §9.5) : « **Corrélation observée le {date}, sur les
  données du {premier} au {dernier}.** » — {date} = génération du Run ; plage = étendue des
  **jours réellement analysés** (jours communs aux facteurs). Le sous-titre de l'écran est
  « Choisis 2 facteurs ou plus, puis lance l'analyse. **Corrélation n'est pas causalité** ».

### 10.5 [ROADMAP] Robustesse de l'extraction
L'extraction numérique actuelle (premier nombre) confond deux facteurs chiffrés dans une
même entrée. Cible : extraction **ciblée par facteur** (fenêtre autour du mot-clé) ou
**champs structurés/typés** à la saisie (unités explicites).

---

## 11. Écran Mon compte

Accessible via le **nom (avatar + pseudo) en haut à droite**, cliquable.

- **Identité** : e-mail (lecture seule), **mot de passe en clair** (ou « reconnecte-toi
  pour l'afficher » si non capturé), bouton **Se déconnecter**. *(Bloc déplacé depuis
  Réglages.)*
- **Profil** :
  - **Date de création** (lecture seule). Défaut = date de la 1re entrée si non stockée.
    [ROADMAP] exposer la vraie date d'inscription via `api.php` (présente dans
    `users.json`) au login.
  - **Entrées au journal** : `entries.length` (les éditions **ne comptent pas** comme de
    nouvelles entrées).
  - **Sexe à la naissance** : H / F / Autre (`M`/`F`/`O`) — « pour les standards du
    métabolisme ». Éditable, persistant.
  - **Date de naissance** : sélecteur de date. Éditable, persistant.
- **Comment ça marche** : court texte d'onboarding **sous Profil**, résumant l'_user journey_
  en langage canonique — Journal → **Entrées** → **Catégories**/**Valeurs** → Données →
  **Corrélations automatiques** (**Déclencheur** ↔ **Symptôme**, **Force**) → **Corrélations
  manuelles** (**Facteurs** : Catégorie ou Valeur). Cf. §17.

---

## 12. Écran Réglages

Écran **réorganisé en 4 grandes parties** (niveau 1), chacune contenant des **sous-groupes**
(niveau 2) et des **sections repliables** (niveau 3). **v7 (02/07/2026) : les 4 parties racine
elles-mêmes sont désormais repliables et FERMÉES par défaut** (`<details class="set-part-block">`,
titre en `<summary>` + chevron) — l'écran s'ouvre en vue compacte ; l'état ouvert/fermé de
chaque partie est **conservé le temps de la session** (`S.partsOpen`, écouteur `toggle` en
capture) pour survivre aux re-renders déclenchés par un réglage interne, mais **repart replié**
au prochain lancement de l'app (non persisté au store). Hiérarchie visuelle : partie en gras +
séparateur fort ; **titres de sous-groupe agrandis (≈ 1,2 rem) et TOUJOURS en noir**, même si
la fonction qu'ils contiennent est inactive ; section = carte dépliable. Le **gris** ne porte
que sur le **contenu** d'une section inactive (jamais sur son titre) — c'est l'unique
indicateur d'inactivité (plus de note explicative dédiée). **Tous les styles de Réglages
sont forkés sous `.settings-screen`** (isolation totale) : on peut les retoucher sans
impacter le reste du site.

### I. Design
Le tableau des **4 préférences** (toggles **pleine largeur**, libellés allégés) :
**Taille du texte** (Normal / Grand +12 %), **Langue** (Français / English), **Thème**
(Turquoise / Corail), **Boutons** (Pictogrammes / Pictogrammes et texte).

### II. Moteur
La matrice
**« Choix du moteur »** (fonction × méthode) est **éclatée en sections « Fonctions »** par
étape. **3 méthodes en colonnes** : **à la main dans réglages**, **moteur en local dans
l'appareil**, **via un modèle IA/LLM** ; boutons radio reflétant l'état réel (aujourd'hui :
tout « en local » sauf la sollicitation, « à la main »). Chaque « Fonctions » a son lien
**« Plus d'informations »** (même grille en texte ; mention « Utilise des tokens — option
payante » sur la colonne LLM). **Cosmétique en démo.** Lié aux [ROADMAP] §6.3/§6.4.

- **Les données entrées** → **Applications à connecter** *(grisé / futur)* : table d'apps
  avec un **interrupteur** par ligne — Apple Santé, Google Fit, Oura, Fitbit, Withings,
  Dexcom, **Localisation & météo** (température & humidité du lieu où l'on est, via la
  géolocalisation) — + **« Plus d'informations »** détaillant les données récupérées par app.
  *(Pas de « Fonctions » ici : aucune fonction du moteur ne s'y rattache.)*
- **Les entrées saisie** → **Fonctions** (*liste des tags* · *transformation* ·
  *sollicitation* · *analyse du ton de la voix*) · **Listes de tags** (chips des 13 thèmes +
  champ **« Ajouter un tag »** grisé) · **Structure des données** (transformation en
  informations ordonnées : catégorisation, extraction de valeurs, négations) ·
  **Campagnes de sollicitation** *(grisé)* = règles d'entrées sollicitées (cf. §7.2 ;
  *Qu'as-tu mangé ?* / *Toujours mal aux cuisses ?* / *As-tu dormi depuis ton dernier
  sommeil ?* avec leurs déclencheurs).
- **Traitement et présentation des données** → **Fonctions** (*facteurs du Récap*) ·
  **Récap des données** (7 / 14 / 30 jours, **actif**, ouvert par défaut) · **Portée de
  l'analyse** *(grisé)*.
- **Corrélations** → **Fonctions** (*moteur de corrélations*) · **Sources médicales**
  *(grisé)* : sources officielles mobilisables par l'IA, en **2 sous-parties** —
  **URL d'API** (8 sources : OMS-GHO, OMS-CIM-11, HAS, ANSM-BDPM, ANSES-Ciqual,
  PubMed/MEDLINE, openFDA, SNOMED CT/UMLS ; toggle + champ URL réel éditable) et **Jeux de
  données** (toggle + import de fichier ; placeholders régimes ; recherche « marketplace ») ;
  **« Ajouter une source »** toujours visible. **Cosmétique** (RAG / tool-use à construire).
  - **[ROADMAP]** *Analyse du ton de la voix* : **indisponible** en « à la main » et « en
    local » ; en **IA/LLM** = analyse du son de la voix pour détecter l'humeur (stress,
    énervement, joie…). Aucune méthode active aujourd'hui.

### III. Gestion des données personnelles
- **Import** → *Importer des données dans le journal* **[ROADMAP, grisé]** · *Importer des
  données (JSON)* (**fonctionnel** : restaure un export, **préserve l'identité** (token/email)
  et le mot de passe, confirmation si le compte a déjà des entrées).
- **Export et partage** → *Exporter le journal (JSON)* **[ROADMAP, grisé]** · *Exporter
  toutes les données* (**fonctionnel** : export **complet** de `store` ; nom
  `wwfm-<user>-AAAA-MM-JJ-HHMM.json`) · *Rapport pour mon médecin* **[ROADMAP, grisé]**.
- **Gestion des données personnelles et fonctions associées** *(grisé / cosmétique)* : items
  à cocher / déplier — *Ne jamais transmettre mes données ni mon nom à un tiers* (coché &
  verrouillé, étiquette « **RESTERA TOUJOURS GRATUIT** ») · *Chiffrer le stockage de mes
  données* (OVH mutualisé / option disque dédié + chiffrement de bout en bout, « **150 €/mois**
  ») · *Me proposer de tester de nouveaux protocoles de laboratoire* · *Partager mon journal
  de façon anonyme* · *Personnaliser mes valeurs de référence* (« **Sur devis** »).

### IV. Informations légales
3 liens ouvrant chacun un **écran texte** dédié (avec bouton retour vers Réglages) —
**Mentions légales**, **Conditions générales d'utilisation (CGU)**, **Conditions générales
de vente (CGV)**. Contenu **lorem ipsum** en démo, à remplacer par la version juridique.

> *« Charger des exemples » a été **retiré** des Réglages.*

**Design de l'écran Réglages** : présentation **neutre et structurée**, **sans le code
couleur du thème** — palette **grise**, **cartes plates** à bord net, en-têtes de **partie
(I–IV) en gras + séparateur**, **sous-groupes en petites capitales grises**, sections
repliables. Exceptions colorées (volontaires) : les **pastilles turquoise/corail** du
sélecteur de thème (c'est le contenu) et la **navigation** (barre d'onglets / haut), communes
à toute l'app. Segmented control « actif » : rail teinté + pastille blanche surélevée (anneau
+ ombre), texte inactif atténué.

---

## 13. i18n
Toutes les chaînes via `t(key)`, dictionnaires `I18N.fr` / `I18N.en`. La bascule de langue
re-rend toute l'app. **Attention encodage** : en JS, les délimiteurs de chaîne doivent être
des apostrophes ASCII `'` ; les apostrophes typographiques `'` ne sont valides qu'à
l'**intérieur** des chaînes. (Bug récurrent : un outil d'édition convertit les délimiteurs
en `'`/`'` et casse le JS → page blanche. Vérifier après chaque édition.)

---

## 14. Sécurité & confidentialité
- **Démo = données de test**, sans durcissement (cf. `api.php`). Mots de passe **en clair**
  côté client/serveur **acceptable uniquement en démo** ; **à proscrire en production**.
- Données de santé = sensibles. Production : chiffrement at-rest, sessions signées,
  consentement explicite avant tout envoi à un tiers (LLM).
- Jamais de push de données réelles sur GitHub.

---

## 15. Déploiement
- **Règle permanente** : chaque modification est **mise en ligne sur la production**
  (FTP/lftp vers `/w/app`) **sans pousser sur GitHub**, sauf demande explicite.
- Après chaque édition de `app.js` : vérifier l'absence de guillemets typographiques comme
  délimiteurs + équilibre accolades/parenthèses, puis valider en ligne par `curl`.

---

## 16. Critères d'acceptation (checklist)
- [ ] Saisie texte/voix/photo ; entrée taguée + horodatée + persistée.
- [ ] Édition/suppression d'entrée ; `editedAt` ; bannière stale ; réintégration au run.
- [ ] Récap configurable 7/14/30 (défaut 7) ; seuils proportionnels ; « informations
      absentes » stylé ; panneau distinct des listes.
- [ ] Corrélations auto : fenêtre 24 h/3 j/1 sem ; pin (sans échéance) ; masquer ;
      obsolètes en section dépliable ; ligne de date normée ; bannière stale.
- [ ] Corrélations manuelles : N facteurs ; méga-menu colonnes sous le champ, **affiché tant
      que le champ est focalisé** et **filtré à la frappe** (ne se ferme pas à la sélection) ;
      2 facteurs → nuage ; 3+ → score global unique (pas la liste des paires) + multi-courbes ;
      pastille verte/jaune/rouge + note **toujours**.
- [ ] Corrélations manuelles : suggestions de **facteurs typées** (catégorie/valeur) ; chip
      **catégorie** au fond plus intense que chip **valeur** (cf. §17 vocabulaire canonique).
- [ ] Réglages → **Liste des valeurs** (§6.5) : valeurs textuelles groupées par catégorie
      (nombres exclus) ; éditer / supprimer (retire le signal, confirmation) / ajouter ;
      **fusion par glisser-déposer** (souris + tactile, valeur reçue conservée) ; alias
      persistés + **normalisation à la saisie** (« Sucré » → « Sucre »).
- [ ] Journal : picto **Masquer le contenu** (floute texte + photos, chips visibles).
- [ ] Données : « Par catégorie » **replié par défaut**.
- [ ] Mon compte accessible via le nom ; identité + profil (création, nb entrées hors
      éditions, sexe, naissance).
- [ ] Réglages : langue, thème, taille texte, récap jours, style boutons, sample, export
      (nom horodaté), import (préserve identité+mdp).
- [ ] Journal : section « Entrées sollicitées » (pull) toujours visible (message si vide) ;
      répondre → vraie entrée auto-taguée ; fond teinté dédié sur « Ton journal » (cartes
      blanches).
- [ ] Données « Par thème » : listes à hauteur fixe + scroll interne + chargement
      progressif (40 puis +20 « Voir plus » / « Afficher plus »).
- [ ] Corrélations manuelles : liste sauvegardée (dédupliquée) + épingler/masquer +
      archive « masquées » ; graphiques neutres (gris) indépendants du thème.
- [ ] Réglages : « Choix du moteur » (matrice fonction × méthode + « Plus d'informations »
      avec note tokens/payant) ; « Gestion des données personnelles » (cosmétique, `*`) ;
      écrans légaux (mentions / CGU / CGV) ; design neutre de l'écran (hors navigation).
- [ ] 5 onglets, libellés complets 2 lignes, séparateurs fins.
- [ ] Bilingue FR/EN ; thèmes turquoise/corail ; grand texte.
- [ ] **[ROADMAP]** userRules ; portée tout l'historique ; export horodaté ; vraie date
      d'inscription serveur ; extraction numérique ciblée ; LLM hybride ; natif iOS
      (dictée, push) ; base de données + sécurité production.

---

## 17. Vocabulaire canonique (Ubiquitous Language)

> Un seul mot par concept, identique partout : **ce que dit Elena = le mot dans le code = le
> mot dans l'UI**. Convention de code : **identifiants en anglais, textes UI via I18N**.
> Référence complète : `app-ios/glossaire.md`.

### 17.1 Termes piliers (corrélations)
- **Catégorie** (`category`, abrégé `cat`/`CATS`/`catName`) — un type, liste fixe (~13 :
  Sommeil, Alimentation, Douleur, Climat…). _Abandonné : « tag », « type », « thème »._
- **Valeur** (`value`) — une instance dans une catégorie (« Sucre », « Pluie », « 7,5 h »).
  _Abandonné : « élément », et « facteur » dans ce sens._
- **Facteur** (`factor`) — **ombrelle** : une chose corrélable = une **catégorie OU une valeur**.
  _Abandonné : « variable », « paramètre »._
- **Force** (`band`) — l'intensité d'une corrélation (faible/modérée/forte côté auto ;
  vert/jaune/rouge côté manuel). _Abandonné : « verdict »._

### 17.2 Homonymes à NE PAS confondre (conservés)
- `theme` = thème **couleur** (turquoise/corail), ≠ catégorie.
- `pinnedTag`/`obsoleteTag`/`hiddenTag`, `.corr-tag` = **badges de statut** d'une corrélation.
- `price-tag`, `pdp*Tag` = étiquettes de **prix** ; `tagline` = **slogan**.

### 17.3 Mises en conformité (faites, 27 juin 2026)
- `manualVocab()` renvoie des **facteurs typés** `{label, kind:'category'|'value'}` ; chips
  différenciés `.mf-sug--category` (fond `--c-200`) vs valeur `.mf-sug` (`--c-50`).
- **`verdict` → `band`** (code + CSS `.v-*` → `.band-*`/`.band-dot`) ; couleurs/libellés
  inchangés ; rétrocompat des données sauvegardées (`band || verdict`).
- **`tag` (sens catégorie) → `category`** : `pendingCategory`, `S.filters.category`,
  `data-act="category"`, `.catchip`/`.catchips`, `categoriesBody()`, libellés « Catégorie /
  Catégories actives / Ajouter une catégorie », textes « par catégorie », etc.

### 17.4 [ROADMAP] Alignement terminologique restant
- Aligner progressivement les mentions « tag »/« thème » des sections antérieures (notamment
  §6 « moteur d'attribution de tags », §8.2 « Par thème ») vers « catégorie ».
- (Optionnel) renommer les badges de statut `pinnedTag`/`.corr-tag` vers un vocabulaire
  « badge » si souhaité.

---

## 18. [VALIDÉ 30/06/2026 · conception] Modèle cible « valeurs plates » & extraction IA

> Issu d'une session de co-conception. **Remplace** la piste « champs typés par catégorie »
> (§17.4 backlog). Validé sur le principe ; **pas encore codé** (le moteur IA est gaté —
> voir §18.5). La démo web garde aujourd'hui le moteur **local** (§6.2) ; ce §18 décrit la
> **cible**.

### 18.1 Positionnement produit
- Le moteur raisonne sur une **masse** d'informations → produit **énormément d'indicateurs
  intermédiaires** (plus qu'un médecin n'en calculerait), puis **repère ce qui sort de
  l'ordinaire** (définition d'« ordinaire » à préciser ultérieurement), et **livre au
  patient s'il le souhaite mais surtout au médecin qui l'accompagne**.
- W **augmente** la relation patient↔médecin ; **ne diagnostique pas** (le médecin
  interprète). « Hors des repères de santé » = **information / repère**, jamais une alerte
  médicale ni un diagnostic.
- **V1 = « boîte de verre »** : seule utilisatrice = Elena (+ investisseurs) ; les
  investisseurs veulent **voir tous les KPI intermédiaires** → tout est **visible et
  auditable**. Filtres / vues = plus tard.

### 18.2 Modèle « valeurs plates »
- Un seul objet : la **valeur**. **Pas de niveaux figés** — la hiérarchie **émerge des
  formules** (graphe de dépendances : brut → calculé → agrégé → comparé).
- **Catégorie = un attribut / tag** sur la valeur, pas un niveau.
- Une **valeur** est une **série** (suite de points dans le temps), pas un scalaire.
- **Champs qualifiants** : toujours `nom (préférence) · type · source · grain` ; selon le
  cas `unité / échelle · formule (si calculée)` ; optionnels `synonymes · favori`.
  - **type** ∈ {numérique, durée, heure-horloge, booléen, ordinal, étiquette}
  - **source** ∈ {extraite (journal), calculée (formule), donnée (constante posée)}
  - **occurrence** = l'unité « par X » (nuit, jour…) = les **lignes** ; les valeurs = les
    **colonnes** ; une formule « point par point » aligne ses opérandes sur l'occurrence.
- **Agrégations (moyennes) & favoris** sortent de la liste plate → **encart Récap dédié à
  règles** (valeur source + agrégation + fenêtre + normale + repère → écart + statut).
  *(Récap/moyennes/formules : parkés pour l'instant — le focus courant est l'extraction.)*

### 18.3 Focus courant : EXTRACTION — partage des rôles
- **Elena fournit la STRUCTURE** (le schéma) ; **l'IA déduit & peuple** les valeurs depuis
  les entrées **et découvre de nouveaux types au fil de l'eau** (le catalogue n'est **pas**
  pré-listé) ; **Elena cure** (renommer / fusionner / corriger). La « Liste des valeurs »
  (§6.5) devient l'outil de **curation** du catalogue déduit par l'IA.

### 18.4 Structure de base (extraction)
- **Entrée** : `id · date-heure · texte · (photo)`
- **Type de valeur** *(catalogue déduit par l'IA, éditable)* : `id · nom (préférence) ·
  synonymes[] · type · unité/échelle · catégorie (tag)`
- **Relevé** *(extrait d'une entrée)* : `id · → type de valeur · valeur (typée) ·
  moment/date de référence (≠ horodatage de l'entrée si le texte le précise) ·
  → entrée source + extrait exact · confiance`
- Liens : une **Entrée** produit plusieurs **Relevés** ; chaque **Relevé** pointe vers un
  **Type de valeur** et vers son **Entrée** d'origine (traçabilité = base de la boîte de verre).

### 18.5 Moteur IA — faisabilité & coût (gate)
- Aujourd'hui l'extraction = **regex local** (`structureEntry`, §6.2). Pour l'IA :
  `api.php` → **API Anthropic** (paiement **à l'usage, sans abonnement**), **clé côté
  serveur uniquement** (jamais dans `app.js`, jamais poussée). **Pas** lié au compte
  claude.ai (chat). Tourne **à chaque entrée** (+ « Tout réanalyser » pour l'historique).
- **Coût** ≈ **46 $/an** avec **Haiku 4.5** à 50 entrées/jour (~0,25 ¢/entrée) — sans forfait.
- **Décision en attente** (débloque le branchement) : clé API · accord pour que le **texte
  des entrées parte vers l'API** (au moins pour le démo) · conception du **prompt
  d'extraction**. Le réglage `fn2` (§6.2) bascule local ↔ IA dès branchement.
- **CONDITION DE BRANCHEMENT — ANONYMISATION (non négociable, dès la phase démo).**
  Exigence explicite d'Elena (30/06/2026) : *« si quelqu'un tape un jour mon nom dans une
  base, même privée, d'Anthropic, il ne doit jamais tomber sur mes infos (poids,
  alimentation, énergie…) ».* L'extraction IA n'est branchée **que** si elle est
  **anonymisée par construction** dans `api.php` :
  1. **Compte API neutre** — clé Anthropic créée sous une identité **projet / pseudonyme**, jamais le nom de l'utilisatrice (le compte qui émet les requêtes n'est pas son identité).
  2. **Payload minimal** — la requête ne contient **QUE le texte de l'entrée** ; **jamais** le nom, l'e-mail, le token de session, ni un champ de profil. L'identité reste sur le serveur OVH (`store_acc_<id>.json`, clé par ID opaque) et dans le navigateur — hors du chemin vers l'API.
  3. **Caviardage des identifiants** — avant l'envoi, retirer du **texte** le nom et le slug d'e-mail connus de l'app (→ « [moi] »), au cas où l'entrée se nommerait elle-même.
  4. **Référence opaque** — si une requête devait porter un identifiant utilisateur (inutile pour l'extraction), ce serait un **id aléatoire**, jamais le nom.
  → **Objectif : aucune donnée reliable au nom de l'utilisatrice** ; une recherche par nom
  ne renvoie rien. Rappels API : **pas d'entraînement** sur les données API, **rétention
  courte** (non indéfinie) puis suppression, contenu **non indexé / non exposé à des tiers**
  — durée exacte / ZDR à confirmer dans le **DPA + conditions** Anthropic du moment. *(La
  gouvernance « vrais patients » — RGPD, donnée de santé hors UE, consentement, DPA — reste
  un chantier distinct, hors démo.)*
### 18.6 Curation & jeux de données (implémenté 02-03/07/2026)
- **Deux jeux ÉTANCHES par entrée** : `signals` (regex, toujours à jour) / `signalsAI` (figé au
  dernier **Run IA** manuel, `store.aiMeta.lastRunAt`). Aucun partage ; en vue IA, une entrée
  postérieure au run n'existe pas ; récap IA ancré sur la date du run. Toggle « Données
  sources » sur Données / Corrélations auto / manuelles (Regex à gauche, IA à droite).
- **Premier Run IA** exécuté le 02/07/2026 sur les 88 entrées (Claude en session, backup
  préalable, texte jamais modifié) — 190 signaux ; bouton « Run IA » gâté tant que l'API
  n'est pas branchée (§18.5).
- **Boucle de curation (React v2 — solution temporaire)** : picto sur chaque ligne de « Par
  catégorie » (hover desktop / tap mobile) → popin « Réagir au traitement fait de l'Entrée
  saisie » : **entrée d'origine** rappelée (texte + date) · **donnée extraite** affichée avec
  **👍/👎** (visibles uniquement en vue IA — le regex n'apprend pas) · **« Aussi extrait de
  cette entrée »** (signaux frères = la scission est visible) · **catégories multi-sélectionnables**
  (clic = ajouter une info avec champ valeur ; désélection = enlever = **vraie scission**,
  chaque info dans sa catégorie) · **« Dire quelque chose au modèle »** (textarea libre).
  Chaque réaction = **donnée** (`store.feedback` : entrée, signal, jeu, verdict, cible, note,
  date), **rejouée après toute réanalyse locale** (`applyRegexFeedback`) et **injectée dans
  les instructions du prochain Run IA**. *(À reprendre avec le point de fond : scission
  propre / ré-extraction par entrée une fois l'API branchée.)*
- **Règles de vocabulaire** (`store.vocabRules`, alimentées par la curation) : appétit (4 valeurs
  canoniques en Symptômes) · « Sans écran » = hygiène de Sommeil (jamais Activité) ·
  « Visage dégonflé » = signe corporel positif (jamais énergie basse).

- **Ligne non négociable** : tout **chiffre de corrélation** reste calculé par du **code
  déterministe auditable** (raccord mantra « Comparaison n'est pas raison ») ; l'IA
  interprète / extrait / explique, ne tranche pas la statistique.


---

## 19. [V2.0 — DÉCIDÉ 04–06/07/2026 · EN CONSTRUCTION] Pipeline 100 % IA

> Pivot majeur. La **V2.0** du site test (nommée ainsi partout, y compris GitHub) **remplace
> le moteur local Regex** par un pipeline 100 % IA orchestré à la main. Les sections V1 de
> ce cahier (§6 moteur de tags, §8–§10 écrans, §18.6 jeux étanches) décrivent la démo
> **encore en prod** ; ce §19 décrit la **cible V2.0**. Le modèle conceptuel du §18
> (valeurs plates, relevés, traçabilité « boîte de verre ») reste la base ; la stratégie de
> branchement du §18.5 (extraction à chaque entrée via `api.php`) est **remplacée** par les
> Runs manuels ci-dessous — l'anonymisation §18.5 redeviendra la condition au moment du
> branchement d'un moteur en ligne.

### 19.1 Décision de pivot
- **Abandon total du moteur local Regex** : retrait du « Choix du moteur » (`fn2`) des
  Réglages, du toggle Regex/IA des 3 écrans, et de la logique deux jeux étanches
  `signals`/`signalsAI`. Tout le traitement passe par l'IA.
- **Aucun moteur branché en ligne** pour cette phase : chaque étape est une **commande**
  lancée à la main par Elena **via Claude Code** sur son ordinateur. Un moteur IA sera
  branché plus tard.
- **Traçabilité** : à chaque Run, tracer le **modèle réellement utilisé + la date**
  (« extrait par Fable le … ») — condition de reproductibilité de la boîte de verre.
- Chaque commande est **documentée par une page de schéma publiée** (le « contrat » donné
  au modèle), créées le 04/07 (vides puis remplies au fil des validations).
- **Page « User Beliefs » (`/user-beliefs`, créée le 06/07)** : registre transverse des
  **croyances de l'utilisateur** — optima connus (repas = 2, coucher 21 h 30 · réveil 6 h · durée 8 h–9 h (plage),
  réveils nocturnes = 0), asymétries (Fadi inerte / Didi = le signal), objectif santé,
  sens des catégoriels, **fenêtres d'application par déclencheur** (délai / cumul, remplies
  par Elena), **valeur par défaut par KPI** (NA = aucune, l'info reste « Non renseigné » ;
  ex. « Envie de manger entre les repas » = Non par défaut). Une croyance = un **a priori révisable** (statut confirmée / infirmée /
  affinée par les analyses ; étape de remise en question prévue si le modèle final ne
  fonctionne pas). Ce registre alimente l'encodage (§19.6 pilier 0), l'extraction (Step 1)
  et le ranking (Step 4).

### 19.2 Les 5 commandes (pipeline)

| Step | Commande | Modèle | Page de schéma | Tagline |
|---|---|---|---|---|
| 1 | `Extract User Data` | Fable | `/app/extraction-schema` | Transforme les Entrées en Données Exploitables |
| 2 | `Run Recap Table` | JS (aucun modèle) | `/derived-metrics` | Résume les Données Exploitables en repères |
| 3 | `Run All Correlations` | Opus 4.8 | `/correlation-schema` | Calcule toutes les corrélations |
| 4 | `Find Insights` | Fable | `/insight-ranking` | Repère les corrélations qui valent le coup |
| 5 | `Run Insights Requested` | Fable | `/insight-generation` | Répond aux demandes d'enquête de l'utilisateur |

- **Step 2 = règles JS déterministes** (pas un Run IA) : le tableau Récap **s'affiche
  toujours automatiquement** au rendu de l'écran Données ; la commande ne sert qu'à
  **vérifier / rafraîchir**.
- **User journey V2.0** : (1) saisie d'Entrées (texte/audio/image) dans Journal ; (2)
  `Extract User Data` → Données Exploitables affichées dans Données ; (3) Récap rempli par
  règles JS ; (4) consultation de Données ; (5) `Run All Correlations` puis `Find Insights`
  → l'écran Corrélations automatiques affiche en permanence les corrélations pertinentes +
  des liens vers des corrélations spécifiques déjà calculées mais non montrées par défaut ;
  (6) sur Corrélations manuelles, l'utilisateur **Request** une analyse (texte optionnel
  hypothèse/question + **plage temporelle obligatoire**) — le CTA **enregistre la DEMANDE**,
  aucune réponse immédiate ; (7) `Run Insights Requested` traite les demandes pending →
  la réponse est **écrite dans le store** et l'écran **l'affiche automatiquement au prochain
  chargement** (aucune action manuelle requise).
- **Hub racine `w.shoette.com` refondu** (04/07, déployé) : 3 sections — Pipeline IA (5
  cartes cliquables commande + tagline + badge modèle), L'application (app démo ·
  howitworks · cahier), Pages de présentation (V1/V2/V3/V3 bis).

### 19.3 Catégories & KPI canoniques (extraction — validé)

**Principe** : le modèle extrait des **valeurs typées** rangées par **catégorie** ; chaque
catégorie définit des **KPI canoniques** (attendus à intervalle régulier) + un espace
**« en vrac »**. Types : heure-horloge · durée (h:mm) · nombre · booléen · ordinal ·
étiquette · texte. **Défaut = « Non renseigné »** — jamais de valeur inventée ni de « non »
implicite. Date de référence ≠ horodatage si le texte le précise. Chaque valeur garde le
lien vers son Entrée source + l'extrait exact.

**Consolidation V2 des catégories** : **Énergie, Douleur et Brouillard mental disparaissent
comme catégories** — elles deviennent des booléens de Symptômes (« Fatiguée », « Douleurs »,
« Brain fog ») ; l'échelle Énergie /5 est **abandonnée**. **Humeur** = étiquette
Bonne | Pas bonne. Appétit réduit à 2 booléens : « **Envie de manger entre les repas** » (optimum Non ; **valeur par défaut Non**), « **Faim entre les repas** » (optimum Non ; oui = mal)
(« Pas faim » = Faim:non ; **« Satiété » = synonyme de Faim:non** — règle de
vocabulaire d'extraction, les booléens Symptômes peuvent porter des synonymes déclarés).

- **🌙 Sommeil** (nuit rattachée **au matin où elle se termine**) : Heure de coucher ·
  Heure de réveil · **Heures de sommeil** (extraite si donnée, sinon **réveil − coucher** ;
  libellé unique, sans mention « estimée ») · Réveils nocturnes (nombre) · **Sommeil
  réparateur** (booléen, subjectif → **toujours demandé le matin**) · en vrac.
- **🍽️ Alimentation** (occurrence = **la prise alimentaire**) : Nombre de repas/jour
  (**dérivé** = nb de prises) · **Heure du dernier repas** (dérivé = heure de la dernière
  prise ; optimum **avant 19 h**, plus tôt = mieux ; hypothèse : après 19 h → perte de
  poids compliquée, mauvaise nuit, soif intense) · Litres d'eau/jour (**déclaration en fin de journée, non
  cumulée** ; sinon « info manquante ») · **Fadi / Didi par prise** (Fadi = « facile à
  digérer », Didi = « difficile à digérer » ; déclaratif ; **[V3]** déduit du contenu de
  l'assiette selon les critères d'Elena) · Détail des aliments (texte, transcrit si donné).
- **🏃 Activité** : Séances de sport (**avec transpiration**, dérivé = compte) ·
  **Mouvements** (booléen : danse, yoga, cœur qui monte **sans** transpiration) ·
  Étirements (booléen). **Le modèle classe** chaque activité décrite en Sport ou Mouvements.
- **👥 Social** : Vu des gens (booléen).
- **🌡️ Climat** (déclaratif ; **[V3]** météo auto via localisation) : Température
  ressentie (Chaud | Neutre | Froid). *Humidité retirée pour l'instant (06/07).*
- **🩺 Symptômes** (9 booléens du jour) : Envie de manger entre les repas · Faim entre les repas · Fatiguée · Brain fog ·
  Douleurs · Paupières irritées · Oreilles irritées · Bouche sèche · Colon irritable le
  matin.
- **🙂 Humeur** : Bonne | Pas bonne.
- **⚖️ Poids** *(nouvelle catégorie, ajoutée le 06/07)* : **Variation de poids (Δ depuis
  jour 0)** — nombre (kg, 2 décimales). Saisie : variation (« perdu 500 grammes » → −0,50)
  ou chiffre absolu (converti en Δ ; **l'absolu n'est jamais affiché** — discrétion phase
  de test, jour 0 = première déclaration = 0,00). **Absent du Récap** ; affiché **en
  dernier** dans la liste de l'onglet Données. Non sollicité. Cible des hypothèses Didi
  (cumul → prise), Sport (→ perte), dernier repas après 19 h (→ perte compliquée).

### 19.4 Moteur de sollicitation (3 niveaux, tous en v2)

**Vision : pas de problème de données manquantes — l'outil demande à l'utilisateur les
données clés dont il a besoin.**

**Règle générale** : question affichée ⟺ info vide ; dès qu'une Entrée renseigne le KPI, la
question disparaît ; la sollicitation persiste **tant qu'on est dans la journée**, puis le
trou reste **visible dans Données** (rattrapable) sans être re-posé.

**Planning (niveau 1 — règles fixes)** :
- **Matin** : KPI Sommeil manquants + Sommeil réparateur (toujours) + Colon irritable le matin.
- **14h** : Climat (température ressentie) si vide.
- **19h** : Eau · Activité (si rien rempli) · Social · Humeur · chaque Symptôme restant —
  **une question distincte par symptôme**.
- **Par prise** : Fadi / Didi pour toute prise non qualifiée.

**Niveau 2 — piloté par les analyses** : à chaque `Run All Correlations`, le moteur produit
une **liste de besoins** (`data-needs_<id>.json`) : les manquants qui bloquent le plus
d'analyses, affichés comme sollicitations **priorisées par valeur d'information**.

**Niveau 3 — questions conditionnelles « au bon moment »** : le Run écrit des questions
pré-compilées (déclencheur + question + moment), exécutées **localement** par l'app
(« SI une prise Didi est loguée aujourd'hui → demander demain matin : colon irritable ? »).
C'est le chaînon qui alimente la **validation prospective** (§19.6).

**Limite structurelle v2** : Runs manuels → la liste ne se rafraîchit qu'à chaque Run.

### 19.5 Récap V2.0 (Derived Metrics — Step 2)

Déterministe, recalculé au rendu ; **période éditable 7/14/30 j** (Réglages) ; deux vues
conservées : **Valeurs santé** / **Complétude du suivi**. Quatre familles d'agrégation :
- **Numérique → moyenne** (heures de sommeil, prises/jour) ;
- **Booléen → nombre de « oui » sur la période**, affiché **« n oui / jours déclarés »**
  (jours déclarés = info renseignée oui OU non ; exclut les « Non renseigné ») ;
- **Catégoriel → répartition** (Climat, Humeur — ex. « 5 j Humide · 2 j Sec ») ;
- **Compte d'événements rares → total sur la période** (séances de sport).

Lignes : Sommeil (h:mm moyen/nuit) · Alimentation (prises/jour + **% Fadi**, ex.
« 60 % Fadi ») · Activité (sport total, mouvements, étirements) · Social · Climat (répartition température) · Symptômes (8 lignes « n oui / jours déclarés » ; **Fatiguée remplace
l'ex-Énergie**) · Humeur (répartition). **Affichage conditionnel (06/07)** : les repères **booléens** (8 Symptômes, Mouvements,
Étirements, Vu des gens) et la **Température ressentie** ne s'affichent au Récap **que
s'il y a au moins un « oui »** (resp. un jour « Chaud ») sur la période — sinon la ligne
est masquée. **Volontairement absents** : Litres d'eau (choix
produit) · **Douleurs** (retiré du Récap mais **toujours collecté** → disponible pour les
corrélations) · Détail des aliments (en vrac) · **Poids** (jamais au Récap ; en dernier dans Données, en variation depuis jour 0).

### 19.6 Moteur de corrélations (Step 3) — objectif & méthodologie

**Objectif** : produire des **règles**, pas seulement des coefficients — forme cible :
*« Lorsque Facteur A, B, C et D pendant 48 h, et seulement en l'absence totale de Facteur
E, alors le 3ᵉ jour, dans 100 % des cas, on observe Facteur F et Facteur G. »*

**Deux couches** :
1. **Dépistage (Pearson)** — toutes les paires × lags. Une seule mesure de fond, trois
   formes : booléen×booléen → **phi / table 2×2** ; numérique×numérique → **Pearson** ;
   numérique×booléen → **écart de moyenne** (point-biserial). Sert d'éclaireur.
2. **Extraction de corrélations (le cœur)** — terminologie V2 : le produit s'appelle une
   **corrélation**, jamais « règle » (« règles métier » reste réservé à l'encodage). Famille
   technique des règles d'association (type Apriori) sur les
   combinaisons **réellement présentes** dans l'historique (jamais les 2^26 théoriques),
   mesurées par **support** (n jours où la condition s'est produite) · **confiance**
   (proportion où l'effet a suivi ; « 100 % » = confiance 1) · **lift** (vs hasard).
   Conditions expressives : état · **cumul** sur fenêtre (« 2 mauvaises nuits ») ·
   **délai** (« au 3ᵉ jour ») · **absence** (« sans E ») ; effet multiple. **Élagage** :
   une combinaison trop rare n'est pas étendue.

**Temporalité** : grain = **le jour** (imposé par les données) ; le **décalage (lag) n'est
jamais fixé** — on balaie J, J−1, J−2… et le meilleur lag est un **résultat**. Distinction
**délai** (effet X jours après) vs **cumul** (effet d'une répétition sur fenêtre glissante).
Elena fournira **par facteur** sa fenêtre crue (1–3 j, délai ou cumul) ; le moteur
l'utilise comme hypothèse ET teste les fenêtres voisines (confirme / infirme / affine).

**Règles métier (encodage, pilier 0)** — chaque facteur est transformé AVANT Pearson.
Source : le **registre `/user-beliefs`** (§19.1). En synthèse :
- **Optimum connu → jamais de linéaire brut** : repas idéal = **2/jour** (booléen « jour à
  2 prises » + paliers 0 · 1 · 2 · 3+) ; sommeil idéal = **durée en plage 8 h–9 h, coucher 21 h 30, réveil 6 h** (réveil : zone 5 h 30–6 h 30 = bien ; avant = neutre ; 6 h 30–8 h = neutre ; après 8 h = mal)
  (écart à l'idéal + booléen « au repère » + paliers ; tolérance à confirmer, proposé
  ± 30 min) ; réveils nocturnes = monotone (0 = idéal ; paliers 0 · 1 · 2+).
- **Asymétrie Fadi/Didi** : Fadi = état neutre **sans impact** (pas de recherche d'« effet
  Fadi ») ; **la variable de travail est Didi** — présence (jour avec Didi) **et** dose
  (0 · 1 · 2+ prises Didi). Sens attendu : Didi → dégradation (testé contre tout pour
  découvrir quoi).
- **Catégoriels** : codage avec un sens explicite (croyance utilisateur), jamais arbitraire.
- Une étape de **remise en question des croyances** est prévue si le modèle final ne
  fonctionne pas.

**Recherche multivariable — méthodes retenues** (recherche **ouverte, pilotée par la
donnée** ; pas de restriction a priori) :
- **A. Profilage des mauvais jours** : partir de l'effet (pires jours) et classer TOUS les
  facteurs × lags par sur-représentation — découvre aussi l'inattendu ;
- **C. Analyse conditionnelle / stratifiée** : pour tout lien X→Y, balayer chaque facteur Z
  comme **amplificateur** (« Didi→douleur fort surtout quand chaleur ») ;
- **Motifs réellement présents** (couche 2 ci-dessus).
- **Rejetés** : score de « charge » pré-défini (le but est de **découvrir** les facteurs) ;
  filtre de plausibilité par connaissance métier (le but est d'aider l'utilisateur à
  comprendre **ce qu'il ne comprend pas**). L'IA = explorateur + traducteur (met en mots,
  y compris le contre-intuitif), pas gardien de plausibilité.

**Les 5 piliers de validité — TOUS TENUS en v2** (v2 = MVP du moteur qui fonctionne) :
- **0. Encodage** (règles métier ci-dessus) ;
- **1. Comparaisons multiples** : des milliers de tests → des centaines de « forts » par
  hasard ; remèdes = distinction **confirmatoire** (hypothèse pré-posée) vs **exploratoire**
  (piste), affichage de n, réplication ;
- **2. Dépendance temporelle & confusion** : jours non indépendants ; **neutralisation
  jour-de-semaine/tendance reportée en v3** (choix utilisateur, décision 06/07) ; débusquer
  les facteurs cachés via l'analyse conditionnelle ;
- **3. Manquants informatifs** : « Non renseigné » = paire jetée, MAIS si les bons jours
  sont moins loggés le manque biaise → contextualiser par la complétude ;
- **4. Validation prospective** : la preuve forte = prédire puis confirmer sur des jours
  neufs.

**Statut d'une corrélation à 100 %** : une corrélation confiance 100 % à faible support est
une **CANDIDATE, pas une découverte** (sur 2-3 jours, 100 % ne prouve rien). Sortie du
moteur = corrélations à haute confiance **classées par support**. **Promotion** : candidate
→ **carnet d'hypothèses** → re-test sur jours futurs → **corrélation confirmée**.

**Seuils & constantes v2 (tranchés 06/07/2026)** : support minimal **n ≥ 3** (« candidate
sérieuse » = observée au moins 3 fois) · bandes de force **V1 conservées** (forte ≥ 0,6 ·
possible ≥ 0,35 · sinon pas de corrélation claire) · **lags balayés 0–3 j** (+ fenêtre
déclarée testée en priorité) · **neutralisation jour-de-semaine/tendance : NON en v2**,
[ROADMAP v3] avec **choix utilisateur** de l'activer.

**Carnet d'hypothèses** (`hypotheses_<id>.json`) : une ligne par hypothèse — facteur(s) ·
fenêtre crue · effet attendu · date · origine (**posée par Elena** ou **par le moteur**) ·
statut (**posée / confirmée / infirmée / affinée**) · force · n · date du test · modèle.
Les demandes de l'écran Corrélations manuelles (Step 5) entrent dans le même carnet.

**Objectif santé** *(CONFIRMÉ le 06/07/2026)* : référentiel codé en dur (non éditable en v2) —
être en bonne santé = pas de douleur, pas de brain fog, de l'énergie, une bonne humeur.
Détermine ce que les analyses montrent comme « bien » / « pas bien ».

**Positionnement** : l'outil est **marketé comme un outil d'enquête statistique** ;
afficher n + force n'est pas un garde-fou, c'est **le produit**. Les garde-fous UI peuvent
être allégés en v2 ; les piliers de validité, non.

### 19.7 Architecture technique V2.0 (proposée, à valider en construction)

Trois étages — **une source de vérité + des couches dérivées séparées, chacune un fichier
JSON inspectable** (boîte de verre) :

| Étage | Stockage | Écrit par | Statut |
|---|---|---|---|
| Entrées saisies | `localStorage` + `data/store_<id>.json` (OVH, sync `api.php`) | l'app | **source de vérité, jamais modifiée** |
| Données Exploitables (Step 1) | `data/derived_<id>.json` | le Run desktop | dérivé, régénérable |
| Base de corrélations (Step 3) | `data/correlations_<id>.json` | le Run desktop | dérivé, régénérable |

- - fichiers annexes : `hypotheses_<id>.json` (carnet) · `data-needs_<id>.json` (besoins).
- Le **Récap n'est stocké nulle part** (recalcul JS au rendu depuis `derived_<id>.json`).
- **Mécanique des Runs** : Claude Code **télécharge** le store depuis OVH (lftp/curl),
  calcule en local, **re-téléverse** le fichier dérivé. L'app ne fait que **lire** les
  dérivés — elle ne calcule jamais rien d'IA. On ne réécrit **jamais** `store_<id>.json`
  pendant un Run.
- **Runs incrémentaux** (Step 1) : ne retraiter que les entrées nouvelles/éditées → prévoir
  un repère (horodatage dernier run ou empreinte par entrée) dans `derived_<id>.json`.
- **Confidentialité** : tant que les Runs sont manuels (Claude Code local), le texte ne part
  chez aucun tiers au-delà de la session. Au branchement d'un moteur en ligne :
  l'anonymisation §18.5 redevient la condition.

### 19.8 Planning de construction (validé le 04/07/2026)
1. Écrire quelques **entrées Journal Test** représentatives (matière brute, tôt).
2. **Draft + audit** de chaque page schéma, ordre 1→5, contre ces entrées. *(En cours :
   extraction-schema et derived-metrics remplis ; correlation-schema = objectif + mesures +
   méthodologie + extraction de règles ; insight-ranking et insight-generation à drafter.)*
3. Lister les **modifs visibles** du site (retrait moteur/Regex, formulaire de demande,
   renommage V2.0…).
4. Gate : Claude confirme avoir tout pour construire.
5. Discussion → génération du **jeu complet** de données Journal Test.
6. Construction du **site démo v2**.
7. **Compte Test** + pipeline joué dessus + estimation de la pertinence.
8. Discussion / édition jusqu'à validation.
9. MàJ doc + cahier + **push GitHub** (via mise-au-net).

### 19.9 Fils ouverts V2.0
- **Fenêtres délai/cumul par facteur** : Elena doit les fournir (1–3 j, par facteur) —
  tableau dédié **à remplir dans `/user-beliefs`**.
- **Tolérances des optima — TOUTES réglées (06/07)** : réveil = zones (5 h 30–6 h 30 bien /
  neutre / mal après 8 h) ; durée = plage 8 h–9 h ; coucher = **± 30 min** (couché entre
  21 h 00 et 22 h 00 = au repère).
- **Format JSON** des Données Exploitables (sortie Step 1) et de la base de corrélations
  (sortie Step 3) — à spécifier.
- Pages `/insight-ranking` (Step 4) et `/insight-generation` (Step 5) — à drafter.
- **Asymétrie des URLs** (`/app/extraction-schema` vs les 4 autres à la racine) — à aligner ?
- **Renommage global V2.0** (repo, cahier) — fait uniquement sur les nouvelles pages.
- Nettoyage du backlog : les items « moteur local/Regex », « toggle Regex/IA », « jeux
  étanches » deviennent obsolètes à la construction.
