Recherche/Modifier une grande base de code de runtime multi-langage sans casser le comportement existant

Modifier une grande base de code de runtime multi-langage sans casser le comportement existant

Pour un grand runtime natif et de scripts aux dépendances embarquées et patchées. L'IA lit d'abord le guide le plus proche, utilise les raccourcis de build et de test, suit ses types et ses interdits, et place les changements derrière des indicateurs de compatibilité.

Pour utiliser ces règles d'IA
## Lire le guide le plus proche du code et vérifier s'il existe un projet parent Dans ce type de dépôt, la documentation est structurée en couches. Un guide racine donne une orientation générale ; des guides à l'intérieur des sous-répertoires apportent un contexte propre à chaque composant, comme les classes clés, des tableaux indiquant où chercher, les conventions locales et les anti-patterns. Lisez toujours le guide le plus proche du code que vous vous apprêtez à modifier, en plus du guide racine. - Déterminez toujours si le dépôt a été récupéré de façon autonome ou s'il est imbriqué comme composant d'un projet parent plus large. S'il est imbriqué, une documentation importante se trouve à la racine du parent et n'est pas visible depuis ici ; lisez le readme du parent, son guide et les autres documents de haut niveau avant de supposer quoi que ce soit. - Explorez et lisez librement, mais rassemblez ce contexte avant de proposer ou d'effectuer des modifications. - Lorsque vous découvrez une information générale durable qui manque dans les guides, proposez de l'y ajouter plutôt que de la garder uniquement dans la conversation. ## Compiler et tester avec les raccourcis du projet, sans commandes improvisées Le projet possède un système de build faisant autorité, complété par une fine couche de raccourcis de lancement de tâches. Utilisez ces raccourcis pour le travail quotidien et ne redescendez vers l'outil de build sous-jacent que lorsqu'un raccourci n'expose pas l'option dont vous avez besoin. N'inventez pas de commandes de compilation improvisées. Raccourcis habituels à rechercher et à réutiliser : compiler, exécuter tous les tests, formater, vérifier le style des sources de script, vérifier le style des sources natives, vérifier le style des paquets en langage système, diffuser la sortie des tests en continu pour le débogage, exécuter une seule suite de compatibilité ou de conformité, générer le squelette d'un nouveau test, générer les définitions de types, générer la base d'index pour l'éditeur, compiler et tester avec le sanitizer d'adresses, produire un rapport de couverture, et surveiller des répertoires source pour relancer une commande à chaque modification. ## Trouver la bonne cible de test et ses variantes générées automatiquement Plusieurs familles de tests coexistent, chacune avec son propre point d'entrée : - Tests d'intégration pilotés par configuration : un fichier de configuration sérialisé qui déclare un service avec des modules de script intégrés, une date de compatibilité, des indicateurs de fonctionnalités, et des liaisons telles que des liaisons de service, des données structurées, des magasins clé-valeur et des espaces de noms d'objets à état. - Tests unitaires natifs construits par une macro dédiée, avec un suffixe de test à trait d'union dans le nom de fichier. - Suites de compatibilité runtime et suites de conformité aux standards du web, chacune exécutée par son nom. - Benchmarks, exécutés par chemin. Les commandes de build et de test acceptent toutes deux des cibles explicites et portent par défaut sur l'arborescence entière. Les noms de cibles portent un marqueur de suffixe obligatoire, et les macros de build génèrent automatiquement plusieurs variantes par test : une variante par défaut fixée sur la référence de compatibilité la plus ancienne, une variante à la date la plus récente avec tous les indicateurs activés, et une variante avec toutes les portes temporaires activées. Pour trouver la cible correcte pour un fichier, lisez le fichier de build du même répertoire ou interrogez le système de build pour obtenir toutes les cibles de ce paquet. ## Repérer les grandes zones du code et suivre une implémentation similaire Construisez-vous une carte mentale avant de modifier quoi que ce soit, et pour tout nouveau travail, trouvez une implémentation existante similaire et suivez son modèle. - API runtime : implémentations natives des interfaces exposées aux scripts, plus la couche de compatibilité avec la bibliothèque standard et leurs tests. - Sous-système d'entrées-sorties : stockage et mise en cache des objets à état, suivi des requêtes, limites de ressources, gestion des threads et cycle de vie des workers. Un objet de contexte propre à chaque requête relie l'ensemble. - Couche de liaison : liaisons avec le moteur, enveloppes de types, gestion des promesses, gestion de la mémoire et système de modules. - Couche serveur : le point d'entrée binaire et la gestion de la configuration, avec un modèle de sécurité fondé sur les capacités décrit par un fichier de schéma. - Arborescences propres à chaque langage pour la couche de compatibilité, un runtime de script alternatif et les composants d'intégration avec le langage système. Les couches de compatibilité sont doubles : la moitié native vit dans une arborescence et la moitié script dans une autre, et les nouveaux modules doivent être enregistrés dans la table de modules désignée. Les définitions de types sont dérivées des informations de type natives complétées par des déclarations écrites à la main, et sont régénérées, jamais modifiées à la main. ## Suivre le guide de style et faire de petits commits qui passent les tests Suivez le guide de style maison de référence, y compris ses exceptions documentées ; lorsque le projet s'écarte délibérément de ce guide, cet écart fait office de règle. - Respectez exactement la norme de langage fixée, les extensions de fichiers source inhabituelles du projet, et le suffixe à trait d'union des fichiers de test. - Une seule commande de formatage exécute tous les formateurs sur tous les langages. Exécutez-la, ainsi que la commande de test complète, avant de soumettre une modification. - Une vérification pré-commit bloque les macros d'affichage de débogage dans le code indexé et relance la vérification de formatage. Ne la contournez pas. - Découpez les modifications en petits commits ; chaque commit doit compiler et passer les tests par lui-même. Ne laissez pas de commits de correction traînants. - Les sources côté script sont strictement typées : la sémantique exacte des propriétés optionnelles, la syntaxe des champs privés et les types de retour explicites sont imposés. ## Utiliser les types de la bibliothèque de base du projet plutôt que ceux du standard La base de code utilise délibérément sa propre bibliothèque de base plutôt que la bibliothèque standard du langage pour la plupart des types. Alignez-vous sur le fichier environnant plutôt que de recourir aux conteneurs standards. Substitutions à appliquer : chaîne possédée et vue de chaîne non possédante à la place de la chaîne standard ; tableau de taille fixe et vecteur redimensionnable à la place du vecteur standard ; poignées de propriété unique, à comptage de références, à comptage de références thread-safe, et faible à la place des pointeurs intelligents standards ; un type maybe à la place d'optional ; une enveloppe appelable à la place de l'objet fonction standard ; une union taguée à la place de variant ; une tranche de tableau à la place des spans bruts ; le type d'exception propre à la bibliothèque ; et la promesse ainsi que la promesse dérivée propres à la bibliothèque à la place des futures standards. Pour la sécurité, préférez une tranche de tableau à un pointeur brut, et une poignée liée à une durée de vie à une référence nue lorsque la référence est liée à la durée de vie de son propriétaire. Pour les erreurs, utilisez la macro dédiée pour déballer un maybe, les macros d'exigence côté script lorsque l'échec doit se manifester comme une exception de script avec un type d'exception approprié, et les macros d'assertion et de précondition natives pour les invariants internes. ## Éviter les motifs interdits qui causent fuites et corruptions cachées Ces règles sont absolues ; les enfreindre provoque une corruption subtile, des fuites, ou des ruptures de compatibilité. - Ne placez jamais de poignées locales ou globales au moteur dans des déclarations de struct de type valeur ; utilisez les enveloppes de référence fournies. - Ne placez jamais de poignées du moteur à l'intérieur de types promise, et ne passez jamais le verrou du moteur dans des coroutines asynchrones. - Ne conservez jamais de références du tas de script vers des objets d'entrée-sortie sans l'enveloppe possédante ; un garde de portée impose cette règle. - Préférez les propriétés de prototype aux propriétés d'instance, lesquelles annulent l'optimisation du ramasse-miettes. - Ne gelez jamais en profondeur un contenu fourni par l'utilisateur, ce qui n'est pas sûr pour les valeurs cycliques. - N'ajoutez jamais de méthodes à une interface qui distribue des noms inconnus à distance sans les verrouiller derrière un indicateur de compatibilité, et ne changez jamais les valeurs d'énumération sérialisées. - Préférez l'appel d'enregistrement de tâche additif à l'accesseur brut de liste de tâches, et évitez les paramètres booléens au profit de types booléens forts. - Toute référence stockée dans un objet natif accessible depuis le tas de script doit implémenter la visite de ramasse-miettes ; les cycles de références natives ne sont jamais collectés. Une vérification de lint dédiée valide ce point. - Les erreurs de mauvaise utilisation de la base de données embarquée lèvent toujours une exception et ne sont jamais supprimées ; les transactions sont interdites dans la base de données d'objets à état. - L'évaluation de module ne doit jamais s'exécuter à l'intérieur d'un contexte de requête, et les entrées-sorties asynchrones en portée globale sont interdites. - Dans les fichiers de déclaration de types partagés, n'utilisez jamais de noms de types ambiants génériques ; préfixez-les toujours avec le nom du produit ou de la fonctionnalité. N'utilisez jamais un objet nu non typé comme type ; déclarez une interface appropriée avec des champs connus, en étendant éventuellement un enregistrement ouvert pour la compatibilité future. - Ne modifiez jamais à la main les instantanés générés. Corrigez la couche source et régénérez. ## Placer les changements de comportement derrière des indicateurs de compatibilité ou des portes temporaires Le projet prend un engagement fort de compatibilité ascendante : une fois qu'un comportement est déployé, il ne peut plus être retiré ni modifié silencieusement. Les changements de comportement doivent donc être introduits derrière une porte, et le choix de la porte dépend de sa permanence. - Les indicateurs de compatibilité pilotés par date sont propres à chaque instance, permanents, et définis dans un schéma dont les annotations portent le nom de l'indicateur et sa date d'activation. Chaque indicateur doit être documenté avant l'arrivée de sa date d'activation. - Les portes temporaires au niveau du processus sont pilotées par configuration et destinées aux déploiements risqués avec activation conditionnelle. Elles sont définies sous forme d'une énumération accompagnée d'une table de correspondance de chaînes, et les deux doivent rester synchronisées. Maintenez une exigence élevée pour les interfaces non standards ; préférez implémenter des standards publiés plutôt qu'inventer un comportement propre au projet. ## Mettre à niveau les dépendances embarquées en gardant les correctifs locaux Les dépendances tierces sont embarquées dans un répertoire externe par le mécanisme de modules du système de build. L'intégration se trouve dans le manifeste de modules et dans un répertoire de build des dépendances ; un fichier d'espace de travail hérité peut encore exister mais n'est plus le mécanisme principal. Consultez directement les sources de la bibliothèque de base embarquée pour toute question sur ses en-têtes et ses espaces de noms plutôt que de deviner. Plusieurs dépendances portent des jeux de patches maintenus localement et appliqués pendant le build. Ces patches introduisent des personnalisations propres au projet et de nouvelles interfaces ; passez-les donc en revue et mettez-les à jour à chaque mise à niveau de la dépendance concernée. Notez également que le projet utilise un allocateur de mémoire alternatif, dont le comportement diffère de celui par défaut ; toute analyse mémoire doit en tenir compte. Pour une mise à niveau majeure du moteur ou d'une dépendance : demandez d'abord la version cible exacte et quels patches ou personnalisations doivent être préservés avant de commencer, puis suivez les étapes documentées de synchronisation, application des patches, rebase, régénération des patches et incrémentation de version. Les conflits de fusion sont fréquents et nécessitent presque toujours un jugement humain pour préserver intacts les changements propres au projet ; ne les résolvez jamais automatiquement sans relecture humaine. Confirmez que la suite de tests complète passe et signalez toute nouvelle dépréciation rencontrée. ## Trouver la documentation dispersée et proposer des corrections si elle est fausse La documentation est répartie, non centralisée. Un répertoire de documents couvre des sujets transversaux tels que la mise en place de l'environnement, les recommandations pour ajouter de nouvelles interfaces, et les procédures de mise à niveau des dépendances, tandis que les répertoires source individuels portent souvent leur propre readme ou guide avec le détail approfondi du sous-système. Cherchez-les de façon proactive lorsque vous travaillez dans une zone qui vous est peu familière, avant de deviner ou de poser la question. Lorsque la documentation est absente, inexacte ou obsolète, proposez une mise à jour plutôt que de rester silencieux. Vérifiez d'abord les faits, et ne validez jamais de modifications de documentation sans en confirmer l'exactitude auprès d'un mainteneur.