green-gate

Par verygoodopensource · vgv-ai-flutter-plugin

Amène un package Dart ou Flutter à un état entièrement valide grâce à une boucle autonome vérifier-corriger-relancer sur quatre portes qualité — analyze, format, test et coverage. Se termine uniquement lorsqu'une dernière itération confirme que les quatre portes passent avec les métriques observées.

npx skills add https://github.com/verygoodopensource/vgv-ai-flutter-plugin --skill green-gate

Green Gate

Boucle autonome de qualité pour les packages Dart et Flutter. Exécute quatre portes — analyze, format, test, coverage — lit la sortie réelle des outils, édite le code et les tests pour corriger les défaillances, et boucle jusqu'à une itération finale qui prouve que les quatre passent simultanément avec les nombres observés. Agit de manière autonome sur les défaillances objectives ; remonte uniquement sur les blocages, l'ambiguïté véritable ou les défaillances d'infrastructure.

Cette skill orchestre les outils et édite les fichiers. Elle déférence le comment de l'écriture des tests à la skill testing — elle ne duplique jamais les mocks, la structure ou les conseils de couverture.


Standards Fondamentaux

Appliquez ceux-ci à TOUT travail green-gate :

  • Utilisez les outils MCP, jamais l'interface Bash, pour les portes — analyze via mcp__dart__analyze_files, format via mcp__dart__dart_format, test et coverage via mcp__very-good-cli__test. Le chemin de test Bash (very_good test, flutter test, dart test) est bloqué par le hook block-cli-workarounds.sh ; dart analyze via Bash est redondant avec l'outil MCP. Bash est réservé au parsing de coverage/lcov.info uniquement.
  • Ne mettez jamais en cache le vert — réévaluez chaque porte à chaque round. Corriger les défaillances d'analyze ou de test et écrire de nouveaux fichiers de test décale à la fois le formatage et le dénominateur de couverture, donc une porte précédemment verte peut régresser.
  • Quittez uniquement sur les nombres observés — la boucle se termine uniquement après une itération finale unique dans laquelle analyze est propre, format rapporte zéro changements, tous les tests passent, et min_coverage est satisfait, tous observés dans le même round. Déclarer le succès de mémoire est interdit ; confirmez le succès uniquement avec les nombres réels observés dans ce round final.
  • Passez coverage: true, min_coverage, et check_ignore: true ensemble — omettre coverage: true produit silencieusement aucun lcov.info (mime une mauvaise configuration) ; omettre check_ignore: true rend le remède // coverage:ignore un no-op.
  • Déférez l'écriture de tests à la skill testing — quand une correction nécessite d'authorer des tests, suivez skills/testing/SKILL.md pour la structure, les mocks et le nommage.
  • Corrigez les causes racines, pas les symptômes — ne faiblirez jamais une porte pour la faire passer (ne supprimez pas les assertions défaillantes, ne baissez pas la cible pour éviter le travail, ou // coverage:ignore le code accessible). Remontez plutôt les décisions produit/API véritables au lieu de deviner.
  • Agissez de manière autonome sur les défaillances objectives — les erreurs d'analyseur, les tests rouges et les lacunes de couverture sont corrigés sans re-prompt. Remontez uniquement selon la matrice.

La Boucle

Pour chaque racine de package (voir Recursive / Monorepo), exécutez cet algorithme :

  1. Découvrez — résolvez la racine du package (l'argument directory ou la racine du workspace) ; confirmez qu'un pubspec.yaml existe. Initialisez l'état de la boucle (compteur d'itération 0, empreintes vides, ensemble de fichiers modifiés vide).
  2. Analyze — exécutez mcp__dart__analyze_files avec applyFixes: true. Si des erreurs persistent, c'est la porte active. Corrigez, enregistrez l'empreinte, allez à l'étape 7.
  3. Format — exécutez mcp__dart__dart_format sur la racine du package. Il reformate le package entier sur place. S'il rapporte des fichiers modifiés, la porte est maintenant verte pour le round suivant.
  4. Test — uniquement si analyze est vert ce round. Exécutez mcp__very-good-cli__test avec les paramètres de couverture de Test Gate. Si les tests échouent, corrigez, enregistrez l'empreinte, allez à l'étape 7.
  5. Coverage — uniquement si les tests passent ce round. Le résultat MCP min_coverage est autoritaire pour le pass/fail. Parsez coverage/lcov.info pour le pourcentage affiché et les cibles de correction par fichier (consultatif). Si inférieur à la cible, authorizez des tests pour les fichiers sous-couverts classés (via la skill testing), allez à l'étape 7.
  6. Exit — si les quatre portes sont vertes dans cette même itération, confirmez le succès avec les nombres observés et arrêtez. C'est le seul chemin exit-vert.
  7. Re-vérifiez — incrémentez le compteur d'itération, recalculez l'empreinte de défaillance, vérifiez les déclencheurs de remontée (pas de progrès, oscillation, cap). Si un déclencheur se déclenche, remontez ; sinon, bouclez à l'étape 2 et réévaluez chaque porte.

Chemin no-op d'un seul passage — invoqué sur un package déjà vert, l'itération 1 trouve analyze propre, format rapportant zéro changements, tous les tests passant, et la couverture à ou au-dessus de la cible. La boucle confirme vert et quitte sans éditer un seul fichier. Un package vert coûte exactement une itération de vérification.


État de la Boucle

État porté sur les itérations — sans lui, « pas de progrès » est indécidable :

État Objectif
Compteur d'itération Imposez le cap (défaut 5, par package)
Empreinte de défaillance par porte (round antérieur) Détectez pas-de-progrès et oscillation
Fichiers modifiés ce round Distinguez un round no-op d'un round no-progrès ; remplissez les rapports de remontée

Clés d'empreinte par porte :

Porte Empreinte
Analyze Ensemble trié de diagnosticCode @ file:line
Format Ensemble de fichiers que dart format changerait (vide = vert)
Test Ensemble d'ID / noms de test défaillants
Coverage Pourcentage observé + ensemble trié de fichiers SF sous-couverts

Définitions :

  • Pas de progrès — l'empreinte de défaillance actuelle est identique à celle du round antérieur, ou son compte de défaillance n'a pas diminué. Remontez.
  • Oscillation — les mêmes deux portes échangent vert/rouge sur deux rounds consécutifs (p.ex. une correction de format re-casse analyze, dont la correction re-casse format). Remontez.

Précédence de Porte

Ordre fixe : analyze → format → test → coverage. Deux règles le gouvernent :

  1. Une porte en aval n'est pas évaluée jusqu'à ce que la porte en amont soit verte ce round. Un analyseur rouge peut faire échouer les tests à la compilation ; la couverture est sans sens quand les tests ne passent pas — ne parsez jamais lcov.info après un échec de compilation. Format s'exécute après analyze pour que son reformatage ne brassouille pas le code que applyFixes d'analyze est sur le point de réécrire.
  2. Chaque porte est réévaluée à chaque round ; le vert n'est jamais mis en cache. Exit nécessite les quatre vertes dans la même itération finale.

Porte Analyze

  • Exécutez mcp__dart__analyze_files avec applyFixes: true pour que les correctifs rapides soient appliqués avant que les diagnostics ne reviennent. roots prend [{ root: "file:///abs/path" }] — un URI file: de la racine du package. Il n'existe pas de flag récursif ; la skill énumère elle-même les racines du package et transmet chacune.
  • La porte est verte quand zéro erreurs persistent. Traitez les diagnostics de gravité erreur comme bloquants ; adressez les avertissements et infos aussi quand ils sont dans la portée de la correction, mais ne laissez pas une info pré-existante sans rapport bloquer la porte.
  • Interplay du hook — le hook PostToolUse analyze.sh se déclenche à chaque Edit/Write et quitte 2 (bloquant) quand une correction introduit une nouvelle erreur d'analyze. Traitez ce rejet comme retour de porte analyze-gate dans le même round, pas un mode de défaillance séparé : l'édition n'a pas atterri, donc révisez-la.

Porte Format

  • Exécutez mcp__dart__dart_format sur la racine du package à chaque round. Il exécute dart format . sur le package entier sur place, donc la porte est basée sur l'observation (elle capture les édits manuels et la dérive pré-existante, pas seulement les fichiers que la boucle a édités) et auto-réparante (un appel laisse le package vert ; un second appel rapporte zéro changements).
  • Pourquoi format est une vraie porte, pas juste le hook — le hook PostToolUse format.sh ne se déclenche que sur les fichiers que la boucle édite via Edit/Write. Un fichier édité manuellement ou pré-existant non-formaté que la boucle ne touche jamais passerait autrement green-gate et échouerait alors CI. Le format de package entier ferme cet écart.

Porte Test

  • Exécutez mcp__very-good-cli__test avec coverage: true, min_coverage: <target>, check_ignore: true, et le glob exclude_coverage (ci-dessous).
  • Dart vs Flutter — omettez dart pour laisser l'outil auto-détecter (Flutter s'exécute quand un projet Flutter est détecté). Passez dart: true uniquement pour un package Dart pur que l'outil classerait mal autrement.
  • directory — passez-le quand le package n'est pas à la racine du workspace (packages sous-monorepo) ; omettez-le uniquement quand pubspec.yaml est à la racine.
  • timeout_seconds — définissez toujours un cap (p.ex. 120). Les tests Flutter pendent indéfiniment quand pumpAndSettle() s'exécute sans timeout ; le cap tue la run au lieu de bloquer la boucle. Un kill timeout est une défaillance d'outil, pas une défaillance de test — remontez-la selon la matrice.
  • La porte est verte quand chaque test passe. Un test défaillant est corrigé de manière autonome sauf s'il encode une décision produit véritable (remontez selon la matrice).

Porte Coverage

Le résultat MCP min_coverage est autoritaire pour le pass/fail. Le parse de coverage/lcov.info est consultatif — il fournit le pourcentage affiché et les cibles de correction par fichier.

  • La cible défaut est 100 (standard maison de VGV), remplaçable par invocation (p.ex. 80) pour les packages hérités ou non-template. Les fichiers générés sortent le dénominateur via exclude_coverage et check_ignore: true honore // coverage:ignore, donc 100% signifie 100% du code testable, écrit à la main.
  • exclude_coverage par défaut**/*.{g,freezed,gen}.dart plus les répertoires générés et l10n. Une seule chaîne de glob (expansion accolade ; revenez à **/*.g.dart si une CLI build ne l'honore pas).
  • Passez coverage: true, min_coverage, et check_ignore: true ensemble — voir Standards Fondamentaux.
  • Quand coverage/lcov.info manque ou est en dessous de la cible, suivez l'arbre de décision et les règles de parsing dans references/coverage.md — il couvre les trois causes d'absence, la gestion de lcov stale, les champs d'enregistrement lcov (SF/LF/LH/DA), la règle advisory-mirrors-the-gate, et la limitation Dart-only de check_ignore.

Correction

  • Corrigez uniquement les éléments défaillants — adressez les diagnostics, tests ou fichiers sous-couverts remontés ce round. Ne refactorisez pas le code sans rapport (YAGNI).
  • Corrections de couverture = authorizez des tests — pour chaque fichier SF classé sous-couvert, écrivez des tests suivant skills/testing/SKILL.md. Priorisez les fichiers par compte de lignes non-couverts (LF - LH).
  • Bornez les fichiers par round — corrigez un batch cohérent, puis re-vérifiez. Exécuter les portes après chaque batch est ce qui rend « pas de progrès » détectable et prévient la correction d'une porte tout en cassant silencieusement une autre.
  • Ne faiblirez jamais une porte — pas d'assertions supprimées, pas de cible baissée pour éviter le travail, pas de // coverage:ignore sur le code accessible.

Escalade

Arrêtez et remontez à l'utilisateur quand :

Déclencheur Détail
Pas de progrès entre rounds Empreinte de défaillance identique ou non-décroissante
Oscillation Les mêmes deux portes échangent vert/rouge sur deux rounds
Cap atteint, portes toujours rouges Terminal — rapportez les défaillances restantes par porte avec leurs empreintes
Test rouge vrai-bug Une défaillance qui ressemble à une décision produit véritable plutôt qu'une erreur de codage
Correction ambiguë Résolutions multiples valides (p.ex. changer l'API vs supprimer le lint) — préférez la cause racine ; remontez quand c'est une décision produit/API
Lacune de couverture code non-accessible Suggérez // coverage:ignore (nécessite check_ignore: true, Dart-only) plutôt que de chasser 100%
Hygiène du dénominateur Un fichier généré non-matché par le glob d'exclusion — élargissez exclude_coverage, pas // coverage:ignore
Défaillance d'outil / hook Timeout de test MCP (timeout_seconds kill), crash d'analyseur, déni de hook manquant CLI (remontez avec le conseil d'installation dart pub global activate very_good_cli), ou un rejet analyze.sh répété qui bloque toujours une édition nécessaire après révision — un seul rejet est du retour de porte analyze-gate dans-boucle (voir Porte Analyze), pas une escalade

Quand remontant, rapportez la porte active, son empreinte actuelle, les fichiers modifiés, le compte d'itération, et la décision spécifique que l'utilisateur doit prendre.


Recursive / Monorepo

  • Tous les packages doivent passer — continuez en cas d'échec (corrigez chaque package défaillant), puis confirmez le résultat de chaque package. La porte rouge d'un package n'avorte pas les autres.
  • Budget d'itération par package — le cap de 5 est par package, pas global, donc un monorepo de 12 packages n'épuise pas un budget global sur le package un.
  • Découverte de racine de package partagée — marchez pour les fichiers pubspec.yaml. L'ensemble roots de analyze_files doit correspondre à l'ensemble de packages que mcp__very-good-cli__test --recursive (recursive: true) couvre.
  • Le chemin lcov est <package>/coverage/lcov.info — résolu par racine découverte.
  • Un seul min_coverage s'applique à tous les packages — limitation documentée : le schéma d'outil n'a aucune override de couverture par package. Déclarez la cible partagée quand confirmant la couverture.

Ressources Supplémentaires

  • references/coverage.md — détail de porte coverage de green-gate (cible défaut, globs d'exclusion, champs lcov, arbre de décision, check_ignore, lcov stale).
  • skills/testing/SKILL.md — comment écrire des tests unitaires Dart, de widget Flutter, et golden (structure, mocking mocktail, nommage).
  • skills/testing/references/coverage.md — motifs de test pilotés par couverture (copyWith, branches, chemins d'erreur) pour fermer les lacunes par fichier.
  • hooks/scripts/block-cli-workarounds.sh — pourquoi le chemin de test Bash est bloqué et les portes utilisent les outils MCP.

Skills similaires