# AUDIT DE CONFORMITÉ GROVEENGINE - AISSIA **Date** : 2025-11-26 **Auditeur** : Claude Code **Version auditée** : Commit bc3b6cb --- ## RÉSUMÉ EXÉCUTIF **Verdict : Le code contourne massivement les principes de GroveEngine.** | Module | Lignes | Conformité Engine | Statut | |--------|--------|-------------------|--------| | AIModule | 306 | VIOLATION | Infrastructure dans module | | MonitoringModule | 222 | VIOLATION | Appels OS dans module | | StorageModule | 273 | VIOLATION | SQLite dans module | | VoiceModule | 209 | VIOLATION | TTS/COM dans module | | SchedulerModule | 179 | CONFORME | Logique métier pure | | NotificationModule | 172 | CONFORME | Logique métier pure | **Score global** : 2/6 modules conformes (33%) --- ## RAPPEL DES PRINCIPES GROVEENGINE Selon `docs/GROVEENGINE_GUIDE.md` : 1. **Modules = Pure business logic** (200-300 lignes recommandées) 2. **No infrastructure code in modules** : threading, networking, persistence 3. **All data via IDataNode abstraction** (backend agnostic) 4. **Pull-based message processing** via IIO pub/sub 5. **Hot-reload ready** : sérialiser tout l'état dans `getState()` --- ## VIOLATIONS CRITIQUES ### 1. AIModule - Networking dans le module **Fichier** : `src/modules/AIModule.cpp:146` ```cpp nlohmann::json AIModule::agenticLoop(const std::string& userQuery) { // ... auto response = m_provider->chat(m_systemPrompt, messages, tools); // Appel HTTP synchrone bloquant ! } ``` **Violation** : Appels HTTP synchrones directement dans `process()` via la boucle agentique. **Impact** : - Bloque la boucle principale pendant chaque requête LLM (timeout 60s) - `isIdle()` retourne false pendant l'appel, mais le module reste bloquant - Hot-reload impossible pendant une requête en cours - Tous les autres modules sont bloqués **Correction requise** : Déléguer les appels LLM à un service infrastructure externe, communication via IIO async. --- ### 2. StorageModule - Persistence dans le module **Fichier** : `src/modules/StorageModule.cpp:78-91` ```cpp bool StorageModule::openDatabase() { int rc = sqlite3_open(m_dbPath.c_str(), &m_db); // Handle SQLite directement dans le module } ``` **Violation** : Gestion directe de SQLite. L'engine préconise `IDataNode` abstractions pour la persistence. **Impact** : - Hot-reload risqué (handle DB ouvert) - Risque de corruption si reload pendant transaction - Couplage fort avec SQLite **Correction requise** : Service StorageService dans main.cpp, modules communiquent via topics `storage:*`. --- ### 3. MonitoringModule - Appels OS dans le module **Fichier** : `src/modules/MonitoringModule.cpp:78-79` ```cpp void MonitoringModule::checkCurrentApp(float currentTime) { std::string newApp = m_tracker->getCurrentAppName(); // Appelle GetForegroundWindow(), OpenProcess(), etc. } ``` **Violation** : Appels Win32 API dans `process()`. Même encapsulé dans `IWindowTracker`, c'est du code plateforme dans un module hot-reloadable. **Impact** : - Dépendance plateforme dans le module - Handles système potentiellement orphelins au reload **Correction requise** : Service PlatformService qui publie `monitoring:window_info` périodiquement. --- ### 4. VoiceModule - COM/SAPI dans le module **Fichier** : `src/modules/VoiceModule.cpp:122` ```cpp void VoiceModule::speak(const std::string& text) { m_ttsEngine->speak(text, true); // Appel ISpVoice::Speak via COM } ``` **Fichier** : `src/shared/audio/SAPITTSEngine.hpp:26` ```cpp HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); ``` **Violation** : Initialisation COM et appels SAPI dans le module. **Impact** : - `CoInitializeEx` par thread, hot-reload peut causer des fuites - Appels asynchrones SAPI difficiles à gérer au shutdown **Correction requise** : Service VoiceService dédié, modules envoient `voice:speak`. --- ## PROBLÈMES DE DESIGN ### 5. Topics incohérents **SchedulerModule.h:26** utilise le format slash : ```cpp // "scheduler/hyperfocus_alert" ``` **AIModule.cpp:52** utilise le format colon : ```cpp m_io->subscribe("scheduler:hyperfocus_alert", subConfig); ``` **Standard GroveEngine** : Format `module:event` (colon) **Impact** : Les messages ne seront jamais reçus si les formats ne correspondent pas. --- ### 6. SchedulerModule - IIO non utilisé **Fichier** : `src/modules/SchedulerModule.cpp:66-68` ```cpp void SchedulerModule::checkHyperfocus(float currentTime) { // ... // Publier l'alerte (si IO disponible) // Note: Dans une version complète, on publierait via m_io } ``` **Problème** : Le SchedulerModule a `m_io` mais ne publie JAMAIS rien. Les autres modules s'abonnent à `scheduler:*` mais ne recevront rien. --- ### 7. État non restaurable - StorageModule **Fichier** : `src/modules/StorageModule.cpp:246-258` ```cpp std::unique_ptr StorageModule::getState() { state->setBool("isConnected", m_isConnected); // ... } void StorageModule::setState(const grove::IDataNode& state) { // NE ROUVRE PAS la connexion DB ! m_logger->info("Etat restore..."); } ``` **Problème** : `setState()` ne restaure pas la connexion SQLite. Après hot-reload, le module est dans un état incohérent. --- ### 8. Libraries statiques dans modules **CMakeLists.txt:86-101** : ```cmake add_library(AissiaLLM STATIC ...) target_link_libraries(AIModule PRIVATE AissiaLLM) ``` **Problème** : Les libs `AissiaLLM`, `AissiaPlatform`, `AissiaAudio` sont compilées en STATIC et linkées dans chaque .so. **Impact** : - Code dupliqué dans chaque module - Hot-reload ne rafraîchit pas ces libs - Pas de partage d'état entre modules --- ### 9. Dépassement limite de lignes | Module | Lignes | Limite recommandée | |--------|--------|-------------------| | AIModule | 306 | 200-300 | Le dépassement est mineur mais symptomatique : le module fait trop de choses. --- ## CE QUI EST CONFORME ### SchedulerModule & NotificationModule Ces deux modules respectent les principes : - Logique métier pure - Pas d'appels système - État sérialisable - Taille appropriée ### Structure IModule Tous les modules implémentent correctement : - `process()` - `setConfiguration()` - `getState()` / `setState()` - `getHealthStatus()` - `shutdown()` - Exports C `createModule()` / `destroyModule()` ### main.cpp La boucle principale est bien implémentée : - FileWatcher pour hot-reload - Frame timing à 10Hz - Signal handling propre - Chargement/déchargement correct --- ## ARCHITECTURE RECOMMANDÉE ### Actuelle (INCORRECTE) ``` ┌─────────────────────────────────────────────────────────┐ │ main.cpp │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │AIModule │ │Storage │ │Monitor │ │Voice │ │ │ │ +HTTP │ │ +SQLite │ │ +Win32 │ │ +COM │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ └─────────────────────────────────────────────────────────┘ Infrastructure DANS les modules = VIOLATION ``` ### Corrigée (CONFORME) ``` ┌─────────────────────────────────────────────────────────┐ │ main.cpp │ │ │ │ ┌─────────────── INFRASTRUCTURE ──────────────────┐ │ │ │ LLMService │ StorageService │ PlatformService │ │ │ │ │ (async) │ (SQLite) │ (Win32) │ │ │ │ └──────────────────────────────────────────────────┘ │ │ ↑↓ IIO pub/sub (async, non-bloquant) │ │ ┌─────────────── MODULES (hot-reload) ────────────┐ │ │ │ AIModule │ StorageModule │ MonitoringModule │ │ │ │ │ (logic) │ (logic) │ (logic) │ │ │ │ └──────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ Infrastructure HORS modules = CONFORME ``` ### Flux de données corrigé ``` User query → voice:transcription → AIModule AIModule → ai:query_request → LLMService (async) LLMService → ai:response → AIModule AIModule → ai:response → VoiceModule → voice:speak ``` --- ## ACTIONS REQUISES ### Priorité HAUTE 1. **Extraire LLM de AIModule** - Créer `LLMService` dans main.cpp ou service dédié - AIModule publie `ai:query_request`, reçoit `ai:response` - Appels HTTP dans thread séparé 2. **Extraire SQLite de StorageModule** - Créer `StorageService` - Modules publient `storage:save_*`, reçoivent `storage:result` 3. **Extraire Win32 de MonitoringModule** - Créer `PlatformService` - Publie `platform:window_changed` périodiquement 4. **Extraire TTS de VoiceModule** - Créer `VoiceService` - Modules publient `voice:speak` ### Priorité MOYENNE 5. **Corriger format topics** : Tout en `module:event` 6. **Implémenter publish dans SchedulerModule** 7. **Corriger setState dans StorageModule** ### Priorité BASSE 8. **Refactorer libs STATIC en services** 9. **Réduire AIModule sous 300 lignes** --- ## CONCLUSION Le code actuel **simule** l'utilisation de GroveEngine mais le **contourne** en plaçant l'infrastructure directement dans les modules. Les modules ne sont **pas véritablement hot-reloadable** car ils : 1. Possèdent des ressources système (DB handles, COM objects) 2. Font des appels bloquants (HTTP 60s timeout, TTS) 3. Ne communiquent pas correctement via IIO **Refactoring majeur requis** pour extraire l'infrastructure des modules vers des services dédiés dans main.cpp. --- *Audit généré automatiquement par Claude Code*