- 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
5.5 KiB
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:
anonymized_improvement— krävs för att överhuvudtaget banka tillai_training_bank. Utan detta lämnasai_correctionskvar men raderna exporteras inte.image_training— krävs för attimageS3Keyska sparas. Utan samtycke sparas endast textparet (proposal,corrected) ochimageS3Keyärnull.
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ärconsentSnapshot.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_correctionsförsvinner (FKON DELETE CASCADE).ai_corrections→ cascade delete →ai_training_bankförsvinner (FKON DELETE CASCADE).- Bilder som refereras av
ai_corrections.imageS3Keyochai_training_bank.imageS3Keymå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.