From b007fee8fb5b39a5f9b369c59af71ac9e795ceaf Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Fri, 17 Jul 2026 22:22:37 +0000 Subject: Implement linear task chains and recurring maintenance buckets Backend, web timeline, and Android widget wiring for the last two unimplemented items from doot-future-task-scheduling-ideas. Chains: task_chains table + chain_id/chain_position/chain_unlocked on native_tasks (migration 026), WIP-limit-1 advancement hooked into CompleteNativeTask, locked tasks excluded from all date-based queries, 5 new /api/widget/chains* endpoints, an N/M position badge on web and Android widget rows. Buckets: maintenance_buckets table + bucket_id/bucket_state/ bucket_last_active_at on native_tasks (migration 027), staleness-then-priority selection scoring, a new RunBucketCycleCheck scheduler loop, 5 new endpoints including the distinct Defer action, a Defer button on web and Android widget rows. Also corrected stale "not yet approved" status headers on the two already-shipped specs this work depended on (labels/projects, budgets/ availability) -- their headers were never updated after implementation. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL --- internal/scheduler/buckets.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 internal/scheduler/buckets.go (limited to 'internal/scheduler') diff --git a/internal/scheduler/buckets.go b/internal/scheduler/buckets.go new file mode 100644 index 0000000..5fa242d --- /dev/null +++ b/internal/scheduler/buckets.go @@ -0,0 +1,33 @@ +package scheduler + +import ( + "context" + "log" + "time" + + "task-dashboard/internal/config" + "task-dashboard/internal/store" +) + +// RunBucketCycleCheck ticks every interval, calling RunBucketCycles until +// ctx is cancelled. Mirrors RunRecurrenceCheck's shape -- errors are +// logged, not fatal, so one bad tick doesn't kill the loop. +func RunBucketCycleCheck(ctx context.Context, s *store.Store, interval time.Duration) { + ticker := time.NewTicker(interval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + n, err := s.RunBucketCycles(config.Now()) + if err != nil { + log.Printf("ERROR [BucketCycleCheck]: %v", err) + continue + } + if n > 0 { + log.Printf("BucketCycleCheck: activated %d item(s)", n) + } + } + } +} -- cgit v1.2.3