Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

State.Economy.Dsl — typer la comptabilité nationale et le budget de l'État

Les parties précédentes ont posé trois racines du compilateur croisé. Common.Dsl en Partie 6 fournit la couche technique neutre — biens, espaces, périodes, procédures. Law.Dsl en Partie 7 monte d'un cran pour dire ce qu'est un container juridique agnostique aux traditions. Commons.Dsl et Citizen.Dsl en Partie 8 ajoutent la politisation des biens et la réception du droit par ses destinataires. Cette partie-ci ajoute une quatrième racine, au même rang que les trois premières : State.Economy.Dsl.

Pourquoi une quatrième racine, et pourquoi à ce moment de la série ? Parce que le droit ne vit pas seul. L'essentiel de la régulation contemporaine passe par des chiffres — ratios budgétaires, secteurs institutionnels, missions, programmes, actions. La Constitution française de 1958 fait référence explicite à l'équilibre des comptes dans son article 34. Les critères Maastricht (3% du PIB de déficit, 60% de dette) sont juridiquement contraignants par le Traité sur le fonctionnement de l'Union européenne (art. 126 TFUE + protocole n°12). La LOLF du 1er août 2001 impose une architecture budgétaire pyramidale Mission → Programme → Action. Aux États-Unis, OMB Circular A-11 §79 fait de même avec Agency → Account → Program Activity. Chacun de ces dispositifs est un type system économique implicite, manipulé quotidiennement par des dizaines de milliers de fonctionnaires, parlementaires, auditeurs, journalistes — mais jamais explicité comme type system. On en trouve des fragments dans des manuels Eurostat, des circulaires DGFiP, des dictionnaires INSEE, des annexes au PLF. Jamais sous forme de code qu'un compilateur puisse vérifier.

Cette quatrième racine n'est pas un luxe pour économistes. C'est une condition d'opérabilité politique du compilateur croisé. Sans elle, un cadre Law.France2026.Etalab peut décrire la LOLF comme loi organique (rang OrganicLaw dans la hiérarchie de Kelsen typée) mais reste aveugle à la sémantique budgétaire que la LOLF impose à toutes les lois de finances qui la suivent. Sans elle, le cas Dumas de la Partie 10 attrape bien une violation de procédure démocratique — LOI003 sur la suppression du financement public des campagnes — mais n'attrape pas la violation parallèle qui se profile dans les comptes publics quand une mesure de suppression déséquilibre le solde budgétaire. L'économie publique doit être typable comme le droit est typable. C'est ce que fait State.Economy.Dsl.

Pourquoi l'économie d'État est un espace blanc absolu dans le corpus Law-as-Code

Le mouvement Law-as-Code a produit, depuis une décennie, des avancées considérables sur le droit codifié : Catala (Merigoux, Huttner, Protzenko et al., POPL 2022) démontre que les articles du Code général des impôts se traduisent fidèlement en un langage formel vérifiable, avec un proof of concept sur l'impôt sur le revenu français en collaboration avec la DGFiP. Blawx, Openfisca, Docassemble, Regelspraak (Pays-Bas), Legalese (Singapour) — la liste est longue. À chaque fois, le terrain visé est le droit lui-même : articles, alinéas, conditions d'application, calculs d'éligibilité. Jamais la comptabilité nationale qui conditionne le droit. Jamais les secteurs institutionnels qu'il structure. Jamais la pyramide budgétaire LOLF qui contraint chaque ministère. Ce blanc est frappant.

Il y a plusieurs raisons à ce blanc, dont aucune n'est satisfaisante. La première est disciplinaire : la comptabilité nationale est tenue par des statisticiens (INSEE, Eurostat, Bureau of Economic Analysis) plutôt que par des juristes ou des informaticiens, et les trois mondes se parlent peu. La deuxième est conceptuelle : SEC 2010 / SCN 2008 est perçu comme du chiffre, donc comme relevant d'un typage faible (des réels, des agrégats), alors qu'il est profondément structuré — chaque opération a un code, chaque secteur a un code, chaque couple (opération × secteur) est contraint par une table de compatibilité Eurostat. La troisième est politique : typer l'économie d'État, c'est rendre auditable la façon dont un gouvernement construit ses chiffres — donc réduire la marge de manœuvre des services qui les produisent. On comprend que ça n'enthousiasme pas spontanément les institutions concernées.

Ce blanc est une opportunité technique et politique. Technique, parce que tout ce qui a été fait pour Law.Dsl (attributs, analyzers, bridges) se transpose mécaniquement à State.Economy.Dsl — le compilateur Roslyn ne fait pas de différence entre un article du Code civil et un programme LOLF, il ne voit que des classes, des attributs, des types génériques. Politique, parce que la première personne qui publie un cadre State.Economy.France2026.InseeOfficial typé et vérifié au compile-time impose aux cadres concurrents (syndicats, think tanks, associations) de se positionner en termes comparables. L'asymétrie de pouvoir actuelle — où seule l'administration dispose des outils internes pour construire les agrégats — se réduit à proportion que le type system se diffuse.

La thèse de cette partie est donc triple. D'abord, que SEC 2010, LOLF et leurs équivalents étrangers sont déjà des type systems — simplement non-explicités. Ensuite, qu'expliciter ces type systems en C# + Roslyn ne demande ni innovation conceptuelle, ni rupture méthodologique, ni validation académique préalable — juste du travail d'encodage. Enfin, que l'ajout de cette quatrième racine ne bouleverse pas l'architecture du compilateur croisé : State.Economy.Dsl est indépendante des trois autres racines au niveau des packages NuGet, les jointures éventuelles passeront par des bridges (Law.Economy.Bridge, Constitution.Economy.Bridge) qu'on introduira dans les parts 9 et 9-bis.

La racine FrenchExDev.Net.State.Economy.Dsl

Comme les trois autres racines, State.Economy.Dsl est un projet C# minimal — pas de Source Generator, pas de dépendance Roslyn, pas d'I/O, juste des interfaces, des phantom types et une poignée d'attributs. Tout le reste se construit autour par composition. L'asset complet est consultable dans content/blog/metacratie-compilateur/assets/constitution-economy/State.Economy.Dsl/ et type-check via dotnet build ConstitutionEconomy.sln.

Secteurs institutionnels — SEC 2010 comme phantom types

Le premier bloc de la racine encode les secteurs institutionnels au sens SEC 2010 / SCN 2008. Ce sont les six regroupements d'unités institutionnelles qui constituent l'économie nationale vue par les comptes nationaux : sociétés non financières, sociétés financières, administrations publiques, ménages, institutions sans but lucratif au service des ménages, et reste du monde. Chacun porte un codeS11, S12, S13, S14, S15, S2 — défini par le Manuel Eurostat (règlement UE n° 549/2013). Classiquement, ce code est manipulé comme une chaîne de caractères ou un entier magique. Ici, il devient un type nominal, un phantom type singleton qui ne transporte aucune donnée mais sert à paramétrer des opérations et des contraintes génériques.

namespace FrenchExDev.Net.State.Economy.Dsl;

public interface IInstitutionalSector
{
    string Code { get; }
}

public sealed class S13_GeneralGovernment : IInstitutionalSector
{
    public string Code => "S13";
    public static readonly S13_GeneralGovernment Instance = new();
    private S13_GeneralGovernment() { }
}

Le gain du passage à un phantom type est triple. Premièrement, l'enum implicite des six secteurs devient fermé — le compilateur refusera toute classe qui prétend être un secteur institutionnel sans implémenter l'interface IInstitutionalSector, et la liste canonique est stable. Deuxièmement, toute opération qui porte une contrainte sectorielle peut l'exprimer comme contrainte générique : IMaastrichtConstraint<S13_GeneralGovernment> est valide, IMaastrichtConstraint<S14_Households> est refusée à la compilation parce que Maastricht ne s'applique pas aux ménages. Troisièmement, la hiérarchie interne des APU — S1311 central, S1313 local, S1314 sécurité sociale — se lit directement dans les noms de classe sans requête base de données ou comparaison de chaînes.

Le fichier Sectors.cs déclare dix sous-classes phantom couvrant l'arbre SEC 2010 standard. Le code S1 (Économie nationale totale) est lui-même un phantom type pour le cas rare où une opération porte sur l'économie entière. Le pattern est volontairement verbeux — un fichier par niveau aurait été plus propre mais perdrait la cohérence de lecture du registre.

Opérations économiques — P, D, F, K au sens SEC 2010

Le deuxième bloc encode les opérations économiques au sens SEC 2010 : la nomenclature en lettres-et-chiffres qui classifie tous les flux de l'économie. P1 production, P2 consommation intermédiaire, B1g valeur ajoutée brute, D opérations de répartition (impôts, subventions, prestations — famille ouverte), P51g formation brute de capital fixe. Chacune devient une classe phantom dans Operations.cs.

public interface IEconomicOperation { string Code { get; } }

public sealed class B1g_GrossValueAdded : IEconomicOperation
{
    public string Code => "B1g";
    public static readonly B1g_GrossValueAdded Instance = new();
    private B1g_GrossValueAdded() { }
}

L'intérêt devient visible quand on croise secteurs et opérations. Le Manuel Eurostat impose des règles fines de compatibilité : B1g ne peut s'appliquer qu'à des unités productrices, donc pas aux ménages pris comme secteur (hors entrepreneurs individuels, qui sont reclassés en S11). P51g ne peut s'appliquer au S2 Reste du monde, par définition. Une observation qui viole ces règles est sémantiquement invalide — elle fait planter la matrice des comptes nationaux si elle remonte jusqu'à l'agrégat. Traditionnellement, ces règles sont vérifiées post hoc, lors de la consolidation INSEE ou Eurostat, des mois après la collecte. Avec le type system, elles deviennent une table statique (SectorOperationCompatibility.IsCompatible) exploitée par un analyzer Roslyn au compile-time.

Cette bascule est la même que celle que l'industrie logicielle a opérée dans les années 2010 pour la validation des API : plutôt qu'attendre les erreurs runtime, on fait parler le compilateur. La comptabilité nationale, qui produit encore aujourd'hui ses tables en déplaçant des chiffres entre des feuilles Excel institutionnelles via des imports et des macros, peut faire le même saut. Rien dans le mécanisme n'est spécifique au droit — c'est la discipline logicielle standard, appliquée à un domaine qui ne l'a pas encore vue passer.

Agrégats macroéconomiques et unité monétaire

Le troisième bloc typé — Aggregates.cs — couvre les agrégats au niveau national : PIB (B1g), RNB (B5g), RDB (B6*g), FBCF (P51g agrégé), épargne brute (B8g). Chacun est un phantom type singleton comme les secteurs et les opérations. Le fichier déclare aussi EurosBillions, un readonly struct qui transporte un decimal exprimé en milliards d'euros — l'unité standard des tables INSEE/Eurostat.

L'existence d'un type dédié pour les montants monétaires n'est pas décorative. Elle corrige un bug omniprésent dans les tableurs budgétaires : la confusion entre euros, millions d'euros et milliards d'euros. Un budget ministériel moyen est de l'ordre de quelques dizaines de milliards ; un compte de campagne présidentielle se chiffre en quelques millions ; un prélèvement à la source se compte en euros. Ces trois ordres de grandeur cohabitent dans les mêmes tableurs sans étiquetage systématique. Avec EurosBillions, l'unité est dans le type, et additionner un EurosBillions à un decimal non-typé devient une erreur de compilation.

Ce pattern suit exactement la doctrine énoncée en Partie 6 pour Common.Dsl : zéro string-as-pivot, zéro primitive obsession. Chaque chose qui compte pour la sémantique devient un type, pas une convention implicite.

Seuils Maastricht et attributs de justification

Le quatrième bloc — Maastricht.cs — encode les deux seuils juridiquement contraignants du traité de Maastricht : 3% de déficit public rapporté au PIB, 60% de dette publique rapportée au PIB. Ils se matérialisent en deux readonly structs DeficitRatio et DebtRatio portant chacun une constante MaastrichtThreshold et une méthode ExceedsMaastricht().

public readonly struct DeficitRatio : IEquatable<DeficitRatio>
{
    public const decimal MaastrichtThreshold = 0.03m;
    public decimal Value { get; }
    public static DeficitRatio Of(decimal value) => new(value);
    public bool ExceedsMaastricht() => Value > MaastrichtThreshold;
}

Trois attributs accompagnent ces structs. [LoiDeFinances(year)] marque une classe comme loi de finances — c'est le point d'entrée qui déclenche l'analyzer ECO001. [Article126TfeuJustification(councilRecommendation, correctiveDeadline)] atteste qu'un déficit supérieur au seuil est accompagné d'une recommandation formelle du Conseil de l'Union au sens art. 126 TFUE — autrement dit, que l'État concerné est sous procédure pour déficit excessif (PDE) avec un calendrier de correction notifié. [ExcessiveDeficitProcedure(opened, openedDate)] est une forme abrégée du précédent pour signaler simplement qu'une PDE est ouverte.

Le choix de rendre la justification obligatoire sous forme d'attribut typé est politique autant que technique. Dans l'état du monde pré-type-system, une loi de finances projetant 4,8% de déficit peut accompagner cette projection d'un paragraphe de prose en exposé des motifs, d'un communiqué de presse du ministre, d'une déclaration en commission des finances. Aucun de ces justificatifs en langage naturel n'est exploitable mécaniquement — le Conseil constitutionnel, la Commission européenne, un journaliste ou un électeur doivent relire la prose pour évaluer. Le type system impose une discipline inverse : la justification est, ou elle n'est pas. Elle est un attribut typé décroché d'une taxonomie fermée. Un paragraphe de prose qui dit « La France respectera son engagement de retour sous les 3% d'ici 2015 » compte pour zéro au build. Une recommandation formelle du Conseil datée du 21 juin 2013 compte pour un.

Ce glissement n'est pas hostile au discours politique. Il le rend articulable à un discours technique. Le ministre des Finances continue d'écrire ses exposés des motifs, ses communiqués, ses déclarations. Mais, sur le terrain précis où le compilateur vérifie la cohérence juridico-économique, la prose ne passe plus. Il faut un attribut typé, donc un acte — la recommandation du Conseil — qui existe ailleurs dans le monde.

Première paire mermaid — Secteurs institutionnels SEC 2010

La bascule conceptuelle qu'opère le passage à des phantom types est particulièrement visible sur la représentation des secteurs institutionnels. Avant, on trouve invariablement dans les manuels pédagogiques de comptabilité nationale une figure plate reliant six bulles — ménages, entreprises, État, reste du monde — par des flèches vagues « échanges », « flux », « transferts ». Aucune hiérarchie visible, aucune contrainte explicite sur les couples compatibles, aucun pont vers un code exécutable. L'élève lit le schéma, comprend vaguement que ça décrit l'économie, puis l'oublie. L'analyste le redessine cinq ans plus tard avec exactement les mêmes ambiguïtés.

Après, avec State.Economy.Dsl, le schéma prend la forme d'un arbre hiérarchique typé : S1 Économie nationale se décompose en cinq secteurs résidents plus un secteur externe (le reste du monde). S13 Administrations publiques se subdivise lui-même en S1311 Central, S1313 Local, S1314 Sécurité sociale. Cette hiérarchie existe dans le Manuel Eurostat depuis 1993 ; elle n'a jamais circulé comme hiérarchie typée en code. La matérialisation en types C# n'est qu'un encodage du corpus déjà stabilisé — mais l'encodage rend exécutable ce qui restait prose.

Diagram
Diagram

Le premier bloc est caricatural mais fidèle à la vulgarisation usuelle — une « économie » faite d'acteurs qui s'échangent des choses, sans discipline de codification. Le second encode les règles du Manuel SEC 2010 : la liste fermée des sous-secteurs, leur parenté, et l'attache de la contrainte Maastricht au seul S13. Le passage du premier au second n'ajoute aucune information qui ne soit déjà dans le Manuel Eurostat ; il transpose l'information d'un document à lire en un graphe à compiler.

Hiérarchie budgétaire LOLF / OMB — Mission, Programme, Action

Le deuxième bloc majeur de la racine est la hiérarchie budgétaire. La LOLF du 1er août 2001 a imposé à la France une architecture pyramidale à trois niveaux : Mission (unité de vote parlementaire, ex. Enseignement scolaire), Programme (unité de responsabilité, ex. Programme 140 — enseignement public du premier degré), Action (unité de spécialité, ex. Enseignement pré-élémentaire). Cette architecture a été vantée à l'époque comme une « Constitution financière de la République », elle-même pensée contre l'ancien budget par ministère et par nature de dépense qui rendait impossible tout contrôle parlementaire sérieux. Aux États-Unis, OMB Circular A-11 §79 organise de façon analogue la classification budgétaire fédérale en trois niveaux Agency → Account → Program Activity.

L'encodage en C# passe par le même pattern de hiérarchie générique que Feature<TParent> utilisé par FrenchExDev.Net.Requirements pour traquer la parenté Epic → Feature → Story. Budget.cs déclare trois interfaces :

public interface IMission { string Designation { get; } }

public interface IProgram<TMission>
    where TMission : IMission
{
    string Designation { get; }
    int ProgramNumber { get; }
}

public interface IAction<TProgram>
{
    string Designation { get; }
}

La parenté est portée par le paramètre générique, pas par une clé étrangère dans un dictionnaire runtime. Programme140EnseignementScolairePublicPremierDegre : IProgram<MissionEnseignementScolaire> encode dans son type même le fait que ce programme appartient à la mission Enseignement scolaire. Un changement de mission parente se fait en changeant le paramètre générique, ce qui recompile tous les programmes descendants en cascade — exactement comme un renommage dans un refactoring IDE.

Le troisième attribut clé est [Expenditure(titre)]. Il marque une propriété (ou un champ) comme dépense budgétaire imputable. L'analyzer ECO002 vérifie alors que la classe déclarante implémente bien IAction<TProgram> — autrement dit, que chaque dépense appartient à une action, d'un programme, d'une mission. Une dépense « flottante », déclarée dans une classe quelconque sans racine typée, fait échouer la compilation avec ECO002: UnattachedBudgetExpenditure. C'est le typage littéral du principe de spécialité budgétaire qui est au cœur de la LOLF française et de la discipline OMB américaine.

Deuxième paire mermaid — Dépense budgétaire LOLF

Avant la LOLF, le budget français était voté par ministère et par nature de dépense — fonctionnement, investissement, intervention. Les parlementaires examinaient un document agrégé où rien ne reliait une ligne de crédits à une politique publique identifiable. Les manuels d'introduction au droit budgétaire des années 1980 représentent encore ce monde comme un flowchart à trois ou quatre boîtes : Ministère → Ligne budgétaire → Bénéficiaire. La « ligne budgétaire » y figure comme une étiquette textuelle qui additionne des crédits au niveau d'un chapitre puis d'un article — sans rattachement à une mission, sans structure imposée, sans contrôle de complétude.

Après la LOLF, le monde typé est strictement pyramidal — et le code l'encode. Une mission typée MissionEnseignementScolaire est parente d'un programme typé Programme140 : IProgram<MissionEnseignementScolaire>, lui-même parent d'une action typée Action01 : IAction<Programme140>. La dépense imputable apparaît comme propriété décorée [Expenditure(titre)] sur une action — nulle part ailleurs. L'analyzer ECO002 détecte immédiatement toute tentative d'imputation orpheline. Le schéma mermaid ci-dessous illustre la bascule.

Diagram
Diagram

Le premier bloc est fidèle aux manuels de budget pré-LOLF — une ligne budgétaire définie textuellement, sans parent typé, sans contrainte de rattachement. Le second encode la pyramide LOLF comme hiérarchie de types génériques avec la dépense en feuille. La valeur du type system apparaît dans l'impossibilité de représenter, dans le second cadre, ce qui était triviellement permis dans le premier : une dépense flottante. La LOLF est déjà une loi organique avec cette propriété en droit. State.Economy.Dsl la transpose en code.

Quatre analyzers Roslyn — ECO001 à ECO004

Les analyzers Roslyn sont le mécanisme qui donne à ce type system son pouvoir coercitif. Un analyzer est un composant standard du pipeline de compilation C# qui scanne le code source, construit son AST et son modèle sémantique, et émet des diagnostics avec ID, sévérité et message. Les plus connus — StyleCop, SonarAnalyzer, Meziantou.Analyzer — vérifient des règles de style ou de qualité logicielle. Rien n'empêche d'écrire un analyzer qui vérifie des règles de droit économique. C'est ce que fait le projet State.Economy.Dsl.Analyzers.

Quatre analyzers constituent le socle de cette première racine :

ID Nom Sévérité Détecte
ECO001 DeficitAboveMaastricht Error Loi de finances projetant un déficit > 3% sans [Article126TfeuJustification] ni [ExcessiveDeficitProcedure(Opened: true)]
ECO002 UnattachedBudgetExpenditure Error Propriété ou champ décoré [Expenditure] hors d'une classe IAction<TProgram>
ECO003 SectorOperationMismatch Error Membre décoré [SectorOperation(sector, operation)] dont le couple est rejeté par la table de compatibilité Eurostat
ECO004 UnauditedClosureAct Warning Classe décorée [ClosureAct(year)] sans [CourDesComptesOpinion] ni [GaoAudit]

Chacun de ces diagnostics a un HelpLinkUri qui pointe vers la source réglementaire ou doctrinale : eur-lex.europa.eu pour l'article 126 TFUE, legifrance.gouv.fr pour la LOLF, eurostat pour le Manuel SEC 2010, ccomptes.fr pour la doctrine de certification des comptes de l'État. Un développeur qui voit un diagnostic dans VS Code peut cliquer sur le code et accéder directement au texte juridique fondateur. C'est la matérialisation concrète de l'idée Law as Code appliquée à l'économie publique — le compilateur n'invente rien, il dérive mécaniquement des règles existantes et pointe vers elles.

ECO001 — le smoke test

L'analyzer Eco001DeficitAboveMaastrichtAnalyzer est le cœur du ship. Il enregistre un SyntaxNodeAction sur ClassDeclarationSyntax — autrement dit, il s'active sur chaque déclaration de classe dans le code compilé. Pour chaque classe, il vérifie trois conditions successivement :

  1. La classe porte-t-elle l'attribut [LoiDeFinances] ? Sinon, ignore.
  2. La classe porte-t-elle un attribut de justification ([Article126TfeuJustification] ou [ExcessiveDeficitProcedure(Opened: true)]) ? Si oui, ignore — la justification est présente, le déficit est défendu.
  3. Pour chaque propriété dont le type est DeficitRatio et dont l'expression-body est DeficitRatio.Of(Xm) avec X littéral, compare X à 0.03m. Si X > 0.03m, émet le diagnostic.

Le choix d'une comparaison sur littéral de compilation plutôt que sur valeur runtime est délibéré. Un déficit qui dépend d'un calcul complexe à l'exécution ne peut pas être vérifié au build — mais un déficit projeté au moment de voter la loi de finances est, par définition, une valeur connue au moment de la rédaction. Le budget initial pour l'année N+1 affiche un chiffre, et ce chiffre est dans le code source de la classe qui représente la loi de finances. L'analyzer intercepte cette valeur à ce moment-là — avant qu'elle devienne un chiffre d'exécution qu'on ne peut plus retirer du réel.

ECO002 — dépense orpheline

L'analyzer Eco002UnattachedBudgetExpenditureAnalyzer s'enregistre comme SymbolAction sur SymbolKind.Property et SymbolKind.Field. Pour chaque membre, il vérifie la présence de l'attribut [Expenditure], puis remonte à la classe contenante (ContainingType), puis inspecte AllInterfaces pour y trouver une interface nommée IAction avec exactement un argument de type. Si l'interface est absente, le diagnostic tombe.

L'implémentation est volontairement tolérante sur le nom exact de la classe implémentant IAction — elle ne fait pas de résolution sémantique complète, juste une recherche lexicale du nom d'interface. C'est cohérent avec la contrainte de netstandard2.0 imposée aux analyzers Roslyn et avec le principe que la discipline de typage est portée par le code métier (les interfaces publiques), pas par des vérifications ad hoc dans l'analyzer.

ECO003 — couple secteur × opération incompatible

L'analyzer Eco003SectorOperationMismatchAnalyzer est celui qui montre le mieux la force du pattern. Il s'active sur les membres décorés [SectorOperation(sector, operation)], extrait les deux arguments typés par la syntaxe d'attribut (donc déjà résolus en INamedTypeSymbol par Roslyn — pas besoin de parsing manuel), et compare les noms de type dans une table de compatibilité hardcodée.

La table est, pour ce ship minimal, volontairement pauvre — deux règles suffisent à illustrer le principe : B1g n'est admis que sur des secteurs producteurs (S11, S12, S13, S1311, S1313, S1314, S15), P51g n'est pas admis sur S2. Un ship ultérieur pourra enrichir cette table jusqu'à couvrir l'intégralité de l'Annexe A du Manuel SEC 2010. Le point pédagogique ici est la possibilité même — qu'un tableur Eurostat à 400 colonnes soit intégralement encodable en une table statique vérifiée à la compilation.

ECO004 — acte de clôture non audité

Le dernier analyzer, Eco004UnauditedClosureActAnalyzer, est classé en sévérité Warning plutôt que Error. C'est un choix délibéré : un acte de clôture budgétaire non audité peut exister en pratique — par exemple parce que l'audit est en cours et n'est pas encore rendu public à la date de rédaction du code. Transformer cela en erreur bloquerait le workflow. Le warning signale l'absence, attire l'attention au build, mais n'empêche pas de compiler. Une équipe peut, dans son .editorconfig de projet, transformer le warning en error si sa discipline interne l'exige.

L'analyzer scanne les classes portant [ClosureAct(year)] et vérifie la présence d'un des deux attributs d'audit — [CourDesComptesOpinion] pour la doctrine FR, [GaoAudit] pour la doctrine US. L'ouverture à ces deux attributs matérialise dans le type system l'extensibilité par tradition : un cadre State.Economy.Germany2026.Bundesrechnungshof pourra déclarer un attribut [BundesrechnungshofOpinionAttribute] et enrichir la liste des justificatifs reconnus sans modifier le cœur de la racine. C'est la clause Common (neutre, extensible) du compilateur croisé appliquée à la doctrine d'audit.

Troisième paire mermaid — Cycle de contrôle du déficit Maastricht

La troisième paire mermaid rend visible la différence, pour un cas réel, entre un monde sans compilateur économique et un monde avec. Le cas choisi est la LFI 2013, loi de finances initiale pour l'année 2013, adoptée fin 2012. Les projections du gouvernement Ayrault à l'époque tablaient sur un déficit proche des 3% ; l'exécution 2013 a atteint 4,0%, puis la France est restée sous procédure pour déficit excessif jusqu'au retour sous le seuil en 2017. Entretemps, le Conseil de l'Union avait formellement ouvert la PDE le 21 juin 2013, avec une échéance corrective à 2015 (puis reportée à 2017).

Avant le type system, le cycle de contrôle est humain : le gouvernement projette un chiffre, le parlement le vote, l'administration l'exécute, Eurostat le mesure deux ans plus tard, la Commission réagit, le Conseil tranche. Entre l'écriture du chiffre et sa vérification externe, il s'écoule typiquement 18 à 30 mois. Pendant cette fenêtre, toute contestation est politique — elle ne dispose d'aucun outil automatisable pour dire « ce chiffre est contradictoire avec l'engagement européen de l'État ».

Après le type system, le cycle prend une forme radicalement différente. Le chiffre de déficit projeté est codé comme une expression DeficitRatio.Of(0.048m) dans une classe [LoiDeFinances(2013)]. L'analyzer ECO001 scanne cette classe au build et, faute de justification, émet error ECO001 à la compilation. Le chiffre ne passe pas la barre de la compilation sans qu'une justification typée ait été jointe — par exemple [Article126TfeuJustification(councilRecommendation: "2013-06-21", correctiveDeadline: "2015-12-31")]. L'asymétrie temporelle s'effondre : le contrôle passe d'un horizon de 18 mois à un horizon de quelques millisecondes, et s'ouvre à quiconque veut publier un cadre State.Economy.France${year}.${author} — administration officielle, syndicats, think tanks, associations citoyennes.

Diagram
Diagram

Le premier diagramme décrit le circuit classique européen — lent, asymétrique, non reproductible. Le second matérialise la même logique de contrôle dans un circuit court compile-time. La nature du contrôle change : dans le premier, un organe tiers (Commission, Conseil) intervient ex post sur un chiffre déjà voté ; dans le second, le contrôle s'intègre au geste même d'écrire le texte, et il est délégable à tout acteur disposant du compilateur. Autrement dit, la barre de coordination internationale descend au niveau de la barre de compilation locale. C'est la forme algorithmique du principe de subsidiarité auquel les textes européens s'accrochent depuis Maastricht — rendu, pour la première fois, opérationnel mécaniquement.

Instances par cadre — Insee, DGFiP, OMB

La racine est neutre. Les instances sont politiques et administratives. Trois instances figurent dans les assets, une par cadre nominal.

State.Economy.France2026.Insee.Dslassets/.../State.Economy.France2026.Insee.Dsl/ — encode un extrait du référentiel INSEE : quelques missions du PLF 2026 (Enseignement scolaire, Défense, Écologie, Solidarité), leurs programmes principaux avec numéros officiels (140, 141, 146…), une action typée Action01EnseignementPreElementaire : IAction<Programme140>. Le même fichier ajoute une classe ComptesNationauxFrance2026 avec quatre propriétés [SectorOperation] — trois valides, une commentée qui déclencherait ECO003 si décommentée. C'est l'instance officielle dans le sens où elle reflète la taxonomie publiée par l'administration statistique.

State.Economy.France2026.DGFiP.Dslassets/.../State.Economy.France2026.DGFiP.Dsl/ — est un overlay qui s'appuie sur Insee et ajoute les objets propres à la Direction générale des finances publiques. Le fichier LoiDeReglement2025.cs contient la classe LoiDeReglement2025Approuvee décorée [ClosureAct(2025)] [CourDesComptesOpinion(...)] — l'exemple positif d'ECO004 qui ne lève pas de warning parce que l'audit est attesté. Un contre-exemple commenté (LoiDeReglement2024NonAuditee) attend d'être décommenté pour vérifier que le warning tombe effectivement.

State.Economy.Usa2026.OMB.Dslassets/.../State.Economy.Usa2026.OMB.Dsl/ — est l'instance américaine. Elle déclare deux missions (DepartmentOfEducation, DepartmentOfDefense), deux programmes Treasury codés selon le plan de comptes fédéral (Account091_0201_EducationForTheDisadvantaged, Account097_0100_Procurement), une action (ProgramActivityGrantsToLeas) avec sa dépense imputable, et un acte de clôture annuel (FinancialReportOfTheUsGovernmentFy2025) décoré [ClosureAct(2025)] [GaoAudit(...)]. Le mapping Agency → Account → Program Activity sur la hiérarchie abstraite IMission → IProgram → IAction démontre que la même racine capte sans adaptation les deux doctrines budgétaires — française LOLF et fédérale américaine OMB A-11.

Trois instances, un seul compilateur. La racine ne préfère aucune tradition administrative. Le bridge ultérieur Law.Economy.Bridge pourra, sans toucher la racine, joindre une loi de finances française typée [LoiDeFinances] à une instance Law.France2026.Etalab qui la mentionne comme loi organique — c'est l'intérêt d'avoir maintenu l'indépendance stricte des racines au niveau NuGet.

Filiation intellectuelle — à qui ce typage doit quelque chose

La série impose la règle des engagements substantiels : pas de note elliptique en bas de page pour les références. Pour cette partie, quatre filiations sont particulièrement dues, et méritent chacune trois à cinq paragraphes.

François Quesnay et les physiocrates — l'idée même d'un tableau économique

Le premier ancêtre lointain est François Quesnay et le Tableau économique de 1758. Quesnay est, à notre connaissance, le premier à avoir tenté une représentation matricielle des flux économiques d'une nation — la fameuse figure en zigzag qui ventile les dépenses entre classe productive, classe stérile et classe des propriétaires. Trois siècles plus tard, la structure de SEC 2010 est reconnaissable dans cette ambition initiale : décomposer l'économie en classes homogènes, tracer les flux entre elles, boucler les comptes. La nomenclature a changé — S11 remplace « classe stérile », S13 remplace « Souverain » — mais le geste cognitif reste le même.

Ce que Quesnay n'avait pas, et que SEC 2010 a, c'est la discipline codificatoire : un manuel de 450 pages maintenu par Eurostat, appliqué par 27 États membres, vérifié par des missions d'audit croisées. Ce que SEC 2010 n'a pas, et que Quesnay avait, c'est l'ancrage philosophique dans une théorie substantielle de la production — Quesnay voulait démontrer que la terre seule crée de la richesse, thèse empiriquement fausse mais constitutive d'une cohérence du modèle. La comptabilité nationale moderne a évacué la théorie au profit de la convention — et c'est précisément ce vide théorique qui rend le typage souhaitable, parce que le type system n'a pas besoin de trancher sur les fondements pour encoder les conventions.

Il faut aussi noter la récupération politique durable du Tableau économique : Marx le reprend au livre II du Capital pour son schéma de reproduction simple et élargie, Leontief y voit l'origine de la matrice input-output, Piketty en mentionne l'influence dans Le capital au XXIe siècle. L'idée qu'une économie nationale peut être codifiée comme un système est un acquis européen profond, distribué sur deux cent soixante-dix ans. State.Economy.Dsl est une itération contemporaine, pas une rupture.

Richard Stone — l'architecte des comptes nationaux d'après-guerre

Plus proche de nous, Richard Stone (prix Nobel 1984) est l'architecte concret du System of National Accounts adopté par l'ONU en 1953 et révisé en 1968, 1993, 2008. C'est lui qui stabilise la distinction entre comptes de production, comptes d'exploitation, comptes de distribution du revenu, comptes d'utilisation du revenu, comptes de capital. C'est lui qui fixe la table des opérations (P production, D distribution, F financement, K autres changements de volume) que SEC 2010 reprend en l'harmonisant à la spécificité européenne.

La leçon méthodologique que Stone laisse pour State.Economy.Dsl est double. D'un côté, une nomenclature fermée et vérifiable est un acquis démocratique — elle rend les chiffres comparables entre pays, entre années, entre régimes politiques. De l'autre, une nomenclature reste une convention — elle ne dit pas si la production militaire vaut autant qu'une production éducative, si l'économie domestique des ménages doit être comptée ou pas, si les activités informelles doivent être intégrées. Ces choix-là sont politiques et ne disparaissent jamais dans la codification.

State.Economy.Dsl prolonge le geste de Stone en le portant sur un autre support. Là où Stone écrivait un manuel, on écrit un type system. Là où Stone demandait aux statisticiens nationaux de respecter des règles, on demande au compilateur de les vérifier. Là où Stone espérait la convergence méthodologique des pays, on organise la divergence maîtrisée des cadres — chaque cadre State.Economy.${Space}${Time}.${Author} peut étendre la racine avec ses propres attributs de tradition (contenu des agrégats, correction des écarts INSEE/Eurostat, prise en compte des activités hors marché), sans casser la compatibilité globale des instances qui partagent la racine.

Maastricht 1992 — la transformation des chiffres en contraintes juridiques

Le traité de Maastricht signe le tournant où les chiffres économiques deviennent juridiquement contraignants pour les États européens. L'article 121 (devenu 126 TFUE) impose explicitement le ratio 3% de déficit et 60% de dette, avec une procédure de surveillance (PDE) qui peut aller jusqu'à des sanctions financières. Le Pacte de stabilité et de croissance de 1997, le Traité sur la stabilité, la coordination et la gouvernance de 2012 (TSCG), puis le Semestre européen affinent le dispositif, ajoutent des exigences structurelles, intègrent un critère sur l'équilibre structurel.

Ce qu'il faut retenir pour le type system : les seuils Maastricht sont déjà du droit dur, pas juste des orientations économiques. Leur violation entraîne des procédures formelles, des échéances de correction, des notifications du Conseil. Mais cette dureté juridique s'accompagne d'une plasticité technique considérable — le calcul du déficit structurel, l'ajustement cyclique, la prise en compte des investissements publics, la définition du périmètre des administrations publiques varient selon les doctrines et les conjonctures. Cette tension entre dureté de la norme et plasticité du calcul est précisément ce que State.Economy.Dsl rend manipulable : le seuil est dur (MaastrichtThreshold = 0.03m), les justifications acceptées pour le dépasser sont ouvertes et typées ([Article126TfeuJustification], [ExcessiveDeficitProcedure], et extensions futures dans des cadres nationaux).

La critique classique de Maastricht, notamment chez Stiglitz ou Piketty, est que ses seuils sont arbitraires (« pourquoi 3% et pas 2% ou 4% ? ») et pro-cycliques (ils serrent la dépense publique au pire moment). Cette critique ne disparaît pas avec le type system — elle s'articule mieux. Un cadre State.Economy.Eu2026.EconomistesAtterres.Dsl peut publier sa racine Maastricht avec MaastrichtThreshold = 0.06m ou avec une fonction d'ajustement cyclique typée. Le compilateur de ce cadre refusera les déficits non justifiés selon sa métrique ; les lois de finances nationales devront alors porter simultanément leur justification au cadre Eurostat officiel et leur justification aux cadres concurrents si elles veulent être compilées partout. La pluralité des seuils devient opérante, pas décorative.

Catala et Merigoux — la preuve française que le droit se type

Dernier pilier, la jonction française vivante entre droit et programmation : Catala, publié à POPL 2022 par Denis Merigoux, Nicolas Chataing et Jonathan Protzenko en collaboration avec la DGFiP. Catala est un langage formel dont chaque programme encode un article du Code général des impôts : le cas d'exception dominant (default logic), la généralité, les conditions d'application sont capturés avec une fidélité littérale au texte juridique. La DGFiP a utilisé Catala pour re-spécifier des pans de l'impôt sur le revenu, et l'équipe publie des traces d'équivalence entre le code et les circulaires officielles.

Ce que Catala valide pour l'économie publique est que le pont est possible. Si l'IR et la CSG peuvent être écrits en Catala, alors la LOLF peut être écrite en type system C#. Les deux traversées ne requièrent aucune rupture scientifique — elles demandent du travail patient d'encodage, une collaboration technique avec les administrations, et une acculturation croisée entre juristes et informaticiens. Catala fait ce travail côté droit ; State.Economy.Dsl le prolonge côté économie publique. La différence est qu'ici, le compilateur est C# + Roslyn plutôt que OCaml + Catala — choix qui reflète l'outillage massivement disponible dans l'administration française, DGFiP côté impôt ayant déjà expérimenté .NET Core, etc.) plutôt qu'une supériorité intrinsèque de l'un sur l'autre.

La leçon politique qu'emporte Catala reste la plus forte : la DGFiP française a accepté de rendre publique une version formelle de son code de calcul de l'IR. Cet acte a valeur de précédent — il ouvre la voie à un INSEE formel, à une DGFiP formelle étendue à la comptabilité publique, à un Eurostat formel. State.Economy.Dsl n'a pas besoin de ces ouvertures institutionnelles pour fonctionner — il fonctionne dès qu'un acteur, même non-officiel, publie un cadre. Mais il en bénéficierait considérablement si ces ouvertures advenaient. Le compilateur croisé y gagnerait en précision, en couverture, et en légitimité.

Le cas LFI 2013 comme smoke test intégral

Le cas démo qui clôt ce ship est ancré dans un épisode historique réel de la politique budgétaire française — la loi de finances initiale pour 2013, adoptée par l'Assemblée nationale en décembre 2012 sous le gouvernement Ayrault, avec un déficit public projeté autour de 3,0% en trajectoire Maastricht. L'exécution 2013 s'est écartée — le déficit réel a atteint 4,0%, et le Conseil de l'Union a formellement ouvert la procédure pour déficit excessif le 21 juin 2013, fixant l'échéance corrective à 2015 (repoussée à 2017 dans une recommandation ultérieure). La France est restée sous PDE jusqu'en 2018, soit cinq ans.

L'asset demos/eco001-deficit-fr-2013/ propose le cas sous la forme didactique standard de cette série : un dossier Failing/ avec une classe LFI2013 qui projette 4,8% sans justification, un dossier Passing/ avec la même classe corrigée par l'ajout de [Article126TfeuJustification(councilRecommendation: "2013-06-21", correctiveDeadline: "2015-12-31")], un fichier ExpectedDiagnostic.md qui décrit l'erreur attendue, et un fichier README.md qui raconte le contexte historique. Le build est organisé en deux projets séparés — Failing.csproj doit rater la compilation, Passing.csproj doit compiler — de sorte que la démonstration se fait par dotnet build sans orchestration supplémentaire.

Pédagogiquement, le cas choisit 4,8% et non 3,0% ou 3,1% pour une raison précise : il faut que l'écart au seuil soit assez net pour que le diagnostic soit immédiatement lisible, mais pas caricatural — 4,8% correspond à un scénario plausible dans une période de récession, pas à une dérive flagrante. Le lecteur qui voit ce chiffre peut se le figurer comme « probable » plutôt que « grotesque », ce qui renforce la portée politique du type system : il ne s'agit pas d'attraper des cas extrêmes, mais de rendre quotidiennement visible la tension entre les projections et les engagements.

Éthiquement, le cas LFI 2013 a été choisi parce qu'il est clos — l'affaire est terminée depuis 2018, la France est sortie de PDE, les acteurs politiques de l'époque ne sont plus aux manettes. Le typer en code ne revient pas à instruire un procès sur un événement en cours. C'est un choix méthodologique cohérent avec celui du cas Dumas 1995 (Partie 10) : on type des événements historiques stabilisés plutôt que des controverses vivantes, parce que le travail de codification est déjà assez politique sans ajouter la polémique. Les cas controversés en cours (PLF 2026, PDE hypothétique 2027) viendront dans un deuxième temps, quand le type system sera suffisamment éprouvé pour que le débat porte sur les valeurs plutôt que sur la mécanique.

Techniquement, le cas valide trois choses à la fois. Premièrement, que la chaîne complète dotnet build → analyzer → diagnostic fonctionne sur un cas non-trivial (0,048m comparé à 0,03m, les deux étant des littéraux decimal). Deuxièmement, que la présence d'un attribut typé [Article126TfeuJustification] bypass effectivement l'erreur — ce qui documente par construction qu'un commentaire en prose ne suffit pas. Troisièmement, que la séparation Failing/ / Passing/ permet de livrer le test sans avoir à orchestrer le diagnostic via CSharpAnalyzerTest — un dotnet build suffit à vérifier que l'un échoue et l'autre compile. C'est le test le plus simple qui démontre la chose la plus radicale — la preuve que le compilateur politique fonctionne sur un cas historique français, avec seulement quatre fichiers C# et un sln de quelques lignes.

Architecture des projets — ce qui tient dans la racine, ce qui sort

Cinq projets dans l'asset :

  • State.Economy.Dsl : la racine, netstandard2.0, aucune dépendance hors BCL. csproj.
  • State.Economy.Dsl.Analyzers : les quatre analyzers Roslyn, netstandard2.0, dépendance Microsoft.CodeAnalysis.CSharp. csproj.
  • State.Economy.France2026.Insee.Dsl : instance française officielle. Référence la racine + l'analyzer en mode OutputItemType="Analyzer" ReferenceOutputAssembly="false". csproj.
  • State.Economy.France2026.DGFiP.Dsl : overlay DGFiP qui dépend d'Insee. csproj.
  • State.Economy.Usa2026.OMB.Dsl : instance américaine fédérale. csproj.

Plus les deux projets de démo :

  • demos/eco001-deficit-fr-2013/Failing/Failing.csproj : le cas fautif, intentionnellement hors de la solution principale (il doit échouer au build, donc l'inclure casserait la solution). Testé manuellement par dotnet build demos/eco001-deficit-fr-2013/Failing/Failing.csproj.
  • demos/eco001-deficit-fr-2013/Passing/Passing.csproj : le cas corrigé, dans la solution. Testé par dotnet build sur la solution complète.

Tous les projets d'instance activent <TreatWarningsAsErrors>true</TreatWarningsAsErrors> de sorte qu'un warning ECO004 dans une instance publique bloque le build — une discipline volontairement stricte pour les cadres officiels, relâchable dans les branches exploratoires via un .editorconfig local qui redescend ECO004 en suggestion.

La solution ConstitutionEconomy.sln référence tout sauf Failing.csproj et organise les projets dans trois dossiers virtuels analyzers/, instances/, demos/. Un seul dotnet build ConstitutionEconomy.sln exécute la vérification complète du ship.

Critique et limites

Il serait malhonnête de ne pas énumérer ce que cette racine ne fait pas dans son état actuel.

Elle ne capture pas la dette publique dans la même richesse typologique que le déficit — DebtRatio existe mais n'a pas encore son analyzer dédié (ECO005 viendra dans un ship ultérieur). Elle ne traite pas la comptabilité sociale séparément de la comptabilité budgétaire centrale — la LFSS (loi de financement de la sécurité sociale) mériterait sa propre hiérarchie de types, distincte de LOLF mais apparentée. Elle ne gère pas les régimes financiers spéciaux — autorité budgétaire restreinte, autorisations d'engagement pluriannuelles, crédits évaluatifs — qui compliquent le principe de spécialité. Elle réduit la table de compatibilité SEC 2010 à deux règles pédagogiques (B1g × secteur, P51g × S2) là où le Manuel Eurostat en contient plusieurs centaines. Aucune de ces limites n'est structurelle — elles indiquent juste le périmètre du ship minimal, pas un plafond de verre de la méthode.

La limite plus profonde est épistémique. Le type system encode des conventions — celles de SEC 2010, de la LOLF, d'OMB A-11, de Maastricht. Il ne dit pas si ces conventions sont justes. Un déficit de 2,9% compile sans diagnostic dans un contexte où il aurait fallu laisser filer à 5% pour relancer l'économie. Un déficit de 3,1% déclenche ECO001 dans un contexte où il s'agit peut-être d'un surplus d'investissement écologique parfaitement souhaitable. Le compilateur n'a pas d'opinion sur l'opportunité politique des seuils — il vérifie leur respect.

C'est un attribut, pas un défaut. La condition d'extensibilité du cadre (un syndicat publie sa racine Maastricht, un parti publie sa hiérarchie budgétaire) n'a de sens que si le cœur du compilateur reste opinion-less. L'opinion est portée par les cadres, pas par la racine. Le citoyen qui veut une politique budgétaire différente a, avec ce type system, un outil pour construire un cadre concurrent typé et vérifiable — pas un oracle qui validerait ses préférences. L'asymétrie usuelle où seule l'administration a les outils formels pour construire sa version se renverse : chacun devient constructeur de cadres, dans la limite de son travail d'encodage.

La limite politique enfin, et la plus délicate, concerne la captation. Un État autoritaire peut prendre State.Economy.Dsl et l'utiliser pour durcir un dispositif d'austérité, en exigeant que tous les budgets locaux compilent selon un cadre central qui n'accepte aucune justification hors la liste officielle. Le type system n'a pas d'immunité contre cet usage. Il faut que l'infrastructure sociale maintienne, à côté, la possibilité d'être auteur d'un cadre — donc la capacité à publier un package NuGet, à le documenter, à en défendre les choix. Cette condition sociale excède le périmètre du type system ; elle est pourtant la condition sans laquelle le type system dégénère en épistocratie — distinction démocratie forte (chacun est constructeur de cadres) contre république épistocratique (seuls les experts certifiés le sont) qui travaille la série depuis sa Partie 1.

Transition vers la partie 9-bis

Ce ship ouvre la porte aux deux parts qui suivent. La partie 9-bis (à venir) introduira Constitution.Dsl, la quatrième racine, qui encode les pouvoirs, le bloc de supra-légalité et les procédures de révision. Elle posera six nouveaux analyzers (CST001 à CST006) dont CST002 sur le dépassement de pouvoir par un organe et CST003 sur la procédure de révision constitutionnelle — deux cas qui recoupent fortement le champ State.Economy.Dsl (une loi de finances organique est à la fois budgétaire et constitutionnelle).

La partie 9-ter (à venir) instanciera ensuite les deux Constitutions officielles (France 1958, États-Unis 2026) et posera le cas démo CST002 sur un Executive Order hypothétique imposant un tarif douanier sans habilitation du Congrès — cas qui fera intervenir simultanément Constitution.Dsl (pouvoir législatif réservé) et State.Economy.Dsl (taxe à l'importation encodable comme opération D sur le secteur S13). C'est là que les deux racines se joindront par bridge, et qu'on mesurera la force du compilateur croisé quand il traverse plus de trois DSLs dans une même démonstration.

Entre-temps, le ship actuel suffit à valider la thèse : la comptabilité nationale et le budget de l'État sont déjà un type system, il suffit de l'écrire.

⬇ Download