Files
Cibello-app/docs/28-lärande-loop.md
Sven (AAMOS AI) c32a7e33c7
CI / Typecheck, test & build (push) Failing after 2s
ci: trigga på master + formatfix inför Gitea Actions
2026-08-13 17:25:14 +07:00

8.5 KiB
Raw Permalink 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).
  • Träningsbilder (image_s3_key): raderas senast 90 dagar efter att de bankats till ai_training_bank, om användaren inte aktivt valt att spara sina bidrag längre. För användare som samtycker till långtidslagring (t.ex. för att förbättra modellen över tid) kan bilderna behållas så länge kontot finns, men aldrig längre än vad användaren samtyckt till. Vid återkallat image_training-samtycke raderas bilderna inom 30 dagar.
  • Bilder som endast ingår i råa scan_jobs (inte bankade som träningsdata): raderas enligt samma 90-dagarspolicy eller när skanningen tas bort, beroende på vilket som inträffar först.

GDPR / kontoradering

DELETE /v1/me soft-deletar (anonymiserar) users-raden för att bevara referensintegritet i aggregat. Därför fyras inte FK-cascade från users till ai_corrections eller scan_jobs. Istället sker raderingen explicit:

  1. Saml alla distinkta bildnycklar för användaren:
    • ai_corrections.image_s3_key
    • ai_training_bank.image_s3_key (via join mot ai_corrections)
    • scan_jobs.s3_keys
  2. Radera varje nyckel i objektlagring med storage.deleteObject. S3-fel loggas och påverkar inte fortsatt radering.
  3. Radera ai_corrections för userId. ai_training_bank försvinner automatiskt via correction_id ON DELETE CASCADE.
  4. Radera scan_jobs för userId (även denna cascade fyrar inte vid soft-delete).
  5. Fortsätt med hård radering av övrig persondata och anonymisera användarposten.

Verifiera alltid att kontoraderingstestet kontrollerar både ai_corrections, ai_training_bank, scan_jobs 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.