La collecte de journaux (#38, PR #40) est déployée et fonctionne — prouvé deux fois avec des instruments propres : un pod écrit 6 lignes, Loki en rend 6 ; un autre pod est supprimé, kubectl logs répond NotFound, et Loki garde sa ligne. Grafana porte la source de données et l'interroge avec succès.
Trois choses restent, mesurées en la déployant.
1. L'application loki n'est pas adoptée par ArgoCD
La cause est connue : la pile a d'abord été installée à la main (helm install) pendant la mise au point, avant que la PR ne soit fusionnée. Les secrets sh.helm.release.v1.loki.* et …alloy.* existent toujours dans tools, et le StatefulSet porte les deux marques :
⚠ Pendant un moment, les deux applications ont aussi été en Unknown avec :
ComparisonError: Failed to load target state: failed to generate manifest
for source 1 of 1: rpc error: code = DeadlineExceeded
Le repo-server d'ArgoCD n'arrivait pas à rendre les manifestes dans son délai. alloy s'en est sorti seul, loki pas encore. ArgoCD n'est pas géré depuis ce dépôt, donc son délai ne se règle pas par une PR ici — c'est à arbitrer.
Le remède propre est probablement de retirer les releases Helm faites à la main pour que git soit la seule source. ⚠ Je ne l'ai pas fait sans avis : au moment où je l'ai envisagé, ArgoCD ne pouvait pas rendre alloy, donc désinstaller aurait détruit une collecte qui marche sans garantie de la voir revenir.
2. La sonde de disponibilité de Loki exige une réponse en 1 seconde
Mesuré : 30 échecs en 25 minutes, context deadline exceeded, pendant que Loki tournait parfaitement — il finissait de rejouer son WAL, avec un checkpoint done time=4m23s. Conséquence : aucun endpoint derrière le service, donc la source de données Grafana était inutilisable tant que ça durait.
Une seconde est un défaut amont raisonnable sur une machine rapide. Sur un Raspberry Pi qui rejoue un WAL, c'est un piège. ⚠ Le remède n'est pas d'assouplir sans réfléchir : c'est de séparer « Loki démarre » de « Loki répond mal », par exemple avec un startupProbe généreux et une readinessProbe qui reste stricte ensuite.
3. pi2 est saturé, et Loki y a atterri
kubectl top nodes ce matin, avant Loki : pi1 77 %, pi2 106 %, pi3 64 %. Après : l'agent a mesuré +3,2 points sur pi2, ~645 Mio ajoutés au cluster.
Le symptôme est arrivé tout de suite : le nouveau pod Grafana a été planifié sur pi2 et y est resté bloqué 20 minutes, Running mais jamais prêt — 1 seconde de CPU consommée. Il a fallu fermer pi2 à la planification pour qu'il démarre sur pi3, en 165 s.
⚠ La cause profonde est nommée par l'agent : le planificateur ne voit que les requests, et elles ne sont presque pas déclarées sur ce cluster (17 % demandés contre 108 % utilisés). Le planificateur croit donc pi2 libre. Tant que ce sera vrai, il continuera d'y poser des charges.
⚠ Et metrics-server a cessé de répondre par moments pendant ces manipulations — à surveiller, c'est peut-être le même symptôme.
Ce que je n'ai pas vérifié
Le compacteur n'a jamais été vu supprimer quoi que ce soit : « le volume ne grossit pas indéfiniment » reste non démontré, avec 30 jours de rétention déclarés.
Aucune gate ne démarre Loki sur la configuration rendue — une config cassée passerait la CI. Les deux pannes de mise au point de ce lot seraient repassées.
Les premières lignes d'un pod très bref sont perdues : ~5 s séparent l'écriture de l'attachement du tailer. Un pod qui vit 2 s n'est pas collecté — je m'y suis fait prendre en le vérifiant.
La collecte de journaux (#38, PR #40) est **déployée et fonctionne** — prouvé deux fois avec des instruments propres : un pod écrit 6 lignes, Loki en rend 6 ; un autre pod est supprimé, `kubectl logs` répond `NotFound`, et Loki garde sa ligne. Grafana porte la source de données et l'interroge avec succès.
Trois choses restent, mesurées en la déployant.
## 1. L'application `loki` n'est pas adoptée par ArgoCD
État : `OutOfSync` / `Healthy`. `alloy` et `grafana` sont, eux, `Synced` / `Healthy`.
La cause est connue : la pile a d'abord été installée **à la main** (`helm install`) pendant la mise au point, avant que la PR ne soit fusionnée. Les secrets `sh.helm.release.v1.loki.*` et `…alloy.*` existent toujours dans `tools`, et le StatefulSet porte les deux marques :
```
managed-by=Helm release=loki app.kubernetes.io/instance=loki
```
⚠ Pendant un moment, les deux applications ont aussi été en `Unknown` avec :
```
ComparisonError: Failed to load target state: failed to generate manifest
for source 1 of 1: rpc error: code = DeadlineExceeded
```
Le repo-server d'ArgoCD n'arrivait pas à rendre les manifestes dans son délai. `alloy` s'en est sorti seul, `loki` pas encore. **ArgoCD n'est pas géré depuis ce dépôt**, donc son délai ne se règle pas par une PR ici — c'est à arbitrer.
Le remède propre est probablement de **retirer les releases Helm faites à la main** pour que git soit la seule source. ⚠ Je ne l'ai **pas** fait sans avis : au moment où je l'ai envisagé, ArgoCD ne pouvait pas rendre `alloy`, donc désinstaller aurait détruit une collecte qui marche sans garantie de la voir revenir.
## 2. La sonde de disponibilité de Loki exige une réponse en **1 seconde**
```
readinessProbe: { timeoutSeconds: 1, periodSeconds: 10, failureThreshold: 3 }
```
Mesuré : **30 échecs en 25 minutes**, `context deadline exceeded`, pendant que Loki tournait parfaitement — il finissait de rejouer son WAL, avec un `checkpoint done time=4m23s`. Conséquence : aucun endpoint derrière le service, donc **la source de données Grafana était inutilisable** tant que ça durait.
Une seconde est un défaut amont raisonnable sur une machine rapide. Sur un Raspberry Pi qui rejoue un WAL, c'est un piège. ⚠ Le remède n'est pas d'assouplir sans réfléchir : c'est de séparer « Loki démarre » de « Loki répond mal », par exemple avec un `startupProbe` généreux et une `readinessProbe` qui reste stricte ensuite.
## 3. pi2 est saturé, et Loki y a atterri
`kubectl top nodes` ce matin, avant Loki : pi1 77 %, **pi2 106 %**, pi3 64 %. Après : l'agent a mesuré **+3,2 points sur pi2**, ~645 Mio ajoutés au cluster.
Le symptôme est arrivé tout de suite : le nouveau pod Grafana a été planifié sur pi2 et y est resté bloqué **20 minutes**, `Running` mais jamais prêt — **1 seconde de CPU consommée**. Il a fallu fermer pi2 à la planification pour qu'il démarre sur pi3, en 165 s.
⚠ La cause profonde est nommée par l'agent : **le planificateur ne voit que les `requests`, et elles ne sont presque pas déclarées sur ce cluster** (17 % demandés contre 108 % utilisés). Le planificateur croit donc pi2 libre. Tant que ce sera vrai, il continuera d'y poser des charges.
⚠ Et `metrics-server` a cessé de répondre par moments pendant ces manipulations — à surveiller, c'est peut-être le même symptôme.
## Ce que je n'ai pas vérifié
- **Le compacteur n'a jamais été vu supprimer quoi que ce soit** : « le volume ne grossit pas indéfiniment » reste non démontré, avec 30 jours de rétention déclarés.
- **Aucune gate ne démarre Loki sur la configuration rendue** — une config cassée passerait la CI. Les deux pannes de mise au point de ce lot seraient repassées.
- Les premières lignes d'un pod très bref sont perdues : ~5 s séparent l'écriture de l'attachement du tailer. Un pod qui vit 2 s **n'est pas collecté** — je m'y suis fait prendre en le vérifiant.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
loki et alloy sont maintenant Synced / Healthy tous les deux. Le ComparisonError: DeadlineExceeded du repo-server était bien transitoire : il n'arrivait pas à rendre les manifestes dans son délai pendant que le cluster était sous tension, et il y est arrivé une fois la pression retombée.
⚠ Je n'ai donc PAS eu à retirer les releases Helm posées à la main, et je ne l'ai pas fait. Les secrets sh.helm.release.v1.{loki,alloy}.* traînent encore dans tools : ArgoCD gère les ressources, mais ces secrets sont des orphelins. Sans conséquence connue, à nettoyer un jour de calme.
2. La sonde à 1 seconde — corrigée (PR #45, fusionnée)
Un startupProbe patient tient désormais le rejeu du WAL (jusqu'à 10 min), et la readinessProbe reste stricte une fois le démarrage acquis, avec 5 s au lieu de 1.
⚠ Ce que le rendu m'a appris : mon premier jet omettaitinitialDelaySeconds en croyant le supprimer, et helm template rendait quand même le 15 amont — le chart fusionne cette table au lieu de la remplacer. Il est maintenant écrit à 0, explicitement.
⚠ La preuve manque encore : le rendu prouve la configuration produite, pas que le pod passera Ready du premier coup sous charge. C'est au prochain redémarrage que ça se constatera.
3. pi2 saturé — intact, et ça dépasse ces charts
La cause de fond n'est pas Loki : les requests ne sont presque nulle part déclarées sur ce cluster (17 % demandés contre 108 % utilisés), donc le planificateur croit pi2 libre et continue d'y poser des charges. Loki, lui, déclare bien les siennes (cpu: 100m, memory: 256Mi, limite 512Mi).
C'est un chantier à part et un arbitrage : déclarer des requests pour l'ensemble des charges du cluster change la façon dont tout se planifie, et sur trois Raspberry Pi ça peut rendre des pods non planifiables là où ils tournaient. Ça ne s'improvise pas la nuit.
⚠ Reste aussi ouvert, et non expliqué : metrics-server a cessé de répondre par moments pendant ces manipulations (kubectl top nodes muet). Peut-être le même symptôme, peut-être autre chose.
## Deux des trois restes sont traités
### 1. L'adoption par ArgoCD — **résolue d'elle-même**
`loki` et `alloy` sont maintenant **`Synced` / `Healthy`** tous les deux. Le `ComparisonError: DeadlineExceeded` du repo-server était bien transitoire : il n'arrivait pas à rendre les manifestes dans son délai pendant que le cluster était sous tension, et il y est arrivé une fois la pression retombée.
⚠ **Je n'ai donc PAS eu à retirer les releases Helm posées à la main**, et je ne l'ai pas fait. Les secrets `sh.helm.release.v1.{loki,alloy}.*` traînent encore dans `tools` : ArgoCD gère les ressources, mais ces secrets sont des orphelins. Sans conséquence connue, à nettoyer un jour de calme.
### 2. La sonde à 1 seconde — **corrigée** (PR #45, fusionnée)
Un `startupProbe` patient tient désormais le rejeu du WAL (jusqu'à 10 min), et la `readinessProbe` reste stricte une fois le démarrage acquis, avec 5 s au lieu de 1.
⚠ **Ce que le rendu m'a appris** : mon premier jet *omettait* `initialDelaySeconds` en croyant le supprimer, et `helm template` rendait quand même le `15` amont — **le chart fusionne cette table au lieu de la remplacer**. Il est maintenant écrit à `0`, explicitement.
⚠ **La preuve manque encore** : le rendu prouve la configuration produite, pas que le pod passera `Ready` du premier coup sous charge. C'est au prochain redémarrage que ça se constatera.
### 3. pi2 saturé — **intact, et ça dépasse ces charts**
La cause de fond n'est pas Loki : **les `requests` ne sont presque nulle part déclarées sur ce cluster** (17 % demandés contre 108 % utilisés), donc le planificateur croit pi2 libre et continue d'y poser des charges. Loki, lui, déclare bien les siennes (`cpu: 100m`, `memory: 256Mi`, limite `512Mi`).
C'est un chantier à part et un arbitrage : déclarer des `requests` pour l'ensemble des charges du cluster change la façon dont tout se planifie, et sur trois Raspberry Pi ça peut rendre des pods **non planifiables** là où ils tournaient. Ça ne s'improvise pas la nuit.
⚠ Reste aussi ouvert, et non expliqué : **`metrics-server` a cessé de répondre par moments** pendant ces manipulations (`kubectl top nodes` muet). Peut-être le même symptôme, peut-être autre chose.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Le point 3 se précise : pi2 porte ~2 cœurs de charge hors du cluster
metrics-server s'est remis à répondre (il avait redémarré — 35 redémarrages en 174 jours, le dernier il y a 7 h, ce qui explique son silence de tout à l'heure). Ce qu'il montre est plus intéressant que « pi2 est saturé » :
nœud
CPU
mémoire
pi1
17 %
81 %
pi2
155 – 188 %
109 %
pi3
12 %
63 %
Et en interrogeant le nœud directement (/stats/summary) :
nœud entier : 3740 m
tous les pods : 1236 m
kubelet : 421 m
─────────────────────────
NON ATTRIBUÉ : ~2080 m ← deux cœurs
Deux cœurs sur pi2 ne sont ni dans un pod, ni dans le kubelet. La mémoire n'était donc que la moitié de l'histoire : ce nœud est d'abord saturé en calcul, par quelque chose que Kubernetes ne voit pas.
Ce que j'ai éliminé, en le mesurant
Ce n'est pas la CI. Deux jobs tournaient pendant la mesure : celui de kadans-api sur arcodange_global_runner_pi3 (et pi3 est à 12 %), celui du front sur arcodange_laptop_runner. Aucun sur pi2.
Ce ne sont pas les charges Kubernetes. Le plus gourmand des pods de pi2 est longhorn-system/instance-manager à 645 m ; tous ensemble ils font 1236 m.
⚠ Je n'ai pas trouvé le consommateur. Il faudrait regarder les processus de l'hôte, et je n'ai pas voulu poser un pod privilégié sur un nœud déjà tendu, la nuit, sans que ce soit nécessaire. ⚠ Une piste que je n'ai pas suivie : ce cluster tourne sous Docker, pas containerd, avec sa racine déplacée sur /mnt/arcodange/docker — tout conteneur Docker hors Kubernetes sur cet hôte compte dans le total du nœud sans apparaître nulle part côté k8s.
Pourquoi ça compte pour la suite
C'est probablement l'explication des deux symptômes de cette nuit, et ils n'étaient pas des coïncidences :
le pod Grafana bloqué 20 minutes sur pi2, Running mais jamais prêt, avec 1 seconde de CPU consommée ;
la sonde de Loki qui expirait en context deadline exceeded alors que Loki allait bien.
Deux charges affamées sur le même nœud, au même moment. Déclarer des requests partout — le remède que je proposais plus haut — n'y changerait rien : le planificateur ne réserve que ce qu'il connaît, et ces deux cœurs lui sont invisibles.
## Le point 3 se précise : pi2 porte ~2 cœurs de charge **hors du cluster**
`metrics-server` s'est remis à répondre (il avait redémarré — 35 redémarrages en 174 jours, le dernier il y a 7 h, ce qui explique son silence de tout à l'heure). Ce qu'il montre est plus intéressant que « pi2 est saturé » :
| nœud | CPU | mémoire |
|---|---|---|
| pi1 | 17 % | 81 % |
| **pi2** | **155 – 188 %** | 109 % |
| pi3 | 12 % | 63 % |
Et en interrogeant le nœud directement (`/stats/summary`) :
```
nœud entier : 3740 m
tous les pods : 1236 m
kubelet : 421 m
─────────────────────────
NON ATTRIBUÉ : ~2080 m ← deux cœurs
```
**Deux cœurs sur pi2 ne sont ni dans un pod, ni dans le kubelet.** La mémoire n'était donc que la moitié de l'histoire : ce nœud est d'abord saturé en **calcul**, par quelque chose que Kubernetes ne voit pas.
## Ce que j'ai éliminé, en le mesurant
- **Ce n'est pas la CI.** Deux jobs tournaient pendant la mesure : celui de `kadans-api` sur `arcodange_global_runner_pi3` (et pi3 est à **12 %**), celui du front sur `arcodange_laptop_runner`. Aucun sur pi2.
- **Ce ne sont pas les charges Kubernetes.** Le plus gourmand des pods de pi2 est `longhorn-system/instance-manager` à 645 m ; tous ensemble ils font 1236 m.
⚠ **Je n'ai pas trouvé le consommateur.** Il faudrait regarder les processus de l'hôte, et je n'ai pas voulu poser un pod privilégié sur un nœud déjà tendu, la nuit, sans que ce soit nécessaire. ⚠ Une piste que je n'ai pas suivie : **ce cluster tourne sous Docker, pas containerd**, avec sa racine déplacée sur `/mnt/arcodange/docker` — tout conteneur Docker hors Kubernetes sur cet hôte compte dans le total du nœud sans apparaître nulle part côté k8s.
## Pourquoi ça compte pour la suite
C'est probablement l'explication des deux symptômes de cette nuit, et ils n'étaient pas des coïncidences :
- le pod Grafana **bloqué 20 minutes** sur pi2, `Running` mais jamais prêt, avec **1 seconde de CPU consommée** ;
- la sonde de Loki qui expirait en `context deadline exceeded` alors que Loki allait bien.
Deux charges affamées sur le même nœud, au même moment. Déclarer des `requests` partout — le remède que je proposais plus haut — **n'y changerait rien** : le planificateur ne réserve que ce qu'il connaît, et ces deux cœurs lui sont invisibles.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
La collecte de journaux (#38, PR #40) est déployée et fonctionne — prouvé deux fois avec des instruments propres : un pod écrit 6 lignes, Loki en rend 6 ; un autre pod est supprimé,
kubectl logsrépondNotFound, et Loki garde sa ligne. Grafana porte la source de données et l'interroge avec succès.Trois choses restent, mesurées en la déployant.
1. L'application
lokin'est pas adoptée par ArgoCDÉtat :
OutOfSync/Healthy.alloyetgrafanasont, eux,Synced/Healthy.La cause est connue : la pile a d'abord été installée à la main (
helm install) pendant la mise au point, avant que la PR ne soit fusionnée. Les secretssh.helm.release.v1.loki.*et…alloy.*existent toujours danstools, et le StatefulSet porte les deux marques :⚠ Pendant un moment, les deux applications ont aussi été en
Unknownavec :Le repo-server d'ArgoCD n'arrivait pas à rendre les manifestes dans son délai.
alloys'en est sorti seul,lokipas encore. ArgoCD n'est pas géré depuis ce dépôt, donc son délai ne se règle pas par une PR ici — c'est à arbitrer.Le remède propre est probablement de retirer les releases Helm faites à la main pour que git soit la seule source. ⚠ Je ne l'ai pas fait sans avis : au moment où je l'ai envisagé, ArgoCD ne pouvait pas rendre
alloy, donc désinstaller aurait détruit une collecte qui marche sans garantie de la voir revenir.2. La sonde de disponibilité de Loki exige une réponse en 1 seconde
Mesuré : 30 échecs en 25 minutes,
context deadline exceeded, pendant que Loki tournait parfaitement — il finissait de rejouer son WAL, avec uncheckpoint done time=4m23s. Conséquence : aucun endpoint derrière le service, donc la source de données Grafana était inutilisable tant que ça durait.Une seconde est un défaut amont raisonnable sur une machine rapide. Sur un Raspberry Pi qui rejoue un WAL, c'est un piège. ⚠ Le remède n'est pas d'assouplir sans réfléchir : c'est de séparer « Loki démarre » de « Loki répond mal », par exemple avec un
startupProbegénéreux et unereadinessProbequi reste stricte ensuite.3. pi2 est saturé, et Loki y a atterri
kubectl top nodesce matin, avant Loki : pi1 77 %, pi2 106 %, pi3 64 %. Après : l'agent a mesuré +3,2 points sur pi2, ~645 Mio ajoutés au cluster.Le symptôme est arrivé tout de suite : le nouveau pod Grafana a été planifié sur pi2 et y est resté bloqué 20 minutes,
Runningmais jamais prêt — 1 seconde de CPU consommée. Il a fallu fermer pi2 à la planification pour qu'il démarre sur pi3, en 165 s.⚠ La cause profonde est nommée par l'agent : le planificateur ne voit que les
requests, et elles ne sont presque pas déclarées sur ce cluster (17 % demandés contre 108 % utilisés). Le planificateur croit donc pi2 libre. Tant que ce sera vrai, il continuera d'y poser des charges.⚠ Et
metrics-servera cessé de répondre par moments pendant ces manipulations — à surveiller, c'est peut-être le même symptôme.Ce que je n'ai pas vérifié
🤖 Generated with Claude Code
Deux des trois restes sont traités
1. L'adoption par ArgoCD — résolue d'elle-même
lokietalloysont maintenantSynced/Healthytous les deux. LeComparisonError: DeadlineExceededdu repo-server était bien transitoire : il n'arrivait pas à rendre les manifestes dans son délai pendant que le cluster était sous tension, et il y est arrivé une fois la pression retombée.⚠ Je n'ai donc PAS eu à retirer les releases Helm posées à la main, et je ne l'ai pas fait. Les secrets
sh.helm.release.v1.{loki,alloy}.*traînent encore danstools: ArgoCD gère les ressources, mais ces secrets sont des orphelins. Sans conséquence connue, à nettoyer un jour de calme.2. La sonde à 1 seconde — corrigée (PR #45, fusionnée)
Un
startupProbepatient tient désormais le rejeu du WAL (jusqu'à 10 min), et lareadinessProbereste stricte une fois le démarrage acquis, avec 5 s au lieu de 1.⚠ Ce que le rendu m'a appris : mon premier jet omettait
initialDelaySecondsen croyant le supprimer, ethelm templaterendait quand même le15amont — le chart fusionne cette table au lieu de la remplacer. Il est maintenant écrit à0, explicitement.⚠ La preuve manque encore : le rendu prouve la configuration produite, pas que le pod passera
Readydu premier coup sous charge. C'est au prochain redémarrage que ça se constatera.3. pi2 saturé — intact, et ça dépasse ces charts
La cause de fond n'est pas Loki : les
requestsne sont presque nulle part déclarées sur ce cluster (17 % demandés contre 108 % utilisés), donc le planificateur croit pi2 libre et continue d'y poser des charges. Loki, lui, déclare bien les siennes (cpu: 100m,memory: 256Mi, limite512Mi).C'est un chantier à part et un arbitrage : déclarer des
requestspour l'ensemble des charges du cluster change la façon dont tout se planifie, et sur trois Raspberry Pi ça peut rendre des pods non planifiables là où ils tournaient. Ça ne s'improvise pas la nuit.⚠ Reste aussi ouvert, et non expliqué :
metrics-servera cessé de répondre par moments pendant ces manipulations (kubectl top nodesmuet). Peut-être le même symptôme, peut-être autre chose.🤖 Generated with Claude Code
Le point 3 se précise : pi2 porte ~2 cœurs de charge hors du cluster
metrics-servers'est remis à répondre (il avait redémarré — 35 redémarrages en 174 jours, le dernier il y a 7 h, ce qui explique son silence de tout à l'heure). Ce qu'il montre est plus intéressant que « pi2 est saturé » :Et en interrogeant le nœud directement (
/stats/summary) :Deux cœurs sur pi2 ne sont ni dans un pod, ni dans le kubelet. La mémoire n'était donc que la moitié de l'histoire : ce nœud est d'abord saturé en calcul, par quelque chose que Kubernetes ne voit pas.
Ce que j'ai éliminé, en le mesurant
kadans-apisurarcodange_global_runner_pi3(et pi3 est à 12 %), celui du front surarcodange_laptop_runner. Aucun sur pi2.longhorn-system/instance-managerà 645 m ; tous ensemble ils font 1236 m.⚠ Je n'ai pas trouvé le consommateur. Il faudrait regarder les processus de l'hôte, et je n'ai pas voulu poser un pod privilégié sur un nœud déjà tendu, la nuit, sans que ce soit nécessaire. ⚠ Une piste que je n'ai pas suivie : ce cluster tourne sous Docker, pas containerd, avec sa racine déplacée sur
/mnt/arcodange/docker— tout conteneur Docker hors Kubernetes sur cet hôte compte dans le total du nœud sans apparaître nulle part côté k8s.Pourquoi ça compte pour la suite
C'est probablement l'explication des deux symptômes de cette nuit, et ils n'étaient pas des coïncidences :
Runningmais jamais prêt, avec 1 seconde de CPU consommée ;context deadline exceededalors que Loki allait bien.Deux charges affamées sur le même nœud, au même moment. Déclarer des
requestspartout — le remède que je proposais plus haut — n'y changerait rien : le planificateur ne réserve que ce qu'il connaît, et ces deux cœurs lui sont invisibles.🤖 Generated with Claude Code