Files
vmux/.planning/research/PITFALLS.md
2026-03-23 11:25:05 +01:00

254 lines
17 KiB
Markdown

# Pitfalls Research
**Domain:** Session monitoring / terminal state detection / i3 IPC integration
**Researched:** 2026-03-23
**Confidence:** MEDIUM-HIGH
## Critical Pitfalls
### Pitfall 1: Session state inference from JSONL is fragile and undocumented
**What goes wrong:**
La structure des fichiers JSONL de Claude Code (`~/.claude/projects/<encoded-cwd>/*.jsonl`) n'est pas une API stable. Le format change entre versions sans avertissement. Les champs (`tool_use`, `tool_result`, `role`, `content.type`) peuvent etre renommes, restructures ou supprimes. Pire : un `tool_use` sans `tool_result` correspondant peut signifier "en cours" ou "plante", sans moyen de distinguer les deux.
**Why it happens:**
Les fichiers JSONL sont un detail d'implementation de Claude Code, pas un contrat d'API. Les outils communautaires (claude-sessions-monitor, clog, claude-JSONL-browser) parsent tous ce format, mais aucun n'a de garantie de stabilite.
**How to avoid:**
- Abstraire le parsing JSONL derriere une interface. Un seul module `session/parser.go` qui convertit le JSONL en structures internes. Un changement de format = un seul fichier a modifier.
- Detecter l'etat "attend input" via la combinaison : dernier message est `role: "assistant"` + pas de `tool_use` en cours + le process Claude tourne encore. Ne pas se fier a un seul signal.
- Ajouter un fallback process-based : si le JSONL est ambigu, verifier via `ps` si le process Claude ecrit encore (check du mtime du fichier JSONL).
**Warning signs:**
- Les tests de parsing echouent apres une mise a jour de Claude Code.
- L'etat affiche ("travaille") ne correspond pas a la realite observee dans le terminal.
**Phase to address:**
Phase 1 (detection des sessions). Concevoir l'abstraction des le depart.
---
### Pitfall 2: Les fichiers JSONL geants font exploser la memoire
**What goes wrong:**
Les sessions longues produisent des fichiers JSONL de plusieurs Go (cas documente : 3.8 Go). Charger ou scanner ces fichiers en entier pour determiner l'etat courant consomme toute la RAM disponible. Claude Code lui-meme souffre de ce probleme (issue #22365).
**Why it happens:**
Les JSONL grossissent sans limite a cause des progress ticks dupliques, sorties de commandes volumineuses et accumulation de metadata de sous-agents. Un monitoring naif qui lit tout le fichier a chaque poll va reproduire le meme probleme que Claude Code.
**How to avoid:**
- Ne JAMAIS charger un JSONL en entier. Lire uniquement les N dernieres lignes (tail-like) pour determiner l'etat courant. En Go : `io.SeekEnd` puis remonter jusqu'a trouver suffisamment de lignes.
- Seuil d'alerte : ignorer ou traiter differemment les fichiers > 50 Mo.
- Utiliser `sessions-index.json` comme source primaire de metadata (timestamps, branches, resumes) au lieu de parser chaque JSONL.
**Warning signs:**
- La consommation memoire de vmux grimpe avec le temps.
- Le temps de rafraichissement se degrade apres quelques heures.
**Phase to address:**
Phase 1. Implementer le tail-read des le premier prototype, pas en optimisation tardive.
---
### Pitfall 3: i3 IPC event subscription race conditions et deadlocks
**What goes wrong:**
Deux problemes documentes avec l'IPC i3 :
1. **Deadlock si les events ne sont pas consommes** : i3 queue les messages sortants avec un timeout de 10 secondes. Si le client ne lit pas les events assez vite, la connexion est terminee. Avec la lib Go officielle (`go.i3wm.org/i3/v4`), le `EventReceiver` DOIT etre lu en boucle via `Next()` sinon i3 deadlock quand le buffer Unix socket se remplit.
2. **Race conditions entre events et requetes** : des que l'on subscribe a un event, l'ordre de traitement des requetes n'est plus garanti. Un event `workspace` peut arriver avant la reponse a `GET_WORKSPACES`.
**Why it happens:**
L'IPC i3 utilise des sockets Unix sans backpressure. Le protocole n'est pas versionne et change a chaque release. La lib Go gere le retry automatique (10s) mais l'`EventReceiver` n'est PAS thread-safe.
**How to avoid:**
- Dedier une goroutine exclusivement a la consommation d'events (`recv.Next()` en boucle). Ne jamais bloquer cette goroutine.
- Separer les sockets : un pour les requetes (get_workspaces, get_tree), un pour les subscriptions d'events. La lib Go le gere, mais il faut comprendre que `Subscribe()` cree une connexion separee.
- Utiliser `i3.Restart()` au lieu de `RunCommand("restart")` (sinon retry infini).
- Gerer le cas ou i3 redemarrage : tous les etats IPC sont reinitialises, toutes les subscriptions perdues sauf une socket.
**Warning signs:**
- vmux se fige apres un certain temps.
- Les events workspace ne sont plus recus apres un `i3 restart` ou `i3 reload`.
**Phase to address:**
Phase 2 (integration i3). Test specifique : laisser vmux tourner, faire `i3 reload`, verifier que les events reprennent.
---
### Pitfall 4: Detection de process Claude Code non fiable par nom de process
**What goes wrong:**
Claude Code peut s'installer via npm (process Node.js) ou via l'installeur natif (binaire `claude`). Selon la methode, `ps aux | grep claude` donne des resultats differents. Avec npm, le process apparait comme `node` parmi des dizaines d'autres processes Node.js. Le nom change entre versions.
**Why it happens:**
Il n'y a pas d'identifiant stable pour un process Claude Code. Pas de PID file, pas de socket nommee, pas de dbus service. L'outil est concu pour etre interactif dans un terminal, pas pour etre observe de l'exterieur.
**How to avoid:**
- Strategie primaire : lister les fichiers dans `~/.claude/projects/` et correler avec les processes actifs via `/proc/[pid]/cwd` pour trouver les correspondances.
- Chercher le process par ses arguments de ligne de commande (`/proc/[pid]/cmdline`) plutot que par son nom.
- Croiser avec le mtime des fichiers JSONL : si le fichier est ecrit recemment (< 5s), la session est probablement active.
- Fallback : scanner les fenetres i3 dont le titre contient "claude" ou un pattern reconnaissable.
**Warning signs:**
- Des sessions sont detectees comme "idle" alors qu'elles travaillent.
- Apres une mise a jour de Claude Code, la detection casse silencieusement.
**Phase to address:**
Phase 1 (detection). Implementer au moins deux signaux independants (fichier + process) pour la detection d'etat.
---
### Pitfall 5: fsnotify/inotify ne garantit pas la correction pour le watch recursif
**What goes wrong:**
Le monitoring des fichiers JSONL via inotify (Go fsnotify) a des failles fondamentales :
1. **Buffer overflow** : les events sont delivres via un buffer de taille fixe, sans mecanisme de backpressure. Des events peuvent etre perdus silencieusement.
2. **Race TOCTTOU** : entre la reception d'un event de creation et l'ouverture du fichier, le fichier peut avoir ete supprime/renomme.
3. **Pas d'ordering garanti entre watchers multiples** : si on watch `~/.claude/projects/` et ses sous-repertoires, l'ordre des events entre watchers differents n'est pas lineaire.
**Why it happens:**
C'est une limitation fondamentale de l'API inotify Linux (documentee en detail par Andy Wingo). La perte d'events est "built-in" au design.
**How to avoid:**
- Utiliser inotify comme signal de "quelque chose a change", pas comme source de verite. Toujours re-scanner l'etat apres un event.
- Ajouter un poll periodique (toutes les 2-3 secondes) en complement de inotify. L'inotify sert a reduire la latence, le poll sert de filet de securite.
- Ne PAS tenter un watch recursif complexe. Watcher uniquement le repertoire racine `~/.claude/projects/` et les fichiers JSONL specifiques deja identifies.
- Attention aux limites systeme : chaque watch consomme un file descriptor. Verifier `fs.inotify.max_user_watches`.
**Warning signs:**
- Des sessions apparaissent/disparaissent avec du retard ou pas du tout.
- Le nombre de watchers augmente sans limite.
**Phase to address:**
Phase 1. Choisir l'architecture "inotify + poll" des le depart. Ne pas partir sur du inotify pur en pensant migrer plus tard.
---
### Pitfall 6: Associer un process Claude a un workspace i3 est plus dur qu'il n'y parait
**What goes wrong:**
La correspondance "session Claude Code <-> workspace i3" semble triviale (meme repertoire de travail) mais echoue dans plusieurs cas :
- Un terminal peut etre deplace d'un workspace a un autre sans que le cwd change.
- Plusieurs terminaux dans le meme workspace peuvent pointer vers des projets differents.
- Le window title du terminal ne contient pas forcement le chemin du projet.
- Apres un `i3 reload`, les metadata des conteneurs sont preservees mais les connexions IPC sont perdues.
**Why it happens:**
i3 gere des fenetres (containers), pas des sessions applicatives. Il n'y a pas de lien natif entre un workspace i3 et un repertoire de travail. La correspondance doit etre construite manuellement.
**How to avoid:**
- Approche recommandee : utiliser l'arbre i3 (`get_tree`) pour lister les fenetres, croiser le PID de la fenetre (`window_properties.instance` ou `_NET_WM_PID`) avec `/proc/[pid]/cwd` pour trouver le repertoire de travail.
- Alternative : exploiter les conventions de nommage de Pierre (worktrees = branches = noms de workspace). Matcher le nom du workspace avec le nom de la branche git detectee dans la session.
- Event `window::move` pour detecter les deplacements de fenetres entre workspaces.
- Bug i3 connu (fixe en 2018) : pas d'event `window::focus` quand on switch depuis un workspace vide. Verifier la version d'i3.
**Warning signs:**
- vmux affiche "workspace 3" pour une session qui est maintenant sur le workspace 5.
- Le switch vers un workspace n'amene pas a la bonne fenetre Claude.
**Phase to address:**
Phase 2 (integration i3). Tester systematiquement les cas de deplacement de fenetres.
---
## Technical Debt Patterns
| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable |
|----------|-------------------|----------------|-----------------|
| Parser JSONL couple au format actuel | Rapide a implementer | Casse a chaque mise a jour Claude Code | Jamais, abstraire des le depart |
| Polling seul (sans inotify) | Simple, correct | Latence 2-3s sur la detection d'etat | MVP Phase 1 uniquement |
| Lecture complete du JSONL | Code simple, pas de seek | OOM sur sessions longues | Jamais |
| Hardcoder le nom de process "claude" | Detection rapide | Casse si installation npm ou changement de binaire | Jamais |
| Stocker l'association workspace en cache sans invalider | Moins de requetes i3 | Desynchronisation apres deplacement de fenetre | OK si invalide sur event window::move |
## Integration Gotchas
| Integration | Common Mistake | Correct Approach |
|-------------|----------------|------------------|
| i3 IPC events | Ne pas consommer les events assez vite | Goroutine dediee, jamais de traitement bloquant dans la boucle d'events |
| i3 `RunCommand("restart")` | Appeler via RunCommand (retry infini) | Utiliser `i3.Restart()` de la lib Go |
| i3 `get_tree` | Parcourir l'arbre entier a chaque refresh | Cacher le resultat, invalider sur events `window::new`, `window::close`, `window::move` |
| Claude JSONL | Parser le fichier entier | Tail-read des N dernieres lignes |
| `sessions-index.json` | Ignorer ce fichier et parser chaque JSONL | L'utiliser comme index primaire pour les metadonnees |
| `/proc/[pid]/cwd` | Ne pas gerer les erreurs de permission | Les process d'autres utilisateurs retournent EACCES, gerer gracieusement |
## Performance Traps
| Trap | Symptoms | Prevention | When It Breaks |
|------|----------|------------|----------------|
| Scan complet de `~/.claude/projects/` a chaque tick | CPU spike periodique | Index incrementiel via inotify + rescan periodique | > 20 projets avec historique |
| Lecture entiere des JSONL pour l'etat | RAM qui grimpe, freeze | Tail-read (derniers 4 Ko) | Fichiers > 50 Mo |
| `get_tree` a chaque rafraichissement | Latence perceptible | Cache + invalidation par events | > 30 fenetres ouvertes |
| Polling agressif (< 500ms) | CPU constant a 5-10% | Poll 2-3s + inotify pour la reactivite | Toujours, meme avec peu de sessions |
| Ouverture de N watchers inotify | File descriptors epuises | Watcher sur le repertoire parent, pas par fichier | > 50 sessions/projets |
## Security Mistakes
| Mistake | Risk | Prevention |
|---------|------|------------|
| Lire les JSONL d'un autre utilisateur via /proc | Violation de vie privee, fuite de tokens API | vmux ne monitore QUE les sessions de l'utilisateur courant ($HOME) |
| Afficher le contenu des messages Claude en clair | Exposition de code/secrets dans le preview | Tronquer, pas de secrets, afficher seulement le dernier message assistant |
| Executer des commandes i3 basees sur du contenu JSONL non sanitize | Injection de commandes i3 | Ne jamais interpoler du contenu JSONL dans des commandes i3 |
## UX Pitfalls
| Pitfall | User Impact | Better Approach |
|---------|-------------|-----------------|
| Afficher "idle" quand la session charge (JSONL pas encore ecrit) | L'utilisateur ignore une session qui demarre | Etat "starting" base sur l'age du process vs le dernier write JSONL |
| Notification a chaque changement d'etat, meme rapide | Spam de notifications quand Claude enchaine les tool_use | Debounce : notifier seulement apres 3s dans l'etat "attend input" |
| Forcer le focus i3 automatiquement | Interrompt le travail en cours | Notifier + keybind pour switcher volontairement |
| Ne pas montrer depuis combien de temps la session attend | Pas de priorisation possible | Afficher le temps d'attente relatif ("il y a 2 min") |
| Preview trop long ou trop technique | L'utilisateur ne comprend pas ce que la session fait | Extraire le dernier message "humain" (pas tool_result), tronquer a 1-2 lignes |
## "Looks Done But Isn't" Checklist
- [ ] **Detection de sessions :** Fonctionne avec l'installeur natif ET npm. Tester les deux.
- [ ] **Etat "travaille" :** Verifier que le process ecrit encore (mtime), pas seulement que le dernier message est `tool_use`.
- [ ] **i3 integration :** Tester apres `i3 reload` et `i3 restart`. Les subscriptions survivent-elles ?
- [ ] **Gros fichiers :** Tester avec un JSONL de > 100 Mo. vmux reste-il reactif ?
- [ ] **Multi-ecran :** Le workspace est sur l'ecran 2, le switch via vmux amene bien a l'ecran 2, pas l'ecran 1.
- [ ] **Session fantome :** Le process Claude a crash mais le JSONL n'a pas de message de fin. vmux detecte-t-il "mort" ?
- [ ] **Nouveau projet :** Un nouveau repertoire apparait dans `~/.claude/projects/` pendant que vmux tourne. Detecte ?
- [ ] **Latence notification :** Le delai entre "Claude attend" et la notification vmux est < 5 secondes.
## Recovery Strategies
| Pitfall | Recovery Cost | Recovery Steps |
|---------|---------------|----------------|
| Format JSONL change apres update Claude | LOW (si abstrait) | Mettre a jour le module parser, re-deployer |
| Deadlock i3 IPC | LOW | Reconnexion auto via la lib Go (retry 10s) |
| OOM sur gros JSONL | MEDIUM | Kill vmux, implementer le tail-read, relancer |
| Desync workspace mapping | LOW | Forcer un rescan complet de l'arbre i3 (bouton/keybind refresh) |
| inotify events perdus | LOW | Le poll periodique rattrape automatiquement |
| Detection process cassee | MEDIUM | Ajouter un nouveau signal de detection (ex: window title) en complement |
## Pitfall-to-Phase Mapping
| Pitfall | Prevention Phase | Verification |
|---------|------------------|--------------|
| JSONL parsing fragile | Phase 1 (detection) | Interface abstraite, tests avec des JSONL reels |
| JSONL memoire | Phase 1 (detection) | Benchmark avec fichier > 100 Mo, memoire < 50 Mo |
| i3 IPC deadlock | Phase 2 (i3 integration) | Test de charge : 100 events/s pendant 60s |
| i3 reconnexion | Phase 2 (i3 integration) | `i3 reload` pendant que vmux tourne |
| Detection process | Phase 1 (detection) | Tester avec install native + npm, process mort |
| inotify fiabilite | Phase 1 (detection) | Creer/supprimer des fichiers rapidement, verifier que vmux suit |
| Mapping workspace | Phase 2 (i3 integration) | Deplacer une fenetre, verifier la mise a jour |
| Notifications spam | Phase 3 (notifications) | Session qui enchaine tool_use : 0 notification jusqu'a idle stable |
| UX preview | Phase 3 (UI) | Tester avec des sessions reelles, verifier la lisibilite |
## Sources
- [i3 IPC documentation](https://i3wm.org/docs/ipc.html) - Event subscription, socket buffer, reconnexion
- [go.i3wm.org/i3/v4](https://pkg.go.dev/go.i3wm.org/i3/v4) - Lib Go officielle, EventReceiver deadlock, Restart()
- [Missing window::focus event #3562](https://github.com/i3/i3/issues/3562) - Bug event focus depuis workspace vide (fixe)
- [claude-sessions-monitor](https://github.com/yepzdk/claude-sessions-monitor) - Approche detection par JSONL
- [Large JSONL issue #22365](https://github.com/anthropics/claude-code/issues/22365) - OOM sur gros fichiers session
- [Correct or inotify: pick one](https://wingolog.org/archives/2018/05/21/correct-or-inotify-pick-one) - Limites fondamentales d'inotify
- [fsnotify Go package](https://pkg.go.dev/github.com/fsnotify/fsnotify) - Race conditions, limites watchers
- [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference) - Session storage structure
- [Baeldung: View process output](https://www.baeldung.com/linux/output-process-another-session) - /proc/pid/fd, pseudo-terminal
---
*Pitfalls research for: vmux - Claude Code session monitoring with i3 integration*
*Researched: 2026-03-23*