Files
Ransom-s-wake/docs/ENGINEERING_GUARDRAILS.md

11 KiB

Barrières techniques avant la verticale

Objectif

Cette politique protège la verticale contre trois dérives principales :

  1. transformer silencieusement les POC en code de production ;
  2. dupliquer une règle dans plusieurs scènes ou interfaces ;
  3. découvrir tardivement des erreurs de dépendance, de chargement ou de régression.

Les contraintes ci-dessous sont volontairement plus strictes que nécessaire pour un petit prototype. Une verticale engage plusieurs mois de travail ; une frontière légèrement contraignante maintenant coûte moins cher qu'une réécriture au milieu de la production.

1. Séparation physique entre prototypes et production

src/                    POC A et B jetables
scenes/                 scènes des POC
game/                   futur code de production
  domain/               règles pures et données typées
  application/          cas d'usage et contrats
  world/                acteurs, physique et monde Godot
  presentation/         HUD, écrans et rendu
  infrastructure/       sauvegarde, audio, plateforme et entrées
  composition/          assemblage des scènes et dépendances
content/                définitions de contenu, sans logique dupliquée
tests/
  unit/                  règles sans scène
  integration/           assemblage de nœuds et services
  contract/              ressources, sauvegardes et compatibilité
docs/adr/                décisions d'architecture immuables
scripts/                 barrières qualité reproductibles

Les dossiers game/ et content/ seront créés avec la première tranche de la verticale. Ils ne contiendront aucune copie directe des scripts des POC.

2. Direction unique des dépendances

domain  <──  application  <──  world
   ▲              ▲             │
   └──────────────┼── presentation
                  └── infrastructure

composition peut assembler toutes les branches.

Domain

Contient les règles qui doivent rester vraies quel que soit l'écran ou la scène : ressources, dégâts, intensité sonar, coût d'une amélioration, identification, inventaire et transitions d'état.

  • Classes RefCounted ou Resource typées.
  • Aucun Node, Input, signal de scène, audio, fichier ou rendu.
  • Aucun accès à une horloge ou à un générateur aléatoire global.
  • Tests synchrones et déterministes.

Application

Exprime ce que le joueur ou le jeu peut demander : démarrer un scan, équiper un module, enregistrer une preuve, terminer une plongée ou vendre un objet.

  • Dépend uniquement du domaine.
  • Définit des ports abstraits pour sauvegarde, audio, temps ou plateforme.
  • Retourne des résultats explicites ; aucune dépendance à un HUD ou un acteur.

World

Adapte Godot aux cas d'usage : véhicule, collisions, capteurs, épaves et outils.

  • Ne possède pas les règles économiques ou de campagne.
  • Convertit les événements physiques en commandes d'application.
  • Ne référence aucun HUD concret.

Presentation

Affiche des snapshots et transforme une interaction en commande.

  • Ne calcule pas la consommation, les dégâts, la valeur ou la réussite.
  • Ne modifie pas directement un acteur ou une ressource de domaine.
  • Les shaders et renderers traduisent les données ; ils ne les inventent pas.

Infrastructure

Implémente les ports externes : sauvegardes, fichiers, audio, entrées, builds et services de plateforme.

  • Ne contient aucune règle de gameplay.
  • Les erreurs d'I/O deviennent des résultats contrôlés et testables.

Composition

Seule couche autorisée à connaître les implémentations concrètes de toutes les autres. Elle instancie, injecte et connecte. Une scène de composition ne doit pas devenir un second système de gameplay.

3. Une seule source de vérité

Chaque information mutable possède un propriétaire unique.

Concept Propriétaire attendu Consommateurs
Oxygène, batterie, coque état de plongée du domaine HUD, alarmes, sauvegarde
Mouvement physique acteur sous-marin du monde caméra, télémétrie, sonar
Relevé sonar service/cartographie sonar renderer, sauvegarde éventuelle
Inventaire agrégat de campagne HUD, vente, sauvegarde
Contrat actif service de contrats objectifs, port, sauvegarde
Paramètres d'accessibilité service de réglages UI, caméra, audio, sonar

Un consommateur reçoit un snapshot immuable ou un événement. Il ne maintient pas une copie concurrente de l'état. Un cache doit être explicitement nommé, invalidé par son propriétaire et vérifié par test.

4. Politique anti-duplication

Avant d'ajouter une fonction, rechercher le concept et ses synonymes avec rg.

Une similitude ne justifie pas toujours une abstraction. Extraire lorsque deux implémentations portent la même règle métier ou doivent évoluer ensemble. Garder deux présentations séparées lorsqu'elles partagent seulement quelques lignes de mise en page.

Interdictions :

  • copier un calcul du domaine dans un HUD ;
  • dupliquer des seuils dans plusieurs scripts ;
  • créer un dossier générique utils, helpers, common ou shared ;
  • coder une variante par difficulté avec un second système complet ;
  • dupliquer les identifiants d'actions ou les chemins de sauvegarde ;
  • faire du prototype une dépendance de production.

Les constantes de réglage deviennent des ressources de configuration validées. Les identifiants stables deviennent des types ou constantes centralisés dans leur domaine propriétaire.

5. Contrats de données

Les dictionnaires anonymes sont tolérés dans les POC mais interdits aux frontières de production. Un contrat doit préciser :

  • le type de chaque champ ;
  • son unité (m, s, %, radians) ;
  • le repère spatial utilisé ;
  • sa mutabilité ;
  • son propriétaire ;
  • sa stratégie de version si elle est sauvegardée.

Exemples attendus : SonarSample, SonarScan, DiveSnapshot, TelemetrySnapshot, WreckDefinition et SaveGameVersion.

Les conversions entre coordonnées monde, véhicule et carte sonar se font dans un adaptateur nommé et couvert par des tests. Aucune convention implicite de signe ou d'axe ne doit traverser plusieurs fichiers.

6. Tests obligatoires

Pyramide

  1. Unitaires : majorité des tests ; domaine pur, rapides et déterministes.
  2. Contrats : ressources, sérialisation, migrations, configurations et invariants de contenu.
  3. Intégration : scènes minimales, signaux, physique et assemblage.
  4. Parcours : peu nombreux ; une boucle complète avec critères observables.
  5. Visuels et humains : lisibilité, contraste, mouvement et compréhension.

Règles

  • Tout bug corrigé commence par un test qui échoue lorsque c'est raisonnable.
  • Aucun test ne dépend du réseau, de l'heure réelle ou d'un ordre aléatoire.
  • Les attentes temporelles utilisent une horloge injectée ou un nombre de ticks borné, jamais un sommeil arbitraire.
  • Une scène d'intégration construit le minimum requis pour le comportement.
  • Les tests vérifient des résultats, pas la structure interne d'une méthode.
  • Une migration de sauvegarde garde un échantillon de chaque version supportée.
  • Le contenu principal reçoit des tests de validation : ID uniques, références résolues, profondeur possible et absence de blocage narratif.

Barrière actuelle

bash scripts/quality_gate.sh exécute dans cet ordre :

  1. règles d'architecture ;
  2. chargement de tous les scripts et scènes ;
  3. tests unitaires existants ;
  4. tests d'intégration du POC B.

La verticale ajoutera ses suites à cette commande unique. Une fonctionnalité ne peut pas être déclarée terminée si la barrière échoue.

La commande locale est la barrière active dans le dépôt actuel. Avant la première fusion de code de production sur un dépôt distant, elle devra devenir un contrôle CI obligatoire avec protection de branche. La CI appellera ce même script ; elle ne maintiendra pas une seconde liste de tests.

7. Taille et responsabilités

Seuils de revue, non objectifs mécaniques :

  • au-delà de 350 lignes par fichier, vérifier si plusieurs responsabilités sont mêlées ;
  • au-delà de 40 lignes par fonction, vérifier si des étapes nommées manquent ;
  • au-delà de cinq dépendances injectées, vérifier si le composant orchestre trop de domaines ;
  • une scène ne doit avoir qu'une racine de composition identifiable ;
  • un signal doit décrire un fait passé, une commande une intention.

Une exception justifiée vaut mieux qu'un découpage artificiel. Une exception durable doit être documentée dans un ADR.

8. Gestion des erreurs et observabilité

  • Toute erreur récupérable produit un résultat explicite et un message utile.
  • Les erreurs de sauvegarde ne doivent jamais écraser la dernière sauvegarde valide.
  • Les ressources invalides échouent au chargement ou au test de contrat.
  • Les logs n'enregistrent aucune donnée personnelle ou secret.
  • Les événements importants portent un contexte : mission, site, scan ou version.
  • Les fuites de nœuds, avertissements et erreurs Godot sont triés avant fusion.

9. Sauvegardes et migrations

  • Format versionné dès le premier prototype de verticale sauvegardé.
  • Écriture dans un fichier temporaire, validation, puis remplacement atomique.
  • Jamais de sérialisation arbitraire de nœuds ou de physique.
  • IDs stables plutôt que chemins de scène comme identité métier.
  • Migration explicite d'une version à la suivante.
  • Sauvegardes de référence anonymes conservées sous tests/fixtures/.

10. Entrées, accessibilité et localisation

  • Le gameplay dépend d'actions abstraites, jamais de touches codées en dur.
  • Une seule infrastructure traduit les périphériques en commandes.
  • Toute nouvelle action est remappable et documentée.
  • Les textes visibles sont identifiables pour la localisation ; aucun texte métier n'est construit par concaténation fragile.
  • Les informations critiques combinent texte, forme, son ou animation avec la couleur.
  • Les options réduisant mouvement, flash et contraste sont consultées par la présentation, pas recodées dans chaque effet.

11. Décisions d'architecture

Un ADR est requis avant :

  • un nouvel autoload ;
  • une dépendance qui inverse le graphe défini ici ;
  • un format de sauvegarde ou une migration ;
  • une technologie externe ou un plugin ;
  • une exception durable à une barrière automatique ;
  • un changement de renderer ou de version Godot pendant un jalon.

Un ADR décrit le contexte, la décision, ses conséquences et les alternatives rejetées. Il ne doit pas être réécrit pour masquer une ancienne décision ; un nouvel ADR le remplace explicitement.

12. Ordre de mise en production

Avant le premier gameplay de la verticale :

  1. créer les couches vides et leur test d'architecture ;
  2. définir les premiers contrats typés ;
  3. porter une règle pure avec ses tests ;
  4. créer une seule scène de composition ;
  5. intégrer le véhicule puis le sonar par adaptateurs ;
  6. ajouter un parcours end-to-end minimal ;
  7. seulement ensuite ajouter contenu, port et économie.

Chaque tranche doit rester jouable et laisser la barrière qualité verte.