Docs : v1.6.0 — prolongation tracé labs (§7.10.bis), session §2, compteur 191 tests

- DEVELOPPEMENT : §7.10.bis (recette ρ constant, horizon, split LAB/LABX,
  avertissement, limites), session v1.6.0 §2, §8 191/168 tests, §11
  séries LAB/LABX, §21 checklist manuelle, TOC 7.10/7.10.bis, fix coquilles
  (E3→E2, efecto→effet, trais→traits), checklist §16 compteur à jour.
- CHANGELOG : entrée [1.6.0]. README : statut + puce Tracé labs prolongé.
- GUIDE_INSTALLATION : chip Prolonger + avertissement (§8).
This commit is contained in:
Siphonight 2026-09-12 23:49:24 +02:00
parent 3e2bf3992e
commit 0768b83a88
4 changed files with 185 additions and 22 deletions

View File

@ -16,7 +16,7 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
> à titre informatif — ce ne sont pas des mesures. Fie-toi toujours à tes analyses de > à titre informatif — ce ne sont pas des mesures. Fie-toi toujours à tes analyses de
> sang et aux consignes de ton endocrinologue. > sang et aux consignes de ton endocrinologue.
- **Statut** : v1.5.0 — build Android ✅, **lint vert** ✅, **183 tests unitaires** ✅ (160 sans les données de test locales ; régressions épinglées sur données réelles **non versionnées**), intégration montre = notifications ✅, **dépôt Gitea privé + releases avec APK** ✅ - **Statut** : v1.6.0 — build Android ✅, **lint vert** ✅, **191 tests unitaires** ✅ (168 sans les données de test locales ; régressions épinglées sur données réelles **non versionnées**), intégration montre = notifications ✅, **dépôt Gitea privé + releases avec APK** ✅
- **Journal des versions** : [docs/CHANGELOG.md](docs/CHANGELOG.md) - **Journal des versions** : [docs/CHANGELOG.md](docs/CHANGELOG.md)
- **Guide utilisateur** : [docs/GUIDE_INSTALLATION.md](docs/GUIDE_INSTALLATION.md) - **Guide utilisateur** : [docs/GUIDE_INSTALLATION.md](docs/GUIDE_INSTALLATION.md)
- **Doc de développement** (architecture, maths, décisions, bugs) : [docs/DEVELOPPEMENT.md](docs/DEVELOPPEMENT.md) - **Doc de développement** (architecture, maths, décisions, bugs) : [docs/DEVELOPPEMENT.md](docs/DEVELOPPEMENT.md)
@ -39,13 +39,15 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
en couvre 6 (sans PEP). Affichés côte à côte avec toggles indépendants (3 couleurs) — **pré-cochés en couvre 6 (sans PEP). Affichés côte à côte avec toggles indépendants (3 couleurs) — **pré-cochés
selon les modèles de tes traitements** (v1.4.7) et **chaque modèle calibré selon les modèles de tes traitements** (v1.4.7) et **chaque modèle calibré
séparément** par tes labs (v1.4.8 — les facteurs s'adaptent à chaque profil) séparément** par tes labs (v1.4.8 — les facteurs s'adaptent à chaque profil)
- **« Tracé labs » (v1.5.0)** : la courbe ancrée sur tes prises de sang - **« Tracé labs » (v1.5.0, prolongé en v1.6.0)** : la courbe ancrée sur tes
(chip `Tracé labs`, off par défaut) — la forme du modèle PK entre les prises de sang (chip `Tracé labs`, off par défaut) — la forme du modèle PK
labs, mais l'amplitude recalée pour passer EXACTEMENT sur chaque lab E2 entre les labs, mais l'amplitude recalée pour passer EXACTEMENT sur chaque
; transition log-linéaire d'un lab au suivant, garde des labs hors lab E2 ; transition log-linéaire d'un lab au suivant, garde des labs hors
fenêtre d'action (#61), fenêtre bornée [1er ; dernier lab] — la courbe fenêtre d'action (#61) ; **chip `Prolonger` (v1.6.0)** : la courbe se
est une référence de COMPARAISON, jamais une estimation d'action (elle prolonge au-delà du dernier lab (modèle × ratio du dernier lab, horizon =
n'entre jamais dans l'accueil/les alertes) extinction du modèle, partie estimée dessinée atténuée + légende dédiée) —
la courbe est une référence de COMPARAISON, jamais une estimation d'action
(elle n'entre jamais dans l'accueil/les alertes)
- **Modèle Bateman** paramétrable (temps au pic, demi-vie, biodisponibilité) pour gel, - **Modèle Bateman** paramétrable (temps au pic, demi-vie, biodisponibilité) pour gel,
patch et voie orale patch et voie orale
- **Simulation prévisionnelle** : configurer la **posologie** (intervalle en jours) sur un - **Simulation prévisionnelle** : configurer la **posologie** (intervalle en jours) sur un
@ -100,7 +102,7 @@ par AGP si les licences sont signées). Le wrapper télécharge Gradle 9.7.1.
git clone <repo> && cd HormoneTrack git clone <repo> && cd HormoneTrack
echo "sdk.dir=/chemin/vers/android-sdk" > local.properties # ou ANDROID_HOME echo "sdk.dir=/chemin/vers/android-sdk" > local.properties # ou ANDROID_HOME
./gradlew assembleDebug # APK : app/build/outputs/apk/debug/app-debug.apk ./gradlew assembleDebug # APK : app/build/outputs/apk/debug/app-debug.apk
./gradlew testDebugUnitTest # 183 tests (160 sans les données locales) ./gradlew testDebugUnitTest # 191 tests (168 sans les données locales)
./gradlew lint # lint vert obligatoire avant release ./gradlew lint # lint vert obligatoire avant release
``` ```

View File

@ -3,6 +3,49 @@
Format : [Keep a Changelog](https://keepachangelog.com/fr-FR/1.1.0/). Format : [Keep a Changelog](https://keepachangelog.com/fr-FR/1.1.0/).
Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.4.10`, …). Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.4.10`, …).
## [1.6.0] — 2026-09-12 (versionCode 32)
### « Tracé labs » prolongé au-delà du dernier lab
- **Nouveau chip `Prolonger`** (à côté de `Tracé labs`, **off par défaut**,
sans effet — donc désactivé — tant que Tracé labs est off) : la courbe
ancrée sur tes prises de sang se PROLONGE désormais au-delà du dernier lab,
au lieu de s'arrêter là (limite v1.5.0 : justement la période la plus
récente était invisible).
- **Recette de la prolongation** : `courbe(t) = M(t) × ρ_dernier lab` où
M(t) = le modèle PK brut (porte TOUTE la dynamique : Tmax, queues,
accumulation **et les doses loguées après le dernier lab** — une nouvelle
injection, même à un autre ester, fait repartir la courbe en pic) et
ρ = le ratio corps-réel ÷ modèle observé au dernier lab, supposé constant.
Demande couverte : simuler à partir des labs précédents, du dosage et du
type d'ester injecté, et de l'évolution classique de l'ester.
- **Horizon honnête** : la prolongation s'arrête quand le MODÈLE lui-même
s'éteint (dernière dose + coupure moteur = 10 t½ terminales V3C/WHS, fin
de table ODS, 30 t½ Bateman) — jamais de ligne à zéro inventée au-delà.
- **Lisibilité** : la partie prolongée est dessinée SÉPARÉMENT (même rose,
atténué) avec sa propre légende — « estimation, plus ancrée » : la partie
mesurée (qui passe par les labs) ne peut pas se confondre avec la partie
simulée.
- **Avertissement visible** (demande) : tant que la partie prolongée est
affichée, un texte sous la légende rappelle que c'est une **simple
simulation sans garantie de correspondre au réel**, extrapolée à partir
de tes résultats de laboratoire — qui peuvent **eux-mêmes être erronés**
— et qu'il faut se fier à la prochaine prise de sang, pas à cette courbe.
- **Garde anti-ratés inchangée** : seuls les labs SIGNIFICATIFS ancrent
(leçon #61) — un lab tardif hors fenêtre d'action ne prolonge pas la
courbe et n'est jamais traversé.
- **Limites documentées** (cf doc de développement §7.10.bis) : ρ est
constant (pas d'extrapolation de pente — elle divergerait sans base
physiologique) ; après un changement d'ester, l'amplitude reste calibrée
par le ρ de l'ancien ester (même limite que la calibration classique) ;
les doses PRÉVISIONNELLES ne participent pas (la projection reste la
série Prévision).
- **8 nouveaux tests** (191 au total / 168 sans les données locales) :
identité ρ constant + continuité de suture, horizon = cutoff du
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
prolongation, gardes du helper d'horizon, `lastAnchorMs`.
## [1.5.0] — 2026-09-11 (versionCode 31) ## [1.5.0] — 2026-09-11 (versionCode 31)
### « Tracé labs » — courbe ancrée sur tes prises de sang ### « Tracé labs » — courbe ancrée sur tes prises de sang

View File

@ -15,7 +15,7 @@
4. [Environnement de build (cette machine)](#4-environnement-de-build-cette-machine) 4. [Environnement de build (cette machine)](#4-environnement-de-build-cette-machine)
5. [Architecture générale](#5-architecture-générale) 5. [Architecture générale](#5-architecture-générale)
6. [Modèle de données (Room)](#6-modèle-de-données-room) + [6.bis Sémantique isActive](#6bis-sémantique-isactive-v124--drapeau-administratif-jamais-un-filtre) 6. [Modèle de données (Room)](#6-modèle-de-données-room) + [6.bis Sémantique isActive](#6bis-sémantique-isactive-v124--drapeau-administratif-jamais-un-filtre)
7. [Moteur pharmacocinétique](#7-moteur-pharmacocinétique) + [7.8 Modèle TFS V3C](#78-modèle-tfs-v3c-v140--pktransfemsciencemodelskt) + [7.9 Modèle WHSAH](#79-modèle-whsah-v146--pkwhsahmodelskt) 7. [Moteur pharmacocinétique](#7-moteur-pharmacocinétique) + [7.8 Modèle TFS V3C](#78-modèle-tfs-v3c-v140--pktransfemsciencemodelskt) + [7.9 Modèle WHSAH](#79-modèle-whsah-v146--pkwhsahmodelskt) + [7.10 « Tracé labs »](#710--tracé-labs--v150--pklabtrajectorymodelkt) + [7.10.bis Prolongation](#710bis-prolongation-au-delà-du-dernier-lab-v160--pklabtrajectorymodelkt)
8. [Tests unitaires](#8-tests-unitaires) + [8.bis Données de test hors dépôt](#8bis-données-de-test-réelles--hors-dépôt-local-test-data) 8. [Tests unitaires](#8-tests-unitaires) + [8.bis Données de test hors dépôt](#8bis-données-de-test-réelles--hors-dépôt-local-test-data)
9. [Système de rappels](#9-système-de-rappels) + [9.bis Alertes de seuil](#9bis-alertes-de-seuil-reminderalertnotifierkt--worker-v142) 9. [Système de rappels](#9-système-de-rappels) + [9.bis Alertes de seuil](#9bis-alertes-de-seuil-reminderalertnotifierkt--worker-v142)
10. [UI & navigation](#10-ui--navigation) 10. [UI & navigation](#10-ui--navigation)
@ -63,6 +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. |
| 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. |
@ -485,18 +486,21 @@ MAIS passant par tous les points ».
- **Garde anti-#61** : labs croissants + `labIsSignificant` — un lab hors - **Garde anti-#61** : labs croissants + `labIsSignificant` — un lab hors
fenêtre d'action (dose de test de janvier, labs tardifs) N'EST PAS un fenêtre d'action (dose de test de janvier, labs tardifs) N'EST PAS un
ancrage (reproduction épinglée dans LabTrajectoryModelTest). ancrage (reproduction épinglée dans LabTrajectoryModelTest).
- **E3 = E2 uniquement** : les labs T sont trop rares + unités variées - **E2 uniquement** : les labs T sont trop rares + unités variées
(bug #26) — hors scope (choix v1.5.0). Pas de courbe T pour la série (bug #26) — hors scope (choix v1.5.0). Pas de courbe T pour la série
(`tStyle = null` → rien de dessiné, miroir CurveChart). (`tStyle = null` → rien de dessiné, miroir CurveChart).
- **Fenêtre = [1er lab significatif ; dernier lab] ∩ fenêtre du graphique** — - **Fenêtre = [1er lab significatif ; dernier lab] ∩ fenêtre du graphique** —
toujours bornée aux labs ; vieillir après le dernier lab = rien dessiné toujours bornée aux labs ; vieillir après le dernier lab = rien dessiné
(l'app n'invente pas de niveau). (l'app n'invente pas de niveau). ⚠️ v1.6.0 : ce comportement reste le
DÉFAUT — avec le chip « Prolonger », la courbe peut se PROLONGER au-delà
du dernier lab (ρ constant, horizon = extinction du modèle — cf
§7.10.bis).
- < 2 labs significatifs → courbe vide (un lab seul = pas d'intervalle ; - < 2 labs significatifs → courbe vide (un lab seul = pas d'intervalle ;
un point isolé ne définit pas de tracé). un point isolé ne définit pas de tracé) — et donc jamais de prolongation.
- **Indépendante de la calibration** : elle EST sa propre calibration - **Indépendante de la calibration** : elle EST sa propre calibration
continue (ratio brut, `scaleFactor` stocké ignoré ET `scalePerEster` continue (ratio brut, `scaleFactor` stocké ignoré ET `scalePerEster`
ignoré — l'inverse serait une DOUBLE correction, épinglé par test). ignoré — l'inverse serait une DOUBLE correction, épinglé par test).
efecto : les modèles rapprochés au sein du même ancrage CONVERGENT effet : les modèles rapprochés au sein du même ancrage CONVERGENT
(le mi-chemin ESE vs WHS colle à ~2 % — `modelOverride` garde une (le mi-chemin ESE vs WHS colle à ~2 % — `modelOverride` garde une
empreinte intermédiaire, testé avec le seuil du test moteur WHS). empreinte intermédiaire, testé avec le seuil du test moteur WHS).
- **Hors pics/creux** (chip "Pics / creux") : la série passe - **Hors pics/creux** (chip "Pics / creux") : la série passe
@ -505,16 +509,93 @@ MAIS passant par tous les points ».
- **UI** : chip « Tracé labs » / "Lab track" dans la RANGÉE MODÈLES (4ᵉ - **UI** : chip « Tracé labs » / "Lab track" dans la RANGÉE MODÈLES (4ᵉ
chip — scroll horizontal CONFINÉ à la rangée ; constat v1.5.0 en émulateur : chip — scroll horizontal CONFINÉ à la rangée ; constat v1.5.0 en émulateur :
le 4ᵉ chip était coupé hors fenêtre avec une Row figée). OFF par défaut. le 4ᵉ chip était coupé hors fenêtre avec une Row figée). OFF par défaut.
v1.6.0 : 5ᵉ chip « Prolonger » (off par défaut, désactivé tant que
Tracé labs est off) — prolongation au-delà du dernier lab (§7.10.bis).
- ⚠️ **Leçon #63 (v1.5.0, émulateur)** : la clé "LAB" dans la liste `curves` - ⚠️ **Leçon #63 (v1.5.0, émulateur)** : la clé "LAB" dans la liste `curves`
doit être EXCLUE de la boucle de légende (`when (model)` — le `else` doit être EXCLUE de la boucle de légende (`when (model)` — le `else`
= TFS imprimerait la légende TFS une 2ᵉ fois). Série → couleur dédiée = TFS imprimerait la légende TFS une 2ᵉ fois). Série → couleur dédiée
`ChartLabTrajectory` #C2185B dashed. `ChartLabTrajectory` #C2185B dashed. v1.6.0 : la clé "LABX" (partie
prolongée) a la MÊME exigence — branche explicite dans le `when`, sinon
le `else` (= TFS) imprimerait la légende TFS une 2ᵉ fois.
- **INVARIANT** : cette courbe n'entre JAMAIS dans `levelAt` — accueil, - **INVARIANT** : cette courbe n'entre JAMAIS dans `levelAt` — accueil,
seuils d'alerte, rappels utilisent toujours le modèle calibré (§9.bis). seuils d'alerte, rappels utilisent toujours le modèle calibré (§9.bis).
### 7.10.bis Prolongation au-delà du dernier lab (v1.6.0) — `pk/LabTrajectoryModel.kt`
**Demande v1.6.0** : permettre au tracé labs de s'étendre au-delà du
dernier lab, en simulant à partir des labs précédents, du dosage et du
type d'ester injecté, et de l'évolution classique de l'ester. Le constat
v1.5.0 : la fenêtre s'arrêtait AU dernier lab — précisément la période la
plus récente (entre la dernière prise de sang et maintenant) était
invisible sur la courbe de comparaison.
**Recette** : `extendBeyondLastLab = true` (paramètre de
`computeLabAnchoredCurve`, chip `Prolonger` — off par défaut, désactivé
tant que Tracé labs est off). La borne droite de la fenêtre devient
`min(demande, horizon)` et **la boucle de calcul est INCHANGÉE** :
`ratioAt` retournait déjà ρ_last au-delà du dernier ancre (garde
défensive v1.5.0) — élargir la fenêtre EST la prolongation. Continuité au
point de suture garantie par construction (ρ(t_last) = ρ_last exactement,
constant à droite comme l'interpolation aboutit à ρ_last à gauche).
- **Formule au-delà du dernier lab** : `courbe(t) = M(t) × ρ_last` où
- `M(t)` = le modèle PK brut : porte l'« évolution classique de l'ester »
(Tmax, queues, accumulation) ET LES DOSES LOGUÉES après le dernier lab —
une nouvelle injection (override d'ester compris : EV après des labs
EEn, etc.) fait repartir la courbe en pic à l'amplitude calibrée
(épinglé par test `une dose apres le dernier lab refait monter la
courbe`) ;
- `ρ_last` = ratio lab ÷ prédiction au dernier lab significatif, supposé
CONSTANT. **Pourquoi pas une extrapolation de pente** : la pente entre
deux labs est un morphing entre deux corrections d'amplitude, pas une
tendance physiologique — l'extrapoler divergerait (un ratio qui monte
de 5 %/jour finirait en facteurs ×10 inventés). ρ_last = le meilleur
estimateur disponible, même sémantique que la calibration classique
(le facteur stocké s'applique aux doses futures).
- **Horizon (`extensionHorizonEndMs`, internal)** : dernière dose E2 +
`cutoffHours(son traitement)` — `cutoffHours` a été rendu PUBLIC (v1.6.0)
pour que la prolongation partage la MÊME sémantique d'extinction que le
moteur (10 t½ terminales V3C/WHS, fin de table ODS, 30 t½ Bateman). Au-delà,
M(t) = 0 : dessiner plus serait une ligne à zéro inventée. Retourne
`null` (pas de prolongation) si aucune dose E2 ou si le modèle est DÉJÀ
éteint au dernier lab.
- **Split visuel "LAB" / "LABX" (ChartScreen)** : `AnchoredCurve` expose
`lastAnchorMs` (timestamp du dernier ancre, `null` si < 2 ancres) ;
l'écran splitte la série au dernier ancre — "LAB" = partie ancrée (rose
plein de la v1.5.0), "LABX" = partie prolongée (MÊME couleur atténuée
α 0,55, dashed) avec SA légende (`legend_lab_track_extend` FR/EN) :
« estimation, plus ancrée ». L'estimation ne peut pas se confondre avec
le mesuré.
- **AVERTISSEMENT (demande v1.6.0)** : quand la partie prolongée est
visible, un texte s'affiche sous la légende
(`lab_track_extend_warning` FR/EN) : « simple simulation, sans garantie
de correspondre au réel — extrapole ton modèle à partir de tes résultats
de laboratoire, qui peuvent eux-mêmes être erronés ; fie-toi à ta
prochaine prise de sang ». Même condition d'affichage que la légende
LABX (`labExtendVisible`) : il ne peut jamais y avoir de courbe
prolongée sans son avertissement.
- **Leçon #63 réappliquée** : la branche `"LABX" ->` du `when` de légende
est EXPLICITE et AVANT le `else` — sinon la légende TFS serait imprimée
une 2ᵉ fois (le `else` = TFS).
- **Garde #61 inchangée** : seuls les labs significatifs ancrent — un lab
tardif hors fenêtre d'action ne prolonge PAS la courbe et n'est jamais
traversé (épinglé par test).
- **Comportement par défaut inchangé** : flag absent ou `false` =
v1.5.0 bit-compatible (testé : points identiques).
- **Limites assumées (documentées, pas des bugs)** :
- changement d'ESTER après le dernier lab : l'amplitude du nouvel ester
reste calibrée par le ρ de l'ancien — même limite que la calibration
classique (pas de lab de la nouvelle période → fallback) ;
- les doses PRÉVISIONNELLES ne participent jamais : la projection future
reste la série « Prévision » (modèles calibrés) — le tracé labs ne
consomme que des doses RÉELLES ;
- **INVARIANT v1.5.0 étendu** : la partie prolongée non plus n'entre
JAMAIS dans `levelAt` (display-end only, série "LABX" purement visuelle).
- 8 nouveaux tests dans `LabTrajectoryModelTest` (191 verts au total).
## 8. Tests unitaires ## 8. Tests unitaires
**183 tests JVM, tous verts** (`./gradlew testDebugUnitTest`) — **160 sans **191 tests JVM, tous verts** (`./gradlew testDebugUnitTest`) — **168 sans
les données de test locales** (cf §8.bis : les 4 classes de régression, les données de test locales** (cf §8.bis : les 4 classes de régression,
6/6/6/5 tests, sont skippées via `Assume`). Dépendance : JUnit 4.13.2. 6/6/6/5 tests, sont skippées via `Assume`). Dépendance : JUnit 4.13.2.
Emplacement : `app/src/test/java/com/hormonetrack/`. Répertoire de travail d'exécution = Emplacement : `app/src/test/java/com/hormonetrack/`. Répertoire de travail d'exécution =
@ -589,8 +670,8 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
dans le code (le scanner refuserait, et ce serait une fuite). dans le code (le scanner refuserait, et ce serait une fuite).
- les tests font `Assume.assumeTrue(file.exists())` dans le `@Before` : **sans le - les tests font `Assume.assumeTrue(file.exists())` dans le `@Before` : **sans le
fichier, la classe est IGNORÉE** (skipped, pas failed) — un clone neuf ou une CI fichier, la classe est IGNORÉE** (skipped, pas failed) — un clone neuf ou une CI
exécute 160 tests au lieu de 183 (v1.5.0 ; chiffres historiques : 44/87 à v1.3.x, exécute 168 tests au lieu de 191 (v1.6.0 ; chiffres historiques : 44/87 à v1.3.x,
150/172 à v1.4.x) ; 150/172 à v1.4.x, 160/183 à v1.5.0) ;
- le workdir des tests Gradle est le dossier du module (`app/`) → les tests - le workdir des tests Gradle est le dossier du module (`app/`) → les tests
cherchent les fichiers à plusieurs chemins (`../local-test-data/…` en premier) ; cherchent les fichiers à plusieurs chemins (`../local-test-data/…` en premier) ;
- **pour les lancer** : exporter un backup JSON depuis l'app → l'enregistrer sous - **pour les lancer** : exporter un backup JSON depuis l'app → l'enregistrer sous
@ -716,7 +797,7 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
sans Posologie ou sans doses, agrégat multi-traitements (le plus tôt sans Posologie ou sans doses, agrégat multi-traitements (le plus tôt
gagne), traitements inactifs/désactivés → null. gagne), traitements inactifs/désactivés → null.
- **`LabTrajectoryModelTest`** (11) : v1.5.0 — « Tracé labs » (§7.10) : - **`LabTrajectoryModelTest`** (19) : v1.5.0 — « Tracé labs » (§7.10) :
passage EXACT sur chaque lab (fp 1e-6), ρ log-linéaire (fonction pure + passage EXACT sur chaque lab (fp 1e-6), ρ log-linéaire (fonction pure +
courbe recomposée via le moteur — M recalcule et ρ = geometric mean), courbe recomposée via le moteur — M recalcule et ρ = geometric mean),
1 lab → vide, **garde #61** (lab tardif PAS un ancrage + fenêtre bornée 1 lab → vide, **garde #61** (lab tardif PAS un ancrage + fenêtre bornée
@ -726,6 +807,14 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
`modelOverride` (ESE vs WHS — divergence franche : ESE≈TFS quasi `modelOverride` (ESE vs WHS — divergence franche : ESE≈TFS quasi
identiques par CONSTRUCTION, seuil 2 % doc §8), labs T ignorés, identiques par CONSTRUCTION, seuil 2 % doc §8), labs T ignorés,
doublons de timestamp (2ᵉ ratio gagne), bornes défensives ratioAt. doublons de timestamp (2ᵉ ratio gagne), bornes défensives ratioAt.
v1.6.0 — **prolongation** (§7.10.bis) : identité `M × ρ_last` exacte
au-delà du dernier lab (10/20/30 j), suture exacte au dernier ancre,
horizon = cutoff du traitement (dernier point ≤ cutoff < dernier point + pas),
dose EV loguée après le dernier lab → pic de prolongation (> ×1,3 le
niveau pré-injection — la forme suit dosage + ester), flag off =
v1.5.0 bit-compatible, garde #61 sur la prolongation (le lab tardif ne
prolonge ni n'ancre), gardes du helper d'horizon (pas de dose / modèle
éteint → null), `lastAnchorMs` (null si < 2 ancres).
**Ce que les tests ont déjà attrapé** : bisection inversée de `computeKa` (présente depuis **Ce que les tests ont déjà attrapé** : bisection inversée de `computeKa` (présente depuis
la session 1 !), plancher 0,01 des queues de profils, mapping silencieux du modèle inconnu. la session 1 !), plancher 0,01 des queues de profils, mapping silencieux du modèle inconnu.
@ -912,6 +1001,13 @@ triangles ▲▼ via `PharmacokineticEngine.detectExtrema` **accompagnés de la
valeur estimée** du pic (au-dessus) ou du creux (en dessous), dans la couleur valeur estimée** du pic (au-dessus) ou du creux (en dessous), dans la couleur
de la série (`drawExtremum`). de la série (`drawExtremum`).
**Séries « Tracé labs » (v1.5.0/v1.6.0)** : le ChartScreen peut ajouter les
clés "LAB" (partie ANCRÉE — passe par les labs, rose #C2185B dashed) et
"LABX" (partie PROLONGÉE — M × ρ_last constant, même rose atténué α 0,55)
— cf §7.10 / §7.10.bis pour le moteur et les gardes ; les deux clés sont
SKIPPÉES par la boucle de légende (leçon #63) et ont leurs entrées dédiées
+ avertissement « simulation » quand LABX est visible.
**Zoom (v1.2.9)** : pinch **et** boutons − / + — plage temporelle bornée **Zoom (v1.2.9)** : pinch **et** boutons − / + — plage temporelle bornée
**6 h → 300 j** (`MIN_RANGE_H`/`MAX_RANGE_H`), point focal du pinch maintenu **6 h → 300 j** (`MIN_RANGE_H`/`MAX_RANGE_H`), point focal du pinch maintenu
fixe dans le temps (formule centroid), échantillonnage **adaptatif** fixe dans le temps (formule centroid), échantillonnage **adaptatif**
@ -1507,8 +1603,8 @@ vérifie pas en tests JVM).
1. **Bumper la version** dans `app/build.gradle.kts` : `versionCode = N+1`, 1. **Bumper la version** dans `app/build.gradle.kts` : `versionCode = N+1`,
`versionName = "X.Y.Z+1"` (SemVer : fix = Z, feature = Y). `versionName = "X.Y.Z+1"` (SemVer : fix = Z, feature = Y).
2. **Tests verts obligatoires** : `./gradlew testDebugUnitTest` — 183 au 2. **Tests verts obligatoires** : `./gradlew testDebugUnitTest` — 191 au
total, 160 si `local-test-data/` est absent (les 4 classes de régression total, 168 si `local-test-data/` est absent (les 4 classes de régression
réelles sont skippées via `Assume`, 6/6/6/5 tests) ; **lint vert réelles sont skippées via `Assume`, 6/6/6/5 tests) ; **lint vert
obligatoire** : `./gradlew lint` (v1.3.4 — `StringFormatMatches` aurait obligatoire** : `./gradlew lint` (v1.3.4 — `StringFormatMatches` aurait
attrapé les crashs #47/#48 dès v1.3.1). Paliers de test du projet : attrapé les crashs #47/#48 dès v1.3.1). Paliers de test du projet :
@ -1836,6 +1932,14 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
du graphique (toggles modèles, calibration) n'est pas modifié ; les du graphique (toggles modèles, calibration) n'est pas modifié ; les
jours sans labs récents : la courbe s'arrête au dernier lab (le jours sans labs récents : la courbe s'arrête au dernier lab (le
vieillir est normal) ; chip décoché = plus de série ; 0 crash vieillir est normal) ; chip décoché = plus de série ; 0 crash
- [ ] **v1.6.0** : **Prolonger le tracé labs** : avec `Tracé labs` ON,
activer `Prolonger` → la courbe continue APRÈS le dernier lab
(rose atténué) jusqu'à l'extinction du modèle, avec légende dédiée
ET AVERTISSEMENT « simple simulation, sans garantie… » sous la
légende ; une dose loguée après le dernier lab fait repartir la
courbe en pic ; désactiver `Prolonger` → retour à la fenêtre
[1er ; dernier lab] exacte ; `Tracé labs` OFF → le chip `Prolonger`
est désactivé ; l'avertissement disparaît avec la série
- [ ] **v1.4.10** : **pan sur la vue 24 h** : glisser horizontalement à - [ ] **v1.4.10** : **pan sur la vue 24 h** : glisser horizontalement à
24 h doit déplacer la courbe (fix #62 : les deltas < 1 h s'accumulent 24 h doit déplacer la courbe (fix #62 : les deltas < 1 h s'accumulent
— avant, le pan ne bougeait jamais sur 24 h) ; tester aussi à 7 j et — avant, le pan ne bougeait jamais sur 24 h) ; tester aussi à 7 j et
@ -1856,7 +1960,7 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
tap ; et TOUTES les courbes affichées reflètent la calibration (test) tap ; et TOUTES les courbes affichées reflètent la calibration (test)
--- ---
*Doc mise à jour le 11 sept. 2026 (v1.5.0) — build OK, lint vert, 183/183 tests verts (160 sans *Doc mise à jour le 12 sept. 2026 (v1.6.0) — build OK, lint vert, 191/191 tests verts (168 sans
les données locales), dépôts Gitea (cloudyfy + farewell) avec releases APK, aucune donnée les données locales), dépôts Gitea (cloudyfy + farewell) avec releases APK, aucune donnée
de santé dans le dépôt ni l'historique. Fil des corrections : v1.3.3 = reprise de de santé dans le dépôt ni l'historique. Fil des corrections : v1.3.3 = reprise de
maintenance (permissions agenda, export logs IO, bump de version) ; v1.3.4 = 2 crashs maintenance (permissions agenda, export logs IO, bump de version) ; v1.3.4 = 2 crashs

View File

@ -204,6 +204,20 @@ Pics de référence (dose unique de 5 mg, IM) :
- **Pics / creux** (chip sur le graphique) : triangles ▲▼ aux extrema estimés de - **Pics / creux** (chip sur le graphique) : triangles ▲▼ aux extrema estimés de
chaque courbe (E2 et T, les deux modèles) — pratique pour visualiser d'un coup chaque courbe (E2 et T, les deux modèles) — pratique pour visualiser d'un coup
d'œil les hauts et les bas entre deux injections d'œil les hauts et les bas entre deux injections
- **Tracé labs** (chip `Tracé labs`, off par défaut) : une courbe E2 qui suit la
forme du modèle PK MAIS passe EXACTEMENT par chacune de tes prises de sang —
la trajectoire que tes labs tracent, avec la dynamique du modèle entre deux
analyses (rose pointillé). Entre le 1er et le dernier lab seulement : la
courbe ne s'invente pas de niveau.
**Prolonger** (chip, off par défaut — actif seulement quand Tracé labs est on) :
la courbe se PROLONGE après ton dernier lab : le modèle (dosages, esters
injectés depuis, pics et descentes classiques) × le ratio mesuré à ton dernier
lab. La partie prolongée est dessinée en rose ATTÉNUÉ avec sa légende
(« estimation, plus ancrée ») et un AVERTISSEMENT : c'est une simple
simulation sans garantie de correspondre au réel, extrapolée à partir de tes
résultats de laboratoire — qui peuvent eux-mêmes être erronés. Elle s'arrête
quand le modèle lui-même s'éteint. Compare-la à ta prochaine prise de sang,
et fie-toi à elle plutôt qu'à cette courbe
- **Calibration automatique** (Paramètres, désactivée par défaut) : quand activée, les - **Calibration automatique** (Paramètres, désactivée par défaut) : quand activée, les
facteurs d'échelle et le modèle T sont ajustés en continu depuis tes labs — pour facteurs d'échelle et le modèle T sont ajustés en continu depuis tes labs — pour
l'affichage seulement, tes réglages stockés ne changent pas. **Chaque ester est l'affichage seulement, tes réglages stockés ne changent pas. **Chaque ester est