Commit Graph

69 Commits

Author SHA1 Message Date
Sven (AAMOS AI) bf04a12b89 fix(gemini): read binary response body as Buffer instead of UTF-8 string
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.
2026-08-12 20:30:24 +07:00
Sven (AAMOS AI) 716e768cd0 feat(deploy): aktivera dedikerad Cibello-Gemini-nyckel + SMTP, ersätt /openclaw-referens 2026-08-12 20:07:32 +07:00
Sven (AAMOS AI) 6e2d794130 feat(storage,deploy): delad S3/mock-lagring, SSM .env-sync, Gemini readyz
- @app/storage med MockStorage + AwsStorage delas mellan API och worker

- Workerns readUrl() ger presignerad S3-URL i aws-läge (fixar mock-s3 404)

- sync-env-from-ssm.py hämtar /cibello/prod/* och skriver .env; first-deploy.sh kör det i prod

- /readyz returnerar 503 om app.aamos.healthCheck() misslyckas

- docs/SECRETS.md med rotations- och SSM-regler
2026-08-12 17:28:58 +07:00
Sven (AAMOS AI) 7dda0fad00 fix(gemini): budget-check före bildhämtning så spärr triggars tidigt 2026-08-12 16:30:49 +07:00
Sven (AAMOS AI) 6c581bec1a feat(cost-guard): global Gemini daily budget + EOC alarm; trial requires verified email 2026-08-12 06:43:32 +07:00
Sven (AAMOS AI) 81927b6cdc fix(db): RDS-CA i poolen (app+migrator delar TLS) 2026-08-12 06:07:07 +07:00
Sven (AAMOS AI) 983f3fb2aa fix(database): explicit RDS SSL via NODE_EXTRA_CA_CERTS 2026-08-12 04:48:42 +07:00
Sven (AAMOS AI) c5a8530fbf fix(deploy): brand-guard compat + db_reachable med RDS SSL + first-deploy SSL 2026-08-12 04:22:24 +07:00
Sven (AAMOS AI) 659d0f9290 feat(deploy): Gemini som committat prod-läge + hermetiska eval-fixtures
- 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
2026-08-12 04:10:10 +07:00
Sven (AAMOS AI) 9a9f8a6a3c feat(worker/ai): Gemini-lärar-tier för scan/detect/allergen + shadow-capture
- 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.
2026-08-12 02:51:05 +07:00
Sven (AAMOS AI) c60158801d gapfill: jordnötssmör-cellen fylld (4 recept) 2026-08-11 19:19:23 +07:00
Sven (AAMOS AI) a7b53c7ba3 gapfill(peanut): rikare middagsrätter som target 2026-08-11 19:16:39 +07:00
Sven (AAMOS AI) 4adde4faff chore(ops): feedback.senaste upp till 10 for EOC-panelen 2026-08-11 18:22:07 +07:00
Sven (AAMOS AI) 989c242d2c gapfill: importera nollcells-recept i seed 2026-08-11 06:42:09 +07:00
Sven (AAMOS AI) a00f0a59ab gapfill: generera+verifiera nollceller (export) 2026-08-11 06:39:58 +07:00
Sven (AAMOS AI) 4116653b51 S6: i18n-paritet, provenans + eval, copy-skanning, fabricerade-minnes-eval 2026-08-11 05:20:27 +07:00
Sven (AAMOS AI) f86a37dd33 S5: onboarding → minne + smaksignaler (user_stated) 2026-08-11 04:43:43 +07:00
Sven (AAMOS AI) 1e18146665 fix(recommendation-engine): S4-FIX — opersonliga vyer fungerar utan samtycke via depersonalize(weights) 2026-08-11 04:02:46 +07:00
Sven (AAMOS AI) 05bba93b90 feat(worker): S3 3b härda UPDATE_USER_MEMORY — budget, kostnad, anti-påhitt, GDPR-regression 2026-08-11 03:23:09 +07:00
Sven (AAMOS AI) 33b0a8267b fix(ops): interpolera varumärke i wall board från brand.config.json 2026-08-11 02:47:25 +07:00
Sven (AAMOS AI) 335cfe0bf6 feat(memory): S3 3a minnes-yta + impact-endpoint 2026-08-11 02:41:39 +07:00
Sven (AAMOS AI) 4296a64aef feat(ops): wall board härlett ur summary-värden 2026-08-11 02:36:08 +07:00
Sven (AAMOS AI) b1b6eb994c feat(seed): import 246 verified recipes as committed seed catalog
- Convert C:\Users\Public\cibello-verified-final-result.json to
  packages/database/src/seed/data/verified-recipes.ts (committed, hermetic).
- Replace/extend the 23 placeholder SEED_RECIPES via re-export.
- Upsert on slug with onConflictDoUpdate of ALL recipe fields.
- Hard-reject recipes with unmapped canonical ingredients (0 rejected this batch).
- Derive allergens and compute nutrition per portion from ingredients at seed time.
- Run food-safety lint; auto-patch 8 legacy raw-protein recipes with safe-cooking phrase.
- Resolve 4 suspected title duplicates via variantOfSlug.
- Guard brand name: creatorDisplayName uses BRAND.name, never JSON placeholder.
- Preserve verificationStatus (editorial/verified) and source-registry FKs.
- Extend allergen-invariant test to cover full 246-recipe catalog.
- Stabilise API tests by disabling file parallelism (flakiness from shared DB state).

Refs: seed pipeline, brand-guard, safety canary
2026-08-11 00:47:08 +07:00
Sven (AAMOS AI) 4687f46384 Phase 1 ops core: base blocks, feedback, canary fixes
- Add app/ekonomi/anvandare/prenumerationer/butik/feedback blocks to computeOpsSummary.
- New feedback table, POST /api/feedback, GDPR erasure wiring.
- Canary: only count unverified/rejected published recipes; treat verified/editorial as safe.
- Add 'rejected' recipe verification status enum value.
- Fix food-safety lint baseline: remove egg/cured fish from raw-protein list, relax
  genomstekt regex, add safe-cooking phrases to seed recipes.
- Seed recipes now get verificationStatus=editorial.
- Tests: ops summary blocks, feedback route, me.residual cleanup.
2026-08-10 06:35:51 +07:00
Sven (AAMOS AI) 8f20b2ef1b feat(ops): /ops/v1/summary med ai/aktivering/engagemang/betalning/jobb/sakerhet + canary
- Nya toppnivåblock i /ops/v1/summary: ai_scan, aktivering, engagemang,
  betalning, jobb, sakerhet. Alla värden läses från DB/cache; null där data
  saknas, inga påhittade värden.
- AI-kostnad i USD mikrocent (native); intäkter fortsatt SEK-öre.
- product_analytics_events är källa för volym, latens, lyckandegrad,
  felfrekvens, aktivering, retention och engagemang.
- Nya händelser: scan_started (API) och scan_failed/scan_completed med
  latencyMs + felkod (worker). latencyMs flödar nu in i scan_completed.
- Safety canary-jobb varje timme: re-härleder allergener för alla recept,
  räknar överifierade publika recept och food-safety-lint; skriver EN rad till
  ops_safety_canary. Endpointen läser endast sista raden.
- Cache-refresh-jobb var 60 s skriver hela summariet till Redis; endpointen
  serverar cachen med 503 vid cache-miss.
- Bearer-token-skydd med OPS_TOKEN; HTTPS-tvång i produktion; ingen PII.
- Tester för endpoint, auth, cache-miss och safety canary.
2026-08-10 05:47:43 +07:00
Sven (AAMOS AI) f4a603e977 fix(recipe-generation): BRAND.name-interpolation för creatorDisplayName + rubriker/filnamn
feat(recommendation-engine,api): S4 Smak/Hälsa/Lager-vyer för 'Vad ska vi äta?'

- Ersätter hårdkodat 'Cibello' i scale-batch, scale-smoke-test och export-verified.
- DB-backfill: 224 recept hade 'Cibello AI' i creator_display_name (värdena
  motsvarar nuvarande BRAND.name, ingen rad ändrades men kontrollen är gjord).
- Lägger till view-query-param (default|taste|health|pantry) med fördefinierade
  ScoringWeights och samtyckesgrind.
- Unit-tester för vyer; integrationstester för vy-param, validering och
  fallback utan personalization-samtycke.
- brand-guard grön; pnpm typecheck 19/19; pnpm test --force x2 grönt (34 tasks,
  275 tester).
2026-08-10 05:17:43 +07:00
Sven (AAMOS AI) 881c5bb1e3 fix(worker): S2 proactive tips logic, i18n parity, hardened test DB reset
- processProactiveTips now iterates all expiring items sorted by urgency and
  emits the first candidate with a recipe that clears 7-day dedup.
- Add pt-PT proactive-tip templates; remove en-GB duplicate; parity test
  asserts against shared-types SUPPORTED_LANGUAGE_TAGS.
- Serialize DB test setup via turbo dependencies; seed truncates only *_test
  DBs, guarded by both --test flag and DB name suffix.
2026-08-10 04:35:22 +07:00
Sven (AAMOS AI) f494b1810e feat(worker): S2 proaktiva puffar (expiring-ingredient)
- Ny notification_type 'proactive_tip' och consent_kind 'notifications'.
- Dubbelgrind: personalization + notifications samtycke måste vara granted.
- Mallbaserade pufftexter i 12 språk; ingen fri AI-text.
- Led med nyttan ('gurkan börjar bli slapp — recept du brukar gilla').
- Max 1 puff/hushåll/dag; ingen upprepning av samma vara+recept inom 7 dagar.
- UTC för all datummatte; createdAt sätts explicit från processorns now.
- Ny worker-jobbtyp SEND_PROACTIVE_TIPS.
- Integrationstester för dubbelgrind, revoke, frekvens, duplicate, UTC.
- Migration 0022 + worker test script kör db:test-setup.
2026-08-10 03:51:57 +07:00
Sven (AAMOS AI) 0885f5bceb feat(recommendation-engine): S1 personalisering för 'Vad ska vi äta?'
- Mallbaserad proveniens i 12 språk (inga fria AI-texter i rekommendationer).
- memoryFit, tasteFit, cookingAssumptionFit endast vid personalization-samtycke.
- Hård grind i API:et: läser memory_items/taste_signals/cooking_assumption_profiles
  endast när userConsents.personalization = granted.
- NON_PERSONALIZED_WEIGHTS bevarar existerande beteende vid avsaknad av samtycke.
- Positiv, icke-restriktiv näringscopy (R7).
- Deterministisk scoring + enhetstester för S1.
- Integrationstest som verifierar provenans-gate med/utan samtycke.
2026-08-10 03:23:31 +07:00
Sven (AAMOS AI) b40e1f9d90 fix(recipe-generation, database): allergen-blocker åtgärdad
- seed/run.ts uppdaterar nu ALLA canonical-ingrediensfält vid re-seed,
  inklusive allergens (tidigare uppdaterades bara nameSv/nutritionPer100).
- seed/run.ts härleder allergener för seed-recept från ALLA ingredienser,
  inte bara obligatoriska.
- verification.ts hård-avvisar inkompletta kandidater (saknar titel,
  ingredienser, steg, portioner eller tider) som rejected.
- Lägger allergen-invariant-test i @app/recipe-generation som verifierar
  att seed-receptens lagrade allergens matchar färsk derivering.
- Allergener omräknade för alla 246 recept; 0 mismatch återstår.
- Raderade 4 trasiga recept + 1 ordningsdubblett tidigare.
2026-08-10 01:52:57 +07:00
Sven (AAMOS AI) 9c5adaa921 fix(recipe-generation): allergen-säkerhet + re-derive + dedup
- Lägger regressionstester: optional allergen-ingrediens deklareras,
  optional rå fågel kräver genomstekningssteg, optional mjölk deklareras.
- Re-derive allergener för alla seedade recept (18 uppdaterade).
- Raderar 4 recept med saknade ingredienser/steg.
- Raderar 1 ordningsdubblett: Ugnsbakad lax med dill och citron.
- 246 godkända recept kvar, 0 dublett-slugs.
2026-08-10 01:29:31 +07:00
Sven (AAMOS AI) 2fda1a5785 feat(recipe-generation): final export script med coverage + dedup + kostnad
- export-verified.ts exporterar nu även editorial (status=editorial)
- Lägger till coverage-matrix, dedup-stats och summary.md
- Inkluderar total kostnad för runda 1 + runda 2
2026-08-10 00:40:01 +07:00
Sven (AAMOS AI) fc3d9daac8 fix(recipe-generation): städning inför final export
- Ta bort felaktig /\bfiber\w*\b/ från SAFE_COOKING_KEYWORDS_SV
- densityGPerMl för kidney_beans_canned, black_beans_canned, chickpeas_canned
- Re-seed DB; typecheck + test gröna
2026-08-10 00:35:39 +07:00
Sven (AAMOS AI) 576c451cfe feat(recipe-generation): STEG 2 RUNDA 2 prep
- Food-safety prompt + lint: doneness krävs, gyllenbrun räcker inte
- DensityGPerMl för ginger, örter, mushroom, salsa, corn, olives, peas
- RUNDA_2_TARGETS fokuserade på gap-celler (paprika, blandfärs, räkor, torsk, svarta bönor)
- Export-verified script + scale-smoke-test
- Temp-skript borttagna; inga nycklar kvar i kod
2026-08-10 00:22:36 +07:00
Sven (AAMOS AI) 344ec8ee3a fix(ai-contracts): customNodeFetch för att kringgå IPv6-häng i WSL
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.
2026-08-09 22:10:36 +07:00
Sven (AAMOS AI) 84f8ff3c45 feat(recipe-generation): scale-batch.ts för Fas A Steg 2 (~200 verified)
- 8 batchar om ~27 recept = ~216 mål
- Budgetguard med pause vid 90 %
- DB-dedup mot recipes.titleSv + session-dedup
- Seed verified till staging DB (recipes, recipeIngredients, recipeSteps)
- Stickprov ~15 % per batch med flaggning
- scale-batch.sh wrapper för Node IPv4-workaround
- Lade till ./client export i @app/database
- Lade till dotenv i @app/recipe-generation deps

Relaterat till docs/32-receptkatalog-buildout.md
2026-08-09 22:03:55 +07:00
Sven (AAMOS AI) 0ae42a15b2 fix(database): applicera compound-allergen-rättningar + vegansk currypasta 2026-08-09 21:15:41 +07:00
Sven (AAMOS AI) c6b9b0278d feat(recipe-generation): matsäkerhetslint för rå fågel/fläsk/ägg/fisk 2026-08-09 20:57:58 +07:00
Sven (AAMOS AI) e4efb150aa fix(recipe-generation): robustare Gemini-enheter, butter-densitet, utökad pilot-output 2026-08-09 20:45:59 +07:00
Sven (AAMOS AI) 1f746dc822 test(recipe-generation): hårda allergen-tester där härledda allergener överkör AI 2026-08-09 20:09:31 +07:00
Sven (AAMOS AI) f321d53b30 fix(recipe-generation): justera mock-ingredienser mot seed-katalogen så pilotbatch blir granskbar 2026-08-09 19:53:44 +07:00
Sven (AAMOS AI) 4b7dec2759 feat(recipe-generation): Cibello Receptkatalog Fas A – STEG 1
- Nytt paket @app/recipe-generation med pipeline, verifieringsgrind,
  gaprapport och pilotbatch-script.
- Ny AAMOS-task GENERATE_RECIPE_CANDIDATES i @app/ai-contracts.
- GeminiAamosClient utökat med receptgenereringsstöd.
- MockAamosClient uppdaterad med deterministiska kandidater.
- Verifieringspipeline: ingrediensmappning (hård spärr), härledda allergener,
  beräknad näring via nutrition-engine, språk-/kvalitetskontroll, dedup.
- Hermetiska tester: 10/10 gröna.
- typecheck + test + build: gröna för hela workspace.

Refs: docs/32-receptkatalog-buildout.md
2026-08-09 19:47:03 +07:00
Sven (AAMOS AI) 9197d93a92 feat(inventory): naturlig-språklig fritextsökning med FoodTwin-fakta, trust-hedge och i18n ×12
- Nytt endpoint GET /v1/inventory/natural-search.
- Robust matchning med unaccent + pg_trgm similarity mot display_name,
  brand och kanoniska ingrediensnamn (sv/en).
- Svar byggs deterministiskt från faktisk data: lagringsplats + sublocation
  om registrerad, trust-state-hedge från befintlig trust-motor.
- Server-sidan i18n-katalog för 12 språk.
- Tester för svensk träff och noll-träff på flera språk.
- Design-dokument docs/30-sökrobusthet-matvaror.md.
2026-08-08 05:53:06 +07:00
Sven (AAMOS AI) ddd6b736ba feat(gdpr): fullständig raderingsflöde med pseudonym-retention, residual-test och hushållshantering
- Implementerar eraseUser() i packages/database/src/gdpr-erasure.ts som
  raderar/anonymiserar/pseudonymiserar alla personliga tabeller.
- DELETE /v1/me orkestrerar nu plan + transaktion + lagringsrensning.
- Enpersonshushåll raderas automatiskt; publika recept anonymiseras;
  draft/private-recept raderas.
- Finansiella poster (subscriptions/store_transactions/subscription_events)
  behålls under retention med slumpmässig pseudonym från
  gdpr_retention_pseudonyms.
- audit_logs/domain_events anonymiseras; kvitton i kvarvarande hushåll
  strippas på bild och OCR-text.
- Lägger till permanent residual-test (me.residual.test.ts) med
  schema-diff-assertion mot information_schema.
- Uppdaterar docs/23 och docs/29 med implementerad mekanism.
- Migration 0021 för gdpr_retention_pseudonyms och nullable
  cooking_sessions.started_by_user_id.
2026-08-08 05:45:49 +07:00
Sven (AAMOS AI) c2cc3878dd fix(skiva-1): spara accept, bildref, lokal träningsbank, lärande-loop-dok
- confirm-loop sparar nu även action=accept som positivt exempel i ai_corrections
- imageS3Key sparas vid image_training-samtycke, annars null
- ai_corrections.proposal lagrar det specifika AI-förslaget per item
- BUILD_TRAINING_SAMPLE bankar lokalt till ai_training_bank (ej externt runTask)
- Jobbet kastar aldrig i AAMOS_MODE=gemini
- Migration 0020: ai_corrections.image_s3_key/proposal + ai_training_bank
- docs/28-lärande-loop.md: datakontrakt, samtycke, retention, GDPR-radering
- Tester: accept + bildref (ja/nej) + lokal bank i gemini-läge
- REQUIRE_REAL=1 är AI-fokuserat i gemini-läge; staging mail/S3 får vara mock
2026-08-08 04:00:49 +07:00
Sven (AAMOS AI) 050c958285 feat(gemini): Skiva 1 – Gemini 2.5 Flash som lärar-tier för kylskåpsskanning
- Gemini-adapter bakom AamosClient-interface (AAMOS_MODE=gemini)
- Serversida/worker: hämtar bild, anropar Gemini, mappar mot canonical_ingredients
- Kostnad/tokens bokförs i ai_usage_counters; global dagsbudget via BudgetStore
- Redis-backed budget i worker, in-memory i tester
- Migration 0019: ai_cost_usd_microcents
- Hermetiska tester med inspelad fixture; separat pnpm eval:scan
- docs/09 uppdaterad ärligt: AAMOS-status, Gemini-flöde, säkerhet/kostnad
- REQUIRE_REAL=1 stödjer AAMOS_MODE=gemini; deploy-grind uppdaterad
2026-08-08 03:30:59 +07:00
Sven (AAMOS AI) 74f95daab2 feat(3d): meal-box merge, stored mutations, undo, mobile undo UI + i18n ×12
- Merge leftovers into existing meal_box when same recipeId + cookedAt date + frozen + available.
- Store mealBoxMutations JSONB on cooking_sessions for deterministic undo.
- Undo decrements portions/remaining, discards box at zero, appends correction ledger rows.
- Mobile: undo button in cooking/[id].tsx after-flow and meal-boxes.tsx within 24h window.
- i18n undo strings across all 12 locales; parity test green.
- 6 new integration tests: merge, no cross-date merge, frozen split, undo restore, undo discard, ledger invariant.
- Update FAS3 audit doc with 3d semantics.

Closes Fas 3d
2026-08-07 17:04:42 +07:00
Sven (AAMOS AI) cb493010d0 3c: partial consumption + undo for cooking sessions
- Append-only undo via correction transactions tied to cookingSessionId.
- POST /v1/cooking-sessions/:id/undo with 24h UTC window (409 + i18n after expiry).
- Complete undo scope: meals removed, meal boxes discarded, recipe_cooks
deleted, cookCount decremented; activation milestones left intact.
- Deterministic assumption-profile rollback via lastSessionAnswers.sessionId;
profile deleted when observationCount reaches 0.
- New status 'undone' as TEXT validated against COOKING_SESSION_STATUSES.
- Analytics event cooking_session_undone + domain events MEAL_BOX_DISCARDED,
MEAL_REMOVED, COOKING_SESSION_UNDONE.
- Partial consumption uses actualPortionsEaten/plannedPortions factor.
- i18n coverage for cooked.undoWindowExpired across all 12 locales + server.
- Invariant tests: computeBalance(transactions) === item.quantity after
complete, undo, and undo + new complete; transaction count increases on undo.
- Migration 0014_expand_event_types.sql adds new enum values.
- Updated FAS3-COOKING-SESSIONS-AUDIT.md with chosen semantics.
2026-08-07 05:47:54 +07:00
Sven (AAMOS AI) bbe7526ef3 fix(3b): delad kompletteringsväg för legacy /cook + deterministiska cooking-assumptions
- cookRecipeInputSchema utökas med actualPortionsEaten, leftoverEstimatePortions, leftoverNote
- completeCookingSession-wrapper i apps/api/src/lib/cooking.ts hanterar summavalidering,
  persistens av svar, profiluppdateringar och analytics (started+completed) för båda vägarna
- Legacy POST /v1/recipes/:id/cook använder wrappern med emitStartedEvent
- GET /v1/recipes/:id/cooking-assumptions väljer deterministiskt bland icke-valfria ingredienser
- i18n: nyckel cooked.portionsSumExceedsPlanned i samtliga 12 lokaler + server-i18n
- Nya tester för legacy /cook och cooking-assumptions med valfri första ingrediens

Refs: steg 3b-fix, granskningsrunda 2026-08-07
2026-08-07 05:13:35 +07:00
Sven (AAMOS AI) e46281b9b5 Fas 3 steg 3b: minimala efterfrågor + hushållsantagandeprofiler per ingrediens 2026-08-07 03:56:41 +07:00