feat(switcher): ensure shared symlinks on target home after flip (A3)
Wire symlinks.EnsureForAccount into executeSwitch, called immediately after the ~/.claude flip. Guarantees the three shared-state links (session-env, file-history, projects) exist on the target account home even for freshly-provisioned accounts, preventing silent transcript duplication and undo-history divergence on first resume. Best-effort: errors are logged as WARN but never abort the swap. If we returned here the daemon would be left inconsistent (symlink flipped, SetActiveAccount never called). Operator sees the warning in logs and resolves divergent links manually. Tests: - TestFlipReconcilesSharedSymlinksOnTargetHome: empty target home gets all three links pointing at canonical targets after the flip. - TestFlipEnsureSymlinksFailureDoesNotAbortSwap: a planted divergent link triggers the symlinks-package error; the swap completes anyway and the active account is updated. Hermetic: added AccountSwitcher.sharedSymlinks override so tests scope the reconcile inside t.TempDir() and never touch /home/ubuntu/.claude-*-shared. Existing tests migrated to this pattern and hardcoded /tmp/claude-*-xxxx paths replaced with tmpdirs. Phase 1 / Chantier A — task A3.
This commit is contained in:
parent
e16e3526a0
commit
8eaf0bbd35
3 changed files with 204 additions and 4 deletions
46
VERSION.md
46
VERSION.md
|
|
@ -1,4 +1,48 @@
|
|||
# Version actuelle : 0.3.6
|
||||
# Version actuelle : 0.3.7
|
||||
|
||||
## [0.3.7] - 2026-04-16
|
||||
**Type:** Patch — Phase 1 / Chantier A3 : wire EnsureForAccount post-flip
|
||||
|
||||
### Ajouté
|
||||
- `AccountSwitcher.executeSwitch` appelle désormais
|
||||
`symlinks.EnsureForAccount(target.Home, ...)` **juste après** le flip
|
||||
du lien principal `~/.claude`. Garantit que les 3 liens partagés
|
||||
(`session-env`, `file-history`, `projects`) existent et pointent aux
|
||||
bons targets sur le compte cible, même si celui-ci vient juste
|
||||
d'être provisionné.
|
||||
- `AccountSwitcher.sharedSymlinks` : override test-only (accepte une
|
||||
liste `[]symlinks.SharedSymlink`). Défaut = `symlinks.RequiredShared`.
|
||||
Les tests peuvent scoper la réconciliation dans un `t.TempDir()` pour
|
||||
ne jamais toucher `/home/ubuntu/.claude-*-shared`.
|
||||
- 2 tests unitaires :
|
||||
- `TestFlipReconcilesSharedSymlinksOnTargetHome` : target home vide →
|
||||
les 3 liens sont créés après le flip et pointent aux targets canoniques.
|
||||
- `TestFlipEnsureSymlinksFailureDoesNotAbortSwap` : lien divergent
|
||||
planté à la main → `EnsureForAccount` renvoie une erreur, logguée
|
||||
en WARN, mais le swap complète quand même (best-effort post-flip).
|
||||
|
||||
### Rationale
|
||||
- Sans cet appel, un compte cible fraîchement provisionné n'aurait
|
||||
pas encore ses 3 liens ; au premier `claude --resume`, Claude Code
|
||||
écrirait dans `~/.claude/projects/` (privé) au lieu de
|
||||
`/home/ubuntu/.claude-projects-shared` → transcripts dupliqués,
|
||||
undo désynchronisé, resume silencieusement cassé.
|
||||
- L'ensure est **best-effort** : une erreur est logguée en WARN mais
|
||||
NE bloque PAS le flip. Si on abortait ici, on laisserait le daemon
|
||||
dans un état incohérent (symlink déjà flippé mais `SetActiveAccount`
|
||||
pas appelé).
|
||||
- L'opérateur voit le WARN dans les logs et peut corriger la
|
||||
divergence manuellement (ex: lien pointant sur le mauvais target).
|
||||
|
||||
### Tests
|
||||
- ✅ `go test ./...` : tous les packages PASS (incluant
|
||||
`internal/switcher` et `internal/symlinks`).
|
||||
- ✅ `go test -race ./internal/switcher/...` : PASS.
|
||||
- ✅ `go vet ./...` : clean.
|
||||
|
||||
### Fichiers modifiés
|
||||
- `internal/switcher/account_switcher.go`
|
||||
- `internal/switcher/account_switcher_test.go`
|
||||
|
||||
## [0.3.6] - 2026-04-16
|
||||
**Type:** Patch — Phase 1 / Chantier A2 : validation des symlinks au startup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue