Forfaits club
Cette page documente les règles Convex de forfaits déclarés sur une compétition.
Sources principales :
convex/schema.ts
convex/competition/club_forfeits.ts
convex/competition/club_forfeit_impacts.ts
convex/competition/club_forfeit_sanctions.ts
convex/competition/bet_settlement.ts
convex/lib/audit_logs.ts
convex/social/announcements.ts
club_forfeits et statut
Les champs clés vérifiés : leagueId, season, clubId, effectiveAt, declaredAt, declaredById, scope, mercatoStartAt, status, reason, adminNote, cancelledAt, cancelledById, cancelReason.
Statuts :
Idempotence métier : la déclaration d’un forfait actif existant retourne l’enregistrement existant.
Détermination de scope
Deux scopes existent :
FULL_COMPETITION
POST_MERCATO_ONLY
Quand une fenêtre de mercato est connue, le scope est dérivé : avant mercato = FULL_COMPETITION, à partir de mercato = POST_MERCATO_ONLY.
Application sportive (applyClubForfeit)
Le moteur applique le forfait sur les matchs actifs où le club est impliqué, selon le scope :
FULL_COMPETITION : tous les matchs en cours de saison,
POST_MERCATO_ONLY : seulement à partir de mercatoStartAt si défini.
Scores imposés :
- forfait simple : club forfaité perd (
0), adversaire marque 1,
- double forfait : score
0-0.
Écriture d’impact :
- scores/évolution match en
resultOrigin = CLUB_FORFEIT,
forfeitClubId, forfeitCreatedResult,
- snapshots de restauration :
previousHomeScore, previousAwayScore, previousResultOrigin, previousMatchStatus,
isDisputed = false, validatedAt posé,
- match repassé
validated.
Répercussions associées
- Invalidation des stats match (
match_player_stats, match_team_stats) avec invalidatedReason = CLUB_FORFEIT.
- Annulation paris :
cancelPendingBetsForMatch avec reason = MATCH_FORFEITED (uniquement PENDING).
- Recalcul classement via
recalculateLeagueStandingsCore.
- Sanctions automatiques via
generateForfeitSanctions.
- Annonce globale
sourceType = CLUB_FORFEIT.
Réversion (revertClubForfeitImpacts)
La réversion re-cible uniquement les impacts signés par le forfait (resultOrigin = CLUB_FORFEIT, forfeitClubId).
- si
forfeitCreatedResult === true : suppression du résultat puis restauration status depuis snapshot previousMatchStatus,
- sinon : restauration
homeScore / awayScore et flags de forfeit,
- réactivation des stats invalidées par ce forfeit,
- recalcul des standings,
- levée des sanctions liées.
Cas complexe :
- si l’adversaire est encore en forfait actif, la restauration de score peut être ignorée avec warning.
Les paris annulés lors du forfeit ne sont pas réouverts ; seuls les PENDING ont été annulés.
Sanctions
generateForfeitSanctions applique un COMPETITION_BAN :
- destinataires GM +
MANAGER / CO_MANAGER actifs,
- scope principal :
["SPORT_ELIGIBILITY"],
banScope par défaut PLAYER_AND_STAFF,
- périodes : de
baseSeason sur seasonCount saisons (défaut 3, cap 10),
- traçage source (
sourceType, sourceForfeitId, sourceClubId).
liftForfeitSanctions met fin à la sanction en mode manuel (END_MANUAL, ENDED_MANUAL) avec raison par défaut "Forfait annulé".
Limites / précisions
- Les effets exacts hors Convex (accès terrain/API externe, emails ciblés, placement visuel final des annonces) ne sont pas tous détaillés dans ce périmètre. [non vérifié]
- La logique métier sur le comportement d’un forfeit en mode replay/écran front n’est pas couverte ici. [non vérifié]
Last modified on June 24, 2026