songyc macbook 4a03868163 fix(goals): cap daily progress contributions to 100% to prevent weekly and monthly progress distortion
Weekly/monthly progress for a daily quest summed each day's raw value into
the numerator, so one over-achieving day leaked its overage into the span
total. Example: two daily quests with a 5-minute target; on one day quest A
did 5 min (100%) and quest B did 10 min (200%). Both are "done" for that day,
but the weekly ratio counted quest B as 600s vs quest A's 300s — B carried
double the weight, and its over-achievement masked other days' shortfalls and
could push per-quest weekly display past 100%.

spanProgress now aggregates a daily 'atLeast' quest's week/month value as the
sum of per-day values each capped at that day's target (min(dayValue, target)),
via a new private spanValue(for:range:now:). This equals averaging per-day
capped ratios, so a single 200% day contributes exactly one day's worth — no
day can cover for another, and per-quest weekly/monthly display never exceeds
100%. Scope is deliberately narrow:

- day span is untouched — a single day still shows 200% over-achievement.
- 'atMost' (stay-under) quests keep their existing per-day 100%/0% logic;
  capping the value would make them always pass, so they use the raw value
  unchanged — the two rules coexist without contradiction.
- weekly/monthly/custom quests accumulate freely within their period, so no
  per-day cap applies to them.

Only the progress calculation changed; raw records are never altered, so the
records/stats screens still show the true 10-minute total.

Verified in the simulator with a temporary isolated in-memory self-test
(removed before commit): quest A (100%) and quest B (200%) produce identical
weekly ratios (0.1429 each), quest B's weekly display stays <= 100%, and its
day-span display remains 200%. Build succeeds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
2026-07-12 22:38:35 +09:00
..