feat(planner): wire variety-aware suggestions into RecipePicker for empty slots #47
@@ -174,7 +174,9 @@ public class PlanningService {
|
||||
VarietyScoreConfig config, Set<UUID> recentlyCookedIds) {
|
||||
List<SimulatedSlot> simulatedSlots = new ArrayList<>();
|
||||
for (WeekPlanSlot slot : plan.getSlots()) {
|
||||
simulatedSlots.add(new SimulatedSlot(slot.getRecipe(), slot.getSlotDate()));
|
||||
if (!slot.getSlotDate().equals(slotDate)) {
|
||||
simulatedSlots.add(new SimulatedSlot(slot.getRecipe(), slot.getSlotDate()));
|
||||
}
|
||||
}
|
||||
simulatedSlots.add(new SimulatedSlot(candidate, slotDate));
|
||||
return scoreFromSimulatedSlots(simulatedSlots, config, recentlyCookedIds);
|
||||
|
||||
@@ -329,6 +329,37 @@ class SuggestionsTest {
|
||||
assertThat(item.hasConflict()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void swappingExistingSlotForCleanRecipeShouldHavePositiveDelta() {
|
||||
// Plan has Mon=ItalianA, Tue=ItalianB → consecutive cuisine tag repeat → currentScore = 8.5
|
||||
// Asking for suggestions for Mon (swap scenario).
|
||||
// CleanRecipe (no Italian tag) → correct simulation: [Mon:CleanRecipe, Tue:ItalianB] → no repeat → 10.0
|
||||
// scoreDelta = +1.5 → hasConflict = false
|
||||
var plan = createPlan();
|
||||
var italianTag = createTag("Italienisch", "cuisine");
|
||||
var italianA = createRecipe("Spaghetti Carbonara");
|
||||
addTag(italianA, italianTag);
|
||||
addSlot(plan, italianA, MONDAY);
|
||||
var italianB = createRecipe("Penne Arrabiata");
|
||||
addTag(italianB, italianTag);
|
||||
addSlot(plan, italianB, MONDAY.plusDays(1));
|
||||
var cleanRecipe = createRecipe("Grillhähnchen");
|
||||
|
||||
stubPlan(plan);
|
||||
stubDefaultConfig();
|
||||
stubRecipes(italianA, italianB, cleanRecipe);
|
||||
stubNoCookingLogs();
|
||||
|
||||
SuggestionResponse result = planningService.getSuggestions(
|
||||
HOUSEHOLD_ID, plan.getId(), MONDAY, List.of(), 5);
|
||||
|
||||
assertThat(result.suggestions()).hasSize(1);
|
||||
var item = result.suggestions().getFirst();
|
||||
assertThat(item.recipe().name()).isEqualTo("Grillhähnchen");
|
||||
assertThat(item.scoreDelta()).isCloseTo(1.5, within(0.001));
|
||||
assertThat(item.hasConflict()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void scoreDeltaIsSortedDescendingCleanBeforeConflicting() {
|
||||
// Clean recipe (scoreDelta = 0.0) should rank above conflicting (scoreDelta < 0).
|
||||
|
||||
Reference in New Issue
Block a user