uttrflow / uttrflow/uttrflow-swift
Insights counts words, apps and spoken days from the calendar day before its first bar, so the caption and list disagree with the chart
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
Insights filters the history with `HistoryPresenter.retained` (`Sources/UttrflowUX/InsightsPresentation.swift:155-156`), which keeps anything newer than `days × 86,400` seconds (`DictationRecord.survives`, `Sources/UttrflowHistory/DictationRecord.swift:54-57`). The chart then draws exactly `days` calendar days ending today (`bars`, `:211-213`). A window of N × 24 hours reaches back into one more calendar day than the chart has bars, so dictations from that day are:
- added to the caption's word total (`caption`, `:233`, `entries.totalWords`),
- counted in the "where the words went" list and its percentages (`places`, `:178`, `:297-322`),
- counted in pace and "Left as dictated" (`:176-177`),
- counted as a spoken day towards the seven needed before charting (`daysSpokenOn`, `:158`),
but appear in no bar and not in the average (`:285-294`).
Measured with a throwaway test over the Insights fixtures (now = 15 June 15:20, default 7-day retention): a week of entries of 10 words in one app, plus one entry of 10 words in a second app dated 6 days 20 hours earlier (8 June, 19:20):
| Figure | Expected (what the bars show) | Actual |
|---|---|---|
| Caption | `70 words · 9–15 June` | `80 words · 9–15 June` |
| Sum of bars | 70 | 70 |
| Places | first app 100% | first app 88%, second app 12% ("10 words") |
## Why it matters
The caption and the list contradict the chart right above them, and an app can be listed as a share of dictating with no bar in which that dictating happened. It happens every day for anyone who dictated in the evening a week ago.
## How to reproduce
In `Tests/UttrflowUXTests/InsightsPresentationTests.swift`, add to `HistoryFixture.aWeek()` one entry at `now - (6 days + 20 hours)` and check that `chartCaption` starts with the sum of `days.map(\.words)`, and that `places` has one app.
## Acceptance criteria
- Every figure on the charted page (caption total, places, pace, accuracy, and the days-spoken count) is computed from the same calendar days the bars show.
- The retention promise itself (`survives`) is unchanged; this is only what the page counts.
- A test pins the row above.
## Where to start
- `Sources/UttrflowUX/InsightsPresentation.swift:150-192`: filter `kept` to entries whose start of day is inside the bars' span before handing it to the figures.
- Related: #675 (when charting starts at all), #615 (weekday arithmetic).
- Run `make verify` (export `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer` first) and read CONTRIBUTING.md.
**Size:** S, about an hour.
Contributor guide
Research direction
Start in Sources/UttrflowUX/InsightsPresentation.swift:150-192 and review the bars and figure calculations. Add the boundary case to Tests/UttrflowUXTests/InsightsPresentationTests.swift using HistoryFixture.aWeek(), then run the focused tests or make verify. Done means the caption, places, pace, accuracy, and days-spoken count use the same calendar span as the bars while DictationRecord.survives remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- analytics
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- Under an hour
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100