aissia/audits/2025-11-26-engine-compliance-audit.md

11 KiB

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

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

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

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

void VoiceModule::speak(const std::string& text) {
    m_ttsEngine->speak(text, true);
    // Appel ISpVoice::Speak via COM
}

Fichier : src/shared/audio/SAPITTSEngine.hpp:26

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 :

// "scheduler/hyperfocus_alert"

AIModule.cpp:52 utilise le format colon :

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

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

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 :

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

  1. Corriger format topics : Tout en module:event
  2. Implémenter publish dans SchedulerModule
  3. Corriger setState dans StorageModule

Priorité BASSE

  1. Refactorer libs STATIC en services
  2. 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