diff --git a/docs/F0_ANTI_CHEAT_FUP_OG_FAKTA.md b/docs/F0_ANTI_CHEAT_FUP_OG_FAKTA.md new file mode 100644 index 0000000..927c3bb --- /dev/null +++ b/docs/F0_ANTI_CHEAT_FUP_OG_FAKTA.md @@ -0,0 +1,88 @@ +# F0 Anti-cheat regler — Fup og Fakta + +## Formål +Fastlægge en enkel, håndterbar anti-cheat baseline for MVP, så spillet forbliver fair uden tung NLP/moderation. + +## Principper (F0) +1. **Server-authoritative regler**: Alle valideringer og afvisninger sker server-side. +2. **Forudsigelige regler**: Spillere skal møde tydelige og konsistente afvisningsårsager. +3. **Lav kompleksitet i MVP**: Kun deterministiske checks i F0; semantisk lighed udskydes. + +## Need-to-have regler (MVP) + +### R1 — Én løgn pr. spiller pr. spørgsmål +- Spiller kan kun have ét aktivt `LieAnswer` per spørgsmål. +- Ny indsendelse før timeout overskriver tidligere svar (samme spiller/samme spørgsmål). +- Efter fase-lock (timeout eller host-advance) afvises nye indsendelser. + +### R2 — Ingen tomme eller trivielt ugyldige svar +- Afvis tom streng, whitespace-only og svar uden bogstaver/tal. +- Normaliser input før validering: trim + collapse af gentagne mellemrum. + +### R3 — Ingen identiske løgne internt i runden +- To spillere må ikke ende med samme normaliserede løgn på samme spørgsmål. +- Duplikatcheck bruger en deterministisk `canonical_form`, fx: + - lowercase + - trim + single-space + - fjern ledende/afsluttende tegnsætning +- Ved konflikt får den seneste indsender en valideringsfejl og skal indsende ny løgn inden tidsfristen. + +### R4 — Ingen identisk løgn med korrekt svar +- Spillerløgn må ikke matche spørgsmålets korrekte svar efter samme normalisering som R3. +- Ved match afvises svaret med fejlbesked. + +### R5 — Basal anti-spam og inputgrænser +- Løgn-længde begrænses (foreslået MVP: 2-120 tegn). +- Payloads over max længde afvises (ikke trunkeres silent). +- Simpelt request-throttle på submit-endpoint per spiller/session (fx 5 requests/10 sek). + +### R6 — Auditérbarhed +- Afviste submit-forsøg logges med årsagskode (fx `duplicate_lie`, `matches_truth`, `phase_locked`). +- Logning må ikke gemme unødige persondata ud over det nødvendige til fejlsøgning/audit. + +## Nice-to-have (efter MVP) +- Semantisk duplikatdetektion ("København" vs "kbh"). +- Levenshtein/fuzzy match mod korrekt svar for næsten-identiske svar. +- Sprog-/profanitetsfilter og moderationspipeline. +- Avanceret anomaly-detektion (bot-lignende submit-mønstre). + +## Implementeringsnære acceptance criteria (F0) +F0 anti-cheat anses som leveret når følgende kan verificeres i tests eller integration: + +1. **Duplicate player submit** + - Givet samme spiller + samme spørgsmål, når spiller submitter to gange før lock, + - så findes kun ét aktivt svar, og sidste version er den gældende. + +2. **Duplicate lie across players** + - Givet to spillere på samme spørgsmål, + - når spiller B submitter en `canonical_form` identisk med spiller A, + - så afvises spiller B med deterministisk fejl `duplicate_lie`. + +3. **Lie equals truth** + - Givet korrekt svar for spørgsmålet, + - når en spiller submitter løgn med samme `canonical_form`, + - så afvises submit med fejl `matches_truth`. + +4. **Phase lock enforcement** + - Når løgnefasen er låst, + - så afvises alle nye submit-forsøg med fejl `phase_locked`. + +5. **Input validation boundaries** + - Svar under min-længde, over max-længde eller whitespace-only afvises med specifik fejl. + +6. **Audit trail present** + - For hver afvist submit oprettes en audit/log-entry med tidsstempel og årsagskode. + +## Foreslåede fejlkoder (kontrakt) +- `invalid_format` +- `too_short` +- `too_long` +- `duplicate_lie` +- `matches_truth` +- `phase_locked` +- `rate_limited` + +## Noter om data/model (ikke bindende design) +- Overvej DB-constraint/unik indeks på `(question_id, canonical_form)` for aktive løgne, + suppleret med applikationsvalidering for gode fejlbeskeder. +- `canonical_form` bør beregnes ens i backend-path (API + evt. admin tooling).