claude-failover/internal
Ubuntu 20063b1939 fix(switcher+symlinks): rollback on ensure failure (Bug #1) + requiredShared contract test (Bug #10)
Bug #1 (CRITIQUE) — A3 flip+ensure inconsistency
- Before: EnsureForAccount failure after flip was WARN-only, SetActiveAccount
  still fired → daemon declared target active while shared symlinks were
  absent/divergent → transcripts silently duplicated, resume broken.
- After: ensure failure triggers rollback flip to previous account home;
  if rollback succeeds → explicit error, ActiveAccount stays on previous.
  If rollback ALSO fails → sticky partialSwap flag + ErrPartialSwap; all
  further swaps refused until operator intervention (daemon restart).
- New public IsPartialSwap() for watchdog / health-check integration.

Bug #10 (MOYENNE) — requiredShared contract never exercised
- All existing tests override a.sharedSymlinks with tmpdir-scoped lists,
  so symlinks.RequiredShared itself was never tested. A rename or drop
  would pass every test but silently break prod failover.
- TestRequiredSharedIsCoherent asserts (no filesystem): 3 entries with
  the exact required names, absolute targets, and a single shared parent
  directory (invariant EnsureForAccount depends on).

Tests:
- go test ./... PASS
- go test -race ./... PASS (no data race)
- 2 new switcher tests: TestFlipEnsureFailureTriggersRollback,
  TestFlipEnsureAndRollbackFailure
- 1 new symlinks test: TestRequiredSharedIsCoherent
- 1 obsolete test replaced: TestFlipEnsureSymlinksFailureDoesNotAbortSwap
  (encoded the old buggy best-effort behaviour)
2026-04-16 19:53:48 +00:00
..
api feat: SessionLifecycleManager — auto-detect and repair dead tmux sessions 2026-04-14 18:02:25 +00:00
config feat(pool): add start_index so manual and auto pools can coexist 2026-04-15 20:39:57 +00:00
dispatcher fix(dispatcher+watcher): never auto-dispatch into dedicated sessions 2026-04-16 13:30:26 +00:00
janitor feat: Phase 2.7+3 — full integration, config update, systemd unit 2026-04-15 00:15:06 +00:00
lifecycle feat(lifecycle): validate shared symlinks at daemon startup (A2) 2026-04-16 19:03:43 +00:00
notify feat(notify): Phase 2.5 — Notifier Telegram + Resend email 2026-04-14 20:28:46 +00:00
quota fix(dispatcher): send a lone Enter after the task paste to submit it 2026-04-15 20:49:59 +00:00
state fix(quota): add cooldown + 2-poll confirmation to prevent swap ping-pong 2026-04-15 19:18:27 +00:00
switcher fix(switcher+symlinks): rollback on ensure failure (Bug #1) + requiredShared contract test (Bug #10) 2026-04-16 19:53:48 +00:00
symlinks fix(switcher+symlinks): rollback on ensure failure (Bug #1) + requiredShared contract test (Bug #10) 2026-04-16 19:53:48 +00:00
tmux fix(dispatcher): send a lone Enter after the task paste to submit it 2026-04-15 20:49:59 +00:00
watcher fix(dispatcher+watcher): never auto-dispatch into dedicated sessions 2026-04-16 13:30:26 +00:00