diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8eec395..b445d7a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,29 @@ > section la plus récente EN PREMIER ; ce fichier est lu par le dialog > « Nouveautés » de l'app web (fetch `docs/CHANGELOG.md`). +## [1.10.0] — 2026-09-27 + +### Corrigé — la recommandation de prise de sang précédait la stabilisation (#68) + +- Miroir de l'Android v1.10.0 (remontée + données réelles → 6ᵉ régression + épinglée côté Android) : le « creux » était le **minimum de la fenêtre + entière** (créneau N−1 → créneau N). Pour un ester à montée lente (EEn : + pic ~J+5 ≈ intervalle 7 j), ce minimum tombe **juste après l'injection + PRÉCÉDENTE** (creux d'absorption, ~3 h) — la date proposée était gouvernée + par l'injection N−1, antérieure à la stabilisation, et le texte « juste + avant ton injection du … » était faux de plusieurs jours. +- **Fix** : le creux = **niveau PRÉ-INJECTION du créneau** (dernier point de + courbe avant l'injection) — restaure le principe v1.8.0 documenté et rend + la carte cohérente. Pour les esters à t½ courte (EV), le point + pré-injection EST le minimum de fenêtre : comportement inchangé. +- Tests : la suite lab-timing (12) passe inchangée — sa sémantique épinglée + (« creux juste avant l'injection, écart ≤ 2 h ») était déjà celle du fix ; + 180 tests + E2E verts (`check.sh`). + +Les autres changements de la v1.10.0 Android (dialog fantôme #69, rappel +sauté si dose déjà loggée) n'ont pas d'équivalent web (notifications et +intents de notification sont spécifiques Android). + ## [1.9.7] — 2026-09-20 ### Corrigé — la suggestion de prise de sang « change tout le temps » à chaque injection diff --git a/js/pk/lab-timing.js b/js/pk/lab-timing.js index 71107be..36f8f7d 100644 --- a/js/pk/lab-timing.js +++ b/js/pk/lab-timing.js @@ -115,18 +115,25 @@ export function nextBloodDrawRecommendation(treatments, doseLogs, labs, nowMs = const minTroughMs = nowMs + MIN_HORIZON_HOURS * HOUR_MS; let windowStart = nowMs; for (const slot of slots) { - // Creux du créneau = minimum de la courbe entre l'injection précédente - // (ou maintenant) et ce créneau - const window = curve.filter((p) => p.timestamp > windowStart && p.timestamp < slot.timestamp); + // ⚠️ FIX #68 (v1.10.0, miroir du Kotlin) : le creux = niveau + // PRÉ-INJECTION du créneau (dernier point de courbe avant l'injection — + // principe 1, « le moment le plus comparable »). L'ancien MINIMUM DE LA + // FENÊTRE ENTIÈRE tombait au DÉBUT de la fenêtre pour les esters à + // montée lente (EEn : pic ~J+5 ≈ intervalle 7 j → le minimum local est + // le creux d'absorption, quelques heures après l'injection PRÉCÉDENTE) : + // la date proposée précédait la stabilisation affichée sur la MÊME + // carte, et le texte « juste avant ton injection du … » était faux de + // plusieurs jours (remontée v1.9.8). Pour les esters à t½ courte (EV), + // le point pré-injection EST le minimum de fenêtre : inchangé. let trough = null; - for (const p of window) { - if (trough === null || p.e2 < trough.e2) trough = p; + for (const p of curve) { + if (p.timestamp > windowStart && p.timestamp < slot.timestamp) trough = p; } if ( trough !== null && trough.timestamp >= minTroughMs && trough.timestamp > lastLabMs - && slot.timestamp >= stabilizedAtMs // sauter au premier creux stabilisé + && trough.timestamp >= stabilizedAtMs // sauter au premier creux stabilisé ) { return { troughMs: trough.timestamp, diff --git a/js/ui/settings.js b/js/ui/settings.js index bb8c59b..8659bd4 100644 --- a/js/ui/settings.js +++ b/js/ui/settings.js @@ -31,7 +31,7 @@ import { el, showDialog, field, switchRow, filterChip, toast } from './component * (APK + web au MÊME numéro, tags appariés `vX.Y.Z` + `vX.Y.Z-web`). * v1.4.10 = portage initial de l'Android v1.4.10. */ -export const WEB_VERSION = '1.9.7'; +export const WEB_VERSION = '1.10.0'; /** Parse un champ numérique FR (virgule → point) ; null si vide/invalide. */ function parseNumOrNull(text) {