diff --git a/docs/03-implementation/configuration/module-versioning.md b/docs/03-implementation/configuration/module-versioning.md new file mode 100644 index 0000000..1a491a0 --- /dev/null +++ b/docs/03-implementation/configuration/module-versioning.md @@ -0,0 +1,677 @@ +# Module Versioning System + +## Vue d'Ensemble + +Le système de versioning des modules utilise un format **MAJOR.MINOR.PATCH.BUILD** automatiquement généré par CMake lors de la compilation. Ce système permet de : + +- **Tracer les versions** : Identifier précisément quelle version du code a créé une save +- **Détecter incompatibilités** : Alerter si une save utilise une version différente +- **Debugging** : Reproduire bugs avec la version exacte du module +- **Développement** : Versions incrémentales automatiques sans maintenance manuelle + +## Format de Version + +### Structure : MAJOR.MINOR.PATCH.BUILD + +``` +0.1.15.3847 +│ │ │ │ +│ │ │ └─── BUILD : Auto-increment à chaque build (hash sources) +│ │ └────── PATCH : Auto-increment à chaque commit +│ └──────── MINOR : Manuel (fonctionnalités nouvelles) +└────────── MAJOR : Manuel (breaking changes) +``` + +### Composantes + +#### MAJOR (Manuel) +- **Incrémenté** : Breaking changes, incompatibilités majeures +- **Exemples** : Refonte complète architecture, changement format save incompatible +- **Gestion** : Modifié manuellement dans fichier `VERSION` +- **Valeur initiale** : `0` (pré-release), `1` (première version stable) + +#### MINOR (Manuel) +- **Incrémenté** : Nouvelles fonctionnalités, ajouts non-breaking +- **Exemples** : Nouveau type de tank, nouveau système économique +- **Gestion** : Modifié manuellement dans fichier `VERSION` +- **Valeur initiale** : `1` + +#### PATCH (Automatique) +- **Incrémenté** : À chaque commit Git +- **Calcul** : Nombre de commits depuis le début du projet +- **Exemples** : Bugfixes, optimisations, refactoring mineur +- **Gestion** : Calculé automatiquement par CMake via `git rev-list --count HEAD` + +#### BUILD (Automatique) +- **Incrémenté** : À chaque rebuild (si sources modifiées) +- **Calcul** : Hash MD5 des fichiers sources (`.cpp`, `.h`) +- **But** : Distinguer builds de dev avec code non-commité +- **Gestion** : Calculé automatiquement par CMake + +### Exemples de Versions + +``` +0.1.0.0 → Première version dev (MAJOR.MINOR manuel, PATCH/BUILD = 0) +0.1.5.1234 → Après 5 commits, build 1234 +0.1.5.1235 → Même commit, sources modifiées → nouveau build +0.1.6.1235 → Nouveau commit, sources identiques → même build (théorique) +0.2.10.3847 → MINOR bump (nouvelle feature) + 10 commits +1.0.0.0 → Release stable, reset PATCH/BUILD +``` + +## Implémentation CMake + +### Fichier VERSION + +Chaque module contient un fichier `VERSION` à la racine : + +``` +modules/tank/VERSION +``` + +Contenu du fichier : +``` +0.1 +``` + +Ce fichier contient uniquement `MAJOR.MINOR`. Les composantes `PATCH.BUILD` sont calculées automatiquement. + +### CMakeLists.txt du Module + +```cmake +cmake_minimum_required(VERSION 3.20) +project(TankModule) + +# ============================================================================ +# MODULE VERSIONING +# ============================================================================ + +# 1. Lire MAJOR.MINOR depuis fichier VERSION +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION") + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" BASE_VERSION) + string(STRIP "${BASE_VERSION}" BASE_VERSION) +else() + set(BASE_VERSION "0.1") + message(WARNING "No VERSION file found, using default: ${BASE_VERSION}") +endif() + +# 2. Calculer PATCH : nombre de commits Git +execute_process( + COMMAND git rev-list --count HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE PATCH_COUNT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE GIT_RESULT +) + +if(NOT GIT_RESULT EQUAL 0) + set(PATCH_COUNT "0") + message(WARNING "Git not available, PATCH set to 0") +endif() + +# 3. Calculer BUILD : hash des fichiers sources +file(GLOB_RECURSE MODULE_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h" +) + +# Concaténer contenu de tous les fichiers +set(SOURCES_CONTENT "") +foreach(SOURCE_FILE ${MODULE_SOURCES}) + file(READ ${SOURCE_FILE} FILE_CONTENT) + string(APPEND SOURCES_CONTENT ${FILE_CONTENT}) +endforeach() + +# Hash MD5 du contenu total +string(MD5 SOURCES_HASH "${SOURCES_CONTENT}") + +# Convertir hash hex en nombre décimal (4 premiers caractères) +string(SUBSTRING ${SOURCES_HASH} 0 4 BUILD_HEX) +# Calculer valeur numérique (modulo 10000 pour limiter à 4 chiffres) +math(EXPR BUILD_NUM "0x${BUILD_HEX} % 10000") + +# 4. Assembler version complète +set(MODULE_VERSION "${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}") + +message(STATUS "Module version: ${MODULE_VERSION}") +message(STATUS " BASE: ${BASE_VERSION} (from VERSION file)") +message(STATUS " PATCH: ${PATCH_COUNT} (git commits)") +message(STATUS " BUILD: ${BUILD_NUM} (sources hash)") + +# 5. Définir macro C++ pour accès au runtime +add_definitions(-DMODULE_VERSION="${MODULE_VERSION}") + +# ============================================================================ +# MODULE BUILD +# ============================================================================ + +# Inclure sources +file(GLOB_RECURSE TANK_SOURCES src/*.cpp) + +# Créer bibliothèque partagée (.so) +add_library(tank-module SHARED ${TANK_SOURCES}) + +# Configuration compilation +target_include_directories(tank-module PRIVATE include) +target_compile_features(tank-module PRIVATE cxx_std_20) + +# Sortie +set_target_properties(tank-module PROPERTIES + OUTPUT_NAME "tank" + PREFIX "" + SUFFIX ".so" +) + +message(STATUS "Building TankModule v${MODULE_VERSION}") +``` + +### Utilisation dans le Code C++ + +```cpp +// src/TankModule.h +#ifndef MODULE_VERSION +#define MODULE_VERSION "unknown" +#endif + +class TankModule : public IModule, public IModuleSave { +public: + std::string getVersion() const override { + return MODULE_VERSION; // Défini par CMake + } + + nlohmann::json serialize() override { + json data; + data["module_name"] = "tank"; + data["module_version"] = getVersion(); // "0.1.15.3847" + // ... reste de la sérialisation + return data; + } +}; +``` + +### Affichage au Runtime + +```cpp +void TankModule::initialize() { + LOG_INFO("TankModule v{} initializing...", getVersion()); +} +``` + +Sortie console : +``` +[INFO] TankModule v0.1.15.3847 initializing... +``` + +## Workflow de Développement + +### 1. Création Nouveau Module + +```bash +# Créer structure module +mkdir -p modules/new_module/src +cd modules/new_module + +# Créer fichier VERSION +echo "0.1" > VERSION + +# Créer CMakeLists.txt avec système versioning +# (copier template ci-dessus) +``` + +**Première compilation** : +```bash +cmake . && make +``` + +Sortie : +``` +-- Module version: 0.1.0.0 +-- BASE: 0.1 (from VERSION file) +-- PATCH: 0 (git commits) +-- BUILD: 0 (sources hash) +-- Building NewModule v0.1.0.0 +``` + +### 2. Développement Itératif + +**Scénario 1 : Modifier code sans commit** + +```bash +# Éditer src/NewModule.cpp +nano src/NewModule.cpp + +# Rebuild +make +``` + +Sortie : +``` +-- Module version: 0.1.0.4582 +-- PATCH: 0 (aucun commit) +-- BUILD: 4582 (hash sources a changé) +``` + +**Scénario 2 : Commit modifications** + +```bash +git add . +git commit -m "Add feature X" + +# Rebuild +make +``` + +Sortie : +``` +-- Module version: 0.1.1.4582 +-- PATCH: 1 (nouveau commit) +-- BUILD: 4582 (sources identiques au commit) +``` + +**Scénario 3 : Rebuild sans modification** + +```bash +# Rebuild immédiat +make +``` + +Sortie : +``` +-- Module version: 0.1.1.4582 + (version identique, aucun changement) +``` + +### 3. Release Mineure (Nouvelle Feature) + +```bash +# Bump MINOR version +echo "0.2" > VERSION + +# Commit +git add VERSION +git commit -m "Bump version to 0.2 (new feature: advanced tactics)" + +# Rebuild +cmake . && make +``` + +Sortie : +``` +-- Module version: 0.2.2.5123 +-- BASE: 0.2 (nouvelle version) +-- PATCH: 2 (commits depuis début projet) +-- BUILD: 5123 (hash actuel) +``` + +### 4. Release Majeure (Breaking Change) + +```bash +# Bump MAJOR version +echo "1.0" > VERSION + +git add VERSION +git commit -m "Release 1.0.0 - Stable API" + +cmake . && make +``` + +Sortie : +``` +-- Module version: 1.0.3.5123 +-- BASE: 1.0 (version stable) +-- PATCH: 3 (total commits) +-- BUILD: 5123 +``` + +## Comparaison de Versions + +### Dans le Système de Save + +Lors du chargement d'une save, comparaison des versions : + +```cpp +bool SaveSystem::loadModule(const std::string& moduleName) { + auto module = moduleSystem->getModule(moduleName); + + json moduleData = readJsonFile(modulePath); + std::string savedVersion = moduleData["module_version"]; + std::string currentVersion = module->getVersion(); + + if (savedVersion != currentVersion) { + LOG_WARN("Module {} version mismatch:", moduleName); + LOG_WARN(" Save version: {}", savedVersion); + LOG_WARN(" Current version: {}", currentVersion); + + // Analyser différences + VersionInfo saved = parseVersion(savedVersion); + VersionInfo current = parseVersion(currentVersion); + + if (saved.major != current.major) { + LOG_ERROR(" MAJOR version mismatch - likely incompatible!"); + return false; // Incompatibilité critique + } + else if (saved.minor != current.minor) { + LOG_WARN(" MINOR version mismatch - some features may differ"); + // Continuer avec warning + } + else if (saved.patch != current.patch) { + LOG_INFO(" PATCH version mismatch - minor changes only"); + // Sûr, juste bugfixes + } + else { + LOG_DEBUG(" BUILD version mismatch - dev builds differ"); + // Totalement sûr + } + } + + return module->deserialize(moduleData); +} +``` + +### Structure VersionInfo + +```cpp +struct VersionInfo { + int major; + int minor; + int patch; + int build; + + static VersionInfo parse(const std::string& versionStr) { + VersionInfo info; + std::sscanf(versionStr.c_str(), "%d.%d.%d.%d", + &info.major, &info.minor, &info.patch, &info.build); + return info; + } + + bool isCompatibleWith(const VersionInfo& other) const { + // Compatible si MAJOR identique + return major == other.major; + } + + bool hasBreakingChanges(const VersionInfo& other) const { + return major != other.major; + } +}; +``` + +## Gestion Multi-Modules + +### Script CMake Global + +Pour centraliser la logique de versioning, créer un fichier CMake réutilisable : + +```cmake +# cmake/ModuleVersioning.cmake + +function(setup_module_versioning) + # Lire VERSION + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION") + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" BASE_VERSION) + string(STRIP "${BASE_VERSION}" BASE_VERSION) + else() + set(BASE_VERSION "0.1") + endif() + + # Calculer PATCH + execute_process( + COMMAND git rev-list --count HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE PATCH_COUNT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE GIT_RESULT + ) + if(NOT GIT_RESULT EQUAL 0) + set(PATCH_COUNT "0") + endif() + + # Calculer BUILD + file(GLOB_RECURSE MODULE_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h" + ) + set(SOURCES_CONTENT "") + foreach(SOURCE_FILE ${MODULE_SOURCES}) + file(READ ${SOURCE_FILE} FILE_CONTENT) + string(APPEND SOURCES_CONTENT ${FILE_CONTENT}) + endforeach() + string(MD5 SOURCES_HASH "${SOURCES_CONTENT}") + string(SUBSTRING ${SOURCES_HASH} 0 4 BUILD_HEX) + math(EXPR BUILD_NUM "0x${BUILD_HEX} % 10000") + + # Assembler version + set(MODULE_VERSION "${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}" PARENT_SCOPE) + + # Log + message(STATUS "Module version: ${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}") +endfunction() +``` + +### Utilisation dans Module + +```cmake +# modules/tank/CMakeLists.txt +cmake_minimum_required(VERSION 3.20) +project(TankModule) + +# Importer fonction versioning +include(${CMAKE_SOURCE_DIR}/cmake/ModuleVersioning.cmake) + +# Setup version automatique +setup_module_versioning() + +# Définir macro +add_definitions(-DMODULE_VERSION="${MODULE_VERSION}") + +# ... reste du CMakeLists +``` + +## Best Practices + +### 1. Quand Bumper MAJOR ? + +**Situations justifiant MAJOR bump** : +- Changement format save incompatible +- Refonte API du module (signatures fonctions changent) +- Suppression de fonctionnalités existantes +- Changement architecture fondamentale + +**Exemple** : +```bash +# Avant : TankModule v0.8.x utilise grille 10x10 +# Après : TankModule v1.0.0 utilise grille 16x16 (incompatible) +echo "1.0" > VERSION +``` + +### 2. Quand Bumper MINOR ? + +**Situations justifiant MINOR bump** : +- Ajout nouveau type de tank/composant +- Nouvelle fonctionnalité (mode formation, tactiques AI) +- Amélioration significative sans breaking change + +**Exemple** : +```bash +# Ajout système de camouflage → 0.1 → 0.2 +echo "0.2" > VERSION +``` + +### 3. PATCH et BUILD sont Automatiques + +**Ne jamais modifier manuellement** : +- PATCH suit automatiquement les commits +- BUILD suit automatiquement les modifications code + +### 4. Versioning pour Tests + +En environnement de test, fixer une version stable : + +```cmake +if(DEFINED ENV{CI_BUILD}) + # Build CI : version fixe pour reproductibilité + set(MODULE_VERSION "0.0.0.0") +else() + # Build normal : versioning automatique + setup_module_versioning() +endif() +``` + +### 5. Affichage Version au Démarrage + +```cpp +void logModuleVersions() { + LOG_INFO("=== Module Versions ==="); + for (auto& module : moduleSystem->getAllModules()) { + LOG_INFO(" {}: v{}", module->getName(), module->getVersion()); + } + LOG_INFO("======================="); +} +``` + +Sortie : +``` +[INFO] === Module Versions === +[INFO] tank: v0.1.15.3847 +[INFO] economy: v0.2.8.1203 +[INFO] factory: v0.1.20.4512 +[INFO] transport: v0.1.5.982 +[INFO] ======================= +``` + +## Debugging avec Versions + +### Reproduire un Bug + +Si un bug est reporté avec une save : + +1. **Lire version du module dans la save** : +```bash +cat saves/abc123/server_1/tank.json | grep module_version +# "module_version": "0.1.15.3847" +``` + +2. **Retrouver commit correspondant** : +```bash +# PATCH = 15 commits +git log --oneline | head -n 15 | tail -n 1 +``` + +3. **Vérifier hash sources** : +```bash +# BUILD = 3847 correspond à un certain hash +# Comparer avec hashes de commits proches +``` + +4. **Checkout version exacte pour debugging** : +```bash +git checkout +cmake . && make +# Version devrait matcher ou être proche +``` + +### Logs de Version + +```cpp +void TankModule::initialize() { + LOG_INFO("TankModule v{} initializing", getVersion()); + LOG_DEBUG(" Compiled: {} {}", __DATE__, __TIME__); + LOG_DEBUG(" Compiler: {}", __VERSION__); +} +``` + +## Alternatives et Limitations + +### Alternative 1 : Semantic Versioning Manuel + +**Avantage** : Contrôle total sur versions +**Inconvénient** : Maintenance manuelle, oublis fréquents + +### Alternative 2 : Git Tags Only + +```cmake +execute_process( + COMMAND git describe --tags --always + OUTPUT_VARIABLE MODULE_VERSION +) +``` + +**Avantage** : Simple, suit git +**Inconvénient** : Nécessite tags, pas de granularité build + +### Limitation Actuelle : Hash Non-Déterministe + +Le hash des sources peut varier selon : +- Ordre de lecture des fichiers (filesystem dépendant) +- Encodage des fichiers +- Whitespace differences + +**Solution future** : Hash déterministe avec tri des fichiers et normalisation. + +## Migration depuis Système Existant + +Si des modules existants utilisent un autre système : + +```cmake +# Détecter ancien système +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/version.txt") + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" OLD_VERSION) + message(WARNING "Found old version.txt, migrating to VERSION file") + + # Extraire MAJOR.MINOR + string(REGEX MATCH "^[0-9]+\\.[0-9]+" BASE_VERSION ${OLD_VERSION}) + file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" "${BASE_VERSION}") + + message(STATUS "Migration complete: ${OLD_VERSION} -> ${BASE_VERSION}.x.x") +endif() +``` + +## Références Croisées + +- `systeme-sauvegarde.md` : Utilisation des versions dans le système de save +- `architecture-modulaire.md` : Interface IModule, contraintes modules +- `claude-code-integration.md` : Optimisation builds pour développement AI + +## Exemples Complets + +### Module Complet avec Versioning + +Voir structure complète dans : +``` +modules/tank/ +├── VERSION # "0.1" +├── CMakeLists.txt # Setup versioning + build +├── src/ +│ ├── TankModule.cpp # Utilise MODULE_VERSION +│ └── Tank.cpp +└── include/ + └── TankModule.h # Déclare getVersion() +``` + +### Test Versioning + +```cpp +#ifdef TESTING +#include + +void testVersioning() { + TankModule module; + + std::string version = module.getVersion(); + assert(!version.empty()); + assert(version != "unknown"); + + // Parse version + VersionInfo info = VersionInfo::parse(version); + assert(info.major >= 0); + assert(info.minor >= 0); + assert(info.patch >= 0); + assert(info.build >= 0); + + std::cout << "Versioning test passed: " << version << std::endl; +} +#endif +``` diff --git a/docs/ai-framework.md b/docs/ai-framework.md new file mode 100644 index 0000000..3525726 --- /dev/null +++ b/docs/ai-framework.md @@ -0,0 +1,1414 @@ +# AI Framework - Unified Decision System + +## Philosophie + +Le système d'IA de Warfactory repose sur un **framework unifié de prise de décision par scoring**. Tous les types d'IA (tactique, opérationnelle, économique, diplomatique) utilisent le même pattern fondamental : + +1. **Générer options** disponibles dans le contexte actuel +2. **Scorer chaque option** selon poids configurables et situation +3. **Choisir la meilleure option** (highest score) +4. **Exécuter l'action** correspondante + +Ce pattern unifié permet : +- **Cohérence** : Même logique à travers tous les systèmes IA +- **Configurabilité** : Comportements ajustables via JSON +- **Apprentissage** : Reinforcement Learning ajuste les poids +- **Modularité** : Nouveaux types de décisions ajoutables facilement +- **Testabilité** : Chaque décision isolée et vérifiable + +## Architecture Globale + +### Hiérarchie des Modules IA + +``` +AI Framework +├── Core Decision System +│ ├── IDecision (interface de base) +│ ├── Decision Factory (création objets) +│ └── Scoring Engine (évaluation uniforme) +│ +├── Helper Modules (services, pas de décisions) +│ ├── PathfinderModule (calcul chemins) +│ ├── AcquisitionModule (sélection cibles) +│ └── MovementModule (exécution mouvement) +│ +├── Decision Modules (utilisent helpers) +│ ├── TacticalModule (combat temps-réel) +│ ├── OperationalModule (stratégie bataille) +│ ├── CompanyAIModule (business) +│ └── StateAIModule (politique) +│ +└── Data Modules (consultés par tous) + ├── DiplomacyModule (relations, traités) + └── EconomyModule (marché, prix) +``` + +### Flux de Décision Type + +``` +OperationalModule + ↓ (donne posture: "rush blindé") +TacticalModule + ↓ (demande chemins pour flanking) +PathfinderModule → retourne 3 chemins possibles + ↓ (demande cibles prioritaires) +AcquisitionModule → retourne 5 cibles scorées + ↓ (choisit meilleure tactique) +TacticalModule → décision: flanking par chemin 2, cible 1 + ↓ (exécute mouvement) +MovementModule → unités se déplacent +``` + +## Interface IDecision - Core Pattern + +### Définition + +Toutes les décisions IA implémentent cette interface : + +```cpp +class IDecision { +public: + virtual ~IDecision() = default; + + // 1. Générer toutes les options disponibles + virtual std::vector