From 695b0b5c3572494c98c45fdacd74d777ab37d36e Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 7 Apr 2026 09:15:08 +0300 Subject: fix: recover gracefully from corrupted alias cache instead of hard-failing When the task alias cache file contains invalid JSON (e.g. from a concurrent write race producing two concatenated JSON objects), the previous code returned a hard error that blocked all `ask` subcommands. Now loadTaskAliasCache discards the corrupt file and starts fresh, assigning new alias IDs on the next run. Validation errors (e.g. next_id reuse) still surface as errors since those indicate a logic bug. Also fix stale v1 reference in integration test aliasCachePath. Co-Authored-By: Claude Sonnet 4.6 --- internal/askcli/task_alias_cache_test.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'internal/askcli/task_alias_cache_test.go') diff --git a/internal/askcli/task_alias_cache_test.go b/internal/askcli/task_alias_cache_test.go index 92d528b..f93a762 100644 --- a/internal/askcli/task_alias_cache_test.go +++ b/internal/askcli/task_alias_cache_test.go @@ -230,7 +230,7 @@ func TestEnsureTaskAliases_DoesNotPruneEntriesAt120DayBoundary(t *testing.T) { } } -func TestEnsureTaskAliases_InvalidCacheReturnsError(t *testing.T) { +func TestEnsureTaskAliases_CorruptedCacheIsResetGracefully(t *testing.T) { dir := t.TempDir() oldRoot := taskAliasCacheRoot @@ -244,12 +244,24 @@ func TestEnsureTaskAliases_InvalidCacheReturnsError(t *testing.T) { if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatalf("MkdirAll: %v", err) } + // Write a corrupted cache (e.g. two JSON objects concatenated due to a + // concurrent write race). The function must recover gracefully by resetting + // the cache instead of returning an error. if err := os.WriteFile(path, []byte("{not-json"), 0o600); err != nil { t.Fatalf("WriteFile: %v", err) } - if _, err := ensureTaskAliases([]TaskExport{{UUID: "uuid-1"}}); err == nil { - t.Fatal("expected error for invalid cache file") + aliases, err := ensureTaskAliases([]TaskExport{{UUID: "uuid-1"}}) + if err != nil { + t.Fatalf("expected graceful recovery from corrupted cache, got error: %v", err) + } + // A fresh alias should have been assigned after the corrupt file was discarded. + if aliases["uuid-1"] == "" { + t.Fatal("expected alias to be assigned after cache reset") + } + // The corrupt file should have been removed and replaced with a valid one. + if _, statErr := os.Stat(path); os.IsNotExist(statErr) { + t.Fatal("expected a new cache file to be written after reset") } } -- cgit v1.2.3