Faire évoluer un contrat

La règle

Un contrat validé ne se modifie jamais en place. Régime de croisière : la révision, snapshot complet qui ajoute des champs ; un champ ajouté required porte un default. Cas rare : la version, pour renommer, supprimer ou changer le sens d'un champ, gravée avec un upcastFrom déclaratif (rename, defaults, remove). Jamais de downcast.

Pourquoi

Seul l'émetteur qui produit la nouvelle donnée est touché ; les émetteurs en retard continuent d'émettre leur révision, le broker complète. Le default ne sert qu'à l'upcast, jamais à la validation : un émetteur déclaré en r1 qui omettrait le champ est rejeté.

Dans le chat

acces_demande a deux révisions : la r1 resserre les bornes du pseudo et du mot de passe. Les deux snapshots sont complets.

Contre-exemple : éditer une révision publiée

Si un client garde l'ancienne r0 et que le serveur la modifie en place, le handshake refuse : « schéma divergent (discipline append-only rompue ?) ». C'est le catalogue qui est faux, pas le client.

ERROR (websocket): contrat incompatible — client→serveur : acces_demande v1 r0 — schéma divergent (discipline append-only rompue ?) — socket fermé

Révision

text_posted: {
	versions: { 1: { revisions: {
		0: { fields: { text: {…}, ref: {…} } },
		1: { fields: {                                   // snapshot complet, jamais un diff
			text:  { type: "string", required: true },
			ref:   { type: "string", required: true },
			color: { type: "string", required: true, default: "black" },
		} },
	} } },
}

Un émetteur resté en r0 émet sans color ; tous les abonnés reçoivent color: "black". Les champs d'une révision 0 ne portent pas de default : il n'y a aucun émetteur antérieur à combler.

Version

2: {
	upcastFrom: {
		rename:   { "color": "style.color" },
		defaults: { "style.font-size": "16px", "style.font-weight": "normal" },
	},
	revisions: { 0: { fields: { /* … style: { type: "object", fields: {…} } */ } } },
},

Le broker met d'abord l'émission en forme canonique de sa version, puis chaîne les upcasts (v→v+1→…→cible) pour servir un abonné plus récent. Gouvernance : les abonnés d'abord, l'émetteur en dernier. Un abonné resté en arrière n'est plus servi ; le broker le signale et le saute, jamais en silence.

À travers un canal

Essayez-le dans le tuto 5.