Skip to content

Bloc 98 — 🐛 Progression : une ligue disponible parce qu'elle a ses valeurs, pas parce qu'elle est dans une liste - #124

Merged
magicgg91 merged 1 commit into
devfrom
claude/bloc-98-progression-leagues
Sep 14, 2026
Merged

magicgg91 merged 1 commit into
devfrom
claude/bloc-98-progression-leagues

Conversation

@magicgg91

Copy link
Copy Markdown
Owner

Numéroté 98 : le 97 est pris par le correctif CI mergé juste avant (PR #122). Ton brief disait 97.

Point C : ton message s'arrêtait sur « dans l'ordre de progression naturel du jeu : », la liste manquait. Tu as confirmé Bronze → Légende (croissant), qui est déjà l'ordre de la constante leagues.

A — 🚨 Le bug

Ton diagnostic était le bon, et c'était encore plus littéral que « vraisemblablement codé en dur » : trois choses ignoraient les données, et toutes nommaient une ligue en dur.

Ce qu'il y avait
src/lib/level-up.ts levelUpTroopsAt s'ouvrait sur if (league === "silver") return null;
src/lib/level-up.ts confirmedLevelUpLeagues, une liste statique de 5 noms
messages/*.json le message public listait ces 5 noms dans son texte traduit

D'où le symptôme exact que tu décris : la saisie partait bien en base, et rien ne la lisait.

Le correctif. La disponibilité est maintenant une question posée aux données : hasLevelUpTroopsFormula(league, parameters) répond oui quand coefficient et ratio sont présents et > 0 — pour n'importe quelle ligue. Une ligue renseignée s'affiche ; une ligue vidée redevient non confirmée toute seule. Aucun nom de ligue ne subsiste dans la logique, et un test le vérifie sur le source lui-même (src/lib/level-up.ts et src/components/level-up-reference.tsx, hors commentaires) — c'est ce qui empêche la rechute.

Le message nomme désormais les ligues qui en ont vraiment une, assemblées par Intl.ListFormat pour que le « A, B et C » reste correct dans les 5 langues sans séparateur écrit à la main. La formulation change donc un peu — c'était inévitable, l'ancienne contenait la liste :

⚠️ Formule de troupes non encore confirmée pour cette ligue. Ligues disponibles : Bronze, Or, Platine, Diamant et Légende.

A-bis — ⚠️ Un second bug trouvé en route, pas dans le brief

src/app/api/admin/guides/references/level-up/route.ts refusait tout payload contenant un zéro :

if (numbers.some((value) => !Number.isFinite(value) || value <= 0))
  return 400 invalid_parameters;

Or {0, 0} est exactement ce qui marque une ligue non confirmée. Conséquence : le référentiel Progression était insauvegardable tant qu'une ligue restait vierge — sur une installation neuve c'est Argent, donc la toute première sauvegarde tentée par un admin revenait en 400. Tu n'y es plus exposé (tes 6 ligues sont remplies), mais la règle « 0/0 = pas encore confirmé » ne tenait pas debout tant que l'API interdisait de stocker ce 0.

La règle devient : une paire est soit renseignée (les deux > 0), soit vierge (les deux à 0). À moitié remplie, négative ou NaN, elle reste refusée.

B — Le texte « (Formule de troupes non confirmée) » en admin

Il suit maintenant ce qui est réellement stocké : il disparaît dès qu'une ligue a ses deux valeurs, et il apparaît sur n'importe quelle ligue laissée vide — il n'avait rien de spécifique à Argent.

C — Ordre des ligues

Bronze, Argent, Or, Platine, Diamant, Légende, admin et public. Le public l'était déjà (il boucle sur leagues) ; l'admin affichait Argent en dernier, après Légende, parce que sa ligne était écrite à la main à la suite des cinq « confirmées ». Une seule boucle sur la liste partagée règle l'ordre et le bug en même temps.

Tests

21 tests unitaires : le prédicat dans les deux sens (une ligue remplie devient disponible, une ligue vidée redevient indisponible — écrits sur une ligue passée en paramètre, jamais sur « silver »), les formes refusées (à moitié remplie, négative, NaN), la validation de sauvegarde, l'ordre de progression, la note admin conditionnelle, et le garde-fou qui interdit un nom de ligue dans le source.

1 test e2e qui refait ton parcours dans l'ordre où tu l'as vécu : constat de l'indisponibilité d'Argent en public → saisie et enregistrement côté admin → table d'Argent affichée en public, avec la valeur calculée depuis les données enregistrées (niveau 2 = 30 × 1,24² = 46, pas juste « une table est là ») → retour à l'état vierge, dont le succès prouve au passage le correctif A-bis.

Contre-vérifié en cassant le correctif : le littéral silver remis dans levelUpTroopsAt rougit 3 unitaires et l'e2e ; la note admin rendue inconditionnelle en rougit 4.

Validation

  • pnpm lint + typecheck + prettier : propres
  • pnpm test : 1296 tests verts (+21)
  • pnpm build : succès
  • pnpm test:e2e : 87/87 verts (5,2 min), sur une base e2e recréée à neuf

Ce qu'il te reste à faire

Rien côté données : tes valeurs d'Argent sont déjà en base, elles s'afficheront dès le déploiement. Si tu veux les revérifier, l'éditeur admin les montre maintenant à leur place dans l'ordre, sans la mention « non confirmée ».

🤖 Generated with Claude Code

https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2


Generated by Claude Code

Numéroté 98 : le 97 est pris par le correctif CI mergé juste avant.

A. Les valeurs d'Argent saisies et enregistrées en admin n'étaient jamais
   regardées par le référentiel public. Trois choses les ignoraient, et
   toutes nommaient une ligue en dur :

   - `levelUpTroopsAt` s'ouvrait sur `if (league === "silver") return null`
   - `confirmedLevelUpLeagues`, une liste statique de 5 noms
   - le message public listait ces 5 noms dans son texte traduit

   La disponibilité vient maintenant des données : `hasLevelUpTroopsFormula`
   répond oui quand coefficient ET ratio sont présents et > 0, pour
   n'importe quelle ligue. Une ligue renseignée s'affiche, une ligue vidée
   redevient non confirmée, sans aucun nom de ligue dans la logique — un
   test le vérifie sur le source lui-même (hors commentaires).

   Le message nomme désormais les ligues réellement disponibles, assemblées
   par `Intl.ListFormat` pour que le « A, B et C » reste correct dans les
   5 langues. Formulation retouchée en conséquence dans les 5 fichiers de
   messages, avec une branche ICU pour le cas où aucune ligue n'en a.

A-bis (trouvé en route, non signalé au brief). La route PUT refusait tout
   payload contenant un zéro, donc le référentiel Progression était
   insauvegardable tant qu'une ligue restait vierge — sur une installation
   neuve, c'est Argent, et la toute première sauvegarde revenait en 400.
   Or c'est précisément {0, 0} qui marque une ligue non confirmée. La règle
   devient : une paire est soit renseignée (les deux > 0), soit vierge (les
   deux à 0) ; à moitié remplie, négative ou NaN, elle reste refusée.

B. Le « (Formule de troupes non confirmée) » de l'éditeur admin suit
   maintenant ce qui est réellement stocké : il disparaît dès que la ligue
   a ses deux valeurs, et apparaît sur n'importe quelle autre ligue laissée
   vide — il n'était pas propre à Argent.

C. Les ligues sont listées dans l'ordre de progression du jeu (Bronze →
   Légende, l'ordre de la constante `leagues`), côté admin comme public.
   Le public l'était déjà ; l'admin affichait Argent en dernier, après
   Légende, parce que sa ligne était écrite à la main à la suite des cinq
   « confirmées ».

Tests : 21 unitaires (prédicat, validation de sauvegarde, ordre, absence
de nom de ligue dans le source, note admin conditionnelle) et 1 e2e qui
refait le parcours signalé — constat de l'indisponibilité, saisie côté
admin, puis table d'Argent affichée en public avec la valeur calculée
depuis les données enregistrées, et retour à l'état vierge.
Contre-vérifié en cassant le correctif : le littéral silver remis en
place rougit 3 unitaires et l'e2e ; la note admin rendue inconditionnelle
en rougit 4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2
@magicgg91
magicgg91 merged commit 87dc06b into dev Sep 14, 2026
2 checks passed
@magicgg91
magicgg91 deleted the claude/bloc-98-progression-leagues branch September 14, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants