diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-17 11:28:19 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-17 11:28:19 +0200 |
| commit | 6f1c8bf7a36eb7044ed7aad30f84664cbbf0d303 (patch) | |
| tree | dd2ac6e1433177fb59c167a12fa0b4b91132f34a /internal/stats/stats.go | |
| parent | 10562cc510f64d5ac38aeb76f03e18eb76cca40f (diff) | |
Fix bugs, remove duplication, and clean up code quality issues
- Log swallowed JSON unmarshal errors in stats and LSP handlers
- Fix debug log file handle leak in tmuxedit (return closer from initDebugLog)
- Check f.Close() errors on write paths in promptstore and tmuxedit
- Fix cacheGet TOCTOU race by using single write lock
- Fix readInput to use passed stdin reader instead of os.Stdin.Stat()
- Remove 45 'moved to' comment tombstones from lsp/handlers.go
- Deduplicate canonicalProvider wrappers (use llmutils.CanonicalProvider directly)
- Remove SetWindow side effect from stats.TakeSnapshot (pure read now)
- Move duplicated splitLines to textutil.SplitLinesBytes
- Collapse StatusSink.SetGlobal 10 params into GlobalStatus struct
- Simplify LRU touchLocked to in-place delete-and-append
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'internal/stats/stats.go')
| -rw-r--r-- | internal/stats/stats.go | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/internal/stats/stats.go b/internal/stats/stats.go index 742a5be..d79025a 100644 --- a/internal/stats/stats.go +++ b/internal/stats/stats.go @@ -154,11 +154,14 @@ func lockStatsFile(ctx context.Context, dir string) (func() error, error) { } // readStatsFile loads the on-disk stats file, returning a fresh File if it is -// missing or has an incompatible version. +// missing, corrupt, or has an incompatible version. func readStatsFile(path string) File { var sf File if b, err := os.ReadFile(path); err == nil { - _ = json.Unmarshal(b, &sf) + if uerr := json.Unmarshal(b, &sf); uerr != nil { + fmt.Fprintf(os.Stderr, "stats: corrupt stats file %s: %v, starting fresh\n", path, uerr) + return File{Version: fileVersion} + } } if sf.Version != fileVersion { sf = File{Version: fileVersion} @@ -233,7 +236,9 @@ func acquireFileLock(ctx context.Context, f *os.File) (func() error, error) { } } -// Snapshot reads and aggregates events within the configured window. +// TakeSnapshot reads the stats file and aggregates events within the stored +// window (falling back to the process-level Window() if the file has none). +// This is a pure read — it does not mutate global state. func TakeSnapshot() (Snapshot, error) { dir, err := CacheDir() if err != nil { @@ -254,8 +259,6 @@ func TakeSnapshot() (Snapshot, error) { win := time.Duration(sf.WindowSeconds) * time.Second if win <= 0 { win = Window() - } else { - SetWindow(win) // align process with file window if changed elsewhere } cutoff := time.Now().Add(-win) snap := Snapshot{Providers: make(map[string]ProviderEntry), Window: win} |
