27 Commits

Author SHA1 Message Date
ae14cee07b v1.13.0 : reco prédictive — valeur E2 au creux, régime poolé entre traitements identiques, cible de creux personnelle
- predictedE2 : valeur brute au creux × facteur du ester actif — fournie
  par Home/Labs quand l'auto-calibration est ON (sinon null : la carte
  n'affiche rien, une valeur brute serait trompeuse). Miroir web.
- Régime POOLÉ (pooledRegimeDoses) : les doses de tous les traitements
  partageant (ester effectif, mg) forment UNE séquence — le re-parenting
  d'historique (« 6d-old », v1.12.0) ne fait plus redémarrer la
  stabilisation. Garde-fous : ester ≠ jamais poolé (régression n°3) ;
  dose ≠ exclue (le 8 mg casse via le trou). Régression n°7 data-driven
  sur le nouvel export (backup-v1.12.0.json).
- Cible de creux E2 (opt-in) : DataStore + carte settings (hint croisé
  « distinct des seuils d'alerte — jamais de notification ») + coloration
  carte reco (primaire/hors cible tertiary) + backup rétrocompatible (un
  backup ancien n'efface pas la cible locale). Système à 3 niveaux
  documenté §7.11. Miroir web complet.

284 tests JVM (250 sans données locales) + 14 UI + lint verts ; web 199
tests + E2E verts (check.sh). Validé émulateur sur données réelles :
« Expected at this trough: ≈ 208 pg/mL — outside your target », régime
poolé = stable depuis le 12 août, 0 crash.
2026-10-07 09:59:19 +02:00
b3372a80e4 v1.12.0 : fix #70 (inactif à Posologie projetait encore) + Doses (icônes de forme, marqueurs prise de sang)
- FIX #70 : generateForecastDoses garde !isActive — un injectable archivé
  avec Posologie et de l'historique projetait encore ses injections
  (graphique Prévision, extension de fenêtre, horizon LabTiming) ; le chip
  Prévision s'activait sur des Posologies inactives. FIX : garde moteur +
  horizon/chip sur les ACTIFS. §6.bis inchangé : l'historique reste simulé,
  seul le FUTUR s'arrête (comme les rappels v1.4.0). Miroir web. 3 tests
  ForecastDosesGuardTest + 3 miroirs web.
- Icônes de forme de prise dans Doses : routeIcon pur (pilule/seringue
  IM+SC teinte tertiary pour la SC/goutte/sparadrap/compte-gouttes ;
  ⚠️ MedicationLiquid absent d'icons-extended 1.7.8 → Colorize).
- Marqueurs « prise de sang le même jour » : labMarkersForDose pur (jour
  calendaire LOCAL, lab à l'heure exacte = APRÈS) → encart 🧪↑/🧪↓ en bout
  de ligne. 7 tests DosesExtrasTest + 10 miroirs web.

274 tests JVM + 14 UI + lint verts ; web 194 tests + E2E verts (check.sh).
Validé émulateur sur APK RELEASE avec données réelles seedées + scénario du
bug (2 inactifs à Posologie 7 j) : Prévision on/off 0 crash, glyphes et
marqueurs en place.
2026-09-29 23:24:34 +02:00
a0f3ac59f9 v1.11.0 : inactifs regroupés en bas de la page Traitements + cartes atténuées
- Demande : « les traitements inactifs sont peu discernables — les placer
  à la fin (tout en bas), et peut-être les rendre plus distincts ».
- Helper pur treatmentsForDisplay (tri STABLE : actifs d'abord, inactifs
  après, ordre relatif conservé dans chaque groupe).
- LazyColumn en 3 sections : actifs / en-tête inactive_section (seulement
  si des inactifs existent) / inactifs — cartes alpha 0.55 en plus du
  badge, lisibles et tappables (l'édition d'un archivé reste possible).
- Miroir web : treatmentsForDisplay dans js/data/models.js + rendu
  sections + opacity 0.55 + i18n inactive_section FR/EN (web v1.11.0 sync).
- 5 tests JVM TreatmentsDisplayTest + 4 tests web (miroir).

264 tests JVM + 14 UI + lint verts ; web 184 tests + E2E verts (check.sh).
Validé émulateur sur APK RELEASE avec données réelles seedées (5 actifs en
haut, en-tête + EV-old/EEn-old tout en bas, 0 crash).
2026-09-29 07:31:25 +02:00
a40d9bc076 v1.9.6 : la carte Accueil liste TOUTES les prochaines doses (triées)
Remontée : le rappel quotidien (CPA) masquait le rappel hebdomadaire
(EEn) — « je ne le vois quasiment pas ».

- NextDoseCard : UNE ligne par traitement, TRIÉES par prochaine prise ;
  1ʳᵉ ligne (la plus proche) en avant, suivantes en style secondaire ;
  titre pluriel « Prochaines doses » dès 2 lignes (next_doses FR/EN)
- Helper PUR nextDoseLine (locale/zone paramétrables, template jours
  localisé next_dose_days) + 3 tests NextDoseLineTest
- Notifications inchangées (une alarme par traitement)
- versionCode 43 / 1.9.6 + CHANGELOG/§2/README/GUIDE
2026-09-21 21:56:32 +02:00
e4f52bc6da v1.9.4 : presets du modèle ESE étendus à ses 6 esters injectables + éditeur dynamique
- PKPresets.kt (25 entrées) : EC huile (5 mg IM), EB (1 mg IM), EUCS
  suspension cristalline (10 mg SC) — champs Bateman informatifs = t½
  terminales des fits (pas utilisés au calcul)
- TreatmentEditorScreen.kt : liste des esters = Esters.choicesForModel
  (même helper que l'override du DoseDialog) ; au changement de modèle,
  l'ester rebascule sur EV si non couvert (garde anti 0 pg/mL)
- PKPresetsTest (nouveau, 6 tests) : couverture des 6 esters ESE,
  unicité, TFS 7 / WHSAH 6 inchangés, garde anti hors couverture,
  plausibilité des t½ informatives — 243 verts + lint
- versionCode 41 / versionName 1.9.4 + CHANGELOG/§2/§7.12/§8/README/GUIDE
- Doc : doublon de la section §7.12 supprimé (collé deux fois)
2026-09-19 23:30:23 +02:00
8078d5cbed v1.9.0 : modèle Estrannaise ANALYTIQUE (abandon de l'ODS) + nuage d'incertitude MCMC
DÉCISION : tous les modèles ont maintenant leurs sources originelles —
on abandonne les liens avec le fichier ODS (qui lui-même était
l'échantillonnage horaire de ces formules ; fidélité vérifiée RMS 0,00).

- pk/EstrannaiseModels.kt (NOUVEAU) : forme close 3C de estrannaise.js
  (paramètres publiés EV/EU/EEn/EC/EB/EUCS), posterior MCMC (313
  échantillons/ester, asset mcmc_samples.json ≈ 48 Ko), t½ terminale
  analytique, cas dégénérés (taux égaux → limites, portés du JS source).
- PharmacokineticEngine : dispatch ESE → EstrannaiseModels (plus de
  fallback PKProfileStore) ; cutoffHours ESE → 10 × t½ analytique (plus
  la longueur de table).
- Esters : +EUCS (undécylate suspension cristalline, exclusif ESE) ;
  choicesForModel ESE = 6 injectables ; TFS = liste EXPLICITE (EUCS sans
  V3C TFS → dispatcher donnerait 0).
- LabTiming : t½ ESE analytique.
- pk/EstrannaiseCloud.kt (NOUVEAU) : nuage d'incertitude — 32 courbes du
  posterior (échelonnées, déterministes) superposant les doses des
  porteurs ESE ; exclusif ESE (TFS/WHSAH sans posterior publié).
- ChartScreen/CurveChart : chip « Nuage » (off, activable si ESE affiché,
  coupure auto si ESE off), ChartSeries.cloud dessiné en alpha faible
  sous les courbes, hors échelles/labels/extrema, légende dédiée.
- Runtime 100 % sources analytiques : PKProfileStore.init retirée du
  démarrage, asset pk_profiles.json → src/test/assets (−550 Ko d'APK ;
  conservé pour les tests de fidélité RMS 0).
- 11 nouveaux tests (234 verts / 204 sans données locales) : fidélité,
  pics ±0,2 %, dégénérés, MCMC 313×6, nuage (dispersion/fenêtre/
  exclusivité/gardes), choicesForModel ESE=6, t½ analytique.
- Validé émulateur §16.ter (release, seed réel v1.7.0) : courbe ESE
  analytique affichée, chips Extend/Cloud, recommandation de prise de
  sang, 0 crash. versionCode 38 / versionName 1.9.0. Web sync v1.9.0
  (publié séparément).
2026-09-19 20:44:30 +02:00
8c19c8f295 v1.8.0 : recommandation de prochaine prise de sang (page Analyses)
Moteur pk/LabTiming.kt (PUR, miroir web js/pk/lab-timing.js) :
- traitement porteur = E2 injectable ACTIF à Posologie (sinon null) ;
- stabilisation = 1ʳᵉ dose du régime + 5 × t½ terminale (TFS/WHS
  analytiques ; Estrannaise : NOUVEAU PKProfileStore.terminalHalfLifeDays,
  refactor de la pente d'extrapolation de sample() — zéro duplication) ;
- creux = minimum de la courbe E2 prévisionnelle entre 2 injections
  (forme brute — sans calibration) ; ON SAUTE au premier creux dont le
  créneau est stabilisé (décision v1.8.0) ; filtres : ≥ now+6 h, jamais
  un creux déjà mesuré, horizon borné (ester ultra-long → null).

UI LabsScreen : carte « Prochaine prise de sang (suggestion) » (creux
exact + créneau associé + mention « ou la veille » + statut de
stabilisation + disclaimer) OU invite « renseigne une Posologie » quand
un injectable actif en est dépourvu (demande v1.8.0) — mutuellement
exclusives ; calcul produceState + tick minute.

Tests : LabTimingTest (8) + régression n°5 étendue (1) → 220 verts
(190 sans données locales) + lint. Validé émulateur §16.ter (release,
seed réel v1.7.0) : creux 20/09 10:37, injection EEN 20/09 11:20, EEN
stabilisé depuis le 06/02, 0 crash. versionCode 35 / versionName 1.8.0.
Web sync v1.8.0 (publié séparément).
2026-09-17 18:47:38 +02:00
2c58418604 v1.7.0 : sauvegarde automatique quotidienne (opt-in) + unités des axes
AUTO-BACKUP JOURNALIER (en plus de l'export manuel, inchangé) :
- AppSettings : enabled / treeUri (SAF persisté) / keep (1..30, défaut 7) /
  lastRun ; BackupManager.writeAutoBackup : tree URI → createDocument d'un
  fichier horodaté (ExportFileNames.autoBackupFileName — signature
  LocalDateTime, règle anti-#48) → écriture via writeBackup TEL QUEL
  (leçon #45) → purge par AutoBackupRetention (PURE, testée : ne touche
  JAMAIS exports manuels/logs/étrangers, keep clampé ≥ 1).
- AutoBackupWorker + AutoBackupScheduler (pattern AlertWorker) : périodique
  24 h (KEEP au démarrage, no-op si désactivé), runNow à l'activation
  (premier backup immédiat), statut dernier run persisté + AppLog ;
  proguard : -keep explicite du worker (réflexion WorkManager, leçon #64).
- Paramètres : carte « Sauvegarde automatique quotidienne » — switch (ON
  sans dossier → picker SAF), dossier persisté (takePersistableUriPermission),
  nom lisible (folderDisplayName), copies conservées, statut OK/ÉCHEC.
- Validé émulateur §16.ter (APK release + données réelles seedées) : dossier
  Download/HormoneTrack choisi via le picker SAF, premier backup v2 écrit
  immédiatement (3 traitements/52 doses/26 labs, importable), rétention
  keep=2 vérifiée (3 vieux autos supprimés, export manuel intact), statut
  « OK (date) », 0 crash.

UNITÉS DES AXES (remontée « jamais ajoutées depuis v1.0 ») : pg/mL (E2,
gauche) / ng/mL (T, droite) au sommet des colonnes de labels (padTop
12→26 dp) — validé émulateur (screencap). Portées web (v1.7.0 web sync).

9 nouveaux tests (200 verts / 177 sans données locales) + lint vert.
versionCode 33 / versionName 1.7.0.
2026-09-16 19:52:04 +02:00
3e2bf3992e v1.6.0 : « Tracé labs » prolongé au-delà du dernier lab (chip Prolonger + avertissement)
- 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.
2026-09-12 23:49:24 +02:00
04f6b8bd64 v1.5.0 : « Tracé labs » — courbe hybride ancrée sur les labs (M(t)×ρ(t))
Demande débattue avec l'utilisatrice (hésitation assumée, décision v1.5.0)
: une courbe biologiquement plausible MAIS passant par tous les labs.
- pk/LabTrajectoryModel.kt (pur) : M(t) = modèle PK brut (scaleFactor
  forcé 1) ; ρ_k = lab/M(t_k) interpolé LOG-LINÉAIREMENT entre labs
  consécutifs — passgage exact garanti, morphing d'amplitude continu.
  Garde anti-#61 (labIsSignificant : lab hors fenêtre d'action PAS un
  ancrage). E2 uniquement, fenêtre [1er ; dernier lab], < 2 labs → vide.
  Indépendante de la calibration (elle est SA propre référence — sinon
  double correction, épinglé). JAMAIS dans levelAt/alertes/rappels.
- UI : chip 'Tracé labs' (off par défaut) dans la rangée modèles,
  horizontalScroll CONFINÉ à la rangée (chip 4ᵉ coupé hors fenêtre —
  constat émulateur) ; couleur ChartLabTrajectory #C2185B dashed ;
  ChartSeries.showExtrema (tracé labs hors pics/creux) ; leçon #63 :
  clé 'LAB' exclue de la boucle légende (sinon légende TFS dupliquée).
- 11 tests LabTrajectoryModelTest (183 verts total, 161 sans données
  locales) + lint ; validé émulateur §16.ter (courbe passe exactement
  sur le lab 248 avec seed réel, 0 crash).
- Docs : §7.10 (maths + décisions), §2, §8, §16, §21, CHANGELOG [1.5.0],
  README (status + feature).
2026-09-11 16:11:02 +02:00
9b83533d72 v1.4.9 : fix #61 — calibration tombant à ×2,21 (auto ET manuelle) : garde de significativité labIsSignificant (prédiction ≥ 15 % du max observé, labs par timestamp croissant) sur les 3 pipelines — une dose EEn de test de janvier + des labs de janvier-mars produisaient des ratios aberrants (×3,3 → ×391) ; facteur WHSAH retombe à 0,55 (reproduit et épinglé par ScaleFactorWhsahReproTest) ; hint UX (auto ON → facteur manuel ignoré à l'affichage) ; nettoyage CHANGELOG (4 titres orphelins doublés) ; 168 tests verts + lint 2026-09-07 18:54:43 +02:00
ca917ba772 v1.4.6 : 3ᵉ modèle PK WHSAH (fit license-free du WHSAH Collective publié dans Mona — crédité) superposable au même niveau qu'Estrannaise/TFS : dispatch parallèle, 6 presets, dropdown 3 choix, chip + courbe verte/violette, choicesForModel (TFS=7/WHS=6/ESE=3) ; #57 : l'écran Graphiques défile (rangée toggles coupée sous le pli) ; 10 tests (155 verts) + lint ; validé émulateur (3 légendes + 3 courbes de couleurs distinctes) 2026-09-07 17:01:28 +02:00
15a7e6614c v1.4.5 : fix #55 — projection paraissant décalée d'un jour (génération exacte confirmée par régression #4 ; illusion = absence de marqueurs + labels à minuit UTC) → marqueurs de doses (prévisionnels pointillés + réels discrets) + xLabelTicks à minuit LOCAL dans le fuseau CHOISI (Paramètres) ; fix #56 — boucle de recomposition (nowMs relu à chaque frame → endMs dérive → main thread saturé, taps perdus) → nowMs mémoïsé sur le tick ; 6 tests (145 verts) + lint ; validé émulateur (chips réactifs, marqueur vertical rendu) 2026-09-07 11:27:38 +02:00
633c6debf4 v1.4.2 : seuils d'alerte configurables E2/T (Paramètres, opt-in, validés haut>bas) — cartes d'avertissement sur l'accueil (niveau ESTIMÉ, calibration incluse) ; notification via worker WorkManager périodique 15 min + check one-time au save, anti-spam par état persisté (Alerts.encodeState/shouldNotify), canal dédié ; backup JSON v2 avec les paramètres utilisateur (langue/auto-cal/seuils, rétrocompat v1, -keep R8) ; 13 nouveaux tests (129 verts) + lint 2026-09-07 00:02:22 +02:00
922d49841f v1.4.1 : prévision étendue et sans saut — activer le chip ne déplace plus la fenêtre (endMs = now − panHours signé, panHours < 0 = futur borné par l'horizon 12×Posologie [30 j ; 1 an], clamp unique clampPanHours) ; delta en jours sur la carte Prochaine dose (> 24 h : '5 j 2 h · sam. 6 18:00') ; 5 tests (112 verts) + lint 2026-09-06 23:00:42 +02:00
208ba56843 v1.4.0 : modèle Transfem Science reconstruit sur la méta-analyse officielle (V3C forme close, 7 esters, pics de l'article reproduits à ~1 % — TransfemScienceModels + 5 tests) ; fix #52 : rappels sur la grille Posologie (nextReminderFireFor, re-programmation après notif et 'Pris', ReminderScheduleTest ×7) ; nouveaux presets EB/EC/ECS/PEP ; 102 tests verts + lint 2026-09-06 22:28:18 +02:00
cb64f0e57e v1.3.3 : 3 bugs racines de l'audit de reprise corrigés — permissions agenda absentes du manifest (#44), export logs réutilise BackupManager.writeBackup (+AppLog fail-safe) (#45), bump de version commité avant le tag (#46) ; doc de dev rafraîchie (DB v3, targetSdk 36, Pixel 9 /e/OS, #38/#43, §19-21) 2026-09-06 11:24:12 +02:00
fa5d2df5a5 v1.3.1 : en-tête « temps sous THS » sur Doses, logs de diagnostic exportables, fix toggle agenda (callback async)
- 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
2026-09-06 10:16:49 +02:00
14f15e69cf v1.3.0 : dialog « Nouveautés » post-update, événements d'agenda récurrents, version + lien releases dans Paramètres
- 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
2026-09-06 08:30:31 +02:00
c888a718d5 v1.2.9 : zoom du graphique (pinch + boutons, 6 h → 300 j, focal stable, pas adaptatif) + disclaimer IA dans le README
- ChartScreen : detectTransformGestures unique (pan 1 doigt + pinch 2 doigts,
  pas de conflit de consommation) ; zoom autour du point focal (le temps sous
  le doigt reste fixe) ; plage bornée 6 h → 300 j (MIN/MAX_RANGE_H) ;
  boutons − / + en accessibilité
- CurveChart : stepForRange (15 min ≤ 12 h, 30 min ≤ 24 h, sinon 1 h) passé à
  computeCurve (courbes lisses à fort zoom) ; labels X adaptatifs 1 h/3 h
- README : disclaimer IA en en-tête (développé avec l'IA, contribution
  humaine essentielle = feedback/retours/suggestions, renvoi §2 doc dev)
  ; DEVELOPPEMENT §1 mention IA-assistée, §11 zoom, §8 67 tests
- ChartZoomTest : 3 tests stepForRange — 67 tests verts
- versionCode 12, versionName 1.2.9
2026-09-05 22:51:27 +02:00
55d0e5134f UI : « Fréquence d'injection » renommé « Posologie » (terme inadapté aux voies non injectables) ; hint généralisé « dernière prise » ; docs à jour
- strings EN (Dosage) / FR (Posologie) ; freq_hint : « dernière injection » →
  « dernière prise » (les deux langues)
- README, GUIDE, DEVELOPPEMENT §10/§21 : mentions mises à jour
- versionCode 11, versionName 1.2.8 ; 64 tests verts
2026-09-05 22:24:24 +02:00
e16d370b2f v1.2.6 : valeurs des pics/creux sur le graphique + import JSON en mode écrasement
- CurveChart : drawExtremum = triangle ▲▼ + VALEUR estimée de l'extremum
  (au-dessus d'un pic, en dessous d'un creux), couleur de la série
- Import JSON : mode ÉCRASEMENT (bug remonté : échec dès que l'app contenait
  des données — conflit d'IDs backup vs existants)
  · DAOs : deleteAll() sur les 3 tables (ordre enfants → parents, FK CASCADE)
  · BackupManager.importJson : wipe puis restauration (IDs conservés → FK
    valides), retourne aussi le tConfig du backup
  · SettingsScreen : après import → tConfig restauré dans DataStore + rappels
    reprogrammés (rescheduleAll) ; dialog renommé « Effacer & restaurer »
    avec avertissement explicite
- docs : §13 (écrasement), §11 (valeurs extrema), §14 #34, §16.bis CHECKLIST
  DE DÉPLOIEMENT complète numérotée (version → tests → docs → commit/tag →
  push 2 remotes → build 2 APK → releases 2 instances → smoke-test R8),
  §20/§21, CHANGELOG, README
- versionCode 9, versionName 1.2.6
2026-09-05 21:41:58 +02:00
34a7b588be v1.2.3 : pics/creux estimés sur le graphique (toggle) + calibration T par période d'ester
- 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)
2026-09-05 18:58:10 +02:00
c71a50429d v1.2.2 : prise de sang E2 + T en une entrée, affichage côte à côte, toggle T masque aussi les labs T
- 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
2026-09-05 18:33:19 +02:00
d9471cadaf v1.2.1 : calibration par période d'ester, édition des labs, tap accueil→Graphiques, auto-cal fusionnée E2+T, lab T en unité aberrante neutralisé
- 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
2026-09-05 17:38:08 +02:00
8ab97d4ed4 UI v1.2.0 : graphique multi-séries panoramique, toggles modèles/prévision, intervalles de dosage, TimePicker centré
- 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
2026-09-05 16:53:53 +02:00
8f7a235c93 v1.1.0 : suivi THS avec courbes E2/T, modèles Estrannaise & Transfem Science, calibration labs, rappels (GT 3), backup JSON, FR/EN
- Moteur PK par tables horaires (8001 h) extraites de Estrogen.ods + Bateman fallback
- Lookup profils insensible à la casse (fix courbes EEn plates)
- Conversion unités T (ng/dL, ng/L, nmol/L -> ng/mL)
- Édition des doses + override d'ester par injection
- 30 tests unitaires dont régression sur données réelles
- UI Compose Material 3, i18n FR/EN, sauvegarde JSON SAF
2026-09-05 16:32:44 +02:00