Skip to content

Fix habit metrics before scheduled start (ORB-127) - #457

Draft
thomasluizon wants to merge 1 commit into
mainfrom
fix/orb-127-goal-progress-start
Draft

Fix habit metrics before scheduled start (ORB-127)#457
thomasluizon wants to merge 1 commit into
mainfrom
fix/orb-127-goal-progress-start

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Aug 7, 2026

Copy link
Copy Markdown
Owner

DEGRADED: same-vendor review

Fixes ORB-127.

Root cause

Habit metrics currently use the habit creation timestamp as the lower bound. That admits dates before the first scheduled due date. Bad habits receive unearned clean days, while good habits can have their streak suppressed.

Intended approach

Persist an optional immutable scheduled start date from the creation due date and use it as the shared expected-date lower bound for current streak, longest streak, and completion rates. Keep a guarded fallback for legacy rows so future habits with no activity are corrected while habits whose due date already advanced retain their historical window.

Add calculator coverage for future good and bad habits, the exact start date, a start yesterday, an advanced due date, a pre-start log, and completion-rate behavior. Add goal service coverage proving a future linked bad habit reads zero.

Verification

Pending implementation.

Copy link
Copy Markdown
Owner Author

Implementation approach

I will add ScheduledStartDate as a nullable persisted domain property and initialize it from HabitCreateParams.DueDate. The field stays internal to the existing API contract, so no shipped DTO changes.

HabitMetricsCalculator.GenerateExpectedDates will use that immutable date. For legacy rows where the field is null, it will use a future DueDate only when there are no completed logs, and otherwise preserve the creation-date lower bound. This fixes the reported legacy row without allowing an advanced due-date pointer to truncate an active habit's history.

The schema change will be one generated EF migration plus its snapshot. Tests will land in HabitMetricsCalculatorTests and GoalStreakSyncServiceTests, covering future good and bad habits, start-date boundaries, completion-rate denominator behavior, pre-start logs, an advanced due date, and goal progress.

I rejected using DueDate directly because logging and catch-up mutate it. I also rejected changing GoalStreakSyncService because it already delegates to the shared calculator.

@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant