Leçons de soumission Stake Engine — le registre des pièges (et leur correctif)
But : chaque bug qui a cassé une soumission réelle est consigné ici avec sa cause, son correctif, et où il vit dans le code. Tous ces correctifs sont dans le moteur/pipeline partagé → toute nouvelle machine en hérite automatiquement. Ce document est la mémoire durable de l'équipe : à lire avant de soumettre, à compléter à chaque nouveau piège.
La règle qui résume tout :
node factory/qa/submission-check.mjs <gameId>doit être 6/6 vert avant de proposer un DOWNLOAD. Ce test reproduit les conditions réelles de Stake et attrape chacun des pièges ci-dessous. Aucune machine ne se soumet sans lui.
Contexte : pourquoi le mock ne suffit pas
Le moteur a d'abord été testé contre un mock RGS dont on avait inventé le format. Le vrai
RGS Stake diffère sur plusieurs points, et l'arborescence servie par Stake n'est pas celle de
l'export brut. Tous les bugs ci-dessous viennent de cet écart. Le mock renvoie désormais le même
format que le vrai RGS (engine/src/devtools/mockrgs.js) pour que dev == production.
1. BOOT ERROR — l'identifiant de jeu de l'URL ≠ le nom de dossier
- Symptôme : écran
BOOT ERROR,game.config.jsonetmath.meta.jsonen 404. - Cause : Stake lance le jeu avec son identifiant dans l'URL (
?game=hell-houndsà tirets, ou un UUID de round), qui n'est PAS notre nom de dossier (hell_hounds). Le moteur construisaitbaseà partir de ce paramètre → chemins vers un dossier inexistant → 404 →JSON.parse("Not Found")→ boot rejeté. - Correctif :
window.__CK_GAME(injecté par l'export = le vrai nom de dossier) prime sur?game=. En dev il n'existe pas → on retombe sur?game=(sélecteur du serveur de preview). →engine/src/main.js:const gameId = window.__CK_GAME || params.gameId || … - Chemin CDN Stake observé :
<team>.live.stake-engine.com/<jeu>/v<N>/<gameId>/game.config.json
2. BOOT ERROR — math.meta.json dans un dossier math/
- Symptôme :
math/math.meta.jsonen 404 sur Stake (marche en local). - Cause : Stake retire le dossier
math/du frontend (il le prend pour le package RGS). - Correctif :
math.meta.json(descripteur front : paytable/paylines/modes) vit à la RACINE du jeugames/<id>/math.meta.json. Le dossiermath/ne contient QUE le package RGS (publish_files/configs/forces), et l'export l'exclut du zip frontend. →factory/math-tools/generate_lines.py(écrit à la racine),engine/src/main.js(fetch racine),factory/site/server.mjs(export exclutmath/).
3. Devise figée sur $
- Cause : symbole
$codé en dur ; le vrai RGS renvoie la devise dansauth.balance.currency. - Correctif : table de devises (JPY/KRW = 0 décimale, ¥/€/£…,
SC= social sans symbole) ; le betbar formate seloncore.s.currency, lue à l'authenticate. →engine/src/stake-rgs/currency.js,engine/src/ui/betbar.js,engine/src/core/core.js.
4. Format d'authenticate réel (imbriqué sous config)
- Cause : le vrai RGS renvoie
{ balance:{amount,currency}, config:{betLevels,minBet,maxBet, stepBet,defaultBetLevel,jurisdiction}, round }— imbriqué, pas au top-level comme le mock. - Correctif :
core.boot()litauth.config.*(fallback top-level pour compat mock) +auth.balance.currency. →engine/src/core/core.js.
5. Mode Replay — le SPIN tentait de miser
- Symptôme : dans l'onglet Replay, « je ne peux pas lancer, la balance est à zéro ».
- Cause : en replay il n'y a pas de portefeuille (balance 0). Le bouton SPIN gardait le handler de mise de la betbar → vérifiait la balance → refusait.
- Correctif : en replay, SPIN = relancer la relecture (
location.reload(), ré-entre via?replay=true), jamais un wager ; plaque BALANCE affiche « REPLAY ». →engine/src/main.js. - Rappel d'usage : le Replay ne rejoue qu'un round déjà joué. Séquence : publier la math → Local Testing → Settings→Balance (créditer) → SPIN (le round s'enregistre) → puis Replay.
6. Publication math lente / échouée (timeout du validateur)
- Symptôme : « Publishing… » qui tourne puis croix rouge, alors que le format est bon.
- Cause : books trop lourds décompressés (ex. 36 Mo) → le validateur Stake sature. TNF accepté = 7,7 Mo.
- Correctif : mode slim du générateur — regroupe les gains par bandes logarithmiques
(un book représentatif réel par bande, préserve la queue des gros gains essentielle au RTP d'un
buy ×100), RTP toujours exact. →
generate_lines.py --max-books 700 --reps 1(à utiliser pour TOUTE machine à free spins lourds). Résultat type : ~2,9 Mo décompressé, RTP 0.96 exact.
7. payoutMultiplier = multiplicateur direct
- Le wire Stake renvoie
round.payoutMultiplieren multiplicateur direct (3.0 = ×3), PAS en centièmes. Le front ne multiplie jamais par 100. Le book stocke en unités ×100 (300), c'est le RGS qui divise. (Convention TNF, respectée pargenerate_lines.pyetnormalizePlay.)
Boot auto-diagnostique
Si un boot échoue malgré tout, le moteur affiche la cause exacte à l'écran (URL + code HTTP)
sans ouvrir la console — engine/src/main.js (fetchJSON + le boot().catch). Le prochain
screenshot suffit à diagnostiquer.
La porte de contrôle (à ne jamais sauter)
factory/qa/submission-check.mjs + factory/qa/stake-sim.mjs reproduisent Stake : export → retire
math/ → sert derrière un RGS au vrai format → vérifie boot en JPY/ja + EUR/fr + USD/en, la
devise, et le replay (SPIN relance). 6/6 obligatoire avant DOWNLOAD. Chaque nouveau piège
rencontré doit devenir une nouvelle assertion ici.