Restructure period logging around per-day entries - #172
Merged
Conversation
Periods were stored as a single record per episode (start, end, one flow level, one symptom set), which cannot represent how periods actually unfold. This makes the individual day the unit of logging: - New period_days table (one row per logged day, unique dates) is the source of truth; DB migration v23 expands existing episode ranges into day rows (ongoing entries capped at 10 days). - Period episodes are now derived by grouping days that fall within a user-configurable gap tolerance (0-3 days, default 1, new Cycle setting). The derived rows keep the existing periods table, ids, and notes, so stats, widgets, reminders, and history keep working unchanged. - Logging a day starts a period, continues one, extends it backwards, or bridges two fragments, all through the same operation; each day carries its own flow, symptoms, and pinned-category values keyed to that date in the tracking logs. - A period with no explicit end is deemed ended once the tolerance window passes without a new period day (reconciled on app start and by the daily worker); an explicit "until" date can also close it, including past the last individually logged day. - Log Period screen is day-centric: it shows which period the day belongs to (day N), loads and saves that day's values, can set or clear the explicit end date, and can remove a single day from a period. - History merge now materialises the gap days; delete/undo carry the day rows; deleting a period cleans per-day logs across its whole span. - Exports gain per-day data (JSON "days" array, CSV logged_days column); import restores it and still accepts legacy exports. - Replaced the one-time overlap/adjacency merge fixups with the reconcile pass, which repairs fragmented or overlapping episodes on every start. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZijqU65RHMEqCnz8TjHQp
The new export/import round-trip tests exercise JSONObject/JSONArray, which are unmocked android.jar stubs in local unit tests: exportData threw and importData surfaced Failure, failing 3 tests in CI. Adding the real org.json artifact to the test classpath (it precedes the mockable android.jar) lets those paths run for real. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZijqU65RHMEqCnz8TjHQp
The licenses CI check requires every libs.versions.toml change to be reflected in LicensesScreen.kt, but a test-only dependency is never shipped and doesn't belong on the attribution screen. Declaring it inline in the test configuration keeps the catalog and the licenses screen in sync. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZijqU65RHMEqCnz8TjHQp
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.
Why
Periods were bundled into one record per episode: a single start/end range with one flow level and one symptom set. That doesn't reflect how periods work: day 1 and day 4 of the same period have different flow, different symptoms, different everything. It also bred a family of boundary bugs (fragmented entries, eternally "ongoing" periods, extend-vs-create races) that previous fixes had to patch one edge at a time.
What changed
The day is now the unit of period logging.
Data model
period_daystable: one row per day the user marks as a period day (unique dates). DB migration v22→23 expands existing episode ranges into day rows (ongoing entries are capped at 10 days so a stale open entry doesn't fabricate months of data).periodstable) are now derived from those days: days that are consecutive, or within a configurable gap tolerance of each other, form one period. The rebuild preserves row ids and notes via span-overlap matching, so History, Stats, widgets, reminders, and export all keep reading the same schema.Behaviour
Consequential cleanups
daysarray in JSON,logged_daysCSV column); import restores it and still accepts legacy exports without it.Tests
PeriodRepositoryTestrewritten around the new model: episode derivation (start/continue/gap/bridge/backfill), auto-end via reconcile, explicit end dates surviving rebuilds and being dropped when superseded, day removal (shrink/split/delete), delete/restore/merge, import/export round-trips including legacy formats, and tolerance-awareperiodForDateboundaries.🤖 Generated with Claude Code
https://claude.ai/code/session_015ZijqU65RHMEqCnz8TjHQp
Generated by Claude Code