Le routeur et la table de compatibilité
Deux fichiers du registre ne décrivent aucun message : ils décrivent l'état du registre lui-même. Le routeur dit quel schéma valide quel message aujourd'hui ; la table de compatibilité dit ce qui a été vrai et jusqu'à quand. Ce sont aussi les deux seuls fichiers que le registre s'autorise à modifier sans changer leur nom.
Le routeur : un portier et un aiguilleur
schemaRouter.json fait deux choses distinctes et il est utile de les séparer parce qu'elles produisent des erreurs différentes.
Il filtre. Un anyOf énumère les couples message + version admis. Un message qui annonce un MIG inexistant, ou une version retirée du service, est rejeté à ce niveau et ce, avant même qu'on regarde son contenu. C'est une décision de conception : mieux vaut refuser franchement qu'accepter par défaut ce qu'on ne connaît pas.
Il aiguille. Une série de if / then dirige ensuite le contenu vers le fichier de schéma qui lui correspond. Une cinquantaine de branches y coexistent aujourd'hui.
Le discriminant est toujours le couple complet : X943, le code du message et X944, sa version. Jamais l'un sans l'autre (X944 est relatif à chaque MIG).
Le filtre : seuls les couples connus passent
"anyOf": [
{ "properties": {
"exchangeUnitBusinessContentDescription":
{ "const": "M0151" },
"exchangeUnitBusinessContentDescriptionVersion":
{ "const": 3 } } }
]
L'aiguillage : vers le bon fichier
"allOf": [
{
"if": { "properties": { … "M0151" … 3 … },
"required": [ … ] },
"then": { "$ref": "…/community/M0151.202701.json" }
}
]
Pourquoi le routeur est mutable
Tout le reste du registre est immuable. Le routeur, non. Et ce n'est pas une inconséquence, c'est ce qui permet à la règle générale de tenir.
L'alternative aurait été d'intégrer le routage dans le schéma du datablock. Mais ce schéma est un fichier versionné : y ajouter une branche à chaque nouveau message aurait imposé de le republier sous un nouveau nom et donc de casser toutes les références qui pointent vers lui. Une mise en service de routine serait devenue un changement de rupture.
Séparer les deux préoccupations résout le problème : le schéma du datablock décrit une structure et ne bouge plus, le routeur décrit un état et bouge librement.
La table de compatibilité : la mémoire
Le routeur ne connaît que le présent : quand une version sort du service, sa branche en disparaît. C'est voulu ! Car un routeur qui accumulerait tout l'historique finirait par accepter des messages qu'on ne veut plus recevoir.
Mais l'information ne doit pas se perdre pour autant. compatibility.json conserve la trace complète : pour chaque version de message, le fichier de schéma correspondant, la release EDIFACT associée, la date d'entrée en vigueur, la date d'obsolescence éventuelle et un statut.
Deux usages en découlent. L'audit : répondre à « quel schéma faisait foi le 12 mars 2024 ? ». Et la validation rétrospective : revalider un message archivé contre le schéma qui l'avait accepté et non contre celui d'aujourd'hui.
La table porte aussi l'en-tête du registre : sa version, la version de la base dont il dérive, la release visée par les travaux en cours et son statut de publication.
Une entrée de la table
{
"x943": "M0151",
"x944": 3,
"migName": "M0151_202701",
"edifactRelease": "01.01.2027",
"jsonSchema": "community/M0151.202701.json",
"validFrom": "2027-01-01",
"obsoleteFrom": null,
"status": "active"
}
L'en-tête
{
"registryVersion": "8.20.0",
"dbVersion": "8.20",
"releaseTarget": "202701",
"status": "pre-release"
}
Lequel interroger, et quand
La règle tient en une phrase : le routeur pour valider, la table pour comprendre.
En production, vous ne consultez jamais le routeur vous-même. C'est le validateur qui le suit, en descendant la cascade depuis l'enveloppe. Votre seul travail est de le tenir à jour dans votre miroir.
La table, elle, se lit. C'est elle qui vous dit quelles versions sont en service, jusqu'à quand une version que vous émettez restera acceptée et à quelle release EDIFACT correspond une release JSON (utile quand vos deux chaînes coexistent).
Un point à connaître : la table et le routeur ne recouvrent pas exactement le même périmètre. Le routeur est la référence pour savoir ce qui valide. En cas de divergence sur une entrée, c'est lui qui décide du comportement du validateur.
Ces deux fichiers sont le seul endroit du registre où le temps existe. Partout ailleurs, un fichier est ce qu'il est et le restera. Ici se concentrent la mise en service, le retrait et l'historique. Ce qui explique qu'ils soient les deux seules exceptions à l'immuabilité et qu'elles soient documentées comme telles plutôt que subies.