fix(rekommendationer): vardagens tidsgräns gömmer inte längre högtids-/bakrecept

Buggen: när användaren uttryckligen valde en högtid (t.ex. Kräftskiva), en
tagg (Baka) eller sökte, hårdfiltrerade scoreCandidate bort alla recept vars
totalTimeMinutes översteg hushållets maxCookingMinutesWeekday (parts.time=-1,
rankAll släpper <0). De smala högtidspoolerna kollapsade då till 0-1 recept
trots att flera fanns korrekt taggade.

Reproducerat mot riktig seedad databas: med en 20-min vardagsgräns gav
kräftskiva 2, grillsäsong 2, skolstart 0, bak nästan tomt. Med fixen ger de
4, 5, 3 respektive 18 – medan standardvyn "Rekommenderat" fortfarande
respekterar tidsgränsen (3 snabba middagar).

Fix: uttrycklig avsikt (holiday/tag/search) förbigår vardagens tidsgräns –
tiden blir mjuk rankning i stället för hårt filter. En uttrycklig q.maxMinutes
i förfrågan respekteras fortfarande. Regressionstest låser mekanismen.
This commit is contained in:
Claude
2026-08-19 15:10:04 +00:00
parent d267effd6c
commit 2e702d6582
2 changed files with 20 additions and 1 deletions
+10 -1
View File
@@ -330,10 +330,19 @@ export async function recommendationRoutes(app: FastifyInstance) {
// --- 8. Tolka "jag är sugen på" (spec §19) ---
const craving = q.craving ? parseCraving(q.craving) : null;
// Uttrycklig avsikt: användaren har valt en högtid, en tagg (t.ex. Baka)
// eller sökt på namn. Då ska hushållets vardags-tidsgräns INTE hårt gömma
// maten de faktiskt bett om (spec §28) en kräftskiva eller ett bak tar
// tid. Tiden blir mjuk rankning i stället för diskvalificerande filter.
// En uttrycklig tidsgräns i förfrågan (q.maxMinutes) respekteras alltid.
const hasExplicitIntent = !!(q.holiday || q.tag || q.search);
const ctx: RecommendationContext = {
mealType: q.mealType,
persons: q.persons ?? (members.length ? members.length : 1),
maxMinutes: q.maxMinutes ?? myPrefs?.maxCookingMinutesWeekday ?? undefined,
maxMinutes:
q.maxMinutes ??
(hasExplicitIntent ? undefined : (myPrefs?.maxCookingMinutesWeekday ?? undefined)),
maxCostMinorPerPortion: q.maxCostMinorPerPortion,
remainingProteinG: Math.max(0, daySummary.remaining.proteinG),
remainingKcal: Math.max(0, daySummary.remaining.kcal),