- ChartScreen : one-liner sur la clé « labResults entière » (le pourquoi
du fix#66, là où on lit le code).
- §20.bis : les 4 pistes d'optimisation écartées/différées de l'audit
(importJson batch, BootReceiver goAsync, fusion generateForecastDoses,
cache terminalDecayParameters) — avec la raison de chaque report, pour
qu'une future session ne redécouvre pas et ne re-pose pas les questions.
Critique v1.8.0 : « changé d'ester, de dosage ET de posologie, et l'app
me disait stabilisée depuis février » — le proxy « 1ʳᵉ dose du traitement »
était aveugle aux changements récents.
- LabTiming.regimeStartMs (nouveau, internal) : le régime courant = la
séquence terminale de doses à (ester effectif, dose mg, écart
inter-doses) CONSTANTS — l'écart est comparé exactement (7 j ± 1 h casse
le régime) : tout changement récent réinitialise la stabilisation et la
reco saute au premier creux post-stabilisation. KDoc complet (règle +
justification conservatrice des intervalles irréguliers).
- LabRecommendation.ester = l'ESTER EFFECTIF de la dernière dose (override
compris) — l'encart/carte racontent le bon ester.
- HomeScreen : carte compacte « Prochaine prise de sang (suggestion) »
(creux daté + créneau associé + mention de stabilisation SEULEMENT si le
régime n'était pas déjà stable) — même calcul que la page Analyses
(demande v1.8.1 : suggestion aussi sur l'Accueil).
- 3 nouveaux tests (223 verts / 193 sans données locales) + lint :
changement de dose / d'intervalle / d'ester → réinitialisation épinglée.
- Validé émulateur §16.ter (release, seed réel v1.7.0) : la carte passe de
« stabilisé depuis le 06/02 » à « EEN pas stabilisé avant le 29/09 —
premier creux fiable après ton dernier changement », creux 27/09 22:43,
0 crash. versionCode 36 / versionName 1.8.1. Web sync v1.8.1.
- LabsScreen : labNotesForDisplay (helper PUR, testé) — notes DISTINCTES
d'une prise E2+T → DEUX lignes préfixées du marqueur (« E2 : … » /
« T : … ») ; note identique (dialog commun) → une seule ligne
(dédupliquée) ; vides ignorées ; note seule → brute (v1.0 préservé).
L'ancien code ne prenait que la première note non vide (hypothèse
« toutes identiques » cassée par l'édition unitaire) : l'autre note
était conservée mais perdue à l'affichage.
- RegressionUserCase5Test (7 tests) : NOUVEL export réel v1.7.0
(local-test-data/backup-v1.7.0.json, gitigné) — 3 traitements dont CPA
oral, 64 doses, 28 labs ; la dernière prise porte EXACTEMENT le cas du
bug (deux notes distinctes E2/T) : les deux affichées, aucune perdue ;
plausibilité moteur (CPA oral + EEn actif + EV inactif simulé),
prévision 7 j, notes de doses préservées. Aucune valeur de santé en dur
(data-driven, garde §8.bis).
- LabsGroupingTest : +5 tests sur labNotesForDisplay. 211 verts
(181 sans données locales) + lint vert.
- Validé émulateur §16.ter : APK release seedé avec l'export v1.7.0 →
écran Analyses affiche « E2 : … » ET « T : … », 0 crash.
- versionCode 34 / versionName 1.7.1. Web sync en miroir (web v1.7.1).
- 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.
- LabTrajectoryModel : extendBeyondLastLab (ρ_last constant au-delà du
dernier lab significatif), lastAnchorMs, extensionHorizonEndMs
(horizon = dernière dose E2 + cutoff du traitement — cutoffHours rendu
public, une seule source de vérité) ; boucle de calcul inchangée.
- ChartScreen : chip « Prolonger » (5ᵉ, off par défaut, désactivé tant
que Tracé labs est off), split série "LAB" (ancrée) / "LABX"
(prolongée, rose atténué α 0,55), légendes dédiées (branche explicite
avant le else — leçon #63), AVERTISSEMENT « simple simulation, sans
garantie de correspondre au réel, labs potentiellement erronés » sous
la légende quand la prolongation est visible.
- 8 nouveaux tests (191 verts / 168 sans données locales) + lint vert.
- Bump versionCode 32 / versionName 1.6.0.
- FIX toggle agenda : Posologie requise (refus + message si absente),
permission vérifiée RÉELLEMENT via ContextCompat au save (le flag
remembered pouvait être faux après recomposition), AppLog à chaque étape
- FIX export logs : réutilise le pattern éprouvé de l'export JSON
(openOutputStream wt), chaque étape journalisée dans AppLog
- FIX dialog changelog : version vue mémorisée AVANT l'affichage (sinon
réapparaissait à chaque réouverture), titre = BuildConfig.VERSION_NAME
(documenté : la version de l'APP, pas du contenu)
- RegressionUserCase3Test mis à jour (3 traitements : EV inactif + EEn
actif + CPA oral avec posologie 1 j, 51 doses, 26 labs)
- versionCode 16, versionName 1.3.2
- DosesScreen : carte « Sous THS depuis le … » (HrtDuration, mois = 30 j estimés)
- AppLog : journal horodaté buffer circulaire 500 lignes persisté
filesDir/debug-log.txt ; export SAF + effacement dans Paramètres ;
alimenté par agenda/permissions/import/export/erreurs
- FIX toggle agenda (bug remonté) : le résultat de permission arrive
ASYNCHRONE — le test synchrone post-launch() était toujours faux → le
callback active le switch + journalisation
- AppLogTest (4) + HrtDurationTest (5) → 87 tests verts
- versionCode 15, versionName 1.3.1
- Dialog « Nouveautés » (v1.3.0) : au démarrage, si la version installée est
plus récente que la dernière vue (DataStore changelog_seen_version), un
AlertDialog affiche les sections CHANGELOG non vues (ChangelogHelper
sectionsSince + comparaison SemVer NUMÉRIQUE — 1.2.9 < 1.2.10, lexicographique
aurait tort) ; asset changelog.md synchronisé à chaque build par la tâche
Gradle copyChangelog (gitignoré) ; fermable, ne réapparaît pas avant la
prochaine mise à jour
- Événements d'agenda récurrents (CalendarEvents.kt) : calendrier LOCAL dédié
« HormoneTrack » (CalendarContract, ACCOUNT_TYPE_LOCAL), événement avec
RRULE FREQ=DAILY;INTERVAL=N dérivé de la Posologie (arrondi demi-supérieur
EXPLICITE floor(x+0.5) — kotlin.math.round arrondit les ties vers l'entier
PAIR : 6,5 → 6, piège épinglé), début = prochaine occurrence à l'heure de
rappel (ou 12:00) ; switch dans l'éditeur sous « Rappels », permissions
WRITE_CALENDAR + READ_CALENDAR demandées à l'activation ; suppression/
recréation au save ; id stocké sur Treatment (Room v3, MIGRATION_2_3)
- Paramètres : version installée (BuildConfig.VERSION_NAME, buildConfig=true)
+ lien cliquable vers les releases Gitea
- Tests : ChangelogHelperTest (8) + CalendarRruleTest (3) → 78 tests verts
- versionCode 14, versionName 1.3.0
- generateForecastDoses : les créneaux déjà passés (oubli d'injection) ne sont
plus simulés — avant, dernier+intervalle tombait dans le passé → faux pic
dans l'historique + rythme décalé ; la prévision démarre au premier créneau
strictement futur, au rythme configuré
- un retard décale toute la prévision (part de la dernière prise réelle) —
comportement voulu, épinglé par 2 tests
- doc §7.3b corrigée (mismatch doc-code détecté par l'utilisatrice)
- docs : §13 écrasement, §19/§20 import, §14 #34/#35, §21, historique
(lignes v1.2.2/6/7), footer — vérification intégrée dans le script de patch
- versionCode 10, versionName 1.2.7 ; 64 tests verts
- build release signé avec la CLÉ DEBUG (même signature → mise à jour
par-dessus l'app installée sans perte de données) mais avec R8 full mode
+ isShrinkResources : 20 Mo → 2,4 Mo, démarrage et fluidité améliorés
- proguard-rules.pro : -keep explicites pour la réflexion Gson (data.model,
BackupData, TConfig) — sinon export/import JSON cassé en release uniquement
- release v1.2.5 : deux APK publiés (release recommandé 2,4 Mo + debug 20 Mo)
- docs : §16.bis (deux APK par release, garde-fous R8), CHANGELOG
Bug remonté : passer un traitement à inactif effaçait sa simulation du graphique
(Home/Chart collectaient activeTreatments) et faussait la calibration, tout en
permettant d'y loger des doses.
- HomeScreen / ChartScreen : simulation + calibration avec ALLTreatments
(actifs + inactifs) — l'historique EV d'un traitement archivé reste simulé
- Home : chips « Log rapide », dialog de création et carte « prochaine dose »
sur les traitements ACTIFS uniquement
- DosesScreen : création → actifs uniquement ; édition d'une dose existante →
tous les traitements (rattachement préservé)
- Rappels : annulés pour les inactifs (save, boot via getAllOnce, prochaine dose)
- RegressionUserCase3Test (6 tests, données réelles HORS dépôt gitignoré) :
transition complète EV inactif (29 doses) → EEn actif (9 doses), 22 labs sur
les deux périodes, calibration par période couvrant EV + EEN, k T par ester,
continuité de courbe, niveau actuel — 62 tests verts
- docs : §6.bis (sémantique isActive), §14 bug #32, §8, §21, CHANGELOG,
README, GUIDE ; versionCode 7, versionName 1.2.4
- RegressionUserCase{,2}Test chargent le backup réel depuis local-test-data/
(gitignoré) et sont IGNORÉS proprement (Assume) si le fichier est absent —
plus aucune donnée de santé personnelle embarquée dans le dépôt
- KDoc LabDialog : exemple 300.0 (au lieu d'une valeur réelle)
- script d'anonymisation /tmp/scrub.py prêt pour filter-branch (historique)
- detectExtrema : extrema locaux stricts (plateaux fusionnés), alternance
pic/creux imposée, filtre d'amplitude (2 pg/mL E2, 0,02 ng/mL T) — sémantique
zigzag documentée (oscillation sous le seuil = un seul pivot)
- CurveChart : triangles ▲▼ aux extrema de chaque série (couleur de la série),
chip « Pics / creux » + légende (désactivé par défaut)
- computeTKPerEster : le k du modèle T est calibré PAR PÉRIODE D'ESTER (labs T
attribués à la période de la dernière dose ≤ lab, médiane) — la suppression T
diffère valerate vs enanthate ; la courbe T utilise le k de l'ester ACTIF à
chaque instant (activeEsterAt + curseur de doses triées dans computeCurve)
- Fix : la calibration T automatique utilise désormais l'E2 CALIBRÉE
(scalePerEster) — calibrer contre l'E2 brute faussait les k
- levelAt/currentLevel : paramètre tKPerEster (fallback = tConfig.k stocké)
- ExtremaTest : 6 tests (alternance, monotone, plat, court, filtre d'amplitude,
anti-corrélation E2/T) — 56 tests verts
- versionCode 6, versionName 1.2.3 ; docs mises à jour (§7.5/§7.6, §11, README, guide)
- LabDialog : mode création avec deux sections (E2 et T, chacune optionnelle,
au moins une valeur requise) → insère 1 ou 2 LabResult au même timestamp ;
mode édition inchangé (un seul marqueur, pré-rempli)
- LabsScreen : regroupement par timestamp (groupLabsForDisplay : E2 avant T,
autres ensuite, tri desc) → affichage « E2 306 pg/mL · T 45 ng/dL » côte à
côte ; tap sur une paire → sélecteur « Quelle entrée modifier ? » puis
édition pré-remplie ; suppression = la prise entière (confirm nommant les
valeurs) ; formatLabValue préserve les décimales
- ChartScreen : le toggle T masque désormais aussi les labs T (avant : seuls
les points restaient visibles)
- LabsGroupingTest : 4 tests de regroupement (48 tests verts au total)
- versionCode 5, versionName 1.2.2 ; docs mises à jour
- computeEsterScaleFactors : chaque lab est attribué à la période d'injection
dans laquelle il tombe (dernière dose E2 <= lab → son ester) ; facteur final
par ester = médiane des ratios de cette période. Corrige le mélange des
périodes valerate/enanthate qui gonflait les courbes (250-375 pg/mL)
- e2At/computeCurve : paramètre scalePerEster (chaque dose scalée par le facteur
de SON ester, fallback = scaleFactor stocké du traitement)
- autoCalibrated : renvoie esterScales + tConfig recalibré, traitements inchangés
- convertTToNgMl : conversion défensive pg/mL et µg/L (un lab T « 38 pg/mL »
écrasait l'axe T et rendait la courbe T invisible — remonté utilisateur)
- LabDialog create/edit : tap sur une ligne de l'écran Analyses → édition
pré-remplie (formatLabValue préserve les décimales)
- Home : tap sur le mini-graphique → écran Graphiques + mini-légende E2/T
- Settings : UNE seule option « Calibration automatique (E2 + T) » (E2 par
période d'ester + modèle T), placée au-dessus des réglages T manuels
- RegressionUserCase2Test : 2e export réel épinglé (9 doses EEn/TFS, 8 labs,
fréquence 6 j) — vérifie l'état d'équilibre EEn (~270 pg/mL calibré, cohérent
labs 306/248 ; non calibré ≈ 367 = les « 375 » rapportés)
- V120FeaturesTest : attribution des labs par période d'ester + scalePerEster
- 44 tests verts ; versionCode 4, versionName 1.2.1
- Docs : CHANGELOG, DEVELOPPEMENT (§7.6 réécrit), GUIDE, README
- CurveChart : API ChartSeries/CurveStyle (superposition de plusieurs modèles,
styles plein/pointillé), labs T normalisés en ng/mL au rendu
- ChartScreen : panoramique horizontal (remonter dans le passé, bouton
« Revenir à maintenant »), toggles Estrannaise/TFS indépendants, chip Prévision
(horizon = 2× l'intervalle configuré, borné 7-30 j), auto-calibration intégrée,
légende dynamique
- HomeScreen : données auto-calibrées pour la courbe 24 h
- DosesScreen : intervalle en jours entre chaque dose et la précédente du même
traitement (colonne « Interval (d) » du .ods)
- TreatmentEditorScreen : section « Fréquence » (switch + intervalle en jours)
- SettingsScreen : option Calibration automatique
- TimePicker : centré dans ses dialogs (bug d'alignement à gauche signalé)
- strings FR/EN complètes pour toutes les nouveautés
- concentrationOfDose/e2At/computeCurve : paramètre modelOverride (dessiner
Estrannaise et Transfem Science simultanément, indépendamment du pkModel stocké)
- generateForecastDoses : projette les doses à venir depuis la dernière injection
réelle + forecastIntervalDays (jamais persistées, ester override conservé)
- autoCalibrated : recalcul à la volée des scale factors et du modèle T depuis les
labs (copies uniquement — les valeurs stockées ne changent jamais)
- Treatment.forecastIntervalDays + migration Room v1→v2 (ALTER TABLE), sans
fallbackToDestructiveMigration (données réelles de l'utilisatrice protégées)
- AppSettings.autoCalibrate (DataStore, désactivé par défaut)
- V120FeaturesTest : 6 tests (rythme des prévisions, override d'ester projeté,
divergence des deux modèles, auto-cal appliquée et préservation des originaux)