SuggestionItem now exposes scoreDelta (simulatedScore − currentScore) and
hasConflict (scoreDelta ≤ 0) so the frontend can render badges without
needing to pass currentVarietyScore as a separate prop.
PlanningService.getSuggestions() computes currentScore once per request
and derives scoreDelta + hasConflict per candidate. Sorting is unchanged
(scoreDelta desc = simulatedScore desc since currentScore is constant).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add @RequiresHouseholdRole("member") to GET /{planId}/variety-preview endpoint
to require household membership (was accessible to any authenticated user)
- Extract scoreFromSimulatedSlots() private method eliminating duplicate logic
between simulateVarietyScore() and the old computeCurrentScore()
- Fix loose variety preview test assertions (isBetween → exact assertEquals)
- Add test verifying negative scoreDelta when candidate is a duplicate recipe
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Returns currentScore, projectedScore, and scoreDelta when a recipe
would be added on a given date. Used by C6 desktop day picker.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PATCH, DELETE, and POST slot endpoints now return 403 Forbidden
when called by a household member.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add VarietyScoreConfig entity, repository, and V020 migration for
per-household scoring weights and configurable tag types
- Rewrite getVarietyScore: tag-type repeats on consecutive days,
non-staple ingredient overlaps, cooking log history, plan duplicates
- Rewrite getSuggestions: simulate variety score for each candidate,
add tag filter (AND, case-insensitive) and configurable topN param
- Update SuggestionResponse to return simulatedScore instead of
fitReasons/warnings, update VarietyScoreResponse to new shape
- Seed default VarietyScoreConfig on household creation
- Extend test suite across all domains (+270 tests, all passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>