feat(game): server-authoritative code-breaker timer (#46) #62

Merged
Reliodas merged 3 commits from feat/46-codebreaker-timer into develop 2026-06-25 13:21:46 +00:00
Owner

Closes #46

Ajoute un chronomètre serveur autoritaire aux épreuves de déchiffrage du code (deuxième manche et finale), avec verrouillage des soumissions à l'expiration.

Changements

  • rules.ts : ROUND2_CODEBREAKER_TIMER_SECONDS et FINAL_CODEBREAKER_TIMER_SECONDS (30 s).
  • rounds/codebreaker.ts (nouveau, partagé manche 2 + finale) : startCodebreakerTimer (compte à rebours setInterval autoritaire, unref), codebreakerLocked, et rankCodebreaker.
  • round2.ts / round3.ts : start() lance le chrono ; recordCodebreakerAnswer refuse après expiration ; revealCodebreaker libère le timer et applique le classement. selectCategory nettoie défensivement tout intervalle résiduel.
  • Classement (rankCodebreaker) : corrects par heure de réception → incorrects par heure de réception → sans-réponse (ordre déterministe). Précise la « règle retenue » du ticket.
  • Projections (round2.state.ts / round3.state.ts) + types (game-state.ts) : le timer est exposé sur les statuts codebreaker / final-codebreaker actifs uniquement.
  • Client : Timer affiché sur les écrans codebreaker actifs (host, joueur, spectateur, manche 2 + finale). Le MJ peut révéler après expiration.
  • Docs : Regles.md et Implémentation.md (durée, verrouillage, classement).

Tests

  • Serveur : démarrage du chrono à 30 s, expiration → verrouillage + soumission tardive refusée, soumission avant expiration acceptée, déduplication, et ordre de classement corrects→incorrects→sans-réponse (manche 2 et finale). Timers déterministes via les mock timers de node:test.

Vérification (checkout propre, sans assets)

  • typecheck OK ; node:test 199 pass (1 skipped), Jest 13/13, Vitest 83/83
  • coverage serveur 93.55 % stmts (seuils respectés), client exit 0
  • build OK, check:assets OK, validate:questions OK (142), smoke OK, e2e Playwright 3/3

Décision produit

Durée du chronomètre fixée à 30 s pour les deux épreuves (configurable dans rules.ts).

Closes #46 Ajoute un chronomètre serveur autoritaire aux épreuves de déchiffrage du code (deuxième manche et finale), avec verrouillage des soumissions à l'expiration. ## Changements - **`rules.ts`** : `ROUND2_CODEBREAKER_TIMER_SECONDS` et `FINAL_CODEBREAKER_TIMER_SECONDS` (30 s). - **`rounds/codebreaker.ts`** (nouveau, partagé manche 2 + finale) : `startCodebreakerTimer` (compte à rebours `setInterval` autoritaire, `unref`), `codebreakerLocked`, et `rankCodebreaker`. - **`round2.ts` / `round3.ts`** : `start()` lance le chrono ; `recordCodebreakerAnswer` refuse après expiration ; `revealCodebreaker` libère le timer et applique le classement. `selectCategory` nettoie défensivement tout intervalle résiduel. - **Classement (`rankCodebreaker`)** : corrects par heure de réception → **incorrects** par heure de réception → **sans-réponse** (ordre déterministe). Précise la « règle retenue » du ticket. - **Projections** (`round2.state.ts` / `round3.state.ts`) + **types** (`game-state.ts`) : le `timer` est exposé sur les statuts `codebreaker` / `final-codebreaker` actifs uniquement. - **Client** : `Timer` affiché sur les écrans codebreaker actifs (host, joueur, spectateur, manche 2 + finale). Le MJ peut révéler après expiration. - **Docs** : `Regles.md` et `Implémentation.md` (durée, verrouillage, classement). ## Tests - Serveur : démarrage du chrono à 30 s, expiration → verrouillage + soumission tardive refusée, soumission avant expiration acceptée, déduplication, et ordre de classement corrects→incorrects→sans-réponse (manche 2 et finale). Timers déterministes via les mock timers de `node:test`. ## Vérification (checkout propre, sans assets) - typecheck OK ; `node:test` 199 pass (1 skipped), Jest 13/13, Vitest 83/83 - coverage serveur 93.55 % stmts (seuils respectés), client exit 0 - build OK, check:assets OK, validate:questions OK (142), smoke OK, e2e Playwright 3/3 ## Décision produit Durée du chronomètre fixée à **30 s** pour les deux épreuves (configurable dans `rules.ts`).
Add a 30s authoritative countdown to the round 2 and final code-breaker rounds
(shared rounds/codebreaker.ts). Submissions lock at expiry while the status
stays so the host reveals afterwards. The reveal order now ranks correct (by
receipt time), then incorrect (by receipt time), then non-answering candidates
deterministically. Projections expose the timer on the active code-breaker
statuses; durations live in rules.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Show the server countdown via the existing Timer component on the active
code-breaker screens (host, player and spectator, second round and final). It
appears only while submissions are open, since the projection clears the timer
on the reveal states.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(rules): document the code-breaker timer (#46)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
dfed340af3
Record the 30s authoritative code-breaker countdown, the expiry lock and the
correct/incorrect/no-answer reveal ranking in Regles.md and Implémentation.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit cf5bb224cc into develop 2026-06-25 13:21:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: jeux/le-grand-concours#62
No description provided.