Skip to content

Bloc 99 — 🐛 Transfert Stuff → ParamĂštres joueur annulĂ© tout seul (tampon de version dans les rĂ©glages) - #125

Merged
magicgg91 merged 1 commit into
devfrom
claude/bloc-99-player-settings-sync
Sep 14, 2026
Merged

magicgg91 merged 1 commit into
devfrom
claude/bloc-99-player-settings-sync

Conversation

@magicgg91

Copy link
Copy Markdown
Owner

Le bug, tel qu'un joueur le vit

Un transfert depuis le simulateur Stuff vers les paramĂštres du joueur pouvait revenir Ă  zĂ©ro tout seul, peu aprĂšs le chargement de la page. C'est le mĂȘme dĂ©faut qui rendait player-settings-panel.test.tsx instable en CI depuis le Bloc 93 — je l'avais signalĂ© sans le corriger.

J'ai capturé un échec réel avant de toucher au code, pour ne pas partir d'une hypothÚse : c'est bien le test reflects an external equipment-skills transfer live qui tombe, sur Attaque avec équipement attendu 12.5, reçu 0. Le transfert est écrasé, pas ignoré.

La cause

safePlayerSettings étalait l'objet stocké en entier :

return { ...fallback, ...parsed, /* 
 */ };

parsed contient v, le tampon de version — de la comptabilitĂ© de stockage, absente du type PlayerSettings. Il repartait donc Ă  l'intĂ©rieur des rĂ©glages, et TypeScript ne le voyait pas (un spread de Partial<PlayerSettings> & { v?: number } passe).

Conséquence : toute comparaison entre la valeur en mémoire et la valeur relue est inégale par construction, quel que soit le contenu. Vérifié sur le vrai code avant correctif :

clés en trop : [ 'v' ]
garde Ă©gale  : false      ← sur des rĂ©glages pourtant identiques

La garde de syncFromStorage en est une :

setSettings((current) =>
  JSON.stringify(current) === JSON.stringify(next) ? current : next,
);

Le panneau rĂ©pondait donc Ă  sa propre sauvegarde par un nouvel objet. Le cycle Ă©criture/diffusion supplĂ©mentaire qui suivait portait un instantanĂ© d'avant le transfert — et c'est lui qui Ă©crasait l'Ă©criture externe arrivĂ©e entre-temps.

Le correctif

v est sĂ©parĂ© des rĂ©glages Ă  la lecture, et sert uniquement Ă  dĂ©cider de la migration v1 → v2 comme avant :

const { v: storedVersion, ...saved } = JSON.parse(raw) as Partial<PlayerSettings> & { v?: number };

Rien d'autre ne change : la sérialisation continue d'estampiller, replaceEquipmentSkills aussi.

Mesure — comparaison contrĂŽlĂ©e

MĂȘme charge CPU (6 boucles saturantes), mĂȘme N, 60 exĂ©cutions du fichier de test dans chaque bras, le bras « avant » tournĂ© sur le code d'origine restaurĂ© :

échecs
avant 6 / 60
aprĂšs 0 / 60

0/60 ne prouve pas l'impossibilitĂ© — c'est une mesure, pas une dĂ©monstration. Mais la cause, elle, est corrigĂ©e de façon dĂ©terministe, et c'est ce que verrouillent les deux tests ajoutĂ©s.

Tests

  • safePlayerSettings rend les rĂ©glages seuls : mĂȘmes clĂ©s que defaultPlayerSettings, et la comparaison JSON que fait syncFromStorage est Ă©gale sur des rĂ©glages inchangĂ©s.
  • Un montage ne produit plus qu'une seule sauvegarde/diffusion au lieu de deux — c'est le cycle en trop, dont l'instantanĂ© pĂ©rimĂ© causait l'Ă©crasement.

Les deux rougissent sur le code d'avant ('v' en clé surnuméraire ; 2 diffusions au lieu de 1), donc ni l'un ni l'autre n'est décoratif.

Validation

  • pnpm lint + typecheck + prettier : propres
  • pnpm test : 1298 tests verts (+2)
  • pnpm build : succĂšs
  • pnpm test:e2e : 87/87 verts (4,9 min), sur une base e2e recréée Ă  neuf

đŸ€– Generated with Claude Code

https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2


Generated by Claude Code

Bug utilisateur : un transfert depuis le simulateur Stuff vers les
paramÚtres du joueur pouvait revenir à zéro tout seul, peu aprÚs le
chargement de la page. C'est aussi ce qui rendait
player-settings-panel.test.tsx instable en CI depuis le Bloc 93.

Cause. `safePlayerSettings` étalait l'objet stocké en entier, donc `v`
— de la comptabilitĂ© de stockage, absente de `PlayerSettings` — repartait
à l'intérieur des réglages. Toute comparaison entre la valeur en mémoire
et la valeur relue était donc inégale par construction, quel que soit le
contenu. La garde de `syncFromStorage` en est une : le panneau répondait
Ă  sa propre sauvegarde par un nouvel objet, et le cycle
écriture/diffusion supplémentaire qui suivait portait un instantané
d'avant le transfert — instantanĂ© qui Ă©crasait l'Ă©criture externe arrivĂ©e
entre-temps.

Correctif : `v` est séparé des réglages à la lecture (déstructuration),
et sert uniquement Ă  dĂ©cider de la migration v1 → v2 comme avant. Rien
d'autre ne change : la sérialisation continue d'estampiller.

Mesure, comparaison contrĂŽlĂ©e (mĂȘme charge CPU, 6 boucles saturantes,
60 exécutions du fichier de test dans chaque bras) :

  avant : 6 échecs / 60
  aprÚs : 0 échec  / 60

0/60 ne prouve pas l'impossibilité, mais la cause est corrigée de façon
déterministe et deux tests l'épinglent : `safePlayerSettings` rend les
rĂ©glages seuls (mĂȘmes clĂ©s que `defaultPlayerSettings`, comparaison JSON
égale), et un montage ne produit plus qu'une seule sauvegarde/diffusion
au lieu de deux. Les deux rougissent sur le code d'avant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2
@magicgg91
magicgg91 merged commit aa5c9be into dev Sep 14, 2026
2 checks passed
@magicgg91
magicgg91 deleted the claude/bloc-99-player-settings-sync branch September 14, 2026 20:40
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