Versioning, packaging, distribution — NuGet applique au droit
Tout ce qui suit existe deja dans l'ecosysteme NuGet/dotnet. On ne reinvente rien. On applique. L'innovation n'est pas dans l'infrastructure — elle est dans le contenu qui transite par cette infrastructure. Quand un package Law.France2026.Etalab.Dsl est publie sur un registre NuGet, il obeit aux memes regles qu'un package Newtonsoft.Json ou Serilog : SemVer, signature, lockfile, restauration deterministe, sources multiples. La difference est que ce package contient du droit type, pas du code utilitaire. Et cette difference change tout pour le destinataire.
SemVer juridique
Le versioning semantique est une convention tripartite : MAJOR.MINOR.PATCH. Chaque niveau a un sens technique precis dans l'ecosysteme .NET — et ce sens se transpose au droit sans forcer.
| Niveau | Sens juridique | Exemple concret |
|---|---|---|
| MAJOR | Refonte structurelle, breaking change pour les cas citoyens | Nouvelle Constitution, refonte du Code du travail, changement de regime fiscal |
| MINOR | Ajout de nouvelles regles sans casser les existantes | Loi qui cree un nouveau droit, ajout d'articles, nouvelle aide sociale |
| PATCH | Correction sans changement de comportement | Decret rectificatif, correction materielle, clarification jurisprudentielle |
| +build | Source de la version | 1.2.3+legifrance-2026-04-10, 1.2.3+cassation-civ-1-26-01-2026 |
| -pre | Loi en discussion | 1.3.0-projet-loi-eau-senat, 2.0.0-rc1-refonte-travail |
Le MAJOR bump est detecte automatiquement : si au moins un cas citoyen existant compile differemment apres la mise a jour, c'est un MAJOR. Le bridge fournit la commande de diff :
dotnet law-bridge diff Law.France2026.Etalab.1.0.0.dll Law.France2026.Etalab.1.1.0.dlldotnet law-bridge diff Law.France2026.Etalab.1.0.0.dll Law.France2026.Etalab.1.1.0.dllCette commande compare les deux assemblies, detecte les changements de types, d'attributs, de diagnostics, et renvoie le bump SemVer requis. Si l'auteur du package a declare un MINOR mais que le diff detecte un breaking change, le build echoue. La meme logique que NerdBank.GitVersioning (ouvre dans une nouvelle fenêtre), transposee au droit.
NuGet packaging — le .csproj d'un cadre juridique
Un cadre juridique publie est un projet .NET standard. Son .csproj contient les memes metadonnees que n'importe quel package NuGet :
// Fichier : Common.France2026.Etalab.Dsl.csproj (extrait des PropertyGroup)
// TargetFramework = netstandard2.0
// PackageId = Common.France2026.Etalab.Dsl
// Version = 1.1.0
// Authors = Etalab — DINUM
// Description = Common.Dsl instance for France 2026 — 142 biens, 36 000 communes, 487 procedures.
// PackageLicenseExpression = Etalab-2.0
// RepositoryUrl = https://git.etalab.gouv.fr/lex/common-france
// RepositoryCommit = a3f9c2e8...
// PackageReleaseNotes = https://lex.france.fr/changelog/Common.France2026.Etalab/1.1.0// Fichier : Common.France2026.Etalab.Dsl.csproj (extrait des PropertyGroup)
// TargetFramework = netstandard2.0
// PackageId = Common.France2026.Etalab.Dsl
// Version = 1.1.0
// Authors = Etalab — DINUM
// Description = Common.Dsl instance for France 2026 — 142 biens, 36 000 communes, 487 procedures.
// PackageLicenseExpression = Etalab-2.0
// RepositoryUrl = https://git.etalab.gouv.fr/lex/common-france
// RepositoryCommit = a3f9c2e8...
// PackageReleaseNotes = https://lex.france.fr/changelog/Common.France2026.Etalab/1.1.0La propriete RepositoryCommit declare le commit source associe au package ; elle ne prouve pas, a elle seule, que le binaire en provient. La verification exige un depot accessible, une chaine de build documentee et reproductible, les memes entrees et outils, puis une comparaison des artefacts pertinents. Une signature de package protege son integrite et identifie un signataire selon la politique de confiance retenue ; elle ne certifie pas la fidelite juridique du contenu. Voir Source Link et builds deterministes (ouvre dans une nouvelle fenêtre).
La signature NuGet X.509 complete le dispositif, sous reserve de configurer explicitement les signataires de confiance et la politique de validation. Le rejet de tout package non signe n’est pas le comportement implicite universel : la politique du client et de son environnement doit etre verifiee. Voir la configuration de confiance NuGet (ouvre dans une nouvelle fenêtre). Le statut « officiel » d’un cadre reste a etablir aupres de l’institution competente ; un certificat ne le cree pas.
Le workflow citoyen : dotnet update et ce qui se passe en trente secondes
Mathilde, parent isole, a installe son cadre citoyen il y a six mois. Elle met a jour :
cd MyCases.MathildeMartin
dotnet add package Law.France2026.Etalab.Dsl
dotnet buildcd MyCases.MathildeMartin
dotnet add package Law.France2026.Etalab.Dsl
dotnet buildLe compilateur repond :
MyCases/MyCase.cs(23,17): warn CIT003: Question "BenefitsIfJobLoss"
-> ATTENTION : la version 1.1.0 a modifie le calcul du RSA majore
-> Votre montant change : 1058 EUR/mois -> 1124 EUR/mois (+66 EUR)
-> Article modifie : L262-9 CASF (PATCH 1.0.0 -> 1.1.0)MyCases/MyCase.cs(23,17): warn CIT003: Question "BenefitsIfJobLoss"
-> ATTENTION : la version 1.1.0 a modifie le calcul du RSA majore
-> Votre montant change : 1058 EUR/mois -> 1124 EUR/mois (+66 EUR)
-> Article modifie : L262-9 CASF (PATCH 1.0.0 -> 1.1.0)Mathilde apprend en trente secondes que son RSA majore augmente de soixante-six euros par mois. Sans appeler la CAF, sans avocat, sans formulaire. Le compilateur lui livre la mise a jour juridique comme npm lui livrerait une mise a jour de bibliotheque. Le diagnostic CIT003 est type (cf. Partie 12 — Les six regimes d'usage), l'article est reference, le delta est calcule par le cadre lui-meme. C'est le sixieme regime d'usage a l'etat pur : le citoyen comme auteur de son propre cas, le compilateur comme guide vers ses droits.
Lockfile — versions et integrite des dependances
dotnet restore --use-lock-file genere un packages.lock.json qui fige l'etat exact des dependances :
// packages.lock.json (extrait)
// Law.France2026.Etalab.Dsl :
// type = Direct
// requested = [1.1.0, )
// resolved = 1.1.0
// contentHash = sha512-7G8Hq...
// signedBy = CN=Etalab, O=DINUM, C=FR
// publishedAt = 2026-03-01T10:00:00Z// packages.lock.json (extrait)
// Law.France2026.Etalab.Dsl :
// type = Direct
// requested = [1.1.0, )
// resolved = 1.1.0
// contentHash = sha512-7G8Hq...
// signedBy = CN=Etalab, O=DINUM, C=FR
// publishedAt = 2026-03-01T10:00:00ZLe lockfile fixe les versions resolues et les empreintes des packages. Reproduire les diagnostics exige aussi le code du cas, les versions du SDK, des analyzers, leurs configurations et toutes les donnees externes. Un hash ne date pas a lui seul un calcul ; un horodatage verifiable et une conservation des pieces sont des mecanismes distincts. Ces artefacts documentent le calcul effectue, sans presumer de leur force probante ni de la validite juridique du resultat.
Release notes typees — le changelog comme code
Les changelogs classiques sont du texte libre. Les release notes d'un cadre juridique sont du code C# type :
[ReleaseNotes(Version = "1.1.0", PublishedAt = "2026-03-01")]
public sealed class V1_1_0
{
[BumpReason(SemverImpact.Minor,
"12 nouveaux articles, 3 nouveaux biens, 0 retrait")]
public void Summary() { }
[Added(typeof(SocialHousingLaw2026.ArticleL353_9_2))]
[SourceJORF("JORF n-0042 du 19 fevrier 2026, NOR: LOGL2604XXX")]
public void NewCeilingForSocialHousingPLAI() { }
[Modified(typeof(SocialAndFamilyActionCode.L262_9),
FromVersion = "1.0.0",
Effect = "RSA majore pour parent isole : 1058 EUR -> 1124 EUR/mois")]
[SourceLegislative("LOI n 2026-156 du 15 fevrier 2026, art. 8")]
public void IncreasedRsaForSingleParent() { }
[BreakingForCases(
Reason = "Nouveaux plafonds pour logement social PLAI",
AffectedCircumstances = new[] {
typeof(SocialHousingTenant),
typeof(PLAIHousing)
})]
public void BreakingChangeSocialHousing() { }
}[ReleaseNotes(Version = "1.1.0", PublishedAt = "2026-03-01")]
public sealed class V1_1_0
{
[BumpReason(SemverImpact.Minor,
"12 nouveaux articles, 3 nouveaux biens, 0 retrait")]
public void Summary() { }
[Added(typeof(SocialHousingLaw2026.ArticleL353_9_2))]
[SourceJORF("JORF n-0042 du 19 fevrier 2026, NOR: LOGL2604XXX")]
public void NewCeilingForSocialHousingPLAI() { }
[Modified(typeof(SocialAndFamilyActionCode.L262_9),
FromVersion = "1.0.0",
Effect = "RSA majore pour parent isole : 1058 EUR -> 1124 EUR/mois")]
[SourceLegislative("LOI n 2026-156 du 15 fevrier 2026, art. 8")]
public void IncreasedRsaForSingleParent() { }
[BreakingForCases(
Reason = "Nouveaux plafonds pour logement social PLAI",
AffectedCircumstances = new[] {
typeof(SocialHousingTenant),
typeof(PLAIHousing)
})]
public void BreakingChangeSocialHousing() { }
}L'attribut [ReleaseNotes] est genere par le Source Generator du cadre. Chaque methode represente un changement individuel, decore par des attributs qui precisent la source legislative ([SourceJORF], [SourceLegislative]), l'impact ([Added], [Modified], [Removed]), et les circonstances citoyennes affectees ([BreakingForCases]). Le tout est filtrable par circonstance : dotnet law-bridge changelog --filter-by ./MyCases.MathildeMartin produit un changelog cible sur la situation de Mathilde. Personne n'a jamais eu ca pour le droit — un changelog legislatif qui ne montre que ce qui concerne votre situation.
Multi-sources NuGet — le pattern PPA Ubuntu applique au droit
Le fichier nuget.config d'un cas citoyen peut lister plusieurs sources :
<!-- nuget.config -->
<configuration>
<packageSources>
<add key="lex-etalab" value="https://lex.france.fr/v3/index.json" />
<add key="lex-laquadrature" value="https://lex.laquadrature.net/v3/index.json" />
<add key="lex-cgt" value="https://lex.cgt.fr/v3/index.json" />
</packageSources>
</configuration><!-- nuget.config -->
<configuration>
<packageSources>
<add key="lex-etalab" value="https://lex.france.fr/v3/index.json" />
<add key="lex-laquadrature" value="https://lex.laquadrature.net/v3/index.json" />
<add key="lex-cgt" value="https://lex.cgt.fr/v3/index.json" />
</packageSources>
</configuration>C'est le pattern PPA Ubuntu : chaque editeur (Etalab pour l'Etat, LaQuadrature pour les libertes numeriques, la CGT pour le droit du travail) publie ses propres cadres sur son propre registre NuGet. Le citoyen choisit qui il fait confiance en ajoutant ou retirant des sources. Le ConsensusScorer (cf. Partie 12 — Les six regimes d'usage) exhibe automatiquement les divergences entre cadres concurrents portant sur les memes articles.
Ce multi-sourcing est la traduction technique de la pluralite politique des cadres theorisee dans la signature META(Ex x Ty) (cf. Partie 4 — META(Ex x Ty)). Le ${Author} de la signature est concretement l'editeur du registre NuGet. Etalab et LaQuadrature ne sont pas d'accord sur le statut de l'eau potable ? Les deux cadres coexistent, le citoyen les compare, le bridge exhibe les diagnostics divergents. C'est la democratie des cadres, pas l'imposition d'un cadre unique.
Legal advisories — les GHSA du droit
Quand le Conseil constitutionnel declare un article non conforme, c'est l'equivalent d'une vulnerabilite de securite dans un package logiciel. Le mecanisme d'advisory juridique s'en inspire directement :
dotnet list package --legally-affected
Project MyCases.MathildeMartin is affected by 2 legal advisories:
> Law.France2026.Etalab.Dsl 1.0.0
LEGAL-2026-001 | Critical | Article L262-9 declare non-conforme
by Conseil constitutionnel
decision n-2026-XX-QPC du 12 mars 2026
Action: Update to 1.0.1 or laterdotnet list package --legally-affected
Project MyCases.MathildeMartin is affected by 2 legal advisories:
> Law.France2026.Etalab.Dsl 1.0.0
LEGAL-2026-001 | Critical | Article L262-9 declare non-conforme
by Conseil constitutionnel
decision n-2026-XX-QPC du 12 mars 2026
Action: Update to 1.0.1 or laterLe format est inspire des GitHub Security Advisories (ouvre dans une nouvelle fenêtre), avec une echelle de severite adaptee : Critical (annulation constitutionnelle), High (revirement de jurisprudence majeure), Medium (interpretation administrative), Low (clarification). Un flux RSS d'advisories juridiques est consomme par tous les dotnet build du pays, comme les flux RSS de vulnerabilites CVE sont consommes par tous les npm audit.
Le citoyen qui lance dotnet build sur son cas est prevenu automatiquement quand un article dont il depend a ete invalide. Pas besoin de suivre le Journal officiel, pas besoin de lire les decisions du Conseil constitutionnel en PDF — le compilateur lui livre l'information, typee, avec la reference exacte et l'action requise.
Time-travel queries — git checkout pour le droit
Chaque annee de publication constitue un package distinct. Revenir en arriere est trivial :
dotnet add package Law.France2024.Etalab.Dsl --version 4.7.2
dotnet build
# Diagnostics tels qu'ils auraient ete le 1er janvier 2024dotnet add package Law.France2024.Etalab.Dsl --version 4.7.2
dotnet build
# Diagnostics tels qu'ils auraient ete le 1er janvier 2024Pour les chercheurs, le time-travel devient un outil de recherche en sciences sociales. Une boucle simple produit une serie temporelle de diagnostics sur un meme cas :
for year in 2010 2012 2014 2016 2018 2020 2022 2024 2026; do
dotnet add package Law.France${year}.Etalab.Dsl --version ${year}.0.0
dotnet build > /tmp/case-${year}.json
donefor year in 2010 2012 2014 2016 2018 2020 2022 2024 2026; do
dotnet add package Law.France${year}.Etalab.Dsl --version ${year}.0.0
dotnet build > /tmp/case-${year}.json
doneReproductibilite scientifique du droit — jamais possible auparavant. Un sociologue peut prouver que les droits sociaux de Mathilde ont regresse entre 2014 et 2020, puis progresse entre 2020 et 2026, avec des diagnostics types, reproductibles, versiones, verificables par quiconque relance le meme build.
Pipeline Legifrance vers .nupkg — le cycle quotidien
Le pont entre le droit vivant et les packages types est un pipeline en six etapes :
Legifrance JURI XML feed
-> LegifranceXmlImporter (lit XML, produit CrossModel)
-> LawDslEmitter (recrit en C# avec attributs types)
-> git commit + git tag v1.1.0
-> dotnet pack Law.France2026.Etalab.Dsl -> .nupkg
-> Push to lex.france.fr NuGet feed
-> Notification RSS aux consommateursLegifrance JURI XML feed
-> LegifranceXmlImporter (lit XML, produit CrossModel)
-> LawDslEmitter (recrit en C# avec attributs types)
-> git commit + git tag v1.1.0
-> dotnet pack Law.France2026.Etalab.Dsl -> .nupkg
-> Push to lex.france.fr NuGet feed
-> Notification RSS aux consommateursCe cycle peut tourner quotidiennement. Quand une loi est promulguee et publiee au Journal officiel, le flux XML de Legifrance est consomme par le LegifranceXmlImporter, qui produit un modele intermediaire (CrossModel). Le LawDslEmitter le recrit en classes C# decorees par les attributs du cadre. Un commit et un tag git figent la version ; dotnet pack produit le .nupkg ; le push vers le registre le rend disponible a tous les consommateurs.
C'est aussi le pont concret avec Catala (cf. Partie 3 — Filiation intellectuelle). Catala fait deja ce travail pour le calcul d'impots en collaboration avec la DGFiP. Le bridge Law.Commons peut consommer les memes flux XML, ou meme importer directement les modules Catala via un Catala.Bridge futur (Ship 6-bis de la roadmap).
Architecture du registre — trois niveaux
Le registre des packages juridiques s'organise en trois niveaux, calques sur le modele NuGet existant :
| Registre | Hebergement | Autorite | Usage |
|---|---|---|---|
Officiel : lex.france.fr |
Etalab / DINUM | Etat | Common.France*.Etalab.Dsl, Law.France*.Etalab.Dsl |
Federations : lex.laquadrature.net, lex.cgt.fr |
Associations | Communaute reconnue | Forks, interpretations alternatives |
Personnel : ~/.nuget/packages/ local |
Citoyen | Soi-meme | Versions epinglees, archives |
Le registre officiel est signe par une cle X.509 emise par Etalab, hebergee dans un HSM hors-ligne. Les registres de federations sont signes par leurs propres cles. Le registre personnel est le cache local standard de NuGet — une fois qu'un package est telecharge, il vit indefiniment sur la machine du citoyen.
Aucune de ces trois couches n'est une nouveaute technique. C'est exactement ce que NuGet supporte depuis 2010, ce que npm supporte depuis 2012, ce que les PPA Ubuntu supportent depuis 2004. L'innovation est dans le contenu, pas dans l'infrastructure. Et c'est precisement cette banalite technique qui rend le projet credible : on ne demande a personne d'adopter un nouveau systeme de distribution. On remplit le systeme existant avec du droit type.
Attestation du calcul — provenance et verification contradictoire
A chaque dotnet build, le compilateur genere un obj/build-attestation.json signe qui recapitule les dependances, les diagnostics et le hash de l'ensemble :
// obj/build-attestation.json (structure)
// schemaVersion = 1.0
// caseFile = MyCases.MathildeMartin
// builtAt = 2026-04-10T14:23:17Z
// builtBy = { machineFingerprint: did:peer:zQ3sh..., anonymized: true }
// dependencies = [
// { name: Law.France2026.Etalab.Dsl, version: 1.1.0, hash: sha512-7G8Hq... },
// { name: Common.France2026.Etalab.Dsl, version: 1.1.0, hash: sha512-9P2Lm... }
// ]
// diagnostics = [
// { code: CIT001, article: L353-9-2, outcome: RsaMajore active },
// { code: CIT003, article: L262-9, outcome: 1124 EUR/mois }
// ]
// signature = MEYCIQDx...
// signedBy = CN=MyCases-Tool, O=Self
// obj/build-attestation.json (structure)
// schemaVersion = 1.0
// caseFile = MyCases.MathildeMartin
// builtAt = 2026-04-10T14:23:17Z
// builtBy = { machineFingerprint: did:peer:zQ3sh..., anonymized: true }
// dependencies = [
// { name: Law.France2026.Etalab.Dsl, version: 1.1.0, hash: sha512-7G8Hq... },
// { name: Common.France2026.Etalab.Dsl, version: 1.1.0, hash: sha512-9P2Lm... }
// ]
// diagnostics = [
// { code: CIT001, article: L353-9-2, outcome: RsaMajore active },
// { code: CIT003, article: L262-9, outcome: 1124 EUR/mois }
// ]
// signature = MEYCIQDx...
// signedBy = CN=MyCases-Tool, O=Self
Mathilde peut joindre le rapport, les versions des cadres, les hypotheses et les pieces de son dossier a une demande. L’administration peut alors examiner et discuter un calcul reproductible. La signature atteste un artefact et son signataire ; elle ne prouve ni l’exactitude des faits declares, ni l’eligibilite juridique, et ne renverse pas automatiquement la charge de la preuve. L’objectif est de rendre une demande mieux documentee et plus facile a verifier.
Pour aller plus loin
- Partie 12 — Les six regimes d'usage (precedente)
- Partie 14 — L'arsenal complet du genie logiciel applique au droit (suivante)
- Hub de la serie
- Serie Ops DSL Ecosystem pour le meme pattern NuGet applique a l'operationnel