Fix #64 : « Tracé labs » vide en release seule (R8 full mode) + étape émulateur obligatoire

- proguard-rules.pro : -keep class LabTrajectoryModel { *; } — le mapping
  R8 montrait R8$$REMOVED$$CLASS (inlining du calcul + du synthétique
  $default dans le producer) : courbe vide en release, debug et 191 tests
  JVM aveugles. Validé émulateur §16.ter sur l'APK release re-buildé
  (données réelles seedées) : ancrée + prolongée + avertissement + 0 crash.
- Checklist §16 : NOUVELLE étape 3.bis — validation émulateur sur l'APK
  RELEASE obligatoire AVANT le tag (leçon #64 : jamais oublier le
  simulateur) + procédure de re-tag si fix avant publication.
- §14 : bug #64 complet (symptôme, diagnostic mapping, fix) ; §2 et
  CHANGELOG mis à jour.
This commit is contained in:
Siphonight 2026-09-13 03:43:11 +02:00
parent 0768b83a88
commit 76a9c0eb63
3 changed files with 67 additions and 3 deletions

View File

@ -15,3 +15,18 @@
# Énumérations : converties en String par Room et Gson (par nom) # Énumérations : converties en String par Room et Gson (par nom)
-keepclassmembers enum com.hormonetrack.data.model.** { *; } -keepclassmembers enum com.hormonetrack.data.model.** { *; }
# --- Moteur PK : « Tracé labs » (v1.6.0, bug #64 — trouvé en émulateur) ---
# Symptôme : en RELEASE SEULE, la courbe « Tracé labs » restait vide (ni
# dessinée ni légendée) alors que le même calcul fonctionne en debug et
# donne 276 points sur les mêmes données (régression web-miroir). Cause
# Prouvée au mapping R8 : `LabTrajectoryModel -> R8$$REMOVED$$CLASS$$...` —
# R8 full mode a SUPPRIMÉ la classe en inlinant computeLabAnchoredCurve
# (et son synthétique $default des paramètres par défaut) dans le call
# site du producer Compose ; le résultat n'y était plus correct. FIX :
# garder la classe ENTIÈRE — c'est le cœur scientifique de l'app (fonctions
# pures, zéro réflexion) : coût = quelques Ko de dex non compactés.
# ⚠️ Toute nouvelle fonctionnalité du pk/ qui « ne marche qu'en debug » :
# vérifier le mapping (`app/build/outputs/mapping/release/mapping.txt`)
# et étendre cette garde si besoin.
-keep class com.hormonetrack.pk.LabTrajectoryModel { *; }

View File

@ -45,6 +45,11 @@ Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.4.1
traitement, montée après une dose EV loguée après le dernier lab, traitement, montée après une dose EV loguée après le dernier lab,
flag off = comportement v1.5.0 bit-compatible, garde #61 sur la flag off = comportement v1.5.0 bit-compatible, garde #61 sur la
prolongation, gardes du helper d'horizon, `lastAnchorMs`. prolongation, gardes du helper d'horizon, `lastAnchorMs`.
- **Validé sur émulateur** (recette §16.ter, APK release + données
réelles seedées) — et heureusement : la validation a TROUVÉ le bug
#64 (courbe vide en release seule, inlining destructeur de R8 full
mode sur `LabTrajectoryModel`, cf doc §14). FIX : garde R8 explicite ;
re-validé en release : ancrée, prolongée, avertissement, 0 crash.
## [1.5.0] — 2026-09-11 (versionCode 31) ## [1.5.0] — 2026-09-11 (versionCode 31)

View File

@ -63,7 +63,7 @@ Fonctionnalités v1 :
| Date | Événement | | Date | Événement |
|---|---| |---|---|
| 12 sept. 2026 (session v1.6.0) | **« Tracé labs » PROLONGÉ au-delà du dernier lab** (demande) : le tracé s'arrêtait AU dernier lab (v1.5.0) — justement la période la plus récente était invisible. FIX : chip `Prolonger` (5ᵉ de la rangée, off par défaut, désactivé tant que Tracé labs est off) → au-delà du dernier lab significatif, `courbe(t) = M(t) × ρ_last` (ρ CONSTANT — pas d'extrapolation de pente, elle divergerait sans base physiologique) ; M(t) inclut AUTOMATIQUEMENT les doses loguées après le dernier lab (une injection EV après des labs EEn refait monter la courbe — épinglé par test) ; horizon = dernière dose E2 + cutoffHours de son traitement (une seule source de vérité : `cutoffHours` rendu public) ; série SPLITTÉE en "LAB" (ancré) / "LABX" (prolongé, rose atténué α 0,55 + légende dédiée — l'estimation ne se confond pas avec le mesuré) ; branche "LABX" EXPLICITE dans le when de légende AVANT le else (leçon #63) ; **AVERTISSEMENT visible sous la légende quand la prolongation est affichée** (demande) : « simple simulation, sans garantie de correspondre au réel, basée sur tes labs qui peuvent eux-mêmes être erronés » (string FR/EN `lab_track_extend_warning`). < 2 ancres, modèle déjà éteint au dernier lab, ou demande finissant avant → pas de prolongation (retour v1.5.0 exact, épinglé bit-compatible). 8 nouveaux tests (191 verts / 168 sans données locales) + lint vert. | | 12 sept. 2026 (session v1.6.0) | **« Tracé labs » PROLONGÉ au-delà du dernier lab** (demande) : le tracé s'arrêtait AU dernier lab (v1.5.0) — justement la période la plus récente était invisible. FIX : chip `Prolonger` (5ᵉ de la rangée, off par défaut, désactivé tant que Tracé labs est off) → au-delà du dernier lab significatif, `courbe(t) = M(t) × ρ_last` (ρ CONSTANT — pas d'extrapolation de pente, elle divergerait sans base physiologique) ; M(t) inclut AUTOMATIQUEMENT les doses loguées après le dernier lab (une injection EV après des labs EEn refait monter la courbe — épinglé par test) ; horizon = dernière dose E2 + cutoffHours de son traitement (une seule source de vérité : `cutoffHours` rendu public) ; série SPLITTÉE en "LAB" (ancré) / "LABX" (prolongé, rose atténué α 0,55 + légende dédiée — l'estimation ne se confond pas avec le mesuré) ; branche "LABX" EXPLICITE dans le when de légende AVANT le else (leçon #63) ; **AVERTISSEMENT visible sous la légende quand la prolongation est affichée** (demande) : « simple simulation, sans garantie de correspondre au réel, basée sur tes labs qui peuvent eux-mêmes être erronés » (string FR/EN `lab_track_extend_warning`). < 2 ancres, modèle déjà éteint au dernier lab, ou demande finissant avant → pas de prolongation (retour v1.5.0 exact, épinglé bit-compatible). 8 nouveaux tests (191 verts / 168 sans données locales) + lint vert. **+ Rattrapage validation émulateur §16.ter (oubliée, demandée par l'utilisatrice) → bug #64 TROUVÉ** : « Tracé labs » vide EN RELEASE SEULE (R8 full mode avait REMOVÉ la classe — mapping `R8$$REMOVED$$CLASS` — et inliné le calcul dans le producer ; debug OK, 191 tests JVM aveugles). FIX : `-keep class ...LabTrajectoryModel { *; }` ; validé émulateur APK release re-buildé avec les données réelles seedées : ancrée (7090 px rose + légende), prolongée (légende + avertissement), 0 crash. Tag v1.6.0 reposé sur le commit de fix AVANT publication d'APK (checklist §16 étape 4). **Checklist §16 : étape 3.bis « validation émulateur release OBLIGATOIRE avant tag » ajoutée.** |
| 11 sept. 2026 (session v1.5.0) | **« Tracé labs »** (demande débattue) : courbe hybride `M(t)×ρ(t)` ancrée sur les labs — ρ log-linéaire entre labs, garde #61, E2 seul, fenêtre labs, chip off par défaut + scroll horizontal CONFINÉ (chip 4ᵉ coupé hors fenêtre, constat émulateur) + leçon #63 légende dupliquée ("LAB" tombant dans else TFS) ; ChartSeries.showExtrema=false pour la série ; 11 tests LabTrajectoryModelTest (183 verts) + lint ; validé émulateur (courbe passe exactement sur le lab 248, 0 crash). | | 11 sept. 2026 (session v1.5.0) | **« Tracé labs »** (demande débattue) : courbe hybride `M(t)×ρ(t)` ancrée sur les labs — ρ log-linéaire entre labs, garde #61, E2 seul, fenêtre labs, chip off par défaut + scroll horizontal CONFINÉ (chip 4ᵉ coupé hors fenêtre, constat émulateur) + leçon #63 légende dupliquée ("LAB" tombant dans else TFS) ; ChartSeries.showExtrema=false pour la série ; 11 tests LabTrajectoryModelTest (183 verts) + lint ; validé émulateur (courbe passe exactement sur le lab 248, 0 crash). |
| 5 sept. 2026 (session 1) | Plan, vérification GT 3 = Lite Wearable, création couche données + ancien moteur Bateman + ancien ReminderManager. Extraction des modèles du `Estrogen.ods` → `/tmp/pk_models.json` (6 profils × 8001 h + params D/k1–k3). | | 5 sept. 2026 (session 1) | Plan, vérification GT 3 = Lite Wearable, création couche données + ancien moteur Bateman + ancien ReminderManager. Extraction des modèles du `Estrogen.ods` → `/tmp/pk_models.json` (6 profils × 8001 h + params D/k1–k3). |
| 5 sept. 2026 | L'utilisatrice mentionne un travail d'un assistant tiers « **Mimo V2.5** » : **aucune trace trouvée** (fichiers identiques à la session 1, timestamps identiques). Reprise depuis l'état existant. Bugs trouvés au passage : settings.gradle, BootReceiver, cancel PendingIntent. | | 5 sept. 2026 | L'utilisatrice mentionne un travail d'un assistant tiers « **Mimo V2.5** » : **aucune trace trouvée** (fichiers identiques à la session 1, timestamps identiques). Reprise depuis l'état existant. Bugs trouvés au passage : settings.gradle, BootReceiver, cancel PendingIntent. |
@ -1478,7 +1478,33 @@ trace = d'abord le reproduire** (émulateur + données réelles, §16.ter) — l
deux « fixes » aveugles de v1.3.2/v1.3.3 (#41/#45) ont laissé passer un bug deux « fixes » aveugles de v1.3.2/v1.3.3 (#41/#45) ont laissé passer un bug
trivial (#48) seulement visible sur l'émulateur ; (n) `./gradlew lint` fait trivial (#48) seulement visible sur l'émulateur ; (n) `./gradlew lint` fait
désormais partie de la vérification avant release : `StringFormatMatches` désormais partie de la vérification avant release : `StringFormatMatches`
aurait signalé #47 dès v1.3.1. aurait signalé #47 dès v1.3.1 ; (o) **les tests unitaires JVM ne voient
JAMAIS la minification R8 — la recette §16.ter sur l'APK RELEASE est la
seule filet** (bug #64 : feature parfaite en debug, vide en release) ;
(p) quand une classe pure disparaît du mapping R8 (`R8$$REMOVED$$CLASS`),
la garder explicitement dans proguard-rules.pro plutôt que débattre avec
l'optimiseur.
### #64 (v1.6.0) — « Tracé labs » vide EN RELEASE SEULE (R8 full mode)
**Symptôme** (émulateur §16.ter, APK release v1.6.0, données réelles seedées) :
le chip « Lab track » s'active MAIS la courbe n'est ni dessinée (0 pixel
#C2185B au screencap) ni légendée ; « Prolonger » idem. En DEBUG, le même
chip sur les mêmes données fonctionne (légende + 7090 px rose après fix).
**Les 191 tests JVM sont verts** (ils ne passent JAMAIS par R8).
**Diagnostic** (méthode de bisection debug/release puis `mapping.txt`) :
`com.hormonetrack.pk.LabTrajectoryModel -> R8$$REMOVED$$CLASS$$…` — R8 full
mode a SUPPRIMÉ la classe en inlinant `computeLabAnchoredCurve` (et son
synthétique `computeLabAnchoredCurve$default` qui gère les paramètres par
défaut) dans le call site du producer Compose ; après fusion, le calcul
renvoyait une courbe vide. Les courbes des modèles (même moteur e2At,
même fichier) fonctionnaient — seul le chemin inliné cassait.
**FIX** : `-keep class com.hormonetrack.pk.LabTrajectoryModel { *; }` dans
proguard-rules.pro (garde commentée + renvoi au mapping). Validé émulateur
sur l'APK release re-buildé : ancrée (courbe + légende), prolongée (légende
+ avertissement), 0 crash.
## 15. Comment régénérer l'asset pk_profiles.json ## 15. Comment régénérer l'asset pk_profiles.json
@ -1613,8 +1639,26 @@ vérifie pas en tests JVM).
3. **Docs** : section `## [X.Y.Z]` en tête de `docs/CHANGELOG.md` (le corps des 3. **Docs** : section `## [X.Y.Z]` en tête de `docs/CHANGELOG.md` (le corps des
releases Gitea en sera extrait automatiquement par le script), + §14 si bug releases Gitea en sera extrait automatiquement par le script), + §14 si bug
corrigé, + §2 (historique) si notable. corrigé, + §2 (historique) si notable.
3.bis. **⚠️ VALIDATION ÉMULATEUR §16.ter — OBLIGATOIRE AVANT LE TAG (leçon
#64, v1.6.0 : oubliée puis rattrapée, un bug release-only est passé
jusque dans l'APK taggué)** : recette complète §16.ter (émulateur
headless hrt36 + seed `scripts/seed-emulator.py` avec le dernier
backup de `local-test-data/` + APK release installé PAR-DESSUS) sur
**l'APK RELEASE** (JAMAIS le debug seul : **R8 ne se vérifie qu'ici** —
les 191 tests JVM ne le voient jamais, cf #64). Parcours minimum :
l'app démarre 0 crash → écran Graphiques → activer les chips de la
release (rangée modèles défilable : `adb shell input swipe 900 716 150
716 400` puis tap aux bounds du `uiautomator dump`) → vérifier dans le
dump `text=` que la légende attendue apparaît → `adb logcat -b crash
-d | grep -c FATAL` reste à 0. Limites : le pan/pinch n'est PAS
testable par adb (§16.ter 4.bis) — le geste reste validé par
l'utilisatrice sur Pixel 9.
4. **Commit** (message descriptif par couche) + **tag annoté** : 4. **Commit** (message descriptif par couche) + **tag annoté** :
`git tag -a vX.Y.Z -m "…"`. `git tag -a vX.Y.Z -m "…"`. ⚠️ Si un fix arrive APRÈS le tag mais
AVANT la publication d'APK (cas #64) : AUCUNE release n'existe encore →
`git tag -d vX.Y.Z` + re-tag sur le commit de fix + `push --tags`
(jamais de re-tag sur une release PUBLIÉE : bump en X.Y.(Z+1) à la
place).
4.bis. **Release SYNC web** (depuis le 8 sept. 2026) : le portage web vit 4.bis. **Release SYNC web** (depuis le 8 sept. 2026) : le portage web vit
dans son PROPRE dépôt `~/projects/HormoneTrack-web` (2 Gitea, dans son PROPRE dépôt `~/projects/HormoneTrack-web` (2 Gitea,
`Siphonight/HormoneTrack-web` — historique 100 % propre, séparé de la `Siphonight/HormoneTrack-web` — historique 100 % propre, séparé de la