Skip to content

fix: expose persisted habit recurrence origins - #820

Merged
thomasluizon merged 1 commit into
mainfrom
thomasluizon/ticket-394-recurrence-origin
Oct 20, 2026
Merged

thomasluizon merged 1 commit into
mainfrom
thomasluizon/ticket-394-recurrence-origin

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

Closes thomasluizon/orbit-tickets#394

Habit detail responses now expose the persisted scheduledStartDate and originalDayOfMonth, so clients can retain the recurrence origin after a completion clamps the next due date to a short month. Missing stored values serialize as null.

HabitDetailResponse and its projection in src/Orbit.Application/Habits/Queries/GetHabitByIdQuery.cs append nullable fields with null defaults. GetHabitFullDetailQuery.cs populates the same fields in its embedded detail response. Both generated contracts, src/Orbit.Api/openapi.json and openapi_v2.json, include the optional additions. Existing fields and request contracts are unchanged.

The entity fields already exist at src/Orbit.Domain/Entities/Habit.cs:81 and :88; historical scheduling already uses the persisted anchor at src/Orbit.Application/Habits/Services/HabitScheduleService.cs:206-207 and :238. This change projects those stored values directly. It needs no migration, backfill, new input validator, or domain mutation. Client reconstruction remains in #395.

Assumptions

  • Updated both producers of the shared HabitDetailResponse, including the full-detail query, rather than leaving that endpoint to return the new constructor defaults for populated entity fields.

Test evidence

  • Before changing tests or implementation, dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~GetHabitByIdQueryHandlerTests passed all 10 existing tests with the omission present, including Handle_HabitFound_MapsAllDetailFields.
  • Added GetHabitRecurrenceOriginTests while the implementation still lacked both fields. dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~GetHabitRecurrenceOriginTests failed all 8 cases with KeyNotFoundException on the missing serialized fields. The cases use real Habit.Create and Habit.Log to advance Jan 31 to Feb 28 and Feb 29 into a non-leap year, exercise both detail producers, and cover daily and legacy null values. Reflection represents legacy nullable persisted properties because the current factory always initializes the origin.
  • After the fix, dotnet test tests/Orbit.Application.Tests --no-build --filter 'FullyQualifiedName~GetHabitRecurrenceOriginTests|FullyQualifiedName~GetHabitByIdQueryHandlerTests|FullyQualifiedName~GetHabitFullDetailQueryHandlerTests' passed all 29 tests, including all 8 regression cases.
  • dotnet test tests/Orbit.Infrastructure.Tests --no-build --filter FullyQualifiedName~HabitRecurrenceOriginContractTests passed both contract tests, proving optional nullable fields in v1 and v2.
  • dotnet build Orbit.slnx passed with 0 errors. Both generated documents were compared with the original committed JSON: removing only the two added detail properties makes each document identical to its original. Their required lists are unchanged. CI remains responsible for the OpenAPI breaking-change gate; this worker does not wait on CI.
  • dotnet test tests/Orbit.Domain.Tests: 767 passed, exit 0.
  • dotnet test tests/Orbit.Application.Tests: 5,232 passed, exit 0.
  • dotnet test tests/Orbit.Infrastructure.Tests: 3,773 passed, exit 0.
  • dotnet test tests/Orbit.Analyzers.Tests --no-build: 40 passed, exit 0.
  • Commit hooks passed formatting, root allowlist, dash, timeless, and suppression checks. No bare narration comments were added.

@sonarqubecloud

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes: Reviewed the persisted recurrence-origin fields across both detail-query producers, both API contracts, regression tests, and the current shared client schemas.

  • Detail responses: Append optional nullable scheduledStartDate and originalDayOfMonth, projecting stored values in both standalone and full-detail responses without inferring missing legacy values.
  • API compatibility: Update v1 and v2 OpenAPI schemas additively without changing existing fields or required lists; client adoption remains the separate follow-up described in the PR.
  • Regression coverage: Verified 29 focused application tests and 2 contract tests pass, including short-month, leap-day, daily, and legacy-null cases; OpenAPI regeneration left the worktree clean. Full suites were not rerun during this review.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@thomasluizon
thomasluizon merged commit 6e4a3a5 into main Oct 20, 2026
23 checks passed
@thomasluizon
thomasluizon deleted the thomasluizon/ticket-394-recurrence-origin branch October 20, 2026 03:14
thomasluizon added a commit that referenced this pull request Oct 20, 2026
… and bulk reparenting (#746) (#827)

* fix: expose persisted habit recurrence origins (#820)

(cherry picked from commit 6e4a3a5)

* feat: support bounded habit log date ranges (#822)

(cherry picked from commit 906f9e4)

* Add bulk habit reparenting (#821)

* refactor: share habit hierarchy validation helpers

* feat: move selected habits under a parent atomically

* fix: register bulk parent action in the capability catalog

(cherry picked from commit f67708f)
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