Recherche/Créer une appli qui rassemble des événements d'activité de nombreuses sources et les affiche sur plusieurs surfaces

Créer une appli qui rassemble des événements d'activité de nombreuses sources et les affiche sur plusieurs surfaces

Pour une appli qui rassemble les événements de nombreux outils et les affiche dans une extension d'éditeur et un serveur autonome. Garde les couches dans un seul sens, ramène chaque source à un type d'événement, ajoute des sources sans rien toucher d'autre et enregistre l'état sans risque.

Pour utiliser ces règles d'IA
## Faire aller les dépendances dans un seul sens pour que les surfaces ne s'importent jamais entre elles Faites en sorte que les dépendances circulent toujours dans le même sens, à travers des couches nommées. Une couche `core` ne contient que les définitions de protocole et d'interfaces, sans aucun effet de bord à l'exécution. Une couche runtime ne dépend que de `core`. Chaque surface hôte — par exemple un adaptateur d'extension d'éditeur et un serveur autonome en ligne de commande — dépend de `core` et du runtime, mais les surfaces ne s'importent jamais entre elles. Déclarez explicitement le sens autorisé et faites-le respecter, car un seul import qui traverse cette frontière couple silencieusement deux surfaces censées rester interchangeables indépendamment l'une de l'autre. ### Pourquoi ça tient Une couche de contrat sans dépendances permet à chaque surface et à chaque intégration de compiler contre les mêmes types sans importer de code spécifique à un hôte. Les nouvelles surfaces composent les éléments partagés ; elles ne vont jamais fouiller dans les entrailles d'une autre surface. Le jour où vous ne pouvez plus ajouter une surface sans modifier une surface existante, la séparation en couches est déjà rompue. ## Générer les liaisons typées depuis un seul fichier de protocole et les vérifier en CI Faites d'un contrat unique, lisible par une machine, la seule source de vérité pour le protocole de communication, puis générez à partir de lui les liaisons typées au lieu de les écrire à la main. Traitez le fichier généré comme un fichier en lecture seule : ajoutez-lui un bandeau signalant qu'il est auto-généré et ne le modifiez jamais manuellement. Ajoutez une étape d'intégration continue qui régénère les liaisons et fait échouer la build au moindre écart non vide, afin que le contrat et le code ne puissent jamais diverger. ### Figer la version du générateur Figez la version du contrat sur ce que votre générateur de code prend réellement en charge. Une version de schéma plus récente que le générateur ne sait pas gérer peut dégrader silencieusement les types générés en un type fourre-tout permissif, effaçant toute sécurité de typage sans erreur visible. Notez pourquoi la version est figée et ne la révisez que lorsque l'outillage aura rattrapé son retard. ## Ramener chaque source au même type d'événement dans un hub unique Faites transiter toute l'activité par un hub unique. Quelle que soit la source — événements poussés en HTTP ou lignes extraites de fichiers de logs et de transcriptions — normalisez chacune en un type d'événement canonique unique avant son entrée dans le runtime. En aval, le code se branche sur le type de l'événement, jamais sur des noms d'action ou d'outil propres à une source, si bien que l'ajout d'une source ne peut pas se répercuter sur le runtime ni sur l'interface. ### Garder un ensemble d'événements restreint et fermé Définissez un petit ensemble fermé de types d'événements : début et fin de session, début et fin de travail, cycle de vie des sous-tâches, progression et demande de permission. Chaque chemin d'ingestion n'a qu'une seule responsabilité : produire ces événements canoniques. Tout ce qui se trouve après le hub est indépendant de la source et reste stable à mesure que de nouvelles sources arrivent. ## Cacher la connexion derrière une seule interface de transport Placez la communication réseau derrière une interface de transport unique, à la surface minuscule : envoyer un message, s'abonner aux messages entrants, exposer une promesse de disponibilité et un état de connexion, et se libérer. Implémentez-la une fois par environnement — par exemple un canal de messages en mémoire pour une surface intégrée et un socket avec reconnexion pour une surface autonome — et faites le branchement entre implémentations dans une seule et unique fonction fabrique. Tout ce qui se trouve en aval dépend de l'interface et ne sait jamais quel transport est réellement utilisé. ### La résilience se niche dans l'implémentation Dotez l'implémentation réseau d'un recul exponentiel et d'une file d'envoi qui se vide à la reconnexion. L'implémentation en mémoire peut se déclarer connectée pendant toute sa durée de vie. Les appelants observent le même comportement dans les deux cas, si bien qu'aucun code métier ne contient de branchement spécifique à un transport. ## Ajouter chaque intégration comme fournisseur sans toucher au reste du code Modélisez chaque intégration externe comme un fournisseur implémentant une seule interface : normaliser un événement brut en événement canonique, installer, désinstaller et interroger ses hooks, formater son statut, et déclarer lesquels de ses noms d'action sont exemptés de règles spécifiques. Proposez les fonctionnalités optionnelles — un repli par sondage, un mode étendu multi-acteurs — sous forme de méthodes optionnelles, pour que les intégrations simples restent légères. ### Le test d'une frontière propre Une nouvelle intégration devrait tenir dans un seul nouveau sous-répertoire implémentant l'interface, sans aucune modification du runtime, de l'interface ou d'un fournisseur existant. Si l'ajout d'une source force des modifications ailleurs, c'est que la frontière fuit et qu'il faut la resserrer avant que d'autres intégrations ne s'empilent sur la fissure. ## Partager un même socle runtime et un même store entre les deux surfaces Faites en sorte que les deux surfaces hôtes composent le même socle runtime ; seuls l'espace de nommage de persistance, le transport et un éventuel adaptateur propre à l'hôte diffèrent. Faites transiter chaque changement d'état par un store unique, propriétaire des données, qui émet des événements de mutation typés et fait office de source de vérité unique. Abonnez une couche de diffusion à ces événements et traduisez-les là, et uniquement là, en messages de protocole sortants — aucun autre module n'appelle directement une méthode de transport. ### Garder étroite la jonction avec l'hôte Exposez une seule et unique interface de rappel entre le runtime et son hôte, pour les quelques éléments réellement propres à l'hôte : lancer un travail, ouvrir des dossiers, importer et exporter. C'est précisément le fait de garder cette jonction étroite qui permet à deux surfaces de partager le socle sans le modifier ; ne l'élargissez que lorsqu'une réelle différence d'hôte l'exige. ## Utiliser d'abord les signaux push et garder le sondage des fichiers en secours Quand un signal rapide et fiable existe, privilégiez-le, et gardez un repli plus lent pour le cas où il serait absent. Un canal push de rappels d'événements en HTTP fournit des signaux instantanés et ordonnés ; le sondage de fichiers sert de repli quand le push n'est pas installé. Verrouillez les deux mécanismes pour qu'ils ne comptent jamais en double : un indicateur de livraison par élément, associé à un interrupteur global, décide si les minuteurs du repli doivent tourner. ### Séparer la lecture du contenu de la dérivation de l'état Certaines données ne viennent parfois que du chemin de repli — progression fine, texte de statut — donc gardez le sondage actif pour cela même en mode push, mais supprimez les minuteurs dérivés du repli (invites de permission, détection d'inactivité) dès que le push est confirmé pour cet élément. C'est cette séparation entre « lire le contenu » et « dériver l'état » qui permet aux deux modes de coexister sans conflit. ## Enregistrer l'état séparément par surface et vérifier la copie avant d'enlever l'ancienne Cloisonnez l'état persisté par surface, pour que deux surfaces s'exécutant en parallèle ne s'écrasent jamais l'une l'autre. Écrivez les fichiers de façon atomique — écrivez un fichier temporaire, puis renommez-le — et marquez vos propres écritures pour qu'un observateur inter-processus ne les relise pas comme des changements externes. Associez toujours la surveillance de fichiers à un sondage de secours, car les observateurs de fichiers natifs ne sont pas fiables sur certaines plateformes. ### Vérifier avant de nettoyer Lors de la migration d'un état hérité, vérifiez avant de nettoyer : écrivez au nouvel emplacement, relisez-le, et supprimez seulement ensuite l'ancienne clé. Tant qu'il reste quelque chose de non migré, affichez un avertissement non bloquant plutôt que de présumer la réussite. Ne supprimez jamais la source de vérité avant que la copie ne soit confirmée sur le disque. ## Regrouper les constantes au même endroit et l'imposer par des règles de lint Centralisez chaque nombre et chaîne magiques — constantes de temporisation, identifiants, littéraux de protocole, jetons de style — dans un petit nombre de modules de constantes, un par couche, et ne les codez jamais en dur ailleurs. Les valeurs codées en dur dérivent, se dupliquent et masquent des couplages sur lesquels les refontes ultérieures viennent buter. ### Faire respecter par le lint, pas par la vigilance Appuyez cette politique sur des règles de lint personnalisées configurées en niveau erreur, pour que toute violation bloque les fusions : interdisez les littéraux de couleur et de style en dur hors du fichier de jetons, exigez l'usage des jetons partagés d'ombre et d'espacement, exigez la référence de police partagée. Une règle imposée par une machine survit au renouvellement des contributeurs ; une convention écrite seulement dans un document, non. ## Tester par couches et utiliser des tests de bout en bout pour le code qui change souvent Adoptez une stratégie de test par couches, avec l'outil adapté à chaque couche. Des tests unitaires et d'intégration rapides couvrent la logique pure : mutations d'état, routage des événements, analyse syntaxique, migration, atomicité de l'installateur. Des tests de bout en bout pilotent les surfaces réelles et vérifient des résultats visibles par l'utilisateur plutôt que des détails internes. ### Préférer des jonctions stables pour une contribution ouverte Pour le code que les contributeurs modifient constamment, comme les détails internes de l'interface, préférez des tests de bout en bout qui figent le comportement perçu par l'utilisateur plutôt que des tests unitaires liés aux détails internes, afin que les refontes n'obligent pas les contributeurs à réécrire des tests internes en plus du travail sur la fonctionnalité. Gardez chaque test isolé — avec son propre répertoire temporaire, son propre espace de travail et son propre répertoire de données — pour qu'aucun état ne fuie entre les tests, et vérifiez toute dérive d'un inventaire de tests auto-généré en intégration continue, exactement comme vous vérifiez la dérive du code généré. ## Ignorer les entrées mal formées au lieu de planter et étiqueter chaque ligne de log Dégradez-vous avec élégance : capturez et journalisez les erreurs, mais ne les laissez jamais planter l'hôte. Ignorez silencieusement une ligne d'entrée mal formée plutôt que d'interrompre tout le flux. Quand une ressource est manquante, journalisez un avertissement et continuez avec une valeur nulle ou de repli plutôt que de faire échouer l'opération entière. ### Rendre les logs faciles à rechercher Préfixez chaque ligne de log par une étiquette de contexte entre crochets qui nomme le sous-système, pour qu'un flux de console plat reste facile à parcourir par recherche. Décidez délibérément si vous avez besoin d'un reporting d'erreurs centralisé ou de télémétrie ; si vous choisissez de vous en passer, consignez cette décision et gardez la journalisation locale cohérente, pour que les futurs lecteurs n'aient pas à deviner. ## Lire sans risque les fichiers qui grossissent et laisser assez de temps aux tests asynchrones Ces règles sont faciles à énoncer et coûteuses à réapprendre. ### Lire des fichiers en ajout seul Associez tout observateur de fichiers natif à un sondage périodique à intervalle court, et conservez dans un tampon, d'une lecture à l'autre, les lignes partielles non terminées, car un lecteur peut surprendre un fichier en cours d'écriture. Une session effacée ou réinitialisée démarre souvent un tout nouveau fichier pendant que l'ancien s'arrête simplement, donc détectez ce changement par le contenu plutôt que de présumer que le même descripteur continue de grossir. ### Budgets de temps dans les tests Quand vous vérifiez un résultat en fin de pipeline asynchrone, budgétez la latence de chaque étape — l'écart entre le signal déclencheur et le signal dérivé, le délai du minuteur, et la marge inter-processus plus le rendu. Un délai d'expiration plus court que ce budget cumulé est instable par construction. ### Rendu et regroupement (batching) Gardez l'état d'animation à haute fréquence dans un store impératif plutôt que dans l'état du framework, et retardez légèrement les transitions « travail terminé » pour que le regroupement (batching) de l'interface ne masque pas à l'utilisateur de brefs états actifs.