ihm_client/doc/PAIRING_SYSTEM_ANALYSIS.md
NicolasCantu 7c2c4bfb46 Fix pairing system: Add waitForPairingCommitment with device sync and update documentation
- Add waitForPairingCommitment function with automatic device synchronization
- Integrate updateDevice() call in waitForPairingCommitment for better sync
- Increase retry attempts to 30 with 2s delay (60s total wait time)
- Add detailed logging for pairing process synchronization
- Update router to call waitForPairingCommitment before confirmPairing
- Remove redundant updateDevice() call from router
- Update PAIRING_SYSTEM_ANALYSIS.md with coherence issues and recommendations
- Identify joiner flow inconsistencies requiring future fixes
2025-10-22 14:15:20 +02:00

12 KiB
Raw Blame History

Analyse du Système de Pairing - Version Actuelle

Vue d'ensemble

Ce document résume l'analyse complète du système de pairing et les corrections apportées pour résoudre les problèmes identifiés.

Problèmes Identifiés et Solutions

1. Problème de checkConnections pour le Pairing

Problème : La méthode checkConnections a été mise à jour il y a un mois pour prendre un Process et un stateId au lieu d'une liste de membres, mais la gestion des processus de pairing était défaillante.

Symptômes :

  • checkConnections échouait pour les processus de pairing
  • Les adresses des membres n'étaient pas correctement récupérées
  • Erreur "Not a pairing process" même pour des processus de pairing valides

Solution Appliquée :

// Correction dans checkConnections pour gérer les pairedAddresses
if (members.size === 0) {
  // This must be a pairing process
  let publicData: Record<string, any> | null = null;
  if (!stateId) {
    publicData = process.states[process.states.length - 2]?.public_data;
  } else {
    publicData = process.states.find(state => state.state_id === stateId)?.public_data || null;
  }

  // If pairedAddresses is not in the current state, look in previous states
  if (!publicData || !publicData['pairedAddresses']) {
    // Look for pairedAddresses in previous states
    for (let i = process.states.length - 1; i >= 0; i--) {
      const state = process.states[i];
      if (state.public_data && state.public_data['pairedAddresses']) {
        publicData = state.public_data;
        break;
      }
    }
  }

  const decodedAddresses = this.decodeValue(publicData['pairedAddresses']);
  members.add({ sp_addresses: decodedAddresses });
}

2. Problème de confirmPairing avec getPairingProcessId()

Problème : confirmPairing échouait car getPairingProcessId() utilisait sdkClient.get_pairing_process_id() qui n'était pas encore disponible car le processus de pairing n'était pas encore committé.

Symptômes :

  • Erreur "Failed to get pairing process" dans confirmPairing
  • Le SDK n'avait pas encore le processus de pairing disponible
  • Échec de confirmation du pairing

Solution Appliquée :

public async confirmPairing(pairingId?: string) {
  try {
    console.log('confirmPairing');
    let processId: string;
    if (pairingId) {
      processId = pairingId;
      console.log('pairingId (provided):', processId);
    } else if (this.processId) {
      processId = this.processId;
      console.log('pairingId (from stored processId):', processId);
    } else {
      // Try to get pairing process ID, with retry if it fails
      let retries = 3;
      while (retries > 0) {
        try {
          processId = this.getPairingProcessId();
          console.log('pairingId (from SDK):', processId);
          break;
        } catch (e) {
          retries--;
          if (retries === 0) throw e;
          console.log(`Failed to get pairing process ID, retrying... (${retries} attempts left)`);
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
    }
    // ... rest of the method
  } catch (e) {
    console.error('Failed to confirm pairing');
    return;
  }
}

3. Problème de pairing_process_commitment à null

Problème : Le pairing_process_commitment restait à null dans le device dump car le device n'était pas synchronisé avec l'état committé du processus.

Symptômes :

  • pairing_process_commitment: null dans le device dump
  • Le commitment n'était pas synchronisé avec l'état committé du processus
  • Échec de la confirmation du pairing

Solution Appliquée :

// Intégration de updateDevice() dans waitForPairingCommitment
public async waitForPairingCommitment(processId: string, maxRetries: number = 10, retryDelay: number = 1000): Promise<void> {
  console.log(`Waiting for pairing process ${processId} to be committed...`);

  // First, try to update the device to sync with the committed state
  try {
    await this.updateDevice();
    console.log('Device updated, checking commitment...');
  } catch (e) {
    console.log('Failed to update device, continuing with polling...', e);
  }

  for (let i = 0; i < maxRetries; i++) {
    try {
      const device = this.dumpDeviceFromMemory();
      console.log(`Attempt ${i + 1}/${maxRetries}: pairing_process_commitment =`, device.pairing_process_commitment);

      // Check if the commitment is set and not null/empty
      if (device.pairing_process_commitment &&
          device.pairing_process_commitment !== null &&
          device.pairing_process_commitment !== '') {
        console.log('Pairing process commitment found:', device.pairing_process_commitment);
        return;
      }
    } catch (e) {
      console.log(`Attempt ${i + 1}/${maxRetries}: Device not ready yet - ${e}`);
    }

    if (i < maxRetries - 1) {
      await new Promise(resolve => setTimeout(resolve, retryDelay));
    }
  }

  throw new Error(`Pairing process ${processId} was not committed after ${maxRetries} attempts`);
}

Et simplification du router :

console.log("⏳ Waiting for pairing process to be committed...");
await services.waitForPairingCommitment(pairingId);

console.log("🔁 Confirming pairing...");
await services.confirmPairing(pairingId);

Architecture du Système de Pairing

Flux de Création du Pairing (Créateur)

  1. Création du processus : createPairingProcess("", [myAddress])
  2. Enregistrement du device : pairDevice(pairingId, [myAddress])
  3. Traitement de l'API : handleApiReturn(createPairingProcessReturn)
  4. Création de la mise à jour PRD : createPrdUpdate(pairingId, stateId)
  5. Approbation du changement : approveChange(pairingId, stateId)
  6. Attente du commit avec synchronisation : waitForPairingCommitment(pairingId) (inclut updateDevice())
  7. Confirmation du pairing : confirmPairing(pairingId)

Flux de Rejoindre le Pairing (Joiner) - ⚠️ INCOHÉRENT

Problème identifié : Le joiner n'a pas de flux de confirmation complet.

Flux actuel (incomplet) :

  1. Création avec liste vide : createPairingProcess("", [])
  2. Établissement des connexions : checkConnections(process)
  3. Pas de confirmation : Aucun waitForPairingCommitment ou confirmPairing

Flux attendu (cohérent) :

  1. Récupération du processus existant : getPairingProcessId()
  2. Rejoindre le processus : Pas de création, mais participation au processus existant
  3. Flux de confirmation complet : Même flux que le créateur
  4. Attente du commit : waitForPairingCommitment()
  5. Confirmation du pairing : confirmPairing()

Gestion des Connexions

La méthode checkConnections gère maintenant :

  • Processus normaux : Utilise les rôles pour trouver les membres
  • Processus de pairing : Utilise pairedAddresses des données publiques
  • Recherche dans les états précédents : Si pairedAddresses n'est pas dans l'état actuel
  • Décodage des adresses : Les données publiques sont encodées et nécessitent un décodage

Points Clés Appris

1. Encodage des Données Publiques

  • Les données publiques sont encodées avec this.sdkClient.encode_json()
  • pairedAddresses nécessite un décodage avec this.decodeValue()
  • Les données ne sont pas directement utilisables sans décodage

2. Gestion Multi-Hosts

  • Le créateur et le joiner peuvent être sur des hosts différents
  • Le joiner doit récupérer les adresses depuis le processus existant
  • this.processId n'est disponible que sur le même host

3. Synchronisation du SDK

  • Le SDK n'a pas immédiatement le processus de pairing disponible
  • Il faut attendre que le processus soit committé
  • updateDevice() est nécessaire pour synchroniser l'état

4. Gestion des États

  • Les processus de pairing peuvent avoir des mises à jour partielles
  • Il faut chercher pairedAddresses dans les états précédents si nécessaire
  • La logique de fallback est cruciale pour la robustesse

Version Actuelle

État des Corrections

  • checkConnections corrigé pour les processus de pairing
  • confirmPairing avec gestion des paramètres et retry
  • waitForPairingCommitment avec synchronisation automatique du device
  • Intégration de updateDevice() dans waitForPairingCommitment
  • Gestion des cas multi-hosts
  • Simplification du flux de création
  • ⚠️ Problème identifié : Incohérence entre créateur et joiner

Fonctionnalités Opérationnelles

  • Création de pairing : Fonctionne avec les adresses correctes
  • Rejoindre un pairing : Flux incomplet, pas de confirmation
  • Établissement des connexions : checkConnections trouve les membres
  • Confirmation du pairing : ⚠️ Seulement côté créateur, pas côté joiner
  • Synchronisation du commitment : Côté créateur, Côté joiner
  • Flux simplifié : Côté créateur, Côté joiner

Problèmes de Cohérence Identifiés

Incohérence Créateur vs Joiner

  • Créateur : Flux complet avec 7 étapes incluant confirmation
  • Joiner : Flux incomplet avec seulement 2 étapes, pas de confirmation
  • Impact : Le joiner ne suit pas le même processus de validation

Problèmes Spécifiques du Joiner

  1. Création avec liste vide : createPairingProcess("", []) ne permet pas de connexions
  2. Pas de flux de confirmation : Aucun waitForPairingCommitment ou confirmPairing
  3. Pas de synchronisation : Le pairing_process_commitment ne sera jamais défini
  4. Pas de validation : Le pairing n'est pas validé côté joiner

Améliorations Récentes

Synchronisation Automatique du Device

  • Intégration de updateDevice() : Appelé automatiquement dans waitForPairingCommitment
  • Gestion des erreurs : Continue le polling même si updateDevice() échoue
  • Logs détaillés : Suivi complet du processus de synchronisation
  • Temps d'attente augmenté : 30 tentatives × 2 secondes = 60 secondes max

Simplification du Flux

  • Moins d'étapes manuelles : updateDevice() intégré dans waitForPairingCommitment
  • Flux plus robuste : Gestion automatique de la synchronisation
  • Code plus maintenable : Logique centralisée dans une seule méthode

Points d'Attention

  • Le système nécessite que les deux côtés soient synchronisés
  • Les retry automatiques sont implémentés pour la robustesse
  • La gestion des erreurs est améliorée avec des logs détaillés
  • Le flux est maintenant plus prévisible et fiable
  • La synchronisation du device est automatique et robuste

Recommandations

Corrections Prioritaires

  1. Corriger le flux du joiner : Implémenter le même flux de confirmation que le créateur
  2. Unifier les processus : Le joiner devrait rejoindre un processus existant, pas en créer un nouveau
  3. Synchronisation bidirectionnelle : Les deux côtés doivent avoir le même niveau de validation

Tests et Monitoring

  1. Tests : Tester le pairing entre différents hosts avec les deux flux
  2. Monitoring : Surveiller les logs pour identifier les problèmes potentiels
  3. Performance : Optimiser les délais de retry si nécessaire
  4. Documentation : Maintenir cette documentation à jour avec les évolutions

Actions Immédiates

  1. Analyser le flux du joiner : Comprendre comment il devrait rejoindre un processus existant
  2. Implémenter la cohérence : Appliquer le même flux de confirmation aux deux côtés
  3. Valider la synchronisation : S'assurer que les deux côtés ont le même pairing_process_commitment

Cette analyse fournit une base solide pour comprendre et maintenir le système de pairing, mais révèle des incohérences importantes qui doivent être corrigées.