Constats mineurs de la review de la pile monitoring des postes #25
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/vps-health-api#25
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Constats non bloquants relevés par
/pr-reviewsur la pile #18-#23 (monitoring des postes). Aucun n'est un défaut de comportement. Analyse du 2026-09-29 : les quatre prémisses ont été vérifiées dans le code, et deux décisions ont été tranchées par Max (points 1 et 3).1.
loadAvg: exiger exactement 3 nombres (décision : corriger)Constat vérifié :
sanitizeCpu()(index.js:348) accepte de 0 à 3 éléments et tronque au-delà.hosts.test.js:702épingle[]comme accepté, ethosts.test.js:763épingle[1,2,3,4,5]tronqué en[1,2,3]. Le consommateur (carte admin,la-compagnie-maximus#149) faitloadAvg.map(...).join(" / ").Décision : 400 si
loadAvgn'a pas exactement 3 nombres finis (messagecpu.loadAvg must hold exactly 3 finite numbers). L'agent envoieos.loadavg(), qui a toujours 3 éléments ; tous les fixtures (agent.test.js,test-curl.sh) en ont déjà 3.[]et[1..5]donnent 400, et rien n'est écrit. Ajouter les cas à 1 et à 2 éléments dans la matrice de validation (hosts.test.js:656).readHostSnapshot()repasse parsanitizeSnapshot(), donc un fichier déjà stocké avec moins de 3 éléments dégraderait enneverSeen. Aucun n'existe en pratique (l'agent envoie toujours 3). Ajouter un cas de dégradation qui le fige.POST /hosts/<id>) etagent/README.md(section Payload) précisentloadAvg= exactement 3 nombres (1, 5 et 15 min).2.
cleanStringconserve les caractères de contrôle (décision : documenter)Constat vérifié :
cleanString()(index.js:315) ne fait que tronquer à 128 caractères. C'est un choix assumé : ne pas mutiler une valeur légitime.cleanString(), plus une phrase dans le README à côté de « strings are capped at 128 chars » : les chaînes ne sont pas filtrées, et le consommateur doit les échapper au rendu. React le fait pour du texte, mais un rendu endangerouslySetInnerHTMLou en attributhrefne serait pas sûr.3. Débris
.tmpaprès un crash en cours d'écriture (décision : balayer au démarrage)Constat vérifié :
writeHostSnapshot()(index.js:394) supprime le.tmpsur exception, mais un SIGKILL ou un OOM entrewriteFileSyncetrenameSynclaisse.<id>.<pid>.<ts>.tmpdansHOSTS_DIR. Rien ne le balaie. Sans conséquence fonctionnelle, puisqueGET /hostsne lit que<id>.json.sweepStaleTempFiles(now). Elle supprime seulement les noms au format exact^\.[a-z0-9][a-z0-9-]{0,31}\.\d+\.\d+\.tmp$(même regex d'id que la route) dont le mtime date de plus d'une heure. Best effort :HOSTS_DIRabsent, fichier illisible ouunlinken échec sont journalisés, jamais bloquants.require.main === module, avantlisten..tmpvieux est supprimé ; un.tmprécent est gardé (écriture concurrente possible) ;<id>.jsonet un fichier au nom hors format sont gardés, même vieux ; unHOSTS_DIRabsent ne lève pas d'exception.CLAUDE.md(Gotchas, écriture atomique) : mentionner le balayage.4.
frozenRequestne fige pasnew Date()(décision : documenter)Constat vérifié : le commentaire de
frozenRequest(hosts.test.js:138) dit déjà que seulDate.nowest remplacé, mais il n'en tire pas la conséquence concrète.POST /hostsdatereceivedAtavecnew Date().toISOString()(index.js:633), qui ne passe pas parDate.now. Un POST sousfrozenRequestreçoit donc l'heure réelle, pasFROZEN_NOW.Date.now()et ce qui en dérive sont figés ;new Date()sans argument lit l'horloge réelle, y compris lereceivedAtd'un POST. Pour unreceivedAtcontrôlé, écrire le fichier viawriteSnapshotAged().Fichiers concernés
index.js:sanitizeCpu,cleanString(commentaire),sweepStaleTempFiles(nouvelle), bloc de démarrage, exports__tests__/hosts.test.js: testsloadAvginversés et étendus, dégradation en relecture, tests du balayage, commentaire defrozenRequestREADME.md,agent/README.md: contratloadAvg, chaînes non filtréesCLAUDE.md: nombre de tests, Gotchas (balayage.tmp,loadAvg)Critères d'acceptation
loadAvgavec 0, 1, 2 ou 4+ éléments donne 400, rien n'est écrit ; 3 éléments donnent 204loadAvghors format dégrade enneverSeenà la relecturesweepStaleTempFilessupprime seulement les.tmpau bon format et vieux de plus d'une heure, et ne lève jamais d'exceptionrequire.main), avantlistencleanStringet defrozenRequestsont documentés avec leur raisonnpm test,bash test-curl.shetsh scripts/boot-from-copy.shrestent vertsslice(0, 3); filtre d'âge ou de nom retiré)Complexité
Simple à moyenne. Pas de nouvelle variable d'environnement, pas de nouveau module runtime (le
COPYdu Dockerfile ne change pas). Un redéploiement est nécessaire (changement deindex.js) ; l'agent déjà installé envoie 3 éléments, donc il n'y a aucune rupture côté poste.Contrôle de dérive : l'issue date du 2026-08-16, mais tous les symboles cités existent dans ce repo.