diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-18 00:14:45 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-18 00:14:45 +0000 |
| commit | f08f06bef47aac2c9effb4cec650d99c2deb2dd7 (patch) | |
| tree | ae06bd2e140c678e67f2879f21b07a4114a41f73 /internal/handlers/atoms_test.go | |
| parent | be4d606e9a1f5b068abcc21bbac58d1e4705ea1f (diff) | |
Rework Tasks tab: Chains section, checklist modal, project visibility
The flat Tasks-tab atom list was silently dumping every chain step
(locked and unlocked) and dormant bucket-pool items in as ordinary
undated cards, with no chain/project context and no protection against
completing a locked step out of order.
- CompleteNativeTask now rejects completing a locked chain task
(ErrChainTaskLocked), mapped to 400 in both the widget and web
complete-atom handlers.
- Chain tasks and dormant bucket items are excluded from the flat atom
list; a new "Chains" section shows one card per active/paused chain
with the current step and N/M progress.
- New chain checklist modal (GET /chains/{id}) lists every position in
order with pause/resume/abandon -- the web view originally deferred
as Android-only.
- Fixed a real bug this surfaced: resuming a paused chain only flipped
the status flag, never unlocking the deferred successor, so a chain
paused right after a completion stayed stuck forever. SetChainStatus
now catches up the deferred advancement on resume, idempotently.
- Atom cards gained a project-name chip for general visibility.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
Diffstat (limited to 'internal/handlers/atoms_test.go')
| -rw-r--r-- | internal/handlers/atoms_test.go | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/internal/handlers/atoms_test.go b/internal/handlers/atoms_test.go index 521b147..7cb94a7 100644 --- a/internal/handlers/atoms_test.go +++ b/internal/handlers/atoms_test.go @@ -44,6 +44,59 @@ func TestBuildUnifiedAtomList_WithNativeTasks(t *testing.T) { } } +func TestBuildUnifiedAtomList_ExcludesLockedChainTasks(t *testing.T) { + s, err := store.New(":memory:", "../../migrations") + if err != nil { + t.Fatalf("failed to create in-memory store: %v", err) + } + defer s.Close() + + if _, err := s.CreateChain("Track", []models.ChainTaskInput{ + {Content: "Step 1"}, {Content: "Step 2"}, {Content: "Step 3"}, + }); err != nil { + t.Fatal(err) + } + + atoms, _, err := BuildUnifiedAtomList(s, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + for _, a := range atoms { + if a.Title == "Step 1" || a.Title == "Step 2" || a.Title == "Step 3" { + t.Errorf("chain task %q should not appear in the flat atom list (chains get their own Chains section)", a.Title) + } + } +} + +func TestBuildUnifiedAtomList_ExcludesDormantBucketItems(t *testing.T) { + s, err := store.New(":memory:", "../../migrations") + if err != nil { + t.Fatalf("failed to create in-memory store: %v", err) + } + defer s.Close() + + bucket, err := s.CreateBucket("Gutters", 30, 1) + if err != nil { + t.Fatal(err) + } + if err := s.CreateNativeTask(models.Task{ID: "pool-item", Content: "Clean gutters", Priority: 1}); err != nil { + t.Fatal(err) + } + if err := s.AddBucketItem(bucket.ID, "pool-item"); err != nil { + t.Fatal(err) + } + + atoms, _, err := BuildUnifiedAtomList(s, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + for _, a := range atoms { + if a.Title == "Clean gutters" { + t.Error("dormant bucket-pool item should not appear in the flat atom list") + } + } +} + func TestBuildUnifiedAtomList_WithClaudomator(t *testing.T) { s, err := store.New(":memory:", "../../migrations") if err != nil { |
