Files
IdeA/.ideai/memory/ticket95-adapter-aware-liveness-probe.md

3.7 KiB

name, description, metadata
name description metadata
ticket95-adapter-aware-liveness-probe memory note ticket95-adapter-aware-liveness-probe
type
project

#95 — Sonde de vivacité du rendez-vous devenue adapter-consciente

Type : correctif architecture / bug racine. Livré sur feature/rendezvous-liveness-probe-per-adapter (commit 376fc9f), AppImage 0.3.0 rebuildée.

Bug racine

Le rendez-vous idea_ask_agent (run_inactivity_watchdog, crates/application/src/orchestrator/rendezvous.rs) coupe en faux NoReply toute cible structurée dont le tour dépasse la fenêtre d'inactivité (défaut 600 s, = turn_timeout_ms du profil cible). Cause : la seule sonde de vivacité (transcript_activity_token) lisait le transcript Claude (~/.claude/projects/<encoded-cwd>/*.jsonl) — invisible pour OpenCode/Codex, et fragilise même Claude en mode -p headless si le transcript ne grossit pas mi-tour. has_probe=true mais la sonde renvoie None ⇒ bras (true,_,None)=>false ⇒ aucun réarmement ⇒ NoReply à la première fenêtre.

Fix (architecture figée)

  1. Port domaine (crates/domain/src/ports.rs) : AgentSession::activity_token() -> Option<u64> (défaut None, zéro régression). Jeton monotone = « la session travaille ».
  2. Machinerie (crates/infrastructure/src/session/process.rs) : run_turn_with_activity(...) bump un Arc<AtomicU64> à chaque ligne stdout lue (drain async ET drain sandboxé thread). run_turn (4 args) délègue avec None ⇒ les ~11 call sites de test sont intacts.
  3. Sessions : ClaudeSdkSession, CodexExecSession, OpenAiCompatibleSession overrident activity_token() via run_turn_with_activity ; OpenCodeSession (drain inline) bump son propre compteur par ligne JSONL.
  4. Sonde composite (resolve_ask_liveness_token, crates/backend/src/lib.rs) : préfère session.activity_token() de la session vivante (structured.session_for_agent), repli inchangé sur le transcript Claude. Câblée par .with_ask_liveness_probe.

Contrats clés

  • has_probe reste true dès qu'une sonde est câblée ; la sonde composite renvoie désormais Some(token) qui avance ⇒ la fenêtre se réarme. Le repli transcript Claude couvre le cas « session vivante sans override ».
  • La fenêtre = turn_timeout_ms du profil cible (turn_timeout_forliveness_for_agent), défaut ASK_AGENT_TIMEOUT 600 s. Pas d'env global pour la fenêtre (seul le plafond a IDEA_ASK_RENDEZVOUS_CEILING_MS, défaut 4 h).
  • Pour un test live rapide sans attendre 600 s : mettre un petit turn_timeout_ms (ex. 20 000) sur le profil de la cible, puis déléguer une tâche de ~60-90 s.

État validation

  • Tests unitaires verts : run_turn_with_activity_bumps_counter_per_line, *_session_activity_token_advances_across_a_turn (claude/codex/opencode), + la sonde composite backend + le watchdog rendezvous existants.
  • AppImage 0.3.0 rebuildée + installée (/home/anthony/Documents/IdeA_0.3.0_amd64.AppImage, backup .old-pre95fix). Relance IdeA requise pour l'activer (le binaire qui tourne = AppImage en mémoire ; relancer depuis l'intérieur tue la session courante).

À noter (dette / hors périmètre)

  • #96 (EffectivePermissions assistants de ticket) laissé ouvert, documenté dans le carnet #96 (décision produit différée).
  • Le souvenir utilisateur initial décrivait un échec « demandeur GLM/OpenCode → cible Claude ». Mécaniquement le watchdog est ciblé-cible (keyed sur l'agent cible) : un échec sur cible Claude longue n'est possible que si le transcript Claude -p ne grossit pas mi-tour (couvert désormais par l'activity_token de ClaudeSdkSession). La théorie principale reste « cible structurée longue non observée → faux NoReply ».