Skip to content

release: v2.3.2 — Classique en mobile, doublons invisibles, Discord à 39 voix - #222

Merged
CodeByHaamza merged 16 commits into
mainfrom
develop
Sep 27, 2026
Merged

CodeByHaamza merged 16 commits into
mainfrom
develop

Conversation

@CodeByHaamza

Copy link
Copy Markdown
Owner

Release de ce qui s'est accumulé sur develop depuis la 2.3.1.

Contenu

Correctifs visibles par un joueur

  • Classique sur téléphone — Indice et Abandon côte à côte au lieu d'être empilés : le champ de réponse remonte de 170 px. Le correctif de la 2.3.1 n'en avait réglé que 46 ; Classique était devenu le mode où il fallait scroller le plus loin pour répondre, il est maintenant celui où le champ est le plus haut.
  • [hidden] et .hidden enfin honorés — deux éléments se peignaient alors qu'ils étaient marqués cachés : le bouton « Supprimer mon compte » en double en bas de la page profil (il n'appartient qu'aux ⚙ Paramètres), et une pastille de notification vide collée à l'icône Amis, sur les huit pages et à toutes les largeurs.

Discord

  • Le quotidien passe de 8 à 39 voix — tout le cast principal, 3 répliques chacune, FR et EN.
  • Le récap du dimanche montre les portraits du podium et les trois amitiés les plus fortes.
  • Les deux crons savent poster dans un salon forum, avec repli automatique dans les deux sens.

Documentation — la conversion d'un salon texte en forum est impossible (Discord la refuse : Value must be one of (0, 5)), et un index des commandes d'exploitation.

Base de données

Aucune migration à jouer. La prod est déjà à la 055 et ce lot n'ajoute aucun .sql.

npm run schema:check-prod, exécuté depuis le webroot avant d'ouvrir cette PR :

✅ Aucune dérive : colonnes et contraintes UNIQUE conformes à bdd_mysql.sql.

Cache

CACHE_VERSION v104 → v105. Le CSS et le JS sont servis en network-first, donc la feuille corrigée arrivait de toute façon ; le bump couvre les images et les sons, en cache-first. Seuls les joueurs déjà venus sont concernés — c'est précisément le cas qu'un test ne voit jamais.

Vérifications

Hors périmètre de cette release

Les commandes /statut, /annonce, /sync et le passage du salon du quotidien en lecture seule vivent dans le dépôt personadle-discord et sur le serveur maison — déjà déployés. Seuls les crons Discord sont hébergés ici.

Les huit voix d'origine brisent le quatrième mur dans les jeux — Velvet Room et
mascottes — et pouvaient donc s'adresser au joueur sans que ça sonne faux. Le
casting s'ouvre au cast principal de P3, P4 et P5 : eux ne parlent pas AU
joueur depuis l'extérieur, ils lui parlent comme à quelqu'un qui joue à côté
d'eux. C'est ce registre qui est tenu, pas celui du narrateur omniscient.

29 voix ajoutées, 3 répliques chacune, en français et en anglais. Chaque voix
s'appuie sur ce qui la rend reconnaissable plutôt que sur une humeur générique :
le baseball de Junpei, les crises de rire de Yukiko, le chou d'Adachi, les vingt
minutes que Yusuke passe à contempler sans répondre, le jardinage de Haru qui
finit en menace polie. Joker et Koromaru ne parlent pas — ce sont des didascalies.

37 voix : pas un multiple de 7, la contrainte documentée en tête de fichier.
Une voix revient tous les 37 jours, le cycle complet fait 111 jours, et chaque
personnage parle environ 9 fois par an.

Les 37 avatars ont été vérifiés un par un contre la production : Discord
télécharge l'image lui-même, un chemin faux donnerait une pastille vide sans
que rien ne le signale.
Je l'avais écrit en didascalies, au motif qu'il est un protagoniste muet. C'est
une convention de jeu, pas une règle : il a des répliques dans P5, et rien ne
justifiait de le priver de voix ici. Décision Hamza.

Ses trois lignes tiennent le registre Phantom Thief — une cible qu'on repère,
une réponse qu'on vole plutôt qu'on ne devine — et restent courtes, comme ses
options de dialogue dans le jeu.

Koromaru garde ses didascalies : c'est un chien.
Les deux protagonistes de Persona 3 ouvrent la section P3 — même année, même
dortoir, deux façons de la raconter. C'est ce contraste qui porte leurs
répliques : lui laconique et fataliste, elle enjouée et taquine.

Comme pour Joker, ils parlent. Le protagoniste muet est une convention de jeu,
pas une raison de les priver de voix ici.

Kotone porte son portrait P5X, celui de sa mise à jour.

39 voix : toujours pas un multiple de 7 (reste 4). Cycle complet de 117 jours,
chaque personnage parle environ 9 fois par an. Les 39 avatars revérifiés contre
la production.
Le top 3 de la semaine gagne un encart illustré par joueur, et un podium des
amitiés les plus fortes. Le mot d'accueil de Margaret tourne sur 7 phrases.

Le piège est le stockage des portraits : un portrait recadré vit en base64 dans
avatar_data, et Discord va chercher l'image à une adresse — il ne sait rien
faire d'une data-URL. Seuls les portraits de galerie non recadrés laissent un
chemin exploitable, soit 43 profils sur 328 en production.

Le portrait est donc un bonus et jamais la structure : le podium reste
entièrement lisible en texte, et l'encart illustré ne s'ajoute que pour ceux
qui en ont un. Aucun encart vide, aucune image cassée.

La résolution d'URL refuse tout ce qui n'est pas un fichier de la galerie —
data-URL, URL externe, remontée de dossier, nom hors liste blanche. Ces valeurs
viennent de la base, donc d'une saisie utilisateur passée par l'API.

Les amitiés ne sont pas bornées à la semaine, contrairement aux victoires : une
amitié se construit dans la durée, et sept jours ne diraient que qui a joué
ensemble. Tri par XP comme la page Amitié, le rang plafonnant à 10.

Les 7 phrases ne divisent pas 52 sans reste, sinon la même phrase retomberait
sur la même semaine chaque année. Un test l'impose.
feat(discord): l'hebdomadaire montre les portraits et les amitiés
Retour de Hamza : le correctif de mise en page de la 2.3.1 « ne s'affiche pas
pour les autres ». Ce n'est pas un problème de cache — la prod sert bien le bon
CSS, sw.js est en v104 et le service worker est en network-first sur le CSS avec
cache: reload. Le correctif était actif pour tout le monde ; il ne valait
simplement que 46 px.

Les 154 px restants venaient de .hint-giveup-row. C'est une rangée flex en
flex-wrap: wrap, et Classique est le seul mode à y placer deux blocs — les cinq
autres n'ont que le bloc Abandon, d'où l'absence du symptôme ailleurs. À 390 px
chaque bloc fait 229 px, soit 478 px avec le gap pour 380 px disponibles : la
rangée passait à la ligne et occupait 292 px au lieu de 136.

Ce ne sont pas les images qui débordent (173 px) mais le padding 12px 20px de
.link-wrapper, qui ajoute 40 px à chaque bloc. On le rogne et on descend l'image
à 60 px : bloc à 176 px, deux blocs plus le gap tiennent jusqu'à 375 px de large.

Gain mesuré : 170 px. Le champ de réponse passe de 894 à 724 px, ce qui place
Classique devant Émoji. La cible tactile reste à 160×80 px.

Il reste 129 px de scroll à 390×844, dus au gabarit commun aux six modes —
aucun des six ne tient sur un écran de téléphone, et les toucher serait une
refonte.
Un fil par jour sous l'annonce : aujourd'hui un score posté par un joueur se
perd entre deux messages du bot, dans un fil il répond à quelque chose.

Le type du salon est une dépendance invisible du cron. Un webhook ne peut pas
poster dans un forum sans thread_name, ni dans un salon texte avec : Discord
renvoie 400 dans les deux cas. Le jour de la conversion, un cron qui l'ignore
s'arrête net et le rendez-vous devient muet — déjà vécu dix jours en septembre
pour une autre raison.

D'où un repli automatique dans les deux sens plutôt qu'un paramètre : on essaie
la forme attendue et, sur un 400, on réessaie l'autre une fois. Le salon peut
être converti ou reconverti sans toucher au code, et la constante
DISCORD_DAILY_FORUM n'économise plus qu'un aller-retour. Quand le repli sert, un
warning le dit dans les logs, sinon la constante resterait fausse en silence.

401, 404, 429 et 500 ne sont pas réessayés : ce ne sont pas des problèmes de
type de salon, et réessayer ne ferait que doubler l'échec.

Le weekly passe par le même helper, et c'est lui qui aurait cassé :
DISCORD_WEEKLY_WEBHOOK est absent de la prod, donc le récap du dimanche part
dans le salon du quotidien. Il ne suit la constante que s'il n'a pas de webhook
à lui.

Le commentaire de rotation du quotidien parlait encore de 8 voix et d'un cycle
de 48 jours, faux depuis le passage à 39 (117 jours).
fix(classique): Indice et Abandon côte à côte sur mobile
# Conflicts:
#	PersonaDLE_Update_Documentation/PersonaDLE 2.3/DEV_CHANGELOG.md
#	ROADMAP.md
#	TODO.md
feat(discord): le quotidien peut vivre dans un salon forum
…mmandes

Rectification du changelog du jour. Il disait « convertir le salon en forum
(Modifier le salon → Type) » : ça n'existe pas. PATCH /channels/:id {"type":15}
répond 400 / 50035, « Value must be one of (0, 5) » — un salon texte ne devient
que texte ou annonces. Un forum se crée, donc nouveau salon, nouveau webhook,
nouvelle valeur en production, et perte de l'historique.

Décision de Hamza : le salon du quotidien reste, en lecture seule. Le code du
lot précédent n'est pas à défaire, il se replie tout seul sur un salon texte.
Vérifié en production qu'un webhook n'est pas soumis aux surcharges de
permission du salon, donc que le rendez-vous quotidien ne risque rien.

Ajoute aussi, §10, le renvoi vers l'index des commandes d'exploitation et deux
pièges qui ont déjà coûté du temps : crontab n'existe pas sur le mutualisé donc
un crontab -l vide ne prouve rien, et display_errors est éteint en CLI donc un
script qui plante n'affiche rien — une sortie vide n'est pas « aucun résultat ».
…mmandes

docs: la conversion en salon forum est impossible, et un index des commandes
Hamza signale le bouton « Supprimer mon compte » en bas de la page profil sur
mobile. Il est dans les ⚙ Paramètres depuis le 2026-09-16 et celui de la page
n'est qu'un relais marqué hidden : il était simplement repeint.

[hidden] n'est display:none que dans la feuille du navigateur, donc n'importe
quelle règle d'auteur posant un display la bat — ici .btn-danger { display: flex }
dans la media query de cible tactile, sous 480 px. Et .hidden n'était défini
nulle part globalement : quatre fichiers l'avaient rustiné dans leur coin, et
leaderboard.css portait déjà un commentaire décrivant le piège.

Le même manque cachait un second bug que personne n'avait signalé : une pastille
de notification rouge et VIDE sur l'icône Amis de la barre du bas, sur les huit
pages et à toutes les largeurs, donc devant tous les joueurs.

D'où une règle unique dans global.css, avant tout le reste. Le !important est
assumé : c'est la seule façon de battre une règle d'auteur plus spécifique, et
c'est ce que font normalize.css et HTML5 Boilerplate pour la même raison.

Rayon d'action mesuré avant d'écrire la règle, page par page sur la production :
9 éléments concernés, et les 9 sont ces deux bugs. Après correction, zéro élément
fantôme et un nombre d'éléments interactifs identique partout — rien de légitime
ne disparaît. Vérifié aussi que les 13 endroits qui écrivent un display inline
n'utilisent pas .hidden, sinon le !important les aurait figés.

Le test E2E interdit la classe entière de bug plutôt que de nommer les deux
coupables : aucun élément portant .hidden ou [hidden] ne doit se peindre, sur
neuf pages et quatre largeurs.
fix(css): ce qui est marqué caché est enfin caché
CACHE_VERSION v104 → v105 : le CSS et le JS sont servis en network-first, donc
la feuille corrigée arrivait déjà, mais les images et les sons sont en
cache-first — et seuls les joueurs déjà venus sont concernés.

Ligne 2.3.2 dans le README, et les trois correctifs visibles par un joueur
ajoutés au changelog joueur, en FR et en EN : Indice et Abandon côte à côte en
Classique, le bouton de suppression en double retiré du profil, la pastille de
notification vide retirée de l'icône Amis.

Aucune migration à jouer : la prod est déjà à la 055 et ce lot n'ajoute aucun
fichier SQL. schema:check-prod passé avant le merge, aucune dérive.
chore(release): préparer la 2.3.2
@CodeByHaamza
CodeByHaamza merged commit 36e00d6 into main Sep 27, 2026
7 checks passed
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.

1 participant