docs(phase-04): add verification and summary for plan 04-02
This commit is contained in:
@@ -76,7 +76,7 @@ Plans:
|
||||
|
||||
Plans:
|
||||
- [x] 04-01-PLAN.md — Notifications dunst (Working->Needs Input), mode focus avec timer, CLI vmux focus
|
||||
- [ ] 04-02-PLAN.md — Widget i3bar avec format compact, wrapping i3status, CLI vmux i3bar
|
||||
- [x] 04-02-PLAN.md — Widget i3bar avec format compact, wrapping i3status, CLI vmux i3bar
|
||||
|
||||
## Progress
|
||||
|
||||
|
||||
77
.planning/phases/04-notifications-et-i3bar/04-02-SUMMARY.md
Normal file
77
.planning/phases/04-notifications-et-i3bar/04-02-SUMMARY.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
phase: 04-notifications-et-i3bar
|
||||
plan: 02
|
||||
subsystem: cli
|
||||
tags: [i3bar, i3status, json-protocol]
|
||||
|
||||
requires:
|
||||
- phase: 04-01
|
||||
provides: shortName function, Notifier, FocusTimer
|
||||
provides:
|
||||
- i3bar JSON widget with session status
|
||||
- i3status wrapping for combined output
|
||||
- CLI vmux i3bar subcommand
|
||||
affects: []
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [i3bar JSON protocol, i3status wrapper, TTY detection for mode selection]
|
||||
|
||||
key-files:
|
||||
created: [i3bar.go, i3bar_test.go]
|
||||
modified: [main.go]
|
||||
|
||||
key-decisions:
|
||||
- "TTY detection: standalone mode in terminal, wrapped mode when called by i3bar"
|
||||
- "Format: vmux: auth[!] portal[W] neia[I] with shortName from notify.go"
|
||||
|
||||
patterns-established:
|
||||
- "i3bar JSON protocol: header + infinite array of block arrays"
|
||||
|
||||
requirements-completed: [I3-03]
|
||||
|
||||
duration: 5min
|
||||
completed: 2026-03-23
|
||||
---
|
||||
|
||||
# Plan 04-02 Summary
|
||||
|
||||
**Widget i3bar avec liste courte des sessions, wrapping i3status, détection TTY pour mode standalone/wrapped**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 5 min
|
||||
- **Tasks:** 3 (2 code + 1 human-verify)
|
||||
- **Files modified:** 3
|
||||
|
||||
## Accomplishments
|
||||
- formatI3BarBlocks : format compact `vmux: auth[!] portal[W]`
|
||||
- runI3Bar : standalone (TTY) ou wrapped (pipe/i3bar)
|
||||
- 10 tests unitaires pour le formatage
|
||||
- TTY detection pour éviter le fallback i3status texte brut
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: Formatage i3bar + tests** - `a28e8d6`
|
||||
2. **Task 2: Boucle i3bar + CLI** - `221a444`
|
||||
3. **Task 3: Human verification** - approved
|
||||
4. **Fix TTY detection** - uncommitted (sera commité avec la validation globale)
|
||||
|
||||
## Files Created/Modified
|
||||
- `i3bar.go` — I3BarBlock, formatI3BarBlocks, queryVmuxBlock, runI3Bar (standalone + wrapped)
|
||||
- `i3bar_test.go` — 10 tests unitaires
|
||||
- `main.go` — case "i3bar" + isTerminal()
|
||||
|
||||
## Decisions Made
|
||||
- Mode standalone quand stdout est un TTY, wrapped quand c'est un pipe
|
||||
- Pas de dépendance externe pour la détection TTY (os.ModeCharDevice)
|
||||
|
||||
## Deviations from Plan
|
||||
- Ajout de isTerminal() pour fixer le bug i3status plain text
|
||||
|
||||
## Next Phase Readiness
|
||||
- Dernière phase. Projet v1 complet.
|
||||
|
||||
---
|
||||
*Phase: 04-notifications-et-i3bar*
|
||||
*Completed: 2026-03-23*
|
||||
133
.planning/phases/04-notifications-et-i3bar/04-VERIFICATION.md
Normal file
133
.planning/phases/04-notifications-et-i3bar/04-VERIFICATION.md
Normal file
@@ -0,0 +1,133 @@
|
||||
---
|
||||
phase: 04-notifications-et-i3bar
|
||||
verified: 2026-03-23T21:00:00Z
|
||||
status: human_needed
|
||||
score: 3/3 must-haves verified
|
||||
human_verification:
|
||||
- test: "Lancer une session Claude Code active, declencher une transition Working -> Needs Input via un hook reel"
|
||||
expected: "Une notification dunst apparait dans la barre de notifications"
|
||||
why_human: "Necessite notify-send + dunst installe et display actif. Impossible a tester sans env graphique."
|
||||
- test: "Configurer i3bar avec status_command = vmux i3bar, puis recharger i3"
|
||||
expected: "Un bloc vmux apparait dans la barre i3 avec le statut des sessions. Couleur rouge si une session attend, verte sinon."
|
||||
why_human: "Necessite un environnement i3 en cours d'execution avec le daemon vmux actif."
|
||||
- test: "Tester vmux i3bar en standalone: lancer ./vmux i3bar dans un terminal"
|
||||
expected: "Header {\"version\":1}, puis [, puis lignes JSON avec bloc vmux toutes les 2 secondes"
|
||||
why_human: "Necessite que le daemon tourne. Verification du format visuel en temps reel."
|
||||
---
|
||||
|
||||
# Phase 4: Notifications et i3bar - Rapport de Verification
|
||||
|
||||
**Phase Goal:** L'utilisateur est notifie passivement quand une session a besoin de lui, sans ouvrir vmux
|
||||
**Verifie:** 2026-03-23
|
||||
**Statut:** human_needed
|
||||
**Re-verification:** Non (verification initiale)
|
||||
|
||||
## Resultats par critere de succes
|
||||
|
||||
### Verites observables
|
||||
|
||||
| # | Verite | Statut | Preuve |
|
||||
|---|--------|--------|--------|
|
||||
| 1 | Une notification dunst apparait quand une session passe de "Working" a "Needs Input" | VERIFIED | `hook.go:84` — condition `state == "Needs Input" && prevState == "Working" && !d.focus.IsActive()` + `d.notifier.Notify(...)`. Tests `TestNotification_WorkingToNeedsInput` et `TestNotification_FocusExpired` passent. |
|
||||
| 2 | Le mode focus supprime temporairement les notifications (`vmux focus <minutes>`) | VERIFIED | `main.go:105-130` — `case "focus"` parse les minutes, envoie `FocusArgs` au daemon. `daemon.go:446-453` — `d.focus.Set(...)`. `hook.go:84` — `!d.focus.IsActive()` bloque la notif. Test `TestFocusHandler` + `TestNotification_FocusActive` passent. |
|
||||
| 3 | Un widget i3bar affiche en temps reel le nombre de sessions et combien attendent de l'input | VERIFIED | `i3bar.go` complet avec `formatI3BarBlocks`, `queryVmuxBlock`, `runI3Bar` (standalone + wrapped). `main.go:145-158` — `case "i3bar"` avec detection TTY. 10 tests dans `i3bar_test.go` passent. |
|
||||
|
||||
**Score:** 3/3 verites verifiees
|
||||
|
||||
### Artefacts requis
|
||||
|
||||
| Artefact | Fournit | Niveau 1 (Existe) | Niveau 2 (Substantiel) | Niveau 3 (Cable) | Statut |
|
||||
|----------|---------|-------------------|------------------------|------------------|--------|
|
||||
| `notify.go` | `Notifier` interface, `ExecNotifier`, `NullNotifier`, `shortName` | Oui | 44 lignes, implementation reelle avec `exec.Command` + timeout 5s | Importe via `d.notifier` dans `daemon.go` et `hook.go` | VERIFIED |
|
||||
| `notify_test.go` | Tests `ExecNotifier`, `NullNotifier`, `shortName` | Oui | 5 tests substantiels | N/A (test file) | VERIFIED |
|
||||
| `focus.go` | `FocusTimer` thread-safe (Set/IsActive/Remaining) | Oui | 38 lignes, mutex, logique correcte | Utilise dans `daemon.go` champ `focus *FocusTimer` et `hook.go` | VERIFIED |
|
||||
| `focus_test.go` | Tests `FocusTimer` | Oui | 4 tests couvrant Set/Expired/Remaining/ZeroValue | N/A (test file) | VERIFIED |
|
||||
| `i3bar.go` | `I3BarBlock`, `formatI3BarBlocks`, `queryVmuxBlock`, `runI3Bar` | Oui | 177 lignes, protocole i3bar complet, wrapping i3status | Appele depuis `main.go case "i3bar"` | VERIFIED |
|
||||
| `i3bar_test.go` | Tests formatage i3bar | Oui | 10 tests couvrant tous les cas | N/A (test file) | VERIFIED |
|
||||
|
||||
### Verification des liens cles (Niveau 3)
|
||||
|
||||
| De | Vers | Via | Statut | Detail |
|
||||
|----|------|-----|--------|--------|
|
||||
| `hook.go` | `notify.go` | `d.notifier.Notify()` apres transition Working -> Needs Input | WIRED | `hook.go:88` — `d.notifier.Notify("vmux: "+shortName(info), ...)` |
|
||||
| `hook.go` | `focus.go` | `d.focus.IsActive()` pour bloquer les notifications | WIRED | `hook.go:84` — `!d.focus.IsActive()` dans la condition |
|
||||
| `main.go` | `daemon.go` | `case "focus"` envoie action focus au daemon | WIRED | `main.go:105` — `case "focus"`, `daemon.go:446` — `case "focus"` |
|
||||
| `i3bar.go` | `protocol.go` | `formatI3BarBlocks` consomme `[]SessionInfo` | WIRED | `i3bar.go:24` — `func formatI3BarBlocks(sessions []SessionInfo)` |
|
||||
| `main.go` | `i3bar.go` | `case "i3bar"` appelle `runI3Bar` | WIRED | `main.go:145` — `case "i3bar"`, `main.go:158` — `runI3Bar(sockPath, i3statusCmd)` |
|
||||
|
||||
### Trace de flux de donnees (Niveau 4)
|
||||
|
||||
| Artefact | Variable | Source | Produit des donnees reelles | Statut |
|
||||
|----------|----------|--------|-----------------------------|--------|
|
||||
| `i3bar.go` | `sessions []SessionInfo` | `queryVmuxBlock` -> `client.Send(Request{Action: "list"})` -> daemon socket | Oui — le daemon repond avec les sessions actives depuis le registre | FLOWING |
|
||||
| `hook.go` | `prevState` | `d.registry.sessions[event.SessionID].PrevState` | Oui — lu depuis le registre avant `UpdateFromHook` | FLOWING |
|
||||
|
||||
### Verifications comportementales (Spot-checks)
|
||||
|
||||
| Comportement | Commande | Resultat | Statut |
|
||||
|--------------|----------|----------|--------|
|
||||
| Build propre | `nix-shell -p go --run "go build -o /dev/null ."` | `build OK` | PASS |
|
||||
| Suite de tests complete avec race detector | `nix-shell -p go --run "go test ./... -count=1 -race"` | `ok github.com/pieMusic/vmux 7.169s` | PASS |
|
||||
| Tests notification (5 tests) | `go test -run 'TestNotification\|TestFocusHandler'` | Tous PASS | PASS |
|
||||
| Tests FocusTimer (4 tests) | `go test -run 'TestFocusTimer'` | Tous PASS | PASS |
|
||||
| Tests shortName (4 tests) | `go test -run 'TestShortName'` | Tous PASS | PASS |
|
||||
| Tests formatI3Bar (10 tests) | `go test -run 'TestFormatI3Bar'` | Tous PASS | PASS |
|
||||
| notification dunst reelle | Necessite display actif | Non testable en CI | SKIP |
|
||||
| widget i3bar dans barre i3 | Necessite i3 + daemon actif | Non testable en CI | SKIP |
|
||||
|
||||
### Couverture des requirements
|
||||
|
||||
| Requirement | Plan source | Description | Statut | Preuve |
|
||||
|-------------|-------------|-------------|--------|--------|
|
||||
| NOTIF-01 | 04-01-PLAN.md | vmux notifie (dunst) quand une session passe de "travaille" a "attend input" | SATISFIED | `hook.go:84-88` — condition + appel `d.notifier.Notify`. Tests `TestNotification_WorkingToNeedsInput`, `TestNotification_IdleToNeedsInput` (negatif). |
|
||||
| NOTIF-02 | 04-01-PLAN.md | vmux supporte un mode focus qui supprime temporairement les notifications | SATISFIED | `focus.go` — `FocusTimer`. `daemon.go:446-453` — handler "focus". `main.go:105-130` — CLI `vmux focus <minutes>`. Test `TestNotification_FocusActive`. |
|
||||
| I3-03 | 04-02-PLAN.md | vmux fournit un widget i3bar affichant le statut des sessions en temps reel | SATISFIED (code OK, verification visuelle necessaire) | `i3bar.go` complet. `main.go:145-158` — `case "i3bar"`. 10 tests passent. Note: `REQUIREMENTS.md` a encore `[ ]` au lieu de `[x]` pour I3-03 — inconsistance documentaire. |
|
||||
|
||||
**Note:** `REQUIREMENTS.md` marque encore I3-03 comme `Pending` (`[ ]` a la ligne 28 et `Pending` dans la table de tracabilite ligne 79). L'implementation est complete mais le fichier n'a pas ete mis a jour. Ce n'est pas un gap fonctionnel.
|
||||
|
||||
### Verite non testee du prompt de verification
|
||||
|
||||
Le prompt indique `vmux focus on/off` comme critere de succes. Le ROADMAP.md dit `vmux focus <minutes>`. L'implementation utilise un timer (pas un toggle on/off), ce qui est conforme au ROADMAP et aux decisions de conception D-04. La formulation `on/off` dans le prompt est incorrecte — le critere reel est satisfait.
|
||||
|
||||
### Anti-patterns detectes
|
||||
|
||||
Aucun anti-pattern bloquant. `TestExecNotifier_CallsNotifySend` dans `notify_test.go` est minimaliste (verifie uniquement l'interface, pas l'appel reel a `notify-send`) mais c'est une limitation justifiee : le test reel necessite un display actif, il est delogue en verification manuelle.
|
||||
|
||||
### Verification humaine requise
|
||||
|
||||
#### 1. Notification dunst lors d'une transition reelle
|
||||
|
||||
**Test:** Avec un daemon vmux actif et dunst qui tourne, declencher un hook `Stop` sur une session en etat "Working" (par exemple en laissant Claude Code finir une tache).
|
||||
**Attendu:** Une notification dunst apparait avec le titre `vmux: <nom-session>` et le corps `Session needs input (question)`.
|
||||
**Pourquoi humain:** Necessite `notify-send` installe, un display X11/Wayland actif, et dunst en cours d'execution. L'environment de CI n'a pas ces prerequis.
|
||||
|
||||
#### 2. Widget i3bar dans la barre i3
|
||||
|
||||
**Test:** Ajouter `status_command /chemin/vers/vmux i3bar` dans `~/.config/i3/config`, recharger i3 (`i3-msg reload`), s'assurer que le daemon vmux tourne.
|
||||
**Attendu:** Un bloc `vmux: all working (N)` (vert) ou `vmux: nom[!]` (rouge) apparait dans la barre i3 aux cotes des infos systeme de i3status. Rafraichissement toutes les 2 secondes.
|
||||
**Pourquoi humain:** Necessite un environnement i3 actif avec le daemon et au moins une session Claude Code.
|
||||
|
||||
#### 3. Mode standalone vmux i3bar
|
||||
|
||||
**Test:** Dans un terminal, lancer `./vmux i3bar` (avec le daemon actif).
|
||||
**Attendu:** Affichage du header `{"version":1}`, puis `[`, puis une ligne JSON toutes les 2 secondes du type `[{"full_text":"vmux: all working (N)","color":"#00ff00","name":"vmux"}]`.
|
||||
**Pourquoi humain:** Necessite le daemon actif et des sessions detectees. La sortie visuelle est difficile a valider automatiquement en mode interactif.
|
||||
|
||||
---
|
||||
|
||||
## Resume
|
||||
|
||||
Phase 4 atteint son objectif fonctionnel. Les trois mecanismes cles sont implementes, cables et testes :
|
||||
|
||||
1. **Notifications** : `ExecNotifier` appelle `notify-send --urgency=critical` sur la seule transition pertinente (Working -> Needs Input). Les 4 scenarios de notification (normal, idle->needsinput, focus actif, focus expire) sont couverts par des tests avec `spyNotifier`.
|
||||
|
||||
2. **Mode focus** : `FocusTimer` thread-safe avec Set/IsActive/Remaining. CLI `vmux focus <minutes>` fonctionne de bout en bout via le daemon. Le focus bloque les notifications mais pas l'i3bar (D-05 respecte).
|
||||
|
||||
3. **Widget i3bar** : `formatI3BarBlocks` produit le format compact `vmux: auth[!] portal[W]` avec les bonnes couleurs. `runI3Bar` implemente le protocole i3bar v1 en mode standalone et en mode wrapping i3status. La detection TTY evite le fallback texte brut.
|
||||
|
||||
La seule chose non verifiable automatiquement est le rendu visuel final dans l'environnement graphique (dunst + i3bar).
|
||||
|
||||
---
|
||||
|
||||
_Verifie : 2026-03-23_
|
||||
_Verificateur : Claude (gsd-verifier)_
|
||||
Reference in New Issue
Block a user