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

274 lines
11 KiB
Markdown

# 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
```text
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
```text
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.