Fix period logging fragmentation, add merge action to History#166
Merged
Conversation
periodForDate only matched dates within an existing period's stored range, treating an ongoing period as extending through today's wall-clock date rather than indefinitely, and had no adjacency check for the day right after an explicit end date. Logging consecutive days (especially after closing a period with an explicit end date instead of leaving it ongoing, or reopening the app on a later day) could silently create a new, disconnected period instead of continuing the existing one. - periodForDate now treats ongoing periods as unbounded, and matches the day immediately after an explicit end date so consecutive-day logging continues the period instead of fragmenting it. - LogPeriodViewModel auto-extends the end date to the tapped date when continuing an adjacent period, so a single Save commits the extension. - Added a manual merge action to History (period card overflow menu) so already-fragmented periods can be joined back together, combining notes and symptoms. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QezQYsNLctrCF2mST3Z2Lf
…close bug Users who already hit the periodForDate adjacency bug are left with fragmented periods on disk; the entry-point fix alone doesn't touch existing data. Adds PeriodRepository.mergeAdjacentPeriods(), a one-time backfill (same pattern as the existing overlap-merge migration) that rejoins periods sitting exactly one day apart, then cleans up the absorbed period's tracking-log entries. Sequenced after the overlap merge, since resolving an overlap can make a period newly adjacent to a third one. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QezQYsNLctrCF2mST3Z2Lf
mapgie
pushed a commit
that referenced
this pull request
Jul 3, 2026
Builds on #166's fix (periodForDate day-after-end adjacency, deferred extension, one-time migration). Two gaps remained against the exact reported scenario (a period ending day N, an unloggable day N+1, and a new period starting day N+2): - periodForDate's day-after-end match only reopens the earlier period for a deferred extension; if a second period already starts the following day, extending the first just leaves them touching, requiring a further manual History merge. PeriodRepository.mergeGapAt detects this and merges both immediately when the tapped date bridges them, wired through HomeScreen/HomeViewModel. - mergeAdjacentPeriods (the one-time repair migration) only merged already-touching periods (zero-day gap), not periods separated by the single unlogged day this bug actually produces. Extended its gap check from "touching only" to "touching or one day apart". - Both the manual History merge and the migration were calling deleteLogsForPeriod on the absorbed period — a helper written for actual period deletion — silently discarding its flow/symptom tracking-log history instead of preserving it. Removed those calls; the data is still valid, dated history and isn't orphaned by merging. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WUWr5zTAXGDw1EooCpHxfy
4 tasks
mapgie
added a commit
that referenced
this pull request
Jul 5, 2026
…166) (#165) * Fix fragmented period logging and add History merge action Logging consecutive days used to fragment into disjoint period entries once a period's end date became fixed (e.g. via the "no end date set" confirmation): the next day no longer fell within any existing range, so tapping it silently started a brand-new, disconnected period with the in-between day unloggable in either one. PeriodRepository.resolvePeriodForLogging now checks, before creating a new entry, whether the logged date is adjacent to an existing period's start or end and extends it, or bridges a one-day gap between two periods and merges them. HomeScreen routes calendar taps and the Log Period FAB through this resolver instead of the old "covers today"-only check. The History tab also gains a manual "Merge with previous period" action per card (via PeriodRepository.mergePeriods, now reusable outside the one-time migration) so users can fix up any already-fragmented history that predates this fix or has a gap too large to auto-detect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WUWr5zTAXGDw1EooCpHxfy * Bridge the remaining single-day gap and stop merge from deleting data Builds on #166's fix (periodForDate day-after-end adjacency, deferred extension, one-time migration). Two gaps remained against the exact reported scenario (a period ending day N, an unloggable day N+1, and a new period starting day N+2): - periodForDate's day-after-end match only reopens the earlier period for a deferred extension; if a second period already starts the following day, extending the first just leaves them touching, requiring a further manual History merge. PeriodRepository.mergeGapAt detects this and merges both immediately when the tapped date bridges them, wired through HomeScreen/HomeViewModel. - mergeAdjacentPeriods (the one-time repair migration) only merged already-touching periods (zero-day gap), not periods separated by the single unlogged day this bug actually produces. Extended its gap check from "touching only" to "touching or one day apart". - Both the manual History merge and the migration were calling deleteLogsForPeriod on the absorbed period — a helper written for actual period deletion — silently discarding its flow/symptom tracking-log history instead of preserving it. Removed those calls; the data is still valid, dated history and isn't orphaned by merging. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WUWr5zTAXGDw1EooCpHxfy --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Root cause:
PeriodRepository.periodForDate— the only check that decides whether a "log period" tap should edit an existing period or create a new one — had two gaps:endDate == null) was treated as extending only throughLocalDate.now(). Reopen the app on a later day (or check a future date) and the same ongoing period silently stopped matching, so the next tap created a brand-new, disconnected period instead of continuing it.There was also no way to recover from fragmentation once it happened — History only supports delete, not merge.
Changes
PeriodRepository.periodForDate: ongoing periods now match any future date (no upper bound); a period also matches the day immediately after its explicit end date, so consecutive-day logging continues the period instead of splitting it.LogPeriodViewModel: when opened for a date that continues an adjacent period (rather than a date already inside its range), the end date is auto-extended to that date so a single Save commits the continuation.PeriodRepository.mergePeriods(new): merges two period entries into one, combining notes and symptoms, keeping the earlier entry and deleting the later.HistoryViewModel.mergePeriods(new): wraps the repository merge and cleans up the absorbed period's tracking-log entries (flow/symptoms), mirroring the existing delete cleanup.HistoryScreen: each period card now has an overflow menu offering "Merge with<date>period" for its chronological neighbours, with a confirmation dialog before merging.PeriodRepository.mergeAdjacentPeriods(), a one-time backfill (same pattern as the existing overlap-merge migration, gated by a newperiodAdjacencyMergeDonepreference flag) that automatically rejoins periods already fragmented by this bug — any two periods sitting exactly one day apart get merged and the absorbed period's tracking logs cleaned up. Sequenced to run after the existing overlap-merge migration, since resolving an overlap can make a period newly adjacent to a third one. Users who already hit this bug won't need to manually fix their data.periodForDatecovering the ongoing/future-date case and the end-date adjacency case.LESSONS.mdentry and changelog fragment.Test plan
python3 a11y_check.py(already passing locally).https://claude.ai/code/session_01QezQYsNLctrCF2mST3Z2Lf