# AUDIT DE CONFORMITÉ GROVEENGINE - CELUNA

**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(CelunaLLM STATIC ...)
target_link_libraries(AIModule PRIVATE CelunaLLM)
```

**Problème** : Les libs `CelunaLLM`, `CelunaPlatform`, `CelunaAudio` 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*
