Les macros arrivent au poignet — affichage, pas saisie
Sylvain, après avoir reçu le widget Hydratation : « il manque juste le suivi des repas calories et lipides etc ». ⚠️ Sa demande est plus fine que ce que j'avais écarté. J'avais dit non à la SAISIE des repas sur la montre — pas de caméra, pas de scanner, pas de saisie de texte : un bouton n'aurait fait que renvoyer vers l'iPhone. Mais VOIR où l'on en est n'a aucune de ces limites. Ce qui manquait, et où ----------------------- Le snapshot portait `kcalToday`/`kcalGoal` et rien d'autre. Les macros existaient pourtant côté serveur, agrégées et servies : /api/meals -> kcal, protein_g, carbs_g, fat_g, fiber_g /api/nutrition/goals -> cibles {target, min, max} pour chacune Il manquait uniquement le transport. Trois maillons ajoutés : `widget-bridge.js` les pousse, `CoachWidgetSnapshot` les porte, `CoachWatchNutritionWidget` les affiche. ⛔ Rien n'est calculé côté natif. Les totaux viennent du journal, les cibles de `nutrition_goals.py`. Le seul calcul est un reste (cible − consommé), la même soustraction que /meals affiche déjà. Le piège évité, parce qu'il est documenté dans ce fichier --------------------------------------------------------- `asOf(_:)` remet les totaux du jour à zéro quand le snapshot date d'hier. Les macros y sont ajoutées : les oublier aurait affiché les grammes de la veille sous la date du jour — le défaut même que cette fonction existe pour empêcher, et qui avait survécu un temps sur les totaux de boisson. ⚠️ Les CIBLES ne se périment pas, elles : une cible n'est pas une mesure. Sans ça, la jauge disparaîtrait chaque nuit jusqu'à la prochaine ouverture de l'app. Deux tests Linux le verrouillent (`testMacrosResetLikeEnergy`, `testMacroGoalsSurviveTheNight`) — 93 au vert. ⚠️ Une cible de type « min » (les protéines) se lit comme un plancher atteint, pas comme un plafond à ne pas dépasser. `widget-bridge.js` ne pousse que `target` ; le widget n'en sait pas plus et ne prétend pas le contraire. Le widget compile-t-il ? Inconnu, comme les précédents : WidgetKit n'existe pas sur Linux. Vérifié en revanche que chaque champ appelé existe, et qu'aucun symbole n'est déclaré deux fois. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,8 +41,14 @@ final class DayRolloverTests: XCTestCase {
|
||||
s.waterMlToday = 1660
|
||||
s.coffeeCountToday = 3
|
||||
s.kcalToday = 1186
|
||||
s.proteinToday = 74
|
||||
s.fatToday = 41
|
||||
s.carbsToday = 158
|
||||
s.waterGoalMl = 2750
|
||||
s.kcalGoal = 1950
|
||||
s.proteinGoal = 118
|
||||
s.fatGoal = 59
|
||||
s.carbsGoal = 225
|
||||
s.zones = HeartRateZones(z2: [109, 118], fcmaxUsed: 152, clinicalTargetBpm: 112,
|
||||
zonesSince: "2026-08-12", zonesFrom: "frozen")
|
||||
return s
|
||||
@@ -69,6 +75,28 @@ final class DayRolloverTests: XCTestCase {
|
||||
XCTAssertEqual(vu.kcalToday, 0)
|
||||
}
|
||||
|
||||
func testMacrosResetLikeEnergy() {
|
||||
// ⚠️ Ajoutées le 25/09/2026 pour le suivi au poignet. Les oublier dans
|
||||
// `asOf` afficherait les grammes d'hier sous la date du jour — le
|
||||
// défaut même que cette fonction existe pour empêcher, et qui avait
|
||||
// survécu un temps sur les totaux de boisson.
|
||||
let vu = snapshot(at: "2026-08-17 22:00").asOf(date("2026-08-18 00:01"), calendar: zurich)
|
||||
XCTAssertEqual(vu.proteinToday, 0)
|
||||
XCTAssertEqual(vu.fatToday, 0)
|
||||
XCTAssertEqual(vu.carbsToday, 0)
|
||||
}
|
||||
|
||||
func testMacroGoalsSurviveTheNight() {
|
||||
// Une CIBLE n'est pas une mesure : elle ne se périme pas à minuit.
|
||||
// Sans elle, la jauge disparaîtrait chaque nuit jusqu'à la prochaine
|
||||
// ouverture de l'app.
|
||||
let vu = snapshot(at: "2026-08-17 22:00").asOf(date("2026-08-18 00:01"), calendar: zurich)
|
||||
XCTAssertEqual(vu.proteinGoal, 118)
|
||||
XCTAssertEqual(vu.fatGoal, 59)
|
||||
XCTAssertEqual(vu.carbsGoal, 225)
|
||||
XCTAssertEqual(vu.kcalGoal, 1950)
|
||||
}
|
||||
|
||||
func testYesterdaysDayScopedFieldsAreDropped() {
|
||||
let vu = snapshot(at: "2026-08-17 22:00").asOf(date("2026-08-18 00:01"), calendar: zurich)
|
||||
XCTAssertNil(vu.routine, "la routine se recoche chaque jour")
|
||||
|
||||
Reference in New Issue
Block a user