Ingénierie
Vingt-six procédures, une seule application
Construire un outil civique quand le contenu appartient à vingt-six administrations
0. D'où vient ce texte
Je ne suis pas suisse. Je me suis installé à Morges en 2014, et en 2026 j'ai entamé la procédure de naturalisation ordinaire, qui dans le canton de Vaud se termine par un test écrit de connaissances organisé par la commune de domicile. J'ai construit cette application parce que j'en avais besoin, et j'ai continué parce que les parties les plus difficiles n'étaient pas celles que j'attendais. En août 2026 j'ai passé cet examen moi-même et je l'ai réussi avec le maximum : 48 sur 48. Dans la salle, ce matin-là, plusieurs autres candidats utilisaient l'application.
Ceci est un texte d'ingénierie, pas une présentation de produit. Il parle de ce qui arrive quand la chose que vous livrez n'est pas vraiment du logiciel : c'est une affirmation sur des faits qui appartiennent à quelqu'un d'autre, et qui changent sans vous prévenir.
1. Le problème, en une ligne
La Suisse n'a pas de test de naturalisation national. La loi fédérale n'en prescrit aucun, et chacun des vingt-six cantons est maître de son format. Certains publient un catalogue complet de questions. D'autres publient du matériel d'étude et aucune question. D'autres encore évaluent à l'oral et ne publient rien. Et dans un canton, le test n'est pas cantonal mais communal : les questions reçues dépendent de laquelle des trois cents communes on habite.
Le modèle naïf, une banque de questions et un examen et une application, s'écroule donc en cinq minutes. La forme réelle, ce sont vingt-six procédures différentes, et à l'intérieur de l'une d'elles, trois cents de plus.
Aujourd'hui l'application porte 13 497 questions d'examen pour les vingt-six cantons, dont 9 565 sont communales : des questions qui n'existent que pour une commune et ne servent à personne d'autre. Choisir sa commune n'est donc pas une préférence. C'est la requête.
2. Pourquoi le plus dur n'est pas l'application
Une application à choix multiples, c'est un week-end. Le travail est ailleurs : obtenir du matériel que vingt-six administrations publient dans des formats différents, en trois langues, à leur propre rythme ; décider ce que chaque élément est vraiment ; et garder tout cela honnête pendant des mois sans que personne ne vous dise que quelque chose a bougé.
Quatorze cantons ont aujourd'hui leur propre catalogue dans l'application. Les douze autres reçoivent la couche fédérale empruntée à l'exécution à un canton qui, lui, en publie une, et l'application le dit sur la question elle-même. Cette distinction, ceci est le matériel de votre canton contre ceci est du matériel fédéral que nous vous montrons parce que votre canton n'en publie pas, n'est pas une note de bas de page. C'est la différence entre un outil d'étude et un outil trompeur.
3. La chaîne du contenu, et ce que porte une question
Chaque question de l'application porte sa propre provenance : d'où elle vient, comment elle a été obtenue, à quelle date, et contre quelle empreinte de la source. La répartition dit honnêtement à quel point le paysage est inégal :
| Méthode | Questions |
|---|---|
| API cantonale en direct | 9 693 |
| Extraction de texte depuis des PDF publiés | 1 525 |
| Traduction automatique, signalée comme non officielle | 522 |
| Rédigées à la main depuis du matériel officiel publié | 890 |
| Curation manuelle | 28 |
| Transcription manuelle vérifiée | 290 |
| Matériel officiel d'apprentissage en ligne | 126 |
| Autres formes déclarées | 423 |
Aucune question de l'application n'est dépourvue de bloc de provenance. C'était une contrainte de conception dès le début, et c'est ce qui rend le reste de ce document possible.
Là où aucun catalogue n'existe et où il faut rédiger, la rédaction n'est pas une composition libre. Chaque question rédigée porte une ancre : une chaîne de caractères reprise mot pour mot d'un document officiel publié. À la compilation, le générateur cherche cette chaîne dans le corpus source, et sur trois cantons il échoue durement si l'ancre est introuvable. Pas de sortie, pas de publication. Une question qui ne peut pas pointer vers une phrase d'un document officiel ne part pas.
La même discipline vaut pour la certitude. Les paramètres de l'examen, combien de questions et quel seuil de réussite et quelle durée, ne sont pas affirmés. Chacun porte un niveau de certitude : officiel, estimé, déclaré par l'organisme, non publié, non applicable. Dans l'ensemble des modèles cantonaux, quarante-neuf de ces paramètres sont marqués non publié, parce que le canton ne les publie réellement pas. Le montrer honnêtement s'est avéré plus convaincant, pour des lecteurs institutionnels, qu'un chiffre à l'air propre.
4. La surveillance nocturne, et le contrôle que personne n'écrit
Les sources bougent. Un canton republie un PDF, renumérote une série, corrige une réponse. Personne n'envoie de notification.
Treize cantons ont donc leur source publiée vérifiée chaque nuit par une tâche planifiée, à des heures décalées. Chaque exécution télécharge la source, en prend l'empreinte, la compare à la référence stockée, et se résout en l'un de cinq résultats : inchangé, changé, source injoignable, régénération échouée, ou écriture en base échouée. Un incident réseau passager est délibérément distingué d'une vraie panne, parce que traiter une connexion capricieuse comme une source cassée produit des alertes que personne ne lit.
Chaque exécution ajoute une ligne signée à un journal en ajout seul, sur une branche séparée : l'horodatage, l'empreinte de la source, le code HTTP, la durée du téléchargement, et la révision du code exécuté. La reproductibilité n'est pas une affirmation, c'est un registre.
Mais le contrôle vers lequel je dirigerais un évaluateur est un autre, et il existe à cause d'un échec. Le détecteur compare les sources en amont à une référence stockée. Il ne pose jamais la seule question qui compte après publication : ce que nous servons correspond-il encore à ce que nous avons validé ? Ce n'était pas le cas, et un canton a servi soixante-deux questions dont la correction avait été validée six semaines plus tôt et jamais publiée. En silence. Rien dans la chaîne n'était conçu pour le remarquer.
Une seconde comparaison tourne donc désormais à chaque cycle, y compris, et surtout, les cycles où rien n'a changé. Elle recalcule l'empreinte du contenu à partir du texte de la question, des réponses et de la bonne réponse, plutôt que de faire confiance à l'empreinte enregistrée, de sorte qu'une empreinte périmée apparaît comme une divergence au lieu d'en cacher une. Un canton auquel personne ne touche est précisément là où une divergence dort.
5. Mettre à jour sans passer par les stores
Un examen a une date. Si le canton d'un candidat corrige une réponse trois semaines avant son test, une application qui ne peut livrer qu'à travers la validation d'un store n'est pas un outil d'étude, c'est un risque.
Le contenu ne voyage donc pas avec le binaire. Les corrections approuvées atteignent les appareils par un canal différentiel : au lancement et au retour au premier plan, le client demande tout ce qui se trouve au-dessus de son propre curseur et le fusionne par-dessus le catalogue embarqué. Pas de soumission, pas de file d'attente, pas d'attente que les utilisateurs mettent à jour.
Le chiffre, mesuré en production cette semaine : sur 12 744 questions publiées, 541, soit 4,2 pour cent, ont été révisées au moins une fois depuis leur première publication et livrées de cette manière. La répartition est inégale et raconte son histoire. Les plus importantes : 148 en Valais, 140 dans le canton de Vaud, 112 à Lucerne, 43 à Bâle-Ville, 36 à Neuchâtel, 27 à Zurich, 24 à Saint-Gall. Les questions d'un canton en sont à leur cinquième version.
Deux garde-fous rendent cela défendable plutôt qu'imprudent.
Rien ne se publie tout seul. Quand un écart est détecté, la chaîne régénère, écrit en base, et marque le canton en attente de revue. Dans cet état, le client refuse de se synchroniser : les utilisateurs continuent de voir le contenu précédemment approuvé. Le passage à en ligne est manuel, toujours, et il est structurellement interdit à la chaîne de le faire. En ce moment, les treize cantons publiés sont tous en ligne.
Rien n'est écrasé en silence. Chaque modification archive la version précédente complète de la question, texte et réponses et bonne réponse et format, avant que la nouvelle n'arrive.
Le cycle le plus rapide à ce jour : une déléguée à l'intégration d'une région germanophone a signalé que les réponses longues étaient tronquées. La cause était de notre fait, et pire que cosmétique : la troncature s'appliquait à la bonne réponse mais pas aux distracteurs, si bien que la bonne réponse était systématiquement la plus courte, celle qui finissait par des points de suspension. Un indice, dans un simulateur d'examen. La réparation a touché 147 des 280 lignes de ce canton dans les deux langues, et la production a enregistré le changement de contenu deux minutes après la validation du correctif, le soir même du signalement.
6. La transparence comme fonction, pas comme page
La plupart des applications traitent la transparence comme un document. Ici c'est une propriété d'exécution, et elle apparaît à trois endroits.
Sur la question. Sous chaque question, en entraînement comme en examen blanc, le candidat voit d'où elle vient, si son format a été adapté de l'original, si elle est empruntée au corpus officiel d'un autre canton, si elle a été traduite, et un marqueur de vérification portant la date du dernier contrôle de la source.
Avant l'examen. L'examen blanc déclare, canton par canton, lesquels de ses paramètres sont officiels et lesquels sont estimés, et distingue la voie écrite de la voie orale, parce que dans plusieurs cantons l'évaluation réelle est un entretien et présenter une simulation à choix multiples comme « l'examen » serait faux.
En public. Une page de transparence, en quatre langues, énonce les engagements de service : sources vérifiées toutes les vingt-quatre heures, mise à jour ordinaire sous sept jours, corrections touchant l'exactitude sous septante-deux heures. Elle offre aussi aux autorités cantonales de naturalisation, au secrétariat d'État aux migrations et aux chercheurs accrédités une inspection du registre de vérification sur demande écrite, traitée sous cinq jours ouvrables.
Publier un engagement de service sur lequel on peut être mesuré est inconfortable. C'est aussi la seule version de la transparence qui veuille dire quelque chose.
7. Un seul développeur, treize versions en dix-huit semaines
Le premier commit est daté du 12 avril 2026. L'application était en production le 2 mai. Depuis : treize versions mineures publiques jusqu'à la 3.12, 243 compilations, et au moins une compilation sur 89 des 142 jours.
Ce rythme n'est tenable qu'à cause de ce qui se trouve dessous : 186 fichiers de tests automatisés, 320 migrations de base de données versionnées, et une chaîne de contenu qui vérifie sa propre sortie au lieu de lui faire confiance. L'interface est tenue à quatre langues par un test qui refuse de compiler si une langue possède une clé que les autres n'ont pas. Actuellement 3 426 clés, identiques dans les quatre.
Rien de tout cela n'est héroïque. C'est la conséquence ordinaire du fait qu'une seule personne ne peut pas tenir l'état de vingt-six cantons dans sa tête, et ne devrait pas essayer.
8. Les agents comme utilisateurs du système
Voici le chapitre que je ne m'attendais pas à écrire.
Une grande partie de ce projet a été construite avec des agents de programmation. L'intéressant n'est pas qu'ils aient écrit du code. C'est qu'ils se sont révélés être des utilisateurs du système de production, et des utilisateurs coûteux.
Un jour d'août, le trafic sortant de la base de données du projet se répartissait ainsi : l'outillage, c'est-à-dire les scripts et les utilitaires internes et les agents qui mesuraient des choses, produisait environ cinq fois le trafic de tous les vrais utilisateurs de l'application réunis. L'application n'a jamais été le problème. Mesurer l'application l'était. Et cela a poussé le projet contre un seuil de facturation avec une échéance.
Le mode de défaillance était précis et, avec le recul, évident. Un agent chargé de vérifier qu'une insertion avait fonctionné relisait la table. Un agent à qui l'on demandait combien de lignes existaient récupérait les lignes et les comptait. Un agent chargé de savoir si quelque chose avait changé le téléchargeait et comparait. Chacun de ces réflexes est raisonnable pour un humain devant un terminal, et catastrophique à fréquence machine.
Il en est sorti une constitution de dépôt, lue automatiquement au début de chaque session d'agent, dont le premier chapitre ne parle pas de style de code. Il dit : chaque requête que tu lances contre cette base est facturée. Puis les règles qui en découlent. Ne jamais lire des lignes pour les mesurer, parce qu'un compte et un poids et une empreinte tiennent chacun sur une ligne. Ne jamais sélectionner toutes les colonnes des tables lourdes. Agréger côté serveur et recevoir dix lignes au lieu de dix mille. Une session par tâche, pas une par commande, parce que chaque nouvelle connexion paie un coût de protocole fixe avant même que la requête ne parte. Et vérifier une écriture avec des nombres, jamais avec un vidage.
À côté se trouve une mémoire de projet persistante, un fait par fichier, indexée, qui porte les décisions qu'un agent ne peut pas redériver du code : quels environnements peuvent être écrits et à quelles conditions, quelles corrections ont déjà été tentées et ont échoué, quelles parties de la chaîne une session neuve ne doit pas toucher seule.
La leçon dépasse ce projet. Nous avons l'habitude de raisonner le coût d'un agent en jetons. Dans un système avec un vrai backend, le coût d'un agent est aussi la charge qu'il met sur votre infrastructure, et ce nombre peut écraser le premier. Personne ne m'avait dit de l'instrumenter. La facture, si.
9. Ce que cela coûte vraiment
L'infrastructure elle-même, backend et distribution et comptes développeur, tourne pour quelques centaines de francs par an. La ligne dominante n'est pas l'infrastructure : c'est l'outillage d'intelligence artificielle qui fait l'essentiel de la construction, un abonnement que j'aurais de toute façon et qui est partagé entre tout ce sur quoi je travaille. Entièrement attribuée, l'opération complète tourne autour de trois mille francs par an. Strictement attribuée à ce projet, c'est une fraction de cela.
Pour cela, au moment où j'écris : 10 010 profils enregistrés, dont 7 317 ont réellement étudié ou joué, dans vingt-cinq des vingt-six cantons.
Je mets ces chiffres parce que c'est la partie que les gens croient le moins, et parce qu'ils posent la vraie question. Ce n'est pas une histoire de faire beaucoup avec peu comme vertu. C'est qu'un outil civique à l'échelle nationale peut désormais être construit et maintenu par une seule personne, et que la contrainte a changé de place. Ce n'est plus la capacité d'ingénierie. C'est de savoir si les institutions qui possèdent le contenu ont un moyen de participer à le tenir correct, et à cette question aucun code ne répond tout seul.
