Erreurs classiques
Les fautes typiques des débutants. Pour chacune : le symptôme, la cause, la correction.
1. Un nom d'instance dans un payload
Symptôme
this.broker.publish(this, { message_demande: { ref, texte, pour: "ecran_fil" } });
Ou pire, le champ est déclaré au catalogue et « ça marche » : les composants se reconnaissent par nom et le découplage est mort.
Cause
On veut adresser un composant précis. Dans fwtozza on adresse un message, pas un objet ; qui l'écoute ne regarde pas l'émetteur.
Correction
Corréler un échange par un ref de message (UUID). Cibler un client par la clé d'enveloppe id. Les composants sont uniques. Référence.
2. Une Date ou une instance de classe dans un payload
Symptôme
this.broker.publish(this, { message_poste: { message: { …, poste_le: new Date() } } });
Cause
Le payload n'est pas du JSON pur. Même si le contrat disait object, la copie locale et le passage réseau donneraient deux résultats différents.
Correction
new Date().toISOString() avec un pattern, ou un timestamp number. Le composant qui reçoit reconstruit la Date chez lui. Référence.
3. Un abonné qui déclare une révision
Symptôme
receives = [{ name: "message_poste", version: 1, revision: 0 }];
Le broker ignore la révision à la souscription ; mais le code du composant attend la forme r0 et s'étonne de champs en plus.
Cause
Confusion émetteur/abonné. L'émetteur est validé contre sa révision ; l'abonné reçoit toujours la forme canonique, c'est-à-dire la révision courante complétée.
Correction
receives = [{ name, version }], et un handleMessage écrit pour la révision courante. Référence.
4. Un objet non détruit
Symptôme
this.panneau = null; // « je m'en débarrasse »
Le panneau continue de recevoir et de peindre dans un support qui n'est plus affiché. La mémoire grimpe. Deux panneaux reconstruits : « already registered ».
Cause
Le broker garde une référence vers tout abonné. null ne désinscrit rien.
Correction
this.panneau.destroy(); this.panneau = null;. La désinscription est immédiate. Référence.
5. Un membre de oneOf avec default (ou required)
Symptôme
oneOf: ["accord", "refus"],
fields: { accord: { type: "object", required: true, … }, refus: { … } }
Cause
Un membre de oneOf est exclusif : il ne peut pas être requis. Et un default serait posé par l'upcast, qui ne re-vérifie pas l'invariant : deux membres présents.
Correction
Membres optionnels, sans default. Le oneOf garantit déjà qu'exactement un est là. Référence.
6. Modifier un contrat validé au lieu de le réviser
Symptôme
On ajoute color directement dans la révision 0 de text_posted. En local tout passe. Puis un client qui a l'ancien catalogue se connecte :
Et tous les émetteurs qui n'envoyaient pas color sont maintenant rejetés.
Cause
Une révision est un snapshot gravé. La modifier casse la promesse faite à tous ceux qui l'ont déjà.
Correction
Ajouter une révision 1, snapshot complet, color requis avec default. Les émetteurs en r0 continuent, complétés. Référence.
7. Importer config.js ou lire process.env depuis un composant
Symptôme
import { DB_URL } from "../config.js";
const pool = await createPool(DB_URL);
Aucune erreur du broker. Mais le test du composant exige une base réelle, et le composant ne peut plus être déployé ailleurs sans ce fichier.
Cause
Le composant va chercher ce qu'il devrait recevoir.
Correction
server.js lit l'environnement, ouvre le pool, et le passe : new Board(broker, "board", { pool }). Le test passe un faux pool. Les cinq règles de deps.
8. Un cycle A→B→A
Symptôme
Cause
A publie X dans son handleMessage de Y, B publie Y dans son handleMessage de X, sans condition d'arrêt. Souvent : « je republie mon état à chaque fois que je reçois un état ».
Correction
Ne publier que si l'état a changé (comparer avant), ou revoir le découpage : si A et B se renvoient sans cesse la même donnée, c'est peut-être un seul composant. Le garde-fou DELIVERY_BUDGET transforme le gel en diagnostic, il ne corrige rien. Référence.
9. Oublier les transits à l'audit
Symptôme
alors que le message traverse bel et bien le canal.
Cause
broker.audit() sans [CHANNEL] : le seul abonné local d'un message qui traverse est le canal, qui ne compte pas.
Correction
broker.audit([CHANNEL]), un CHANNEL par canal monté. Référence.
10. Poser allowMessage après un await
Symptôme
Pas de message d'erreur : une trame envoyée par un client malveillant juste après son handshake est publiée avant que la grille existe.
Cause
Une attente asynchrone entre le connected et la pose de la grille.
Correction
Deny-sauf-login synchrone au connected, resserré ensuite. Référence.