Skip to content

Expose repairable streak gap dates - #522

Closed
thomasluizon wants to merge 3 commits into
mainfrom
fix/ticket-505-repair-gaps
Closed

thomasluizon wants to merge 3 commits into
mainfrom
fix/ticket-505-repair-gaps

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Resolves thomasluizon/orbit-tickets#505

Summary

  • Adds optional repairableGapDates to the streak info response and generated OpenAPI contract.
  • Returns exact scheduled occurrences validated by the repair command's shared rules.
  • Preserves isRepairAvailable, repairDate, and every existing response field.

Assumptions

  • An empty list represents no eligible gap. Null was rejected to keep the returned collection stable.
  • PreGapLastActiveDate uses LastActiveDate as its fallback boundary. Scanning backward to older activity was rejected because it changes the identified gap.

Test evidence

  • Before implementation, WeeklyGapWhosePriorOccurrenceIsAWeekBack_IsRepairable passed at commit 9dfb065e. Command: dotnet test tests\Orbit.Infrastructure.Tests\Orbit.Infrastructure.Tests.csproj --filter "FullyQualifiedName~StreakGapRepairTests.WeeklyGapWhosePriorOccurrenceIsAWeekBack_IsRepairable" --logger "console;verbosity=minimal". Result: 1 passed. Existing coverage proved sparse repair acceptance but did not expose dates to clients.
  • With the defect present, the strengthened Handle_RepairAvailable_AppendsRepairFieldsAndCapturesOffer failed. Command: dotnet test tests\Orbit.Application.Tests\Orbit.Application.Tests.csproj --filter "FullyQualifiedName~GetStreakInfoQueryHandlerTests.Handle_RepairAvailable_AppendsRepairFieldsAndCapturesOffer" --logger "console;verbosity=detailed". Failure: Expected contract.TryGetProperty("RepairableGapDates", out _) to be True, but found False.
  • After the fix, that same test passed. Command: dotnet test tests\Orbit.Application.Tests\Orbit.Application.Tests.csproj --filter "FullyQualifiedName~GetStreakInfoQueryHandlerTests.Handle_RepairAvailable_AppendsRepairFieldsAndCapturesOffer" --no-build --no-restore --logger "console;verbosity=minimal". Result: 1 passed.
  • Weekly, daily, boundary, predecessor, completion today, and echoed repair cases passed. Command: dotnet test tests\Orbit.Infrastructure.Tests\Orbit.Infrastructure.Tests.csproj --filter "FullyQualifiedName~StreakGapRepairTests" --no-restore --logger "console;verbosity=minimal". Result: 34 passed.
  • dotnet build Orbit.slnx --no-restore --verbosity minimal: 0 errors.
  • dotnet test Orbit.slnx --no-build --no-restore --logger "console;verbosity=minimal": 6,248 passed.

@thomasluizon

Copy link
Copy Markdown
Owner Author

Approach:

  1. Add optional RepairableGapDates to src/Orbit.Application/Gamification/Queries/GetStreakInfoQuery.cs.
  2. Derive the list from the schedule and continuity rules in src/Orbit.Infrastructure/Services/UserStreakService.cs.
  3. Extend the existing gamification query and service tests for daily, weekly, boundary, and completion today cases.
  4. Prove the returned weekly list succeeds when echoed into the existing repair command.

This keeps rule authority server side and rejects client calendar reconstruction. Existing single day fields remain untouched for shipped clients.

pullfrog[bot]
pullfrog Bot previously approved these changes Sep 13, 2026

@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 sole commit at the current head against main; there is no source, contract, or test diff yet.

  • Empty implementation baseline9dfb065 changes no files, so no functional behavior is available to assess in this review.

Pullfrog  | View workflow run | Using GPT Sol𝕏

@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.

Important

The new gap discovery can hide a valid repair after an older unrepaired break.

Reviewed changes Reviewed the implementation commit added since the prior Pullfrog review at 9dfb065.

  • Extended the streak contract Appended optional repairableGapDates to StreakInfoResponse and OpenAPI without changing existing fields.
  • Derived server-confirmed gaps Shared schedule and coverage context with command eligibility and returned the full terminal scheduled gap.
  • Added regression coverage Covered daily and weekly gaps, completion today, lookback refusal, and echoing discovered dates into the repair command.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using GPT Sol𝕏

if (gapEndIndex < 0 || IsCovered(context, gapEnd))
return [];

var precedingDate = user.PreGapLastActiveDate ?? user.LastActiveDate;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PreGapLastActiveDate is the first saved break, not necessarily the predecessor of the terminal gap being offered. After an older gap is left unrepaired, a restarted run followed by a new gap makes this slice begin at the old break, include intervening completions, and return [] even though the command accepts the newer terminal gap when the bank is sufficient.

Technical details
# Derive the latest terminal gap

## Affected sites
- `src/Orbit.Infrastructure/Services/UserStreakService.cs:104` selects the persistent first-break snapshot.
- `src/Orbit.Domain/Entities/User.cs:582` intentionally retains that snapshot across later decreases until repair or account reset.

## Required outcome
- Return the newest terminal scheduled gap that the repair command would accept, even when an older snapshot remains.
- Preserve the completion-today and sparse-schedule behavior.

## Suggested approach
- Walk backward from `gapEndIndex` over uncovered scheduled dates to the nearest covered scheduled predecessor instead of unconditionally anchoring to `PreGapLastActiveDate`.
- Add a regression with an old unrepaired gap, a restarted completed run, and a newer terminal gap whose exact returned dates succeed through `RepairStreakGapCommand`.

@thomasluizon

Copy link
Copy Markdown
Owner Author

Closing as a duplicate I should not have opened.

Pull request 518 already implements thomasluizon/orbit-tickets#505 and has since 2026-09-11. It is APPROVED with zero unresolved threads, and its only red check was drift, the same architecture map regeneration this branch carried. I have now regenerated that map on 518 at 6ac02c2a, so 518 is the single surviving delivery for #505.

I opened this one because I read the ticket as unstarted without first listing the open pull requests in this repository. The branch fix/ticket-505-repair-gaps stays in place until 518 merges.

@thomasluizon
thomasluizon deleted the fix/ticket-505-repair-gaps branch September 16, 2026 22:53
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