Adds internal/symlinks package that encodes in code the convention previously maintained by hand on the VM: every Claude account home must expose `session-env`, `file-history` and `projects` as symlinks to a single shared target, so account failover does not create divergent state (duplicate JSONL transcripts, broken undo history). - EnsureForAccount(home, required) creates missing links and target directories, refuses to auto-correct a divergent link (risks data loss), and errors when a regular file sits where the link belongs. - ValidateAll(homes, required) aggregates errors across both accounts so the operator sees every problem at once rather than fixing one per restart cycle. - RequiredShared exposes the production defaults so lifecycle and switcher (A2/A3) can depend on it directly. 9/9 unit tests green. Part of Phase 1 Chantier A — Failover robuste.
78 lines
4.1 KiB
Markdown
78 lines
4.1 KiB
Markdown
# Travaux en Cours - claude-failover
|
|
|
|
## Dernière mise à jour
|
|
2026-04-16 19:00:00
|
|
|
|
## Version Actuelle
|
|
0.3.5 (en cours de progression vers 0.4.0)
|
|
|
|
## Demande Actuelle
|
|
**Phase 1 / Chantier A — Failover robuste** (spec dans `ccl-platform/phases/phase1/A-failover.md`).
|
|
Rendre le failover compte1 ↔ compte2 déterministe en intégrant dans le code les fixes manuels
|
|
(symlinks partagés), en ajoutant un registre UUID fiable, et en durcissant tmux send-keys.
|
|
|
|
Branche : `feat/phase1-A-failover-robust`.
|
|
|
|
## Sous-tâches Chantier A
|
|
- [x] A1 — `internal/symlinks/shared.go` (+ tests) — v0.3.5
|
|
- [ ] A2 — `lifecycle/manager.go` : `ValidateAll` au startup
|
|
- [ ] A3 — `switcher/account_switcher.go` : `EnsureForAccount` post-flip
|
|
- [ ] A4 — `internal/registry/uuid_registry.go` (+ tests)
|
|
- [ ] A5 — `internal/tmux/send.go` avec retry exponentiel (+ tests)
|
|
- [ ] A6 — Capture UUID 200 → 500 lignes
|
|
- [ ] A7 — `scripts/test-failover.sh` dans ccl-platform + scripts associés
|
|
|
|
## Étapes Complétées
|
|
- [x] v0.2.1 — Cooldown post-swap + log forensique (trigger_session, pattern, snippet)
|
|
- [x] v0.2.2 — Confirmation 2-polls pour les hits sans reset time
|
|
- [x] v0.2.3 — Veto 5xx (`api_error` / `overloaded_error` / `internal server error`)
|
|
et retrait du pattern générique `"rate limit"` (remplacé par `rate_limit_error`)
|
|
- [x] Documentation : `docs/architecture.md` §2.2.1 "False-positive protection"
|
|
- [x] Tests unitaires exhaustifs (14 cas pour `isQuotaExhausted` dont les 3 veto 5xx)
|
|
- [x] Déploiement prod : `/usr/local/bin/claude-failover` + service redémarré
|
|
- [x] Push sur Forgejo `origin/main` (commits `7c5f838` et `62e98cb`)
|
|
|
|
## Prochaines Étapes
|
|
- [x] ~~préserver les sessions dédiées lors d'un swap légitime~~ — fait en v0.3.0
|
|
via `saveDedicatedUUIDs` + `relaunchDedicatedSessions`.
|
|
- [ ] **Optionnel** : telegram alert quand `SwapRequested` est émis pour
|
|
que l'opérateur soit au courant sans lire les logs. Le `notifier.Telegram`
|
|
existe déjà — il suffit de câbler.
|
|
- [ ] **Optionnel** : exposer `/quota/status` via `internal/api` avec les champs
|
|
`last_swap_at`, `suspected_hit_at`, `cooldown_remaining` pour le dashboard.
|
|
|
|
## Contexte Important
|
|
- **Symptôme en prod (2026-04-15)** : daemon faisait des swaps compte1↔compte2
|
|
en boucle (intervalle descendant à 1 min), tuant les sessions interactives
|
|
ccl-1 et ccl-2 en permanence. `reset=""` sur tous les events.
|
|
- **Cause racine identifiée via le log forensique v0.2.1** : les 500 d'Anthropic
|
|
contenaient le texte "rate limit" dans leur payload. Snippet capturé :
|
|
`API Error: 500 {"type":"error","error":{"type":"api_error",...}}`.
|
|
Le monitor les confondait avec de vrais 429.
|
|
- **Config `reactivate_cooldown: "5m"`** existait déjà dans config.yaml mais
|
|
n'était consommée que par le dispatcher — pas par le monitor. v0.2.1 a
|
|
branché le monitor dessus.
|
|
- **Comptes disponibles** : `compte1` (Claude Max), `compte2` (Claude Team).
|
|
Symlink actuel : `~/.claude → .claude-compte2`.
|
|
- **Sessions tmux gérées** : pool autonome `ccl-auto-*` (min=2, max=10) +
|
|
dédiées `ccl-1-conformvault`, `ccl-2-scanyze`.
|
|
|
|
## Fichiers Modifiés (cette série de fixes)
|
|
- `internal/quota/monitor.go` — quotaPatterns, serverErrorPatterns, suspectedHitAt, cooldown
|
|
- `internal/quota/monitor_test.go` — 14 sous-tests isQuotaExhausted + 3 tests poll
|
|
- `internal/state/state.go` — LastSwapAt/From/To + RecordSwap + LastSwapInfo
|
|
- `internal/switcher/account_switcher.go` — appel `state.RecordSwap()` après swap
|
|
- `docs/architecture.md` — §2.2.1 False-positive protection
|
|
- `VERSION.md` — changelog 0.2.1 → 0.2.3
|
|
|
|
## Bugs Connus
|
|
- **Sessions dédiées tuées lors d'un swap légitime** : comportement documenté
|
|
et voulu (respawn sur le nouveau compte), mais coupe brutalement le travail
|
|
interactif en cours. Voir Prochaines Étapes.
|
|
|
|
## Historique des Demandes (Récentes)
|
|
| Date | Version | Demande | Status |
|
|
|------|---------|---------|--------|
|
|
| 2026-04-15 | 0.2.1 | Casser le ping-pong + logs forensiques | Terminé |
|
|
| 2026-04-15 | 0.2.2 | Confirmation 2-polls pour absorber les flashes | Terminé |
|
|
| 2026-04-15 | 0.2.3 | Veto 5xx + patterns stricts (root cause) | Terminé |
|