aissia/audits/2025-11-26-engine-compliance-audit.md
StillHammer 26a5d3438b refactor: Services architecture for GroveEngine compliance
- Create 4 infrastructure services (LLM, Storage, Platform, Voice)
- Refactor all modules to pure business logic (no HTTP/SQLite/Win32)
- Add bundled SQLite amalgamation for MinGW compatibility
- Make OpenSSL optional in CMake configuration
- Fix topic naming convention (colon format)
- Add succession documentation

Build status: CMake config needs SQLite C language fix (documented)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 11:57:53 +08:00

341 lines
10 KiB
Markdown

# 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<grove::IDataNode> 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*