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

123 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.