summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-07-17Document deferred UI screens for chains and bucketsPeter Stone
Fleshes out the "not built" notes in both specs into actionable follow-up scope: what data/API layer already exists, what the screen needs to do, and precedent to follow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-17Guard deploy script to only run on tungstenPeter Stone
Refuses to run if hostname doesn't match the documented deploy host, preventing an accidental deploy from a sandbox/dev environment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-17Implement linear task chains and recurring maintenance bucketsPeter Stone
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-17chore(deploy): remove abandoned push-to-deploy scaffoldingPeter Stone
deployment/deploy duplicated scripts/deploy (the one actually in use). deployment/post-receive documented installing a git hook at /site/doot.terst.org/app-code/hooks/post-receive, but that hook was never actually installed and the app-code checkout it depended on has been removed -- this path was never wired up.
2026-07-17fix(widget): autofocus quick-add title field, redesign as blank edit formPeter Stone
Quick Add's text field never requested focus or triggered the keyboard, so tapping it opened a sheet with no visible way to type. Added a FocusRequester + delayed requestFocus()/keyboard show (ModalBottomSheet needs a beat to finish its enter animation before focus requests land). While in there, rebuilt the quick-add sheet to match the task edit popup instead of being a bare title field: due date, recurrence, project, and label chips, plus a description field, reusing the same dialogs the edit popup already uses. POST /api/widget/add now returns the created task's id so the client can chain the same project/labels/recurrence/due-date setter calls edit already relies on.
2026-07-16Add implementation plan for task budgets and availabilityPeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Show scheduled/available badge on widget TODAY headerPeter Stone
Threads the /api/widget budget_status field through the Android widget's DataStore-backed cache (a new BUDGET_STATUS_JSON pref, since the widget decomposes WidgetResponse into individual prefs rather than caching it whole) and renders a small "Nm/Nm" badge next to TODAY when there's a nonzero tracked load.
2026-07-16Show a scheduled-vs-available indicator on the web timeline's Today sectionPeter Stone
Task 11 of the task-budgets-and-availability plan: reuse the computeBudgetStatus helper (Task 8) in HandleTimeline so the dashboard's Today section header shows scheduled/available minutes when a budget-tracked task exists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Suggest an estimate from same-project/label averages on task detailPeter Stone
2026-07-16Add availability CRUD, task estimate, and budget-tracked toggle endpointsPeter Stone
Adds 6 widget HTTP handlers (availability get/create/delete, task estimate, project and label budget-tracked toggles) plus route registration, following the existing widget handler conventions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Surface budget_status on GET /api/widget when tracked tasks existPeter Stone
Wires ComputeBudgetPeriod together with availability blocks, tracked project/label sets, calendar events, and native tasks into a new computeBudgetStatus helper on *Handler. HandleWidgetGet now populates WidgetResponse.BudgetStatus with today/week periods, but only when at least one incomplete budget-tracked task exists in the rolling week window -- otherwise the field is omitted entirely so unconfigured users see no new UI. Errors are logged and swallowed, matching the existing resilience pattern for this widget endpoint. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Fix overlapping-event double-subtraction in ComputeBudgetPeriod; clarify ↵Peter Stone
task-filter doc comment; add multi-day test Overlapping calendar events within the same availability block were each subtracted independently, double-counting their intersection and making availability under-counted (a 120-min block with two 60-min-overlap events that overlap each other 18:30-19:00 came out to 0 min instead of the correct 30 min). Replace the per-event overlapMinutes subtraction with busyMinutesInBlock, which clips each event to the block, merges the clipped intervals, and subtracts the union's total length. Also clarify ComputeBudgetPeriod's doc comment: task filtering only enforces an upper bound (due < end); start is intentionally not used to filter tasks, since callers are expected to pre-fetch and pass in already-overdue tasks. Add a multi-day-window test verifying availability sums correctly across days, a block only contributes on its matching weekday, and the day-iteration loop excludes the day at `end`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Add pure availability-minus-events and scheduled-load computationPeter Stone
ComputeBudgetPeriod is a standalone, dependency-free function over in-memory availability blocks, calendar events, and tasks: sums weekly availability minus overlapping calendar events for [start, end), and sums estimated minutes for tracked, incomplete tasks due in that window.
2026-07-16Infer a default estimate from same-project/label averagesPeter Stone
2026-07-16Add budget-tracked toggles for projects/labels; fix SetLabelColor wiping the ↵Peter Stone
flag
2026-07-16Add availability_blocks CRUD to the store layerPeter Stone
2026-07-16Add estimated_minutes to native task read/write/recurrence pathsPeter Stone
2026-07-16gofmt internal/models/types.go and budget.goPeter Stone
Fix formatting and alignment violations: align struct field tags in Task, realign Weekday comment in AvailabilityBlock, and remove extra blank line before CalendarEvent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session
2026-07-16Add budget/availability model typesPeter Stone
Add EstimatedMinutes to Task, BudgetTracked to Project and LabelColor structs. Create budget.go with AvailabilityBlock, BudgetPeriod, and BudgetStatus types for modeling task budgets and calendar availability. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16Add schema for task budgets and availability blocksPeter Stone
Creates migrations/025_task_budgets_and_availability.sql with: - New availability_blocks table for manual weekly availability templates - estimated_minutes column on native_tasks for time budgeting - budget_tracked flag on projects and labels for opt-in tracking Fixes pre-existing bug in sqlite_test.go's setupTestStoreWithNativeTasks where project_id column was missing from the schema, causing test failures. Updates all hand-rolled test helpers (sqlite_test.go, native_tasks_test.go) to include the new columns, and adds availability_test.go with newAvailabilityTestStore helper for Task 4's availability CRUD tests. All store tests pass, including the two that were previously failing (TestGetNativeTasksByDateRange_ExcludesOverdue, TestGetOverdueNativeTasks_IncludesOnlyPastDue). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
2026-07-16fix(agent): pass project_id through on Agent API task creationPeter Stone
HandleAgentTaskCreate decoded project_id from the request but never forwarded it to CreateNativeTask, so a task created via the external Agent API with a project assigned would silently create the task unassigned instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16Update worklog for task labels and projects featurePeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16feat(widget): show project color as a small accent on task rowsPeter Stone
2026-07-16feat(widget): add project picker and label editor to task detail popupPeter Stone
2026-07-16feat(widget): add Android data layer for projects and label colorsPeter Stone
2026-07-16test(tasks): add tests for project color threadingPeter Stone
Tests verify ProjectColor is populated in BuildTimeline and copied to WidgetItem.
2026-07-16feat(tasks): thread project color from BuildTimeline to WidgetItemPeter Stone
Projects are fetched once per BuildTimeline call into a color lookup map, not queried per-task -- same pattern as RecurringEventID's existing TimelineItem->WidgetItem threading.
2026-07-16test(tasks): add test cases for project and label endpointsPeter Stone
Tests for HandleWidgetProjectsGet, HandleWidgetProjectsCreate, HandleWidgetTaskProject, HandleWidgetTaskLabels, HandleWidgetLabelsGet, HandleWidgetLabelsColorSet, and the extended HandleWidgetTaskDetail response with project and labels fields. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16feat(tasks): add HTTP endpoints for projects and label colorsPeter Stone
Extends the task-detail response with project/labels so the popup can display them without a second round trip. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16feat(tasks): add label color CRUD store methodsPeter Stone
2026-07-16feat(tasks): add Projects CRUD store methodsPeter Stone
2026-07-16feat(tasks): add projects/labels schema, wire project_id through native tasksPeter Stone
project_id joins the existing labels JSON column as series-level metadata: CreateNextIteration copies both onto every new recurring occurrence, matching content/description/priority's existing behavior.
2026-07-16Add implementation plan for task labels and projectsPeter Stone
Nine tasks: schema/model + project_id wiring, Projects CRUD, label-color CRUD, HTTP endpoints, TimelineItem/WidgetItem project-color threading, Android data layer, task-detail popup UI (project picker + label editor), widget grid color accent, build/deploy.
2026-07-16Add design docs for four backlog task-scheduling ideasPeter Stone
Labels/projects, budgets/availability, recurring maintenance buckets, and linear task chains -- refined via a 24-question interview (2026-07-15) into concrete data models, mechanisms, and API shapes. None approved for implementation yet; each spec notes its dependencies on the others (labels/projects is foundational to two of the other three). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16refactor(widget): split DootWidget.kt by responsibilityPeter Stone
DootWidget.kt (582 lines) mixed the GlanceAppWidget entry point/root composable, all the row-rendering composables, and multi-day-event detection logic in one file. Split into: - MultiDayEvents.kt: MultiDayVariant, effectiveEndDay, isMultiDayEvent, multiDayVariant, multiDayLabel, timeSuffix. - WidgetRows.kt: sourceColor, calendarViewIntent, and all row/section composables (AllDayRow, RefreshButton, QuickAddButton, HourRow, EventBlock, TaskFragmentBlock, TaskRow, TomorrowSection, TomorrowEventRow), plus hourLabel/calcGridStart/calcGridEnd. - DootWidget.kt: just the GlanceAppWidget class and WidgetRoot, now 145 lines. All same package (org.terst.doot.widget.ui), so no import changes needed for cross-file references. Pure move, no behavior change -- full unit test suite (including DootWidgetGridTest/ DootWidgetMultiDayTest, which call the internal functions directly) passes unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16refactor(store): extract agent session/trust methods from sqlite.goPeter Stone
Pure move: all agent-session and agent CRUD/trust methods (~340 lines) plus their full test suite and setupTestStoreWithAgents helper, out of sqlite.go/sqlite_test.go into agents.go/agents_test.go. No behavior change. Mirrors internal/handlers/agent.go's domain naming. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16refactor(store): extract calendar and Google Tasks methods from sqlite.goPeter Stone
Pure move: SaveCalendarEvents/GetCalendarEvents/GetCalendarEventsByDateRange into calendar.go, SaveGoogleTasks/GetGoogleTasks/GetGoogleTasksByDateRange into google_tasks.go. Neither cluster had dedicated tests in sqlite_test.go to move. No behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16refactor(store): extract shopping methods from sqlite.go into shopping.goPeter Stone
Pure move: UserShoppingItem type, its CRUD methods, and SetShoppingItemChecked/GetShoppingItemChecks, plus their tests and setupTestStoreWithShopping helper, out of sqlite.go. No behavior change. Mirrors the existing internal/handlers/shopping.go naming. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16refactor(store): extract meal methods from sqlite.go into meals.goPeter Stone
Pure move: SaveMeals/GetMeals/GetMealsByDateRange and their test (plus its setupTestStoreWithMeals helper, used only by that test) out of the 1400+ line sqlite.go into their own file. No behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16Update worklog for widget polish batch (fonts, instant complete, recurrence ↵Peter Stone
dialog) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(widget): redesign recurrence dialog layoutPeter Stone
The 4 frequency chips and 7 weekday chips were each laid out in a single non-wrapping Row -- on a real phone width these overflow/get cut off rather than wrapping. The interval field was a full-width OutlinedTextField with the unit baked into its label ("Every N dailys"/"weeklys" -- ungrammatical for anything but weekly), and the whole dialog had no visual grouping. Redesigned: FlowRow (wraps instead of overflowing) for both chip rows; single-letter weekday chips (S M T W T F S) to stay compact; a narrow fixed-width (72dp) interval field paired with a correctly-pluralized unit label rendered separately from the field; muted section labels (REPEATS / EVERY / ON THESE DAYS) for structure. No callback/API changes -- purely a layout rewrite of the same onSave/onClear/onDismiss contract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(widget): match task font color to events; complete instantlyPeter Stone
TaskRow used a flat hardcoded gray (0xFFDDDDDD) while EventBlock used Color.White (dimmed only when past) at the same size/weight -- the color mismatch read as a font difference. Both now use the same Color.White base. CompleteTaskAction previously did no local update at all: the row stayed visible until CompleteWorker's full complete() -> fetchAndPersist() -> updateAll() round trip finished (two sequential network calls). It now optimistically removes the completed item from the cached list and re-renders immediately, matching RefreshTaskAction's existing synchronous-flag-then-updateAll pattern -- the background worker's own fetchAndPersist still replaces this with the authoritative server state (including a newly-created recurring successor, if any) moments later. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16Update worklog for widget periodic-refresh self-healing fixPeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(widget): re-arm periodic refresh on every onUpdate, not just onEnabledPeter Stone
onEnabled only fires when the first widget instance is added to a home screen, so if the periodic RefreshWorker job is ever silently dropped (an app reinstall can clear WorkManager's persisted schedule without the widget itself being removed/re-added -- exactly what happens when sideloading a new APK build, as opposed to a Play Store update), there was no way for it to come back except manually removing and re-adding the widget. onUpdate fires far more often (reboot, periodic OS ticks) and now also re-arms the schedule (a no-op via KEEP if already running). Root-caused via manual refresh restoring all missing content instantly (rules out a data/rendering bug) plus the widget only showing one stale morning event beforehand (consistent with the periodic job having stopped ticking hours earlier, right around today's APK reinstalls). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16Update worklog for post-recurrence fixups and dead-code cleanupPeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16chore: remove dead IsRecurring field and its always-false branchPeter Stone
Task.IsRecurring/Atom.IsRecurring were never assigned anywhere in the codebase (confirmed via full-repo search), so PartitionAtomsByTime's "hide future recurring tasks until due" branch was permanently dead. RecurrenceSeriesID is the real recurring indicator now; wiring up "hide future recurring successors" as an actual feature is a separate design decision, not part of this cleanup pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16chore: remove dead code (unused atom constants, orphaned handler)Peter Stone
- SourceMeal/TypeMeal (AtomSource/AtomType): leftover from the removed MealToAtom conversion (b2d8fc4); zero references anywhere else. - HandleGetSourceOptions: never registered as a route, and its own test comment already noted "may fail if template not found, which is acceptable" -- the settings-source-options template it rendered doesn't exist in web/templates/ at all. Fully unreachable/broken, not just unused. go build/vet/test all clean, no behavior change for anything reachable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(agent): restore doot-native task support in Agent API, remove stale testPeter Stone
Two independent pre-existing failures, both from incomplete refactors: - agent.go's four task write/create switches (complete/uncomplete, update due date, update details, create) never got a "doot" case added when the Todoist integration was removed (945c345) in favor of native tasks -- the test file was updated to use source=doot, but the handlers themselves still only recognized "trello"/"gtasks", so every native-task Agent API call 400'd with "Unknown source". getAtomDetails already had a "doot" case, confirming this was an incomplete migration, not an intentional gap. - TestMealToAtom in atom_test.go tested MealToAtom, a function removed from atom.go months earlier (b2d8fc4) when meals were dropped from the unified Atom/timeline system; the Meal struct itself is still used elsewhere (shopping/meals feature) but no longer produces atoms, and the test was never cleaned up to match. go test ./internal/... ./cmd/... is now fully green with no failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(widget): remove red text color for overdue tasksPeter Stone
Overdue and non-overdue tasks now render with the same plain title color; no more red highlighting for overdue items. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16fix(tasks): make CreateNextIteration atomically self-guardingPeter Stone
Folds the "is this still the latest row in its series?" check directly into the INSERT as a single atomic INSERT...SELECT...WHERE NOT EXISTS statement, instead of a separate SELECT-then-INSERT sequence. Closes a narrow race where the completion trigger and the periodic due-date check could both pass their "still latest" check before either had inserted, producing two duplicate successor rows for the same series. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD