DOCS/kanban/done/210-lot-f-cote-manager-service-les-quatre-chantie.md
2026-09-03 14:00:51 +02:00

5.8 KiB

title: Lot F côté manager-service : les quatre chantiers de dette backend, en une passe

dotnet test 163 → 200, aucun test sauté, quatre commits, manager-service seul. 1) Le journal d'audit voyait tout sauf le contenu : AuditedTypes.Contains(entry.Entity.GetType()) exigeait l'égalité exacte, or Section est abstraite — aucune des 13 sortes de section n'était journalisée, soit précisément ce que l'écran du 12/08 devait tracer. Resource, Configuration, Device, User et Instance passaient, eux : ils sont concrets, et c'est ce qui rendait le trou invisible. Tranché : normalisation côté serveurEntityType porte Section, donc le filtre déjà présent dans l'écran se met à rendre des lignes sans toucher manager-app ; élargir le filtre front aurait coûté 13 entrées et 39 clés i18n et laissé tout futur sous-type sortir du filtre en silence — la classe de panne exacte qu'on ferme. Le sous-type n'est pas perdu : le discriminateur TPH est sérialisé dans NewValues, un test le vérifie. 8 tests, dont un par réflexion sur les 13 sous-types — la liste d'origine n'obligeait personne à la suivre, c'est ce qui l'a laissée devenir fausse. 2) Plafond de 5 utilisateurs : CreateUser rend 422. 5 en dur (le faire varier par plan serait une colonne, donc une migration après le gel du lot B — dette V1 assumée) et SuperAdmin exempté, seule porte de service tant qu'aucun champ ne permet de relever la limite d'un client. Rien à retoucher côté front. 3) GetSummary agrège en SQL au lieu de charger 13 mois en mémoire ; les six agrégats qui se lisent dans le JSON de Metadata ne remontent plus que deux colonnes, pour leur seul type d'événement, et les stats avancées ne sont plus calculées puis effacées pour les plans qui n'y ont pas droit. ⚠️ La branche « stats avancées » n'était couverte par aucun test : les cas existants ne seedent pas d'Instance, donc hasAdvancedStats était toujours faux et la moitié de la méthode n'était jamais exécutée. 4) Le vector store est éprouvé à DEUX instances, sur un vrai Postgres — 14 tests Testcontainers sur l'image de Dockerfile.postgres, qui se sautent proprement sans démon Docker (186 passés / 14 sautés / 0 échec). pgvector 0.8.6 : le SET hnsw.iterative_scan que pose SearchAsync est accepté — sur une version antérieure, toute recherche échouait en production. À 30 contre 1, la recherche rend le bon nombre de résultats, tous de la bonne instance, aucune fuite. ⚠️ Deux résultats contraires à ce que le plan supposait : ce qui protège du post-filtrage n'est pas le parcours itératif mais l'index sur (InstanceId, ContentType) — le planificateur filtre d'abord et trie exactement, l'index HNSW n'est jamais touché (vérifié à 620 lignes et à 22 000) ; et cet index retiré, relaxed_order ne rattrape rien, le parcours s'épuisant après ~335 lignes sans atteindre l'instance minoritaire. Le même jeu de données avec l'index HNSW construit après l'insertion rend bien ses 20 lignes : c'est la connectivité du graphe qui décide, et nos migrations créent l'index sur une table vide. Outillage : Testcontainers épinglé en 3.10.0 (la 4.x parle l'API Docker 1.44, l'engine local plafonne à 1.43) et image construite par le CLI docker — le constructeur de Testcontainers ne sait pas parser le tag@sha256: du Dockerfile, digest qui protège la base d'un changement de glibc sous ses index et ne se retire pas pour un test. ⚠️ Et une régression du point 1, trouvée et corrigée le même jour. WeatherSyncService écrit section.WeatherResult sur cron, à 6 h et 13 h. Le job était bénin tant que les sections n'étaient pas auditées ; depuis, chaque rafraîchissement produisait une ligne portant la prévision OpenWeather complète en avant ET en après — quelques dizaines de Ko, deux fois par jour, par section météo. Le stockage est le moindre problème : ce bruit noie les modifications humaines que l'écran existe pour montrer. Correctif : colonnes machine (WeatherResult, WeatherUpdatedDate, DateUpdate) exclues du journal, et aucune ligne produite quand une modification ne touche qu'elles — plutôt qu'une ligne au diff vide, qui aurait déplacé le bruit sans le retirer. DateUpdate y est pour une raison distincte : estampillé à chaque SaveChanges, il figurait dans tous les diffs sans rien y apprendre — et le signal était déjà là, un test écrit le matin même devait l'écarter à la main pour rester lisible. AgendaSyncService vérifié au passage : il écrit des EventAgenda, non audités. ⚠️ Trouvé en cherchant à justifier un index sur Timestamp signalé par réflexe — la question « pourquoi un index ? » a montré que ce qui faisait grossir la table n'était pas ce que je croyais. L'index est retiré du backlog : pas de migration, gel du lot B intact. dotnet test 203/203.