1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
# Session State
## Current Focus
Cleaned Backlog
## Recently Completed
- **Tasks tab rework: Chains section, chain checklist modal, chain-completion lock guard, project-name visibility** — the flat Tasks-tab atom list was silently dumping every chain step (locked and unlocked) and dormant bucket-pool items into the grid as ordinary undated cards, with no chain/project context and, worse, a raw Complete checkbox that `CompleteNativeTask` didn't actually guard against for locked steps (would have corrupted the WIP-1 invariant if clicked). Fixed: `CompleteNativeTask` now returns `ErrChainTaskLocked` for a locked chain task (mapped to 400 in both the widget and web complete-atom handlers); chain tasks (locked or unlocked) and dormant bucket items are excluded from the flat atom list entirely; a new "Chains" section on the Tasks tab shows one card per active/paused chain (`GetChains`, `BuildChainSummaries`) with the current step, N/M progress, and a click-through to a new modal (`GET /chains/{id}`, `chain-detail.html`) listing every position in order (locked/unlocked/completed) with pause/resume/abandon buttons -- the web checklist view originally deferred as Android-only. Along the way, found and fixed a real bug this surfaced: resuming a paused chain only flipped the status flag, never actually unlocking the deferred successor, so a chain paused right after a completion would stay stuck forever -- `SetChainStatus` now catches up the deferred advancement on resume, idempotently (no due-date reset if nothing was actually stuck). Regular atom cards also gained a project-name chip for general visibility. Fully covered by store+handler tests (`go test ./...` green). Not yet deployed.
- **Linear task chains + recurring maintenance buckets** — implemented the last two items from `[[doot-future-task-scheduling-ideas]]` (items 1 and 2, budgets/availability and labels/projects, turned out to already be shipped -- their spec status headers and the budgets plan's checkboxes had just never been updated to say so; corrected both). Chains: `task_chains` table + `chain_id`/`chain_position`/`chain_unlocked` on `native_tasks` (migration 026), WIP-limit-1 sequencing wired into `CompleteNativeTask`'s existing recurrence-hook pattern, locked tasks excluded from all date-based queries, 5 new `/api/widget/chains*` endpoints, a position badge ("N/M") on web timeline rows and the Android widget row. 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 mirroring `RunRecurrenceCheck`, 5 new endpoints including the distinct Defer action (returns to pool without crediting completion, unlike Complete), a Defer button on both web timeline rows and the Android widget row. Both fully covered by store+handler tests (`go test ./...` green). Deferred (backend/API exists, UI doesn't): a dedicated Android chain-checklist screen, and bucket-management create/add-item screens on web or Android -- both explicitly out of scope in their specs' own interviews. Not yet deployed or built into the Android APK.
- **Task labels and projects** — doot-native tasks get a lightweight Projects concept (name + user-assignable color, exactly one per task) and the previously-dormant `Labels` field is finally wired up end-to-end (free-text tags, each assigned a deterministic color on first use). Both are inherited automatically across recurring task series, just like content/description already are. Editable in the task-detail popup (project picker with inline "create new" + color swatches, a label chip editor); the widget's time-grid rows show a small project-color accent. Trello/Google Tasks cards are unaffected. Built via a 9-task subagent-driven plan, all tasks reviewed clean; deployed server + widget APK.
- **Widget polish: task/event font parity, instant task completion, recurrence dialog redesign** — TaskRow's title color (a flat hardcoded gray) now matches EventBlock's (Color.White, dimmed only when past) at the same size/weight — the color gap was reading as a font mismatch. CompleteTaskAction now optimistically removes the completed item from the cached list and re-renders immediately (matching RefreshTaskAction's existing pattern) instead of waiting for the full complete->fetch->render round trip. Redesigned RecurrenceEditDialog: the 4 frequency chips and 7 weekday chips were each in a non-wrapping Row (overflowing/cut off on real phone widths) — now FlowRow-based so they wrap; single-letter weekday chips; a narrow fixed-width interval field with a correctly-pluralized unit label (was "Every N dailys"); muted section labels for visual structure. Deployed new APK.
- **Widget periodic-refresh self-healing fix** — root-caused a report of "all-day events and tasks gone, now-line stuck on this morning" to the widget's periodic background refresh (`RefreshWorker`, every 15 min) having silently stopped ticking, likely because reinstalling the APK (as happened repeatedly this session, outside the Play Store update path) can clear WorkManager's persisted schedule without the widget itself being removed/re-added — the only place that re-establishes the periodic job was `onEnabled`, which only fires on first-widget-add. Manual refresh always worked (confirmed data/rendering were fine); `onUpdate` (fires far more often: reboot, periodic OS ticks) now also re-arms the schedule via `KEEP` (a no-op if already running), making it self-healing. Deployed new APK.
- **Post-recurrence fixups: no more overdue-red, Agent API regression fixed, dead code removed** — removed the red text color for overdue widget tasks (plain title color regardless of overdue state). Found and fixed a real regression via systematic debugging: `agent.go`'s four task write/create switches (complete, update due date, update details, create) never got a `"doot"` case when Todoist was removed in favor of native tasks, so every native-task call through the external Agent API 400'd with "Unknown source" — `go test ./internal/...` is now fully green (also removed a stale `TestMealToAtom` test for a function deleted months earlier). Dead-code sweep: removed unused `SourceMeal`/`TypeMeal` atom constants, an orphaned `HandleGetSourceOptions` handler (never routed, rendered a template that no longer exists), and the always-false `IsRecurring` field/branch (never assigned anywhere; the real recurring indicator is `RecurrenceSeriesID`). Deployed server + widget APK.
- **Task recurrence + task-detail popup editing** — doot-native tasks now support server-owned recurrence (daily/weekly/monthly/yearly, optional specific weekdays, custom interval): a new row for the next occurrence is created either when the current one is completed or once its due date passes (a 15-minute background check), whichever comes first — never both, and never blocked by an ignored/overdue task. New endpoints (`GET /api/widget/task`, `POST /api/widget/task/{update,recurrence,next-date}`). The widget's task-detail popup is redesigned: editable title/description (Edit → Cancel/Save), a linkified description (tappable URLs and phone numbers), and independently-tappable date/recurrence/next-date chips with a recurrence-editing dialog. Trello and Google Tasks cards are unaffected — same title + Complete button as before. Deployed both the Go server and `doot-widget.apk`.
- **Widget regressions + multi-day calendar events** — fixed popup-shows-behind-settings (missing `taskAffinity` on popup activities caused `FLAG_ACTIVITY_NEW_TASK` to reuse SettingsActivity's task), floored header text at NORMAL scale even when the Small text-size setting is selected, fixed settings-screen label colors, and replaced the event-detail popup with a direct tap-to-open-source link (removed `EventDetailActivity` and its now-dead recurrence-lookup endpoint). Separately, fixed multi-day calendar events: they previously either only rendered in a single hourly grid slot on their start day (vanishing on later days) or, for genuine all-day events, never had their end date forwarded at all. Now render as an all-day-style row on every day they span (web Today/Tomorrow sections + widget), labeled "starts/ends HH:MM" or plain, correctly accounting for Google Calendar's exclusive all-day end-date convention (caught and fixed during review — a single-day all-day event's raw end date is one calendar day past its own day). Deployed both the Go server and `doot-widget.apk`.
- **Widget tomorrow-section fix + configurable text size** — fixed `calcGridStart`/`calcGridEnd` (`DootWidget.kt`) skewing today's hour-grid bounds off tomorrow's event hours, which manufactured empty rows and pushed the non-scrolling TOMORROW section below the widget's visible area; added `WidgetTextSize` enum (Small/Normal/Large, independent header/content scale+weight, default Normal) wired through widget rendering and a new picker in widget Settings. Deployed to `doot-widget.apk`.
- **Google Tasks Unification & Multi-List Support** — implemented SQLite caching layer for Google Tasks, integrated with unified `Atoms` loop (now showing in Tasks tab), updated Planning tab to include Google Tasks, and enhanced Quick Add form with Todoist project selector. Fixed issue where only the default list was shown; now respects all enabled task lists and calendars from settings.
- **Agent Context API Phase 2 & 3** — Write operations (complete, uncomplete, update due, update task), create operations (task, shopping), and management UI in settings. Fixed SQLite timestamp scanning issue.
- **Sync log + clear cache feedback** — migration `016_sync_log.sql`, store methods `AddSyncLogEntry`/`GetRecentSyncLog`, handler changes, template partial `sync-log.html`
- `HandleClearCache` now renders sync log HTML (replaces `hx-swap="none"`)
- `HandleSyncSources` adds log entry after sync
- `HandleSettingsPage` passes `SyncLog []store.SyncLogEntry` to template
- Tests: `TestStore_AddAndGetSyncLog`, `TestStore_GetRecentSyncLog_LimitsResults`, `TestHandleClearCache_AddsLogEntry`, `TestHandleClearCache_ReturnsHTMLSyncLog`, `TestHandleSettingsPage_IncludesSyncLog`, `TestHandleSyncSources_AddsLogEntry`
- **Bug 1: Todoist incremental sync** — added 5 tests exercising the incremental merge path (upsert, delete completed/deleted, sync token storage/reuse, forceRefresh). Code was already correct, just untested.
- Tests: `TestFetchTasks_IncrementalSync_UpsertsActiveTasks`, `TestFetchTasks_IncrementalSync_DeletesCompletedAndDeletedTasks`, `TestFetchTasks_IncrementalSync_StoresNewSyncToken`, `TestFetchTasks_IncrementalSync_UsesSavedSyncToken`, `TestFetchTasks_ForceRefresh_ClearsSyncToken`
- **Bug 2: Task completion response/headers** — added assertions for response body (`rendered:completed-atom`), Content-Type header, HX-Reswap/HX-Trigger headers, template data verification. Code was correct, assertions were missing.
- Tests updated: `TestHandleCompleteAtom_Todoist`, `TestHandleUncompleteAtom_Todoist`
- New test: `TestHandleCompleteAtom_RendersCorrectTemplateData`
- **Bug 3: Google Calendar cache layer** — calendar events now cached via `CacheFetcher` pattern, surviving API outages.
- New migration: `migrations/015_calendar_events.sql`
- New store methods: `SaveCalendarEvents`, `GetCalendarEvents`, `GetCalendarEventsByDateRange`
- New cache key: `store.CacheKeyGoogleCalendar`
- New handler method: `fetchCalendarEvents` (uses `CacheFetcher` with stale-cache fallback)
- `BuildTimeline` now reads events from store (removed `calendarClient` param)
- Tests: `TestBuildTimeline_ReadsCalendarEventsFromStore`, `TestFetchCalendarEvents_CacheFallbackOnAPIError`, `TestSaveAndGetCalendarEvents`
- All tests pass (`go test ./...`)
## Previously Completed
- Extracted project-agnostic dev methodology to `~/.claude/CLAUDE.md`
- Created `~/.claude/roles/` with architect.md, implementor.md, reviewer.md
- Slimmed task-dashboard `CLAUDE.md` (87→72 lines, references global for methodology)
- Trimmed `DESIGN.md` (removed Development Workflow, Git Practices, TDD methodology, ADR methodology, Config Reference duplication)
- Deleted `ARCHITECT_ROLE.md`, `IMPLEMENTOR_ROLE.md`, `REVIEWER_ROLE.md` from repo
## Previously Completed
- Build version footer with ldflags injection (`deploy.sh`, `index.html`)
- `assertTemplateContains` test helper, refactored existing template tests
- `scripts/logs` for fetching production journalctl
- Fix passkey registration: hide UI when WebAuthn not configured (WebAuthnEnabled flag)
- Added no-cache header tests for #66
## Completed Bugs (All Verified)
- **#74**: Feature toggles — tests: `TestHandleToggleFeature`, `TestHandleCreateFeature`, `TestHandleDeleteFeature`; docs: DESIGN.md §4.3
- **#56**: Box contents overflow — CSS-only fix, documented in DESIGN.md
- **#65**: Google Tasks — timeline tests cover integration; API client lacks dedicated unit tests
- **#66**: No-cache headers — tests: `TestHTMLResponse_SetsNoCacheHeaders`, `TestJSONResponse_SetsNoCacheHeaders`
- **#67**: Z-index — CSS-only fix, documented in DESIGN.md §z-index hierarchy
- **#68**: Track completion — tests: `TestHandleCompleteAtom_Todoist`, `TestHandleCompleteAtom_Trello`
- **#69**: Timeline calendar — tests: `TestCalcCalendarBounds`, `TestBuildTimeline_IncludesOverdueItems`; docs: DESIGN.md §Timeline View
- **#70**: Clear inputs — tests: `TestShoppingQuickAdd_Success`; docs: DESIGN.md §Quick Add UX
- **#71**: Shopping checkmarks — tests: `TestShoppingModeItemsTemplateFiltersChecked`
- **#72**: Inline add per store — tests: `TestShoppingQuickAdd_ShoppingModeReturnsStoreItems`
- **#73**: Store grouping — partial tests, partial docs
## Agent Context API
- Status: [COMPLETED] Phase 1, 2, & 3
- Tests: `internal/handlers/agent_test.go` (comprehensive)
- Docs: ADR-005, DESIGN.md §Agent Context API
- Write operations, Creation, and Management UI all implemented and verified.
## Known Gaps
- Google Tasks API client lacks dedicated unit tests (integration tested via timeline)
- WebAuthn passkeys require `WEBAUTHN_RP_ID` and `WEBAUTHN_ORIGIN` env vars in production
## Remaining Items (Feature Requests)
- #33-38: Shopping/timeline features
## Next Steps
1. Set `WEBAUTHN_RP_ID` and `WEBAUTHN_ORIGIN` in production to enable passkeys
## Process Improvements
- Extracted dev workflow to `~/.claude/CLAUDE.md` — reusable across projects
- Role definitions now in `~/.claude/roles/` — project-agnostic
- CLAUDE.md reduced from 87 to 72 lines — faster to parse
- DESIGN.md trimmed ~200 lines of duplicated methodology
|