Files
Cibello-app/docs/28-lärande-loop.md
T
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

5.5 KiB
Raw Blame History

Del 28 Lärande-loop (ai_corrections → ai_training_bank)

Ingen AI är facit. Varje skanning där användaren granskar förslag blir ett träningsexempel — om hon samtycker. Detta dokument beskriver datakontraktet, samtyckesgätning och GDPR-radering.

Översikt

App → skanna → worker → AI-förslag → app (awaiting_confirmation)
                         ↓
              användaren granskar varje item
                         ↓
              POST /v1/scans/:id/confirm
                         ↓
           ai_corrections (ett rad per item)
                         ↓
         BUILD_TRAINING_SAMPLE (scheduler, 1×/vecka)
                         ↓
              ai_training_bank (cibello-ägt dataset)

ai_training_bank är den consenteda platsen för rikare data (bildreferens, förslag, korrigering). Analytics får aldrig innehålla PII eller råa bilder (se §56/§58).

Datakontrakt per skanning

Varje rad i ai_corrections representerar ett item från en skanning:

Fält Innehåll
scanJobId Källskanningen (scan_jobs.id).
taskType T.ex. ANALYZE_FRIDGE_IMAGE, READ_RECEIPT.
aiOutput Hela AI-raw-resultatet från scan_jobs.result.
proposal Det specifika AI-förslag item:et kom från (detectedName, canonicalIngredientId, brand, estimatedQuantity, unit, bestBeforeDate, confidence, requiresConfirmation).
userCorrection { action: "accept" | "edit" | "reject" | "add", corrected?: {...} }
corrected (inbäddad) Användarens slutgiltiga värden vid accept/edit/add: displayName, canonicalIngredientId, brand, quantity, unit, bestBeforeDate, useByDate.
imageS3Key Första lagrade bildnyckeln från skanningen, endast om image_training-samtycke fanns vid bekräftelsen. Annars null.
modelVersion / promptVersion Vilken modell och prompt som producerade förslaget.
consentSnapshot { anonymized_improvement: "granted"|"denied", image_training: "granted"|"denied", ... } som JSON vid bekräftelsetillfället.
createdAt Tidsstämpel för bekräftelsen.

Åtgärder som sparas

  • accept — positivt exempel. AI-förslaget var korrekt nog att användaren accepterade det oförändrat.
  • edit — användaren ändrade något (namn, kvantitet, enhet, datum …).
  • add — AI missade item:et helt; användaren lade till det manuellt.
  • reject — AI hittade något som inte finns; användaren kastade det.

Alla fyra åtgärder sparas. Bara accept/edit/add leder till att ett inventory_items-rad skapas; reject gör det inte.

ai_training_bank

När BUILD_TRAINING_SAMPLE kör (veckoschema i worker) bankas rader med anonymized_improvement = granted till ai_training_bank:

Fält Innehåll
correctionId Referens till ai_corrections.id (cascade delete).
scanJobId Källskanningen.
version Dataset-version, t.ex. v1. Bumpar när formatet ändras.
taskType Samma som källan.
imageS3Key Kopierad från ai_corrections.image_s3_key (kan vara null).
proposal AI-förslaget för just det item:et.
action Användarens åtgärd.
corrected Slutgiltiga värden, eller null vid reject.
modelVersion / promptVersion Spårbarhet till modell/prompt.
consentSnapshot Kopia av samtyckesläget.
exportedAt När raden bankades.

Banken ägs av cibello och är versionerad. Ingen extern leverantör anropas under exporten — jobbet får aldrig kasta på grund av att AAMOS_MODE=gemini saknar EXPORT_TRAINING_SAMPLE-stöd.

Samtycke

Två separata samtycken styr vad som sparas och var:

  1. anonymized_improvement — krävs för att överhuvudtaget banka till ai_training_bank. Utan detta lämnas ai_corrections kvar men raderna exporteras inte.
  2. image_training — krävs för att imageS3Key ska sparas. Utan samtycke sparas endast textparet (proposal, corrected) och imageS3Key är null.

Samtyckessnapshoten sparas per rad så att framtida ändringar av användarens samtycke inte påverkar redan bankade data.

Retention

  • ai_corrections: behålls så länge användarkontot finns. Underlättar support och debugging.
  • ai_training_bank: behålls så länge användarkontot finns, om inte användaren återkallar samtycke — då raderas endast rader där consentSnapshot.anonymized_improvement = "denied" (i praktiken exporteras de aldrig).
  • Bilder i lagring: följer samma regler som imageS3Key — sparas så länge kontot finns, raderas vid kontoradering.

GDPR / kontoradering

Vid kontoradering (eller rätten att bli glömd):

  • users → cascade delete → ai_corrections försvinner (FK ON DELETE CASCADE).
  • ai_corrections → cascade delete → ai_training_bank försvinner (FK ON DELETE CASCADE).
  • Bilder som refereras av ai_corrections.imageS3Key och ai_training_bank.imageS3Key måste raderas från lagring. Detta görs av en GDPR-raderingsprocessor (se Del 12) som läser bildnycklarna innan användarposten tas bort.

Verifiera alltid att kontoraderingstestet kontrollerar både ai_corrections, ai_training_bank och att inga överblivna bildnycklar finns kvar i S3/mock-lagringen.

Inget PII i analytics

Träningsdatan (rikare bild+förslag+korrigering) finns endast i ai_corrections/ai_training_bank under samtycke. Analytics-events som AI_CORRECTED innehåller endast scanJobId, taskType och field (åtgärd), aldrig bilder, namn eller detaljerade värden.