feat: Add atomic write pattern for state files (gt-wled7)

Prevents data loss from concurrent/interrupted state file writes by using
atomic write pattern (write to .tmp, then rename).

Changes:
- Add internal/util package with AtomicWriteJSON/AtomicWriteFile helpers
- Update witness/manager.go saveState to use atomic writes
- Update refinery/manager.go saveState to use atomic writes
- Update crew/manager.go saveState to use atomic writes
- Update daemon/types.go SaveState to use atomic writes
- Update polecat/namepool.go Save to use atomic writes
- Add comprehensive tests for atomic write utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-28 15:57:53 -08:00
parent 36dbea9618
commit 213b3bab20
7 changed files with 146 additions and 35 deletions

View File

@@ -7,6 +7,8 @@ import (
"path/filepath"
"sort"
"sync"
"github.com/steveyegge/gastown/internal/util"
)
const (
@@ -175,7 +177,7 @@ func (p *NamePool) Load() error {
return nil
}
// Save persists the pool state to disk.
// Save persists the pool state to disk using atomic write.
func (p *NamePool) Save() error {
p.mu.RLock()
defer p.mu.RUnlock()
@@ -185,12 +187,7 @@ func (p *NamePool) Save() error {
return err
}
data, err := json.MarshalIndent(p, "", " ")
if err != nil {
return err
}
return os.WriteFile(p.stateFile, data, 0644)
return util.AtomicWriteJSON(p.stateFile, p)
}
// Allocate returns a name from the pool.