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)
This commit is contained in:
parent
8fc6d07772
commit
d7c0ae312c
@ -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
|
||||
> sang et aux consignes de ton endocrinologue.
|
||||
|
||||
- **Statut** : v1.9.2 — build Android ✅, **lint vert** ✅, **237 tests unitaires** ✅ (207 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.9.4 — build Android ✅, **lint vert** ✅, **243 tests unitaires** ✅ (213 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)
|
||||
- **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)
|
||||
@ -123,7 +123,7 @@ par AGP si les licences sont signées). Le wrapper télécharge Gradle 9.7.1.
|
||||
git clone <repo> && cd HormoneTrack
|
||||
echo "sdk.dir=/chemin/vers/android-sdk" > local.properties # ou ANDROID_HOME
|
||||
./gradlew assembleDebug # APK : app/build/outputs/apk/debug/app-debug.apk
|
||||
./gradlew testDebugUnitTest # 237 tests (207 sans les données locales)
|
||||
./gradlew testDebugUnitTest # 243 tests (213 sans les données locales)
|
||||
./gradlew lint # lint vert obligatoire avant release
|
||||
```
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@ android {
|
||||
// tag : v1.3.0→v1.3.2 contenaient tous versionCode 14 / "1.3.0"
|
||||
// (bump jamais commité) → BuildConfig.VERSION_NAME était faux dans
|
||||
// les APK publiés (Paramètres + titre du dialog « Nouveautés »).
|
||||
versionCode = 40
|
||||
versionName = "1.9.2"
|
||||
versionCode = 41
|
||||
versionName = "1.9.4"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@ -46,6 +46,39 @@ object PKPresets {
|
||||
absorptionHours = 152f, eliminationHalfLifeHours = 150f, bioavailabilityFraction = 1f,
|
||||
defaultDoseUnit = "mg", defaultDoseAmount = 10.0
|
||||
),
|
||||
// --- v1.9.4 : le modèle ESE est ANALYTIQUE (estrannaise.js, cf
|
||||
// pk/EstrannaiseModels.kt) et couvre 6 esters injectables —
|
||||
// presets ajoutés pour EC (huile), EB et EUCS (undécylate
|
||||
// suspension cristalline, exclusif à ce fit). Champs Bateman =
|
||||
// t½ terminales des fits (informatifs, pas utilisés au calcul —
|
||||
// le dispatch passe par la forme close).
|
||||
PKPreset(
|
||||
nameRes = R.string.preset_ec_ese,
|
||||
type = TreatmentType.ESTRADIOL,
|
||||
route = AdministrationRoute.INJECTION_IM,
|
||||
esterType = Esters.EC,
|
||||
pkModel = PKModels.ESTRANNAISE,
|
||||
absorptionHours = 7f, eliminationHalfLifeHours = 202f, bioavailabilityFraction = 1f,
|
||||
defaultDoseUnit = "mg", defaultDoseAmount = 5.0
|
||||
),
|
||||
PKPreset(
|
||||
nameRes = R.string.preset_eb_ese,
|
||||
type = TreatmentType.ESTRADIOL,
|
||||
route = AdministrationRoute.INJECTION_IM,
|
||||
esterType = Esters.EB,
|
||||
pkModel = PKModels.ESTRANNAISE,
|
||||
absorptionHours = 1f, eliminationHalfLifeHours = 4f, bioavailabilityFraction = 1f,
|
||||
defaultDoseUnit = "mg", defaultDoseAmount = 1.0
|
||||
),
|
||||
PKPreset(
|
||||
nameRes = R.string.preset_eucs_ese,
|
||||
type = TreatmentType.ESTRADIOL,
|
||||
route = AdministrationRoute.INJECTION_SUBCUT,
|
||||
esterType = Esters.EUCS,
|
||||
pkModel = PKModels.ESTRANNAISE,
|
||||
absorptionHours = 22f, eliminationHalfLifeHours = 756f, bioavailabilityFraction = 1f,
|
||||
defaultDoseUnit = "mg", defaultDoseAmount = 10.0
|
||||
),
|
||||
// --- Injections: Transfem Science models ---
|
||||
PKPreset(
|
||||
nameRes = R.string.preset_ev_tfs,
|
||||
|
||||
@ -271,10 +271,17 @@ fun TreatmentEditorScreen(treatmentId: Long, onDone: () -> Unit) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
if (PharmacokineticEngine.isInjectionRoute(route)) {
|
||||
// v1.9.4 : la liste des esters suit la couverture RÉELLE du
|
||||
// modèle choisi (Esters.choicesForModel — miroir du DoseDialog
|
||||
// et du treatment-editor web) : le modèle ESE ANALYTIQUE offre
|
||||
// ses 6 esters injectables (EV/EU/EEn/EC/EB/EUCS) directement
|
||||
// dans l'éditeur, au lieu des seuls EV/EU/EEn de l'époque des
|
||||
// tables ODS. Chaque ester listé est dispatché par le moteur —
|
||||
// aucun choix possible ne produit 0 pg/mL.
|
||||
DropdownField(
|
||||
label = stringResource(R.string.ester),
|
||||
selectedLabel = ester,
|
||||
options = listOf(Esters.EV, Esters.EU, Esters.EEN).map { it to it },
|
||||
options = Esters.choicesForModel(model).map { it to it },
|
||||
onSelect = { ester = it }
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@ -292,7 +299,17 @@ fun TreatmentEditorScreen(treatmentId: Long, onDone: () -> Unit) {
|
||||
PKModels.TRANSFEM_SCIENCE to stringResource(R.string.model_tfs),
|
||||
PKModels.WHSAH to stringResource(R.string.model_whs)
|
||||
),
|
||||
onSelect = { model = it }
|
||||
onSelect = { model = it
|
||||
// v1.9.4 : l'ester courant peut sortir de la couverture
|
||||
// du nouveau modèle (ex. EUCS + TFS : le V3C n'a pas de
|
||||
// paramètres EUCS → le dispatcher donnerait 0) — on
|
||||
// rebascule sur le premier ester couvert (EV dans les
|
||||
// trois listes). Le recompose reconstruit ensuite la
|
||||
// liste des esters (options = choicesForModel(model)).
|
||||
if (ester !in Esters.choicesForModel(it)) {
|
||||
ester = Esters.choicesForModel(it).first()
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
|
||||
@ -238,6 +238,9 @@
|
||||
|
||||
<!-- Presets -->
|
||||
<string name="preset_ev_ese">Injection EV — Estrannaise</string>
|
||||
<string name="preset_ec_ese">Injection EC (huile) — Estrannaise</string>
|
||||
<string name="preset_eb_ese">Injection EB — Estrannaise</string>
|
||||
<string name="preset_eucs_ese">Injection EUCS (suspension cristalline) — Estrannaise</string>
|
||||
<string name="preset_eu_ese">Injection EU — Estrannaise</string>
|
||||
<string name="preset_een_ese">Injection EEn — Estrannaise</string>
|
||||
<string name="preset_ev_tfs">Injection EV — Transfem Science</string>
|
||||
|
||||
@ -238,6 +238,9 @@
|
||||
|
||||
<!-- Presets -->
|
||||
<string name="preset_ev_ese">EV injection — Estrannaise</string>
|
||||
<string name="preset_ec_ese">EC injection (oil) — Estrannaise</string>
|
||||
<string name="preset_eb_ese">EB injection — Estrannaise</string>
|
||||
<string name="preset_eucs_ese">EUCS injection (crystal suspension) — Estrannaise</string>
|
||||
<string name="preset_eu_ese">EU injection — Estrannaise</string>
|
||||
<string name="preset_een_ese">EEn injection — Estrannaise</string>
|
||||
<string name="preset_ev_tfs">EV injection — Transfem Science</string>
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
package com.hormonetrack.data.model
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Tests des PRESETS de traitements (v1.9.4 — miroir de `tests/presets.test.js`
|
||||
* côté web) : le modèle ESE ANALYTIQUE couvre 6 esters injectables — les
|
||||
* presets de création doivent offrir les 6 (comme TFS offre les 7 du V3C et
|
||||
* WHSAH les 6 du fit Mona). Avant v1.9.4, les presets ESE n'offraient que
|
||||
* EV/EU/EEn (l'héritage des tables ODS) — remontée : « les presets n'ont pas
|
||||
* été mis à jour lors de l'ajout du modèle source ESE ».
|
||||
*
|
||||
* Garde centrale : **aucun preset ne peut créer un traitement non couvert par
|
||||
* son propre modèle** (ester ∈ choicesForModel(pkModel)) — un preset hors
|
||||
* couverture produirait 0 pg/mL sans aucun avertissement (leçon §12).
|
||||
*/
|
||||
class PKPresetsTest {
|
||||
|
||||
/** Presets injectables d'un modèle (ester réel — le NONE Bateman sort). */
|
||||
private fun injectables(model: String) =
|
||||
PKPresets.all.filter { it.pkModel == model && it.esterType != Esters.NONE }
|
||||
|
||||
@Test
|
||||
fun `les presets ESE couvrent les 6 esters du fit analytique`() {
|
||||
val esters = injectables(PKModels.ESTRANNAISE).map { it.esterType }.sorted()
|
||||
// Même ensemble que Esters.choicesForModel(ESE) — l'éditeur et les
|
||||
// presets doivent proposer exactement la couverture du dispatch.
|
||||
assertEquals(Esters.choicesForModel(PKModels.ESTRANNAISE).sorted(), esters)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `chaque ester couvert a EXACTEMENT un preset ESE (pas de doublon)`() {
|
||||
val names = injectables(PKModels.ESTRANNAISE).map { it.esterType }
|
||||
assertEquals(names.size, names.toSet().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `les presets TFS (7) et WHSAH (6) restent inchangés`() {
|
||||
assertEquals(7, injectables(PKModels.TRANSFEM_SCIENCE).size)
|
||||
assertEquals(6, injectables(PKModels.WHSAH).size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `aucun preset injectable ne peut créer un traitement non couvert`() {
|
||||
// La garde ne vise que les presets à ester RÉEL (profil PK) : un
|
||||
// preset Bateman (esterType NONE, ex. gel/patch/oral/anti-androgène)
|
||||
// ne passe pas par le dispatch par ester — sa couverture n'a pas de
|
||||
// sens. Un preset injectable hors couverture produirait 0 pg/mL sans
|
||||
// aucun avertissement (leçon §12).
|
||||
for (preset in PKPresets.all.filter { it.esterType != Esters.NONE }) {
|
||||
assertTrue(
|
||||
"preset " + preset.nameRes + " : ester " + preset.esterType +
|
||||
" hors couverture de " + preset.pkModel + " → 0 pg/mL garanti",
|
||||
preset.esterType in Esters.choicesForModel(preset.pkModel)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `les presets ESE non injectables (gel patch oral) restent en Bateman`() {
|
||||
val nonInjectable = PKPresets.all.filter {
|
||||
it.pkModel == PKModels.ESTRANNAISE && it.esterType == Esters.NONE
|
||||
}
|
||||
// 3E2 (gel/patch/oral) + 3 anti-androgènes (CPA/spiro/bica)
|
||||
assertTrue("gel, patch, oral + anti-androgènes toujours présents", nonInjectable.size >= 6)
|
||||
assertTrue(nonInjectable.all { it.bioavailabilityFraction in 0.01f..1f })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `les champs Bateman informatifs des nouveaux presets ESE restent plausibles`() {
|
||||
// Les champs Bateman des presets ESE reflètent les t½ terminales des
|
||||
// fits (informatifs, pas utilisés au calcul) : EC ≈ 202 h (k3 0,669/j),
|
||||
// EB ≈ 4 h (k3 4,34/j), EUCS ≈ 756 h (k2 0,022/j) — on garde des
|
||||
// bornes larges pour ne pas figer les valeurs des fits.
|
||||
val ec = PKPresets.all.first { it.esterType == Esters.EC && it.pkModel == PKModels.ESTRANNAISE }
|
||||
val eb = PKPresets.all.first { it.esterType == Esters.EB && it.pkModel == PKModels.ESTRANNAISE }
|
||||
val eucs = PKPresets.all.first { it.esterType == Esters.EUCS && it.pkModel == PKModels.ESTRANNAISE }
|
||||
assertTrue("t½ EC ESE ≈ 8,4 j (fit 0,669/j)", ec.eliminationHalfLifeHours in 100f..300f)
|
||||
assertTrue("t½ EB ESE courte (fit 4,34/j)", eb.eliminationHalfLifeHours in 1f..24f)
|
||||
assertTrue("t½ EUCS ESE ≈ 31,5 j (suspension cristalline)", eucs.eliminationHalfLifeHours in 400f..1200f)
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,31 @@
|
||||
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`, …).
|
||||
|
||||
## [1.9.4] — 2026-09-19 (versionCode 41)
|
||||
|
||||
### Ajouté — les presets du modèle ESE couvrent ses 6 esters injectables
|
||||
|
||||
- **Remontée** : depuis l'ajout du modèle source Estrannaise (v1.9.0), les
|
||||
presets de création n'offraient toujours que EV/EU/EEn — « les presets
|
||||
n'ont pas été mis à jour lors de l'ajout du modèle source pour ESE ».
|
||||
- **Presets (`PKPresets.kt`, 25 entrées)** : 3 presets ESE ajoutés au
|
||||
même niveau que les autres — EC huile (5 mg IM), EB (1 mg IM), EUCS
|
||||
undécylate suspension cristalline (10 mg SC, ester exclusif à ce fit).
|
||||
Champs Bateman informatifs = t½ terminales des fits (pas utilisés au
|
||||
calcul — le dispatch passe par la forme close).
|
||||
- **Éditeur (`TreatmentEditorScreen.kt`)** : la liste des esters suit la
|
||||
couverture RÉELLE du modèle choisi (`Esters.choicesForModel` — même
|
||||
liste que l'override du DoseDialog) : ESE liste ses 6 esters
|
||||
injectables directement à la création. Au changement de modèle, si
|
||||
l'ester courant sort de la couverture (ex. EUCS + TFS), il rebascule
|
||||
sur EV — garde anti « 0 pg/mL ».
|
||||
- **Tests** : `PKPresetsTest` (nouveau, 6 tests — miroir
|
||||
`tests/presets.test.js` web) : couverture des 6 esters ESE, unicité,
|
||||
TFS (7) / WHSAH (6) inchangés, garde « aucun preset injectable hors
|
||||
couverture de son modèle », plausibilité des t½ informatives.
|
||||
243 tests verts + lint.
|
||||
- **Doc** : doublon de la section §7.12 supprimé (collé deux fois).
|
||||
|
||||
## [1.9.2] — 2026-09-19 (versionCode 40)
|
||||
|
||||
### Corrigé — le nuage d'incertitude exigeait un traitement STOCKÉ en ESE
|
||||
|
||||
@ -63,6 +63,7 @@ Fonctionnalités v1 :
|
||||
|
||||
| Date | Événement |
|
||||
|---|---|
|
||||
| 19 sept. 2026 (session v1.9.4) | **Presets du modèle ESE étendus à ses 6 esters injectables** (remontée : « depuis l'ajout du modèle source ESE, les presets n'ont pas été mis à jour ») : 3 presets ajoutés (EC huile 5 mg IM, EB 1 mg IM, EUCS suspension cristalline 10 mg SC — 25 entrées), champs Bateman informatifs = t½ des fits ; **éditeur** : la liste des esters suit `Esters.choicesForModel` (parité DoseDialog/web) et rebascule sur EV si l'ester sort de la couverture au changement de modèle ; **web** : 2 trous du portage v1.9.0 corrigés (`Esters.EUCS` manquant dans pk-engine.js — preset référençant `undefined` — et `choicesForModel` resté sur la couverture ODS à 3 esters) + `tests/presets.test.js` (6 tests, miroir `PKPresetsTest`). 243 verts / 213 sans données locales + lint + check web (175). Doc : doublon §7.12 supprimé. Web v1.9.4 sync. |
|
||||
| 19 sept. 2026 (session v1.9.2) | **Fix nuage vide sans traitement stocké ESE** (remontée : « il ne s'active que autour du tracé émulé, pas autour du modèle Estrannaise ») : le filtre du nuage testait le pkModel STOCKÉ — or la courbe ESE redessine TOUTES les doses E2 (modelOverride ESE) quel que soit le modèle stocké. FIX : le nuage couvre les doses à ester effectif couvert par ESE (peu importe le stocké) ; l'exclusivité reste portée par le chip ; l'oral Bateman reste hors nuage. 2 tests réécrits (237 verts / 207 sans). Web miroir v1.9.2. |
|
||||
| 19 sept. 2026 (session v1.9.1) | **Fix nuage calibré + suggestion sur l'Accueil + explication +4 pg/mL** : (a) remontée « le nuage ne s'active que autour du tracé, pas autour du modèle Estrannaise » : la courbe ESE est CALIBRÉE (scalePerEster) mais le nuage était BRUT → échelles différentes. FIX : EstrannaiseCloud.compute reçoit le MÊME scalePerEster que la courbe ESE (Android + web miroir) ; test nuage calibré ×2 (Android). (b) Le +4 pg/mL constaté depuis v1.8.2 : l'ARRONDI de la médiane (fix v1.8.2, plus juste que la troncature) a déplacé une échelle auto-calibrée d'un cran — le niveau actuel est le CORRIGÉ, documenté CHANGELOG 1.9.1. (c) Émulateur : nuage visible autour de la courbe ESE calibrée (1363 px rose pâle, seed réel + traitement EV ESE de test), 0 crash. Web v1.9.1 sync (harmonisation de l'arrondi — les niveaux web/android convergent). 235 verts / 205 sans données locales. |
|
||||
| 17 sept. 2026 (session v1.9.0) | **Modèle Estrannaise ANALYTIQUE (abandon de l'ODS) + nuage d'incertitude MCMC (Android + web sync)** (demande) : découverte des sources originelles (github.com/WHSAH/estrannaise.js — forme close 3C + paramètres publiés + posterior MCMC 313/ester). Vérification numérique AVANT débranchement : **RMS 0,00 vs tables ODS** (l'ODS était l'échantillonnage de ces formules). ESE → analytique (dispatch, cutoff 10×t½, t½ LabTiming), PKProfileStore retiré du runtime (asset ODS → src/test/assets, −550 Ko d'APK), ESE couvre 6 esters (+EUCS), TFS = liste explicite (EUCS sans V3C TFS). **Nuage MCMC exclusif ESE** : chip `Nuage` (off, activable si ESE affiché, coupure auto si ESE off), 32 courbes du posterior déterministes, alpha faible sous les courbes, hors échelles/labels/extrema. 11 nouveaux tests (234 verts / 204 sans données locales) + lint + check web (166). Validé émulateur §16.ter : courbe ESE analytique affichée, unités, chips Extend/Cloud, 0 crash. |
|
||||
@ -701,50 +702,25 @@ devient à son tour**.
|
||||
miroirs ; le fetch des tables ODS au démarrage web est remplacé par le
|
||||
fetch MCMC (démarrage plus rapide) ; nuage dessiné par `chart-canvas.js`.
|
||||
|
||||
### 7.12 Modèle Estrannaise ANALYTIQUE + nuage MCMC (v1.9.0) — `pk/EstrannaiseModels.kt`, `pk/EstrannaiseCloud.kt`
|
||||
#### Presets & éditeur — les 6 esters sélectionnables à la création (v1.9.4)
|
||||
|
||||
**DÉCISION v1.9.0** (utilisatrice) : « tous les modèles ont maintenant leurs
|
||||
sources originelles — on abandonne complètement les liens avec le fichier
|
||||
ODS, qui lui-même était une extrapolation de ces mêmes sources ». TFS
|
||||
(v1.4.0) et WHSAH (v1.4.6) étaient déjà analytiques ; **l'Estrannaise le
|
||||
devient à son tour**.
|
||||
|
||||
- **SOURCE** : https://github.com/WHSAH/estrannaise.js/ — modèle 3
|
||||
compartiments en forme close : `C(t) = dose·d·k1·k2·[e^(−k1t)/((k1−k2)(k1−k3))
|
||||
− e^(−k2t)/((k1−k2)(k2−k3)) + e^(−k3t)/((k1−k3)(k2−k3))]` (t en JOURS).
|
||||
Paramètres publiés par ester : EV [478, 0,236, 4,85, 1,24], EU [471,5,
|
||||
0,01729, 6,528, 2,285], EEn [191,4, 0,119, 0,601, 0,402], EC [246,
|
||||
0,0825, 3,57, 0,669], EB [1893,1, 0,67, 61,5, 4,34], EUCS [16,15,
|
||||
0,046, 0,022, 0,101] (nouveau code ester v1.9.0 : « EUn casubq »).
|
||||
- **FIDÉLITÉ (vérifiée AVANT débranchement)** : la forme close reproduit
|
||||
les tables ODS **RMS 0,00** sur 0→200 j (EV/EU/EEn), écart de pic
|
||||
≤ 0,1 % — l'ODS n'était que l'échantillonnage horaire de ces formules.
|
||||
Épinglé par `EstrannaiseModelsTest` (Android) et
|
||||
`estrannaise-models.test.js` (web).
|
||||
- **Débranchement runtime** : `concentrationOfDose` dispatche ESE →
|
||||
`EstrannaiseModels.sample` (plus de fallback `PKProfileStore.sample`) ;
|
||||
`cutoffHours` ESE → 10 × t½ terminale analytique (plus la longueur de
|
||||
table) ; `LabTiming` t½ ESE analytique ; `PKProfileStore.init` retirée
|
||||
du démarrage. **L'asset `pk_profiles.json` quitte `src/main/assets`
|
||||
(−550 Ko d'APK) pour `src/test/assets/`** : l'ODS survit UNIQUEMENT
|
||||
comme référence des tests de fidélité. `PKProfileStore` est conservé
|
||||
(lecteur pur) pour ces tests.
|
||||
- **Couverture étendue** : ESE passe de 3 à **6 esters injectables**
|
||||
(EV/EU/EEn/EC/EB/**EUCS**) — `Esters.choicesForModel` mis à jour (TFS
|
||||
reste 7, WHSAH 6 ; ⚠️ TFS = liste EXPLICITE : EUCS n'a pas de V3C TFS).
|
||||
- **NUAGE D'INCERTITUDE (exclusif ESE, demande v1.9.0)** : Estrannaise
|
||||
publie le **posterior MCMC** de ses paramètres (313 échantillons par
|
||||
ester — asset `mcmc_samples.json` ≈ 48 Ko, chargé au démarrage). Chip
|
||||
`Nuage` du graphique (off par défaut, activable à volonté, ACTIVABLE
|
||||
SEULEMENT si ESE est affiché — éteindre ESE coupe le nuage) →
|
||||
`EstrannaiseCloud.compute` trace 32 courbes du posterior (échelonnées,
|
||||
déterministes) superposant les doses des porteurs ESE. Dessin en alpha
|
||||
faible SOUS les courbes ; hors échelles/labels/extrema. Limites : les
|
||||
contributions TFS/WHSAH ne sont pas dans le nuage (pas de posterior
|
||||
publié) ; les patchs du repo (tw/ow) ne sont pas portés.
|
||||
- **Web sync** : `js/pk/estrannaise-models.js` + `js/pk/estrannaise-cloud.js`
|
||||
miroirs ; le fetch des tables ODS au démarrage web est remplacé par le
|
||||
fetch MCMC (démarrage plus rapide) ; nuage dessiné par `chart-canvas.js`.
|
||||
- **`PKPresets.kt` (25 entrées)** : 3 presets ESE ajoutés — EC huile
|
||||
(5 mg IM), EB (1 mg IM), EUCS suspension cristalline (10 mg SC, ester
|
||||
exclusif à ce fit). Champs Bateman **informatifs** (t½ terminales des
|
||||
fits : EC ≈ 202 h pour k3 0,669/j, EB ≈ 4 h pour k3 4,34/j, EUCS
|
||||
≈ 756 h pour k2 0,022/j) — pas utilisés au calcul, le dispatch passe
|
||||
par la forme close.
|
||||
- **`TreatmentEditorScreen.kt`** : la liste des esters =
|
||||
`Esters.choicesForModel(model)` (même helper que l'override du
|
||||
DoseDialog — plus aucune divergence des listes). Au changement de
|
||||
modèle, si l'ester courant sort de la couverture (EUCS + TFS par ex.),
|
||||
il rebascule sur EV : aucun choix possible ne produit 0 pg/mL.
|
||||
- **Garde épinglée** : `PKPresetsTest` (miroir web
|
||||
`tests/presets.test.js`) — « aucun preset injectable hors couverture de
|
||||
son propre modèle » ; ESE 6 / TFS 7 explicite (sans EUCS) / WHSAH 6.
|
||||
- **Web sync v1.9.4** : mêmes presets + i18n ; 2 trous du portage v1.9.0
|
||||
corrigés au passage (`Esters.EUCS` manquant dans `pk-engine.js`,
|
||||
`choicesForModel` resté à 3 esters).
|
||||
|
||||
## 8. Tests unitaires
|
||||
|
||||
@ -918,6 +894,11 @@ Emplacement : `app/src/test/java/com/hormonetrack/`. Répertoire de travail d'ex
|
||||
- **`EstrannaiseCloudTest`** (5) : v1.9.0 — nuage d'incertitude : 32 courbes
|
||||
à dispersion réelle (les posterior couvrent une plage), fenêtre respectée,
|
||||
exclusivité ESE (TFS/oral → vide), sans dose → vide, nbCurves < 2 → vide.
|
||||
- **`PKPresetsTest`** (6) : v1.9.4 — presets de création : les presets ESE
|
||||
couvrent les 6 esters du fit (unicité, même ensemble que
|
||||
`choicesForModel`), TFS (7) / WHSAH (6) inchangés, **garde anti
|
||||
« 0 pg/mL »** (aucun preset injectable hors couverture de son modèle),
|
||||
champs Bateman informatifs plausibles (t½ des fits).
|
||||
- **`LabTimingTest`** (11) : v1.8.0/v1.8.1 — recommandation de prochaine
|
||||
prise de sang : creux juste avant le créneau, saut au premier creux
|
||||
STABILISÉ (5 × t½ ; régime non stabilisé → creux suivant), prise récente →
|
||||
|
||||
@ -88,7 +88,10 @@ Les notifications de l'app remontent automatiquement sur la montre via **Huawei
|
||||
|
||||
## 6. Premiers pas dans l'app
|
||||
|
||||
1. **Traitements → +** → choisis un preset (ex : *Injection EV — Estrannaise*)
|
||||
1. **Traitements → +** → choisis un preset (ex : *Injection EV —
|
||||
Estrannaise*). Le modèle Estrannaise propose ses 6 esters injectables
|
||||
(EV, EU, EEn, EC huile, EB, EUCS suspension cristalline) ; le menu
|
||||
déroulant Ester liste toujours les esters couverts par le modèle choisi.
|
||||
- Tu as changé d'ester ? Crée (ou garde) le traitement de l'ancien ester et
|
||||
passe-le **inactif** (switch « Actif ») : il disparaît de la saisie et de tes
|
||||
rappels, mais **son historique reste simulé et calibré** sur les graphiques —
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user