# 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.