- 3 översättningar (de: 2, es: 1) föll deterministiskt på numbersPreserved:
AI:n skrev ut ett litet tal i bokstäver (t.ex. "4" -> "vier"/"cuatro") i ett
steg, så siffran försvann. Prompten säger nu explicit: skriv alltid tal med
siffror, aldrig bokstäver, även små tal i löptext. Kör om de misslyckade så
bör de klara verifieringen och publiceras.
Co-Authored-By: Claude <noreply@anthropic.com>
I AAMOS_MODE=gemini (direkt Gemini-nyckel) hanterade klienten bara bild-/
skann-uppgifterna; TRANSLATE_RECIPE föll i default-grenen och returnerade
'failed' - därför funkade foto-avläsning men INTE receptöversättning för den
som kör med egen Gemini-nyckel.
Lägger till en text-only översättningsväg (samma mönster som
generateRecipeCandidates): buildTranslatePrompt bevarar tal/stegantal/
stegnummer och kräver JSON enligt translateRecipeOutput; svaret valideras mot
kontraktet. Verifierat med mockad Gemini-respons: status=ok, korrekt titel +
stegantal, kostnad bokförd.
Detta var grundorsaken till 'TRANSLATE_RECIPE misslyckades: failed' i kön.
Streckkod / produktbidrag:
- Tydlig bekraftelse 'Sparad i delade katalogen - tack!' visas nu efter att en
fotad produkt lasts av, sa man ser att bidraget gick fram (forut bara
'Skanna igen' utan aterkoppling).
- Naringsetiketter laser nu ocksa enkelomattat och fleromattat fett (t.ex.
olivolja visar tre fettrader). Nya valfria falt monounsaturatedFatG/
polyunsaturatedFatG i NutritionValues + READ_NUTRITION_LABEL + prompt +
produktpanelen. Obligatoriska EU-falt oforandrade.
Kvitto:
- Rader som ar samma vara (samma normaliserade namn + enhet) slas nu ihop till
EN vara med ratt antal - '2 x mjolk' pa kvittot blir en vara a 2 st i stallet
for tva rader a 1 st. Priser summeras, rabatter dras som forut. En kvittorad
raknas som minst 1 exemplar aven om antal saknas.
Verifierat: typecheck hela repot gront, nutrition-engine 19/19, ai-contracts
24/24, worker 23/23, api 104/104, samt repro mot testdatabas (2 mjolk-rader ->
1 vara a 2; olivolja sparar fett/mattat/enkel-/fleromattat).
Veckoplan/kalender:
- Byt ratt: PATCH satter nu titeln (och portioner/status) efter det nya
receptet, inte bara recipeId - annars visade kalendern kvar gamla ratten.
- Planera om veckan: ersatter nu veckans plan (raderar tidigare + entries via
kaskad) sa man aldrig far dubbletter och alltid ser den nya planen. Nytt
plan-id ger ocksa ny variation.
- Variation: liten deterministisk jitter per recept, seedad pa plan-id +
veckostart, sa olika veckor OCH omgenereringar blir olika. Tackning/utgang
dominerar fortfarande. Skalas av varietyLevel.
- Veckoplaneraren visar alltid mandag-sondag (mondayOf), oavsett dagens dag.
Streckkod (fota okand produkt):
- Fotar nu fram- OCH baksida (multi-foto) sa AI:n far bade namn (fram) och
naring/innehall (bak). Prompt uppdaterad for flera bilder.
- Worker uppdaterar en befintlig delad produkt aven utan nytt namn (behaller
namnet, fyller pa naring/innehall/allergener) - och sparar ny produkt aven
fran baksidesfoto (fallback-namn) sa data inte tappas.
- Produktpanelen visar 'Fota baksidan (naring & innehall)' nar info saknas, sa
man kan komplettera en halvfardig produkt. Fel visas som dialog utan att
tappa vyn.
- 5 nya i18n-nycklar x 12 sprak.
Verifierat: typecheck (ai-contracts/worker/api/mobil), worker 23/23,
ai-contracts 24/24, api 104/104, samt repro mot testdatabas (byt ratt satter
titel; planera om ger 1 plan; 3 veckor + omgenerering varierar; delvis produkt
kompletteras och behaller namnet).
Kvitto-skanning (rapporterad krasch 'svar matchar inte schema … invalid value'):
- AI-skan-enheter (kvitto/kyl/maltid) normaliseras nu fore validering:
'st'->COUNT, 'kg'->KILOGRAM, 'forp'/'pase'->PACKAGE osv. Okand enhet -> null
i stallet for att falla hela svaret. Skarpt kvitto-prompt med exakt enhetslista.
17 nya tester bevisar normaliseringen.
Sok pa 'Vad ska vi ata':
- Endast TITELN (inte beskrivningen) -> 'pannkaka' ger inte langre appelkompott
(som bara namnde pannkakor i beskrivningen).
- Stavningstolerant via trigram-similarity: 'pankakor' hittar pannkakor.
Hogtidsknapparna (kraftskiva/grill/jul ...):
- Filtrerar nu pa recept-holidayTag (slug) i stallet for en titelsok som gav
tomt. Har event inga recept an visas ett arligt tomt-lage.
Full typecheck gron, ai-contracts 24 tester grona.
Koden/docs pastod overallt gemini-3.5-flash-lite fast .env kor 3.1. Nu enhetligt
3.1 i .env.example, config.ts-default, gemini.ts-default, tester, eval och docs
(09 + 10). Dessutom en RIKTIG bugg: estimateCostUsd rakna pa 3.5-priser
($0,30/$2,50) medan vi kor 3.1 -> overskattade spend och troffade budgetlarmet
for tidigt. Nu 3.1-priser ($0,25/$1,50). docs/10 helt omraknad pa 3.1 (per
uppgift, per anvandare, skala, 100k-trial-scenariot). Referenslinje kvar som
visar 3.5-priset for att motivera valet.
Prompten bad modellen uppskatta *andel av en forpackning* (0.0-1.0), vilket gav
nonsens som "keso 0,8 paket", "smetana 0,6 paket", "matrester 0,5 paket". Ny
ordning enligt Johans onskan: 1) las vikt/volym om den syns (500 g, 4 dl) 2)
annars rakna hela forpackningar som heltal + "st" 3) oppnad vara: uppskatta
kvarvarande i dl/g 4) vet ej -> 1 st. Aldrig decimaler av paket. La ocksa till
regel: samma vara i flera foton listas EN gang. promptVersion -> gemini-fridge-v4.
Forra andringen blev for strikt: modellen nollade ALLA datum eftersom svenska
stamplar (DDMMYY/YYMMDD) alltid ar "tvetydiga". Nu far modellen dagens datum
och tolkar 2-siffriga artal som narmaste rimliga ar runt idag (04-09-26 ->
2026-09-04, inte 2024). Kod-sparren isPlausibleFoodDate star kvar som skydd mot
grova fel. promptVersion -> gemini-fridge-v3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WZdew6cWn1MeHqoYWFfxzo
Gemini gissade fel artal pa kryptiska tryckstamplar (t.ex. "2024" pa en farsk
gradde) vilket kan trigga falska "utgangen"-varningar. Tva lager:
- Prompt: modellen far aldrig gissa artal, returnerar null vid tvetydiga/
kryptiska koder (buildFridgePrompt + buildExpiryPrompt).
- Kod: ny isPlausibleFoodDate() nollar orimligt gamla/framtida datum i
toDetectedItems. Hellre inget datum an ett felaktigt (spec §13).
promptVersion -> gemini-fridge-v2. Tester 7/7 grona.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WZdew6cWn1MeHqoYWFfxzo
BUG: forseglad vara utan tryckt datum fick fabricerat utgang (purchasedAt + shelfLifeGuidance, som ar hallbarhet EFTER oppning) -> falska 'gar ut snart'-varningar OCH gav sken av att datum inte lastes. Nu: ingen data -> unknown (hedrar appens egen princip 'aldrig gissa'). parseDate laser aven YY-MM-DD/YYMMDD/YYYYMMDD (svenska stamplar) som forr slangdes. Regressionstester tillagda. 36/36 gront.
customNodeFetch previously used res.setEncoding('utf8') and concatenated
chunks into a string. This corrupted JPEG/PNG binary data with UTF-8
replacement characters, causing Gemini to return:
400 Unable to process input image.
Now chunks are collected as Buffers and concatenated, preserving binary
integrity when images are fetched from presigned S3 URLs before being
sent to Gemini.
- config.ts: tillåt AAMOS_MODE=http|gemini i prod; mock förbjudet
- first-deploy.sh: Grind 1 accepterar gemini (kräv GEMINI_API_KEY);
Grind 5 kör eval:scan mot gemini; Grind 8 behandlar gemini som riktig AI
- gemini.ts: stöd för data-URLer (inline base64-bilder) i fetchOneImage
- eval-fixtures: 4 lokala bilder (fridge-1, fridge-2, label-1, receipt-1)
- scan-eval.ts: läser lokala fixtures, inga externa hämtningar
- capture-eval.ts: använder lokal fixture som data-URL
- Utöka GeminiAamosClient med ANALYZE_MEAL_IMAGE, READ_NUTRITION_LABEL,
READ_EXPIRY_DATE och READ_RECEIPT (vision-prompts mot kontraktsscheman).
- Lägg till apps/worker/src/lib/shadow-capture.ts: S3/local fallback,
imageTraining-gating, ingen PII, aldrig faila användarvägen.
- Integrera capture i scan-processorn efter lyckad runTask med consentFlags.
- Lägg till @aws-sdk/client-s3 i worker samt eval:capture-skript.
- Uppdatera eval:scan till Wikimedia Special:FilePath + redirect-following.
- Exkludera .terraform i brand-guard för att undvika false positives.
- Uppdatera gemini-test för DEDUPLICATE_INVENTORY som unsupported.
Node.js fetch() hänger på POST till Gemini via IPv6 i WSL.
Ersätter default fetch med customNodeFetch som använder node:https
och därmed kör över IPv4. Signifikant hastighetsförbättring
(~1 sek vs timeout).
Relaterat till scale-batch.ts i Fas A Steg 2.