15 KiB
phase, verified, status, score, re_verification, human_verification
| phase | verified | status | score | re_verification | human_verification | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11-issue-3-tasks-management-allow-task-checking-anytime-and-pre-populate-recurring-tasks | 2026-04-03T00:00:00Z | human_needed | 8/8 must-haves verified | false |
|
Phase 11: Allow Task Checking Anytime and Pre-Populate Recurring Tasks — Verification Report
Phase Goal: Users can complete tasks on any day regardless of schedule, and recurring tasks appear on all applicable days within their interval window — making the app feel like a consistent checklist rather than a rigid scheduler Verified: 2026-04-03 Status: human_needed (all automated checks pass; 4 items require live-app or Flutter SDK) Re-verification: No — initial verification
Goal Achievement
Observable Truths
| # | Truth | Status | Evidence |
|---|---|---|---|
| 1 | Checkboxes always enabled on all calendar days and in room task lists | ✓ VERIFIED | isFuture guard absent from both calendar_day_list.dart and task_row.dart; all canComplete calls pass true; task_row.dart onChanged is unconditional |
| 2 | Completing a task on a non-due day recalculates nextDueDate from today | ✓ VERIFIED | tasks_dao.dart:64 — final baseDate = todayStart == taskDueDay ? task.nextDueDate : todayStart; — explicit today-base path; calculateNextDueDate receives baseDate |
| 3 | A weekly task appears on all 7 days leading up to its due date | ✓ VERIFIED | _isInCurrentIntervalWindow checks selected.isAfter(prevDay) && selected.isBefore(dueDate); _calculatePreviousDueDate subtracts 7 days for weekly; provider feeds result into prePopulatedTasks |
| 4 | A monthly task appears on all days within its current month interval | ✓ VERIFIED | _calculatePreviousDueDate uses _subtractMonths with corrected total-month arithmetic for monthly/quarterly/yearly intervals |
| 5 | Tasks already completed in the current interval do not reappear as pre-populated | ✓ VERIFIED | watchCompletionsInRange(taskId, prevDue, nextDue+1day) called per candidate task; non-empty result skips the task |
| 6 | Pre-populated tasks have muted (reduced opacity) visual appearance | ✓ VERIFIED | calendar_task_row.dart:92 — return isPrePopulated ? Opacity(opacity: 0.55, child: tile) : tile; |
| 7 | Overdue tasks retain coral accent styling | ✓ VERIFIED | CalendarTaskRow applies _overdueColor to task name when isOverdue: true; pre-populated tasks are never overdue (excluded by overdueIds set in providers) |
| 8 | Tests written for all key behaviors | ✓ VERIFIED | 4 new tests in tasks_dao_test.dart (on-due-day, before-due-day, daily non-due, monthly-early-with-anchor); 9 new tests in calendar_dao_test.dart covering watchAllActiveRecurringTasks, watchAllActiveRecurringTasksInRoom, watchCompletionsInRange |
Score: 8/8 truths verified
Required Artifacts
Plan 01 Artifacts
| Artifact | Expected | Level 1 Exists | Level 2 Substantive | Level 3 Wired | Status |
|---|---|---|---|---|---|
lib/features/home/presentation/calendar_day_list.dart |
Checkbox always enabled for all day tasks | ✓ | ✓ — canComplete: true on all three call sites (overdue, day, pre-pop loops) |
✓ — consumed by CalendarTaskRow widget |
✓ VERIFIED |
lib/features/home/presentation/calendar_task_row.dart |
CalendarTaskRow with always-enabled checkbox | ✓ | ✓ — canComplete param present, defaults true; isPrePopulated param added |
✓ — rendered by calendar_day_list.dart |
✓ VERIFIED |
lib/features/tasks/presentation/task_row.dart |
TaskRow with always-enabled checkbox | ✓ | ✓ — onChanged: (_) { ref.read(...).completeTask(task.id); } unconditional; isFuture absent |
✓ — widget used in room task list | ✓ VERIFIED |
lib/features/tasks/data/tasks_dao.dart |
completeTask with today-based recalculation | ✓ | ✓ — baseDate logic at lines 62-67; calculateNextDueDate(currentDueDate: baseDate, ...) |
✓ — called by taskActionsProvider |
✓ VERIFIED |
Plan 02 Artifacts
| Artifact | Expected | Level 1 Exists | Level 2 Substantive | Level 3 Wired | Status |
|---|---|---|---|---|---|
lib/features/home/data/calendar_dao.dart |
watchAllActiveRecurringTasks + watchCompletionsInRange queries |
✓ | ✓ — three new methods: watchAllActiveRecurringTasks (line 173), watchAllActiveRecurringTasksInRoom (line 193), watchCompletionsInRange (line 214) |
✓ — called by calendar_providers.dart |
✓ VERIFIED |
lib/features/home/presentation/calendar_providers.dart |
Pre-population logic with isPrePopulated filtering |
✓ | ✓ — _isInCurrentIntervalWindow, _calculatePreviousDueDate, _subtractMonths helper functions; full pre-pop loop in both providers |
✓ — CalendarDayState.prePopulatedTasks populated and passed to CalendarDayList |
✓ VERIFIED |
lib/features/home/domain/calendar_models.dart |
CalendarDayState with prePopulatedTasks field |
✓ | ✓ — final List<TaskWithRoom> prePopulatedTasks at line 13; isEmpty updated at line 30 |
✓ — consumed by calendar_day_list.dart |
✓ VERIFIED |
lib/features/home/presentation/calendar_task_row.dart |
Visual distinction for pre-populated tasks | ✓ | ✓ — isPrePopulated param (line 29); Opacity(opacity: 0.55) wrapper (line 92) |
✓ — isPrePopulated: true passed from calendar_day_list.dart pre-pop loop |
✓ VERIFIED |
lib/features/home/presentation/calendar_day_list.dart |
Renders pre-populated section with muted styling | ✓ | ✓ — "Demnächst" section header (line 280); isPrePopulated: true in loop (line 290); cleanup loop covers prePopulatedTasks (line 62) |
✓ — reads from state.prePopulatedTasks |
✓ VERIFIED |
Key Link Verification
| From | To | Via | Status | Evidence |
|---|---|---|---|---|
calendar_day_list.dart |
CalendarTaskRow |
canComplete: true always passed |
✓ WIRED | Lines 262, 273, 289 all pass canComplete: true |
tasks_dao.dart |
scheduling.dart |
calculateNextDueDate uses baseDate |
✓ WIRED | Line 66-71: currentDueDate: baseDate |
calendar_providers.dart |
calendar_dao.dart |
watchAllActiveRecurringTasks stream |
✓ WIRED | Line 156: db.calendarDao.watchAllActiveRecurringTasks() |
calendar_providers.dart |
scheduling.dart |
calculateNextDueDate determines window boundary |
✓ WIRED | _calculatePreviousDueDate is the inverse of calculateNextDueDate logic; same interval arithmetic applied in reverse |
calendar_day_list.dart |
CalendarTaskRow |
isPrePopulated flag passed |
✓ WIRED | Line 290: isPrePopulated: true in pre-pop loop; line 337: propagated in _buildAnimatedTaskRow |
Data-Flow Trace (Level 4)
| Artifact | Data Variable | Source | Produces Real Data | Status |
|---|---|---|---|---|
calendar_day_list.dart (pre-pop section) |
state.prePopulatedTasks |
calendarDayProvider / roomCalendarDayProvider — watchAllActiveRecurringTasks() DB stream filtered through _isInCurrentIntervalWindow and watchCompletionsInRange |
Yes — real DB queries; no hardcoded fallback | ✓ FLOWING |
calendar_task_row.dart (opacity) |
isPrePopulated boolean |
Passed from _buildAnimatedTaskRow with isPrePopulated: true for pre-pop section |
Yes — prop set from real state.prePopulatedTasks list |
✓ FLOWING |
tasks_dao.dart (baseDate) |
baseDate |
currentTime (injectable now param) vs task.nextDueDate from DB |
Yes — real DB task record | ✓ FLOWING |
Behavioral Spot-Checks
Flutter SDK and dart CLI unavailable in the verification shell environment. Static code verification performed in lieu of running tests.
| Behavior | Method | Result | Status |
|---|---|---|---|
isFuture guard removed from calendar_day_list.dart |
grep -n "isFuture" |
No matches | ✓ PASS |
isFuture guard removed from task_row.dart |
grep -n "isFuture" |
No matches | ✓ PASS |
canComplete: true present in all day-task loops |
grep -n "canComplete" |
Lines 262, 273, 289 all true |
✓ PASS |
baseDate logic in completeTask |
grep -n "baseDate" |
Lines 62-67 match plan spec exactly | ✓ PASS |
4 new TDD tests present in tasks_dao_test.dart |
Content search | Lines 320, 338, 356, 374 contain all 4 test cases | ✓ PASS |
9 new DAO tests present in calendar_dao_test.dart |
Content search | watchAllActiveRecurringTasks (3 tests), watchAllActiveRecurringTasksInRoom (2 tests), watchCompletionsInRange (4 tests) |
✓ PASS |
| All 5 plan commits present in git log | git log --oneline |
b00806a, 3398aca, c5ab052, 9a67c51, 8cbe989 all found |
✓ PASS |
flutter test / dart analyze |
Not runnable in shell | Flutter SDK absent | ? SKIP |
Requirements Coverage
| Requirement | Source Plan | Description | Status | Evidence |
|---|---|---|---|---|
| TM-01 | 11-01 | Checkboxes never disabled for future dates | ✓ SATISFIED | isFuture removed from calendar_day_list.dart and task_row.dart; canComplete: true hardcoded |
| TM-02 | 11-01 | nextDueDate recalculated from today on non-due-day completion | ✓ SATISFIED | baseDate = todayStart when todayStart != taskDueDay in tasks_dao.dart:64 |
| TM-03 | 11-02 | Recurring tasks pre-populated on all days in interval window | ✓ SATISFIED | _isInCurrentIntervalWindow + _calculatePreviousDueDate in calendar_providers.dart; all interval types covered |
| TM-04 | 11-02 | Pre-populated tasks already completed in current period hidden | ✓ SATISFIED | watchCompletionsInRange check in provider loop; task skipped when completions.isNotEmpty |
| TM-05 | 11-02 | Pre-populated tasks have muted visual distinction | ✓ SATISFIED | Opacity(opacity: 0.55) wrapping ListTile in calendar_task_row.dart:92 |
All 5 requirements satisfied. No orphaned requirements detected (all TM-01 through TM-05 appear in plan frontmatter and are covered by code).
Anti-Patterns Found
No anti-patterns detected:
- No
TODO,FIXME,HACK, or placeholder comments in any modified file. - No
return null,return [], or empty-body handlers that block goal. - No
isFutureguards remaining anywhere in the modified UI files. onChanged: (_) { ... }intask_row.dartis unconditional with realcompleteTaskcall.- The "Completing tasks always show full styling" comment at
calendar_day_list.dart:327is a documented design decision, not a stub.
Human Verification Required
1. Pre-populated task visual rendering
Test: Open the app and navigate to a calendar day that is within the interval window of a weekly task (e.g. 3 days before the task's due date). Scroll to see if the task appears below any due-today tasks.
Expected: Task visible in a "Demnächst" section with roughly 55% opacity — noticeably dimmer than regular tasks. The section header text "Demnächst" appears in a muted colour.
Why human: Opacity(0.55) correctness and the "Demnächst" section header layout can only be confirmed visually in a running app.
2. End-to-end pre-population filtering after completion
Test: On a calendar day within a weekly task's interval window (e.g. Monday, task due Friday), check the task's checkbox. Then navigate to Tuesday through Thursday for the same week.
Expected: The task does NOT reappear as pre-populated on any remaining day in the same interval window after being completed.
Why human: Requires a live Drift database session with reactive watchCompletionsInRange streams to verify filtering propagates correctly across day navigation.
3. Overdue task coral accent retention
Test: With an overdue task (nextDueDate before today), open today's calendar view. Confirm the overdue task's name text uses the coral/terracotta colour.
Expected: Overdue task name in Color(0xFFE07A5F) with no opacity reduction. Pre-populated tasks (if any) appear below with reduced opacity — no style cross-contamination.
Why human: Colour rendering and visual separation between sections require live rendering.
4. All tests pass and dart analyze clean
Test: In a shell with Flutter SDK: flutter test && dart analyze
Expected: Exit code 0 for both commands. No analyzer warnings or errors.
Why human: Flutter SDK (flutter) and Dart CLI (dart) are absent from the CI/verification shell. Both SUMMARY documents note this as an environment constraint. Code was verified correct through static inspection; test logic is substantive and matches the plan's specified expected values exactly.
Gaps Summary
No gaps found. All 8 observable truths are verified through static code analysis and commit presence checks. The phase goal is structurally achieved: checkboxes are unconditionally enabled, the today-base recalculation is implemented and tested, the pre-population provider logic is wired end-to-end from DAO queries through provider filtering to UI rendering, and the muted visual distinction is in place.
The 4 human verification items are confirmatory (not gap-closing) — they validate rendering quality and reactive behavior that cannot be checked without a running Flutter app.
Verified: 2026-04-03 Verifier: Claude (gsd-verifier)