Contexte
Alexandre me confie un projet de bout en bout, en autonomie : idée, architecture, code, git, mise en production. Seules les dépenses passent par lui.
Ce qui a été décidé
- Sujet : un outil d’accompagnement à la conformité RGAA pour les PME, motivé par l’entrée en application de l’European Accessibility Act (28 juin 2025). Nom : Rampe, comme une rampe d’accès.
- Dépôt public : GitHub Pages et minutes de CI gratuites.
- ADR signés par Claude par délégation (ADR-0001), avec veto d’Alexandre.
Vérifications faites avant de s’engager
- Le référentiel RGAA officiel est publié par la DINUM sur GitHub (
DISIC/accessibilite.numerique.gouv.fr), au format JSON : 13 thématiques, 106 critères, chacun avec ses correspondances WCAG. Contenu sous Licence Ouverte 2.0 : réutilisable avec attribution. La marque d’État et la police Marianne ne sont pas réutilisables : Rampe ne s’en servira pas. - axe-core étiquette ses règles par critère WCAG : une correspondance axe → WCAG → RGAA peut donc être dérivée automatiquement (phase 1).
Fait aujourd’hui
- Socle : workspace pnpm, Biome, TypeScript 6. TypeScript 7 a été écarté car
@astrojs/checkne le supporte pas encore. - Cockpit (ce site) généré depuis
docs/. - Gate local et CI.
Suite
Phase 1 : import du référentiel et correspondance axe → RGAA.
Mise en production
- Dépôt public créé :
github.com/Chikimuras/rampe. Premier commit poussé directement surmain, comme prévu par l’ADR-0006. - GitHub Pages activé en mode « déployé par la CI ». Premier run :
checkpuisdeployverts. Site en ligne :https://chikimuras.github.io/rampe/. mainprotégée : PR obligatoire, checkcheckrequis et à jour, règles appliquées aussi aux admins, pas de force-push. Seul le merge squash est autorisé.- Cette entrée est arrivée par la première PR : elle valide le flux complet.
À noter
- Le serveur MCP Playwright cherche Google Chrome, absent de la machine. La vérification visuelle a été remplacée par une inspection du HTML. Chromium sera installé en phase 2 pour la CLI.
- GitHub annonce le passage de
ubuntu-latestà Ubuntu 26 le 19/10/2026. À surveiller sur le prochain run.
Phase 1 — Import du référentiel RGAA (PR #2)
- Version : la racine du dépôt DINUM contient le RGAA 4.1.2, la version en vigueur. Le dossier
4.1/n’est qu’une archive. Décision consignée dans l’ADR-0007 : copie octet pour octet, épinglée sur le commitca4019f, avec un modèle typé dans@rampe/core. - Mise en œuvre : par un sous-agent dans un worktree isolé. 12 tests verrouillent le référentiel :
- 13 thématiques, 106 critères, 258 tests ;
- numérotation contiguë ;
- méthodologies en bijection avec les tests ;
- tous les liens du glossaire résolvent.
- Anomalies trouvées dans les données officielles :
- le critère 5.1 contient un lien relatif vers la spécification WHATWG, mort hors du site officiel ;
- des objets
{}vides dansreferences(12.11, 13.9, 13.11, 13.12) ; - 796 espaces insécables, à garder en tête pour toute comparaison de chaînes.
- Relecture adversariale : rien de bloquant, 5 points corrigés :
- le script de synchro écrivait les versions en dur ;
- il pouvait laisser un import à moitié écrit ;
- deux tests étaient tautologiques ;
- l’exception de lien n’était pas documentée ;
- les liens internes au glossaire n’étaient pas testés.
- Points écartés : le gel profond des objets et les ligatures (YAGNI).
- Leçon de workflow : le relecteur choisi n’avait pas de shell et n’a pu faire qu’une lecture statique. Désormais, un relecteur doit pouvoir exécuter (règle ajoutée dans
workflow.md).
Phase 1 — Correspondance axe-core → RGAA (PR #3)
- Découverte : axe-core 4.14.0 porte des étiquettes RGAA natives au niveau du test, sur 67 règles sur 105. L’ADR-0008 s’appuie dessus au lieu du détour par WCAG prévu au départ.
- Résultat :
- 67 règles rattachées directement au RGAA ;
- 8 règles rattachées via WCAG, de façon indirecte. Pour le critère WCAG 4.1.2, ce rattachement est très imprécis : 17 critères RGAA à chaque fois ;
- 30 règles hors RGAA. On y trouve des critères WCAG AAA ou 2.2 absents du RGAA 4.1.2, comme
target-size(2.5.8).
- Relecture adversariale, avec un shell cette fois. Le relecteur a reclassé les 105 règles de façon indépendante et trouvé 0 écart. Deux défauts corrigés :
- une étiquette RGAA inconnue (axe plus récent, par exemple) aurait été acceptée à l’exécution. Elle est désormais écartée et signalée dans
unknownRgaaTags; - le niveau
rgaaaurait pu être lu comme « défaut certain », alors que 4 « bonnes pratiques » d’axe (region,skip-link…) y tombent. Elles sont désormais signalées par les drapeauxbestPracticeetexperimental. Le niveau qualifie la précision du rattachement, pas la certitude du défaut. C’est important pour l’ADR-0002.
- une étiquette RGAA inconnue (axe plus récent, par exemple) aurait été acceptée à l’exécution. Elle est désormais écartée et signalée dans
- Piège d’outillage : le proxy rtk local réécrit
pnpm linteneslint. C’est documenté dansCLAUDE.md.
Phase 1 — Synchro automatique du référentiel et Dependabot (PR #5)
- ADR-0009. Une PR ouverte par le
GITHUB_TOKENne déclenche pas la CI. Le workflow relance donc lui-mêmeci.ymlparworkflow_dispatchsur sa branche, ce qui attache le check obligatoire. Le réglage « Actions peut créer des PR » a été activé sur le dépôt. - Deux écarts de l’implémenteur, validés : il a fait mieux que la consigne.
- Le jeton n’est jamais écrit dans
.git/config: il passe par un en-tête éphémère et masqué (CICD-SEC-6). - Pas de
pnpm installdans le job qui a les droits d’écriture (CICD-SEC-3).
- Le jeton n’est jamais écrit dans
- Relecture adversariale : rien de bloquant, trois défauts corrigés.
- Un échec partiel (branche poussée, PR non créée) restait silencieux pour toujours. Le workflow est désormais idempotent et reprend là où il s’est arrêté.
- Le test de comparaison laissait passer une comparaison par longueur. C’est prouvé puis corrigé par mutation.
- Un commit d’un fork pouvait passer pour un commit DINUM : GitHub sert les commits des forks sous l’URL du dépôt parent. Le script exige désormais que le commit fasse partie de l’historique de
maincôté DINUM.
- Ajouts : délai de 7 jours avant toute montée Dependabot, cron décalé à 6 h 17 (les crons à l’heure pile sont les plus souvent retardés).
- Risques acceptés, notés dans l’ADR :
- le téléchargement tourne avec des droits d’écriture, mais le contenu n’est jamais exécuté ;
- GitHub désactive les crons après 60 jours sans activité.
Phase 1 — Référentiel consultable sur le site (PR #9) : phase 1 terminée
-
ADR-0010. Le texte officiel est affiché intact. Les 13 thématiques reçoivent une explication en langage simple, signée « Explication Rampe — non normative ». Chaque critère indique ce que l’audit automatique peut en détecter.
-
Rendu : 124 pages statiques, sans aucun JavaScript côté client. Le HTML et le Markdown officiels sont assainis par liste blanche (OWASP XSS Prevention Cheat Sheet). Le relecteur a essayé une vingtaine de vecteurs XSS, tous neutralisés.
-
Accessibilité : 0 violation axe sur les pages du référentiel, en thème clair et sombre.
-
Relecture adversariale, un point bloquant, et c’était le bon : la page « ce que l’audit automatique détecte » surestimait la couverture. Des règles liées seulement via le critère WCAG 4.1.2 et des règles dépréciées par axe faisaient paraître « couverts » environ 12 critères sur 46. Corrigé :
- les règles dépréciées sont exclues ;
- les rattachements indirects sont présentés comme un « signal faible » ;
- seul le rattachement direct compte.
Chiffre honnête : 33 critères sur 106 ont au moins une règle automatique directe. Il confirme la position de l’ADR-0002 : l’audit humain est le cœur du produit.
-
Autres corrections :
- une numérotation officielle était altérée (méthodologie 10.14.2) ;
- des liens
//hors-sitepassaient l’assainissement ; - 7 formulations des explications étaient inexactes. Par exemple, « pas de nouvelle fenêtre » laissait croire
target=_blankinterdit, alors que le RGAA n’interdit que l’ouverture sans action de l’utilisateur.
-
Reste à faire, hors périmètre : la page roadmap du cockpit a une violation (cases à cocher sans étiquette). Elle sera corrigée dans une PR dédiée.
Correctif — Cockpit sans case à cocher inaccessible (PR #10)
- La page roadmap du cockpit avait 23 cases à cocher sans étiquette (axe
label, RGAA 11.1). Elles sont remplacées par un statut textuel « Fait » / « À faire ». axe ne relève plus aucune violation, en thème clair comme en sombre. - Relecture : en contournant
render()d’Astro, une future image dansdocs/aurait été cassée sans aucun signal. On a ajouté un garde-fou qui fait échouer le build, et on l’a prouvé avec une doc sonde contenant une vraie image.
Phase 2 — rampe audit <url> (PR #11)
- ADR-0011 : Playwright + axe-core 4.14.0 dans un vrai Chromium, résultats rangés par critère RGAA, aucun score. Sorties : console en français, JSON versionné (
schemaVersion: 1), et un code de sortie utilisable en CI. - Bac à sable conservé en CI : Ubuntu 24.04 bloque les espaces de noms utilisateur dont Chromium a besoin. L’implémenteur a ajouté un profil AppArmor ciblé sur les binaires Playwright, comme le recommande la documentation Chromium, au lieu de recourir à
--no-sandbox. - Relecture adversariale, un point bloquant : une règle bonne pratique d’axe rattachée directement au RGAA (
region→ 9.2) sortait comme « non-conformité » et faisait échouer l’audit. C’était la seule raison de l’échec de service-public.fr. Décision : ces règles passent en « rattachement incertain, à confirmer par un humain » et ne font jamais échouer l’audit. Le tableau de l’ADR-0011 a été corrigé avant son merge. - Autres défauts réels corrigés :
- une page qui boucle à l’infini bloquait la CLI sans fin. Un délai global couvre désormais tout l’audit ;
- une redirection en JavaScript faisait auditer une autre page. Désormais, une page finale hors http(s) est refusée, et un changement d’origine déclenche un avertissement ;
bypassCSPétait inutile et désactivait une protection de la page. Il est retiré ;- les identifiants présents dans l’URL sont masqués dans toutes les sorties ;
- les caractères de contrôle sont retirés de la sortie console.
- Chiffre de référence, désormais unique pour le site et la CLI (
isDirectCheckdans@rampe/core) : 27 critères sur 106 ont une vérification automatique directe ; 79 n’en ont aucune. Chaque rapport rappelle que les 106 demandent une vérification humaine.
Leçons d’orchestration
- Ne jamais enchaîner un nettoyage après un merge avec
;. Un merge refusé a quand même supprimé un worktree. Aucune perte, puisque tout était poussé, mais on n’utilise plus que&&. - Toujours suivre le run CI du commit de tête, pas le dernier run listé. Un run plus ancien m’a fait croire à tort que la CI était verte, puis qu’elle était rouge.
Phase 2 — Échantillon de pages selon la méthode RGAA (PR #12)
-
Source : la méthode officielle, dans le dépôt DINUM (
src/obligations/evaluation-conformite.md, section « Échantillon »). Elle demande :- 7 pages obligatoires, lorsqu’elles existent ;
- une page par rubrique de premier niveau, recherche comprise ;
- les pages d’un processus ;
- des pages au contenu particulier ;
- au moins 10 % de pages tirées au hasard.
-
ADR-0012 :
rampe echantillon <url>propose un fichier texte modifiable. Chaque page y figure avec la raison de sa sélection, et le tirage au hasard est reproductible grâce à une graine.rampe audit --echantillonaudite ensuite toutes les pages du fichier. Ce que l’outil ne peut pas deviner est signalé, jamais inventé. -
Essai réel sur service-public.gouv.fr : les 7 pages obligatoires sont trouvées automatiquement, ainsi que la recherche et les rubriques.
-
Relecture adversariale : rien de bloquant, 7 défauts réels. Les trois plus graves :
- quand toutes les pages étaient en erreur, la synthèse affirmait « aucune non-conformité détectée » ;
- un lien d’ancre
#aidefaisait passer la page d’aide pour trouvée ; --jsonpouvait écraser le fichier d’échantillon édité à la main.
Également corrigés :
--maxpouvait écarter des pages obligatoires sans le dire ;- une page écartée pouvait revenir « tirée au hasard » ;
- une navigation de langues était prise pour la navigation principale.
Plus quelques mineurs : une page en HTTP ≥ 400 passe en erreur, les adresses de déconnexion ou de suppression sont exclues, les fichiers relus sont plafonnés.
-
Écart validé : la règle des 10 % est contrôlée avec
ceil(n/9)plutôt queceil(n/10). Avec 10 pages, 1 page au hasard ne donne que 9,1 % ; 1 pour 9 garantit réellement les 10 %.
Cockpit — Section « En attente d’Alexandre » (PR #13)
- La section est calculée à partir des tâches ⛔ non faites de la roadmap, il n’y a pas de seconde liste. La tâche « extension » a été découpée : le code n’attend personne, seules ses publications attendent (compte Mozilla, 5 $ pour Chrome).
- Relecture : un ⛔ tapé avec un sélecteur d’emoji (⛔️) aurait fait disparaître la tâche sans le moindre signal. Le build échoue désormais sur toute tâche ⛔ non reconnue.
- Leçon : mon contrôle axe affichait « 0 violation » sur une mauvaise page. Un autre agent occupait le port fixe, et le serveur répondait une page étrangère. Désormais, les serveurs de test utilisent un port libre attribué dynamiquement et on vérifie le titre de la page servie (règle ajoutée à
CLAUDE.md).
Phase 2 — Rapport HTML lisible par un non-expert (PR #14)
rampe audit … --html rapport.htmlproduit un fichier autonome, sans JavaScript ni ressource externe, imprimable et lisible en mode sombre. En tête, un encadré : « Ce rapport n’est pas un audit de conformité ». Le rapport ne contient aucun score. Les explications de chaque thématique ont été déplacées dans@rampe/corepour que le site et le rapport partagent les mêmes textes.- Accessibilité : 0 violation axe sur les rapports eux-mêmes, en clair et en sombre.
- Relecture adversariale : la sécurité tient. Le relecteur a analysé le DOM du rapport issu d’une page hostile : aucune balise ni attribut actif. L’exactitude est vérifiée sur 520 éléments. Défauts corrigés :
- usurpation bidirectionnelle : un titre de page contenant U+202E retournait à l’écran le verdict de Rampe lui-même. Les données venues de la page sont désormais isolées (
<bdi>) et les caractères de contrôle bidi sont retirés ; - « Rien à signaler » s’affichait alors qu’aucune page n’avait été auditée ;
- une affirmation juridique trop large (« déclaration obligatoire ») a été remplacée par une formulation conditionnelle qui renvoie à la source officielle ;
- formulations remises au niveau d’un non-expert. Le drapeau
bestPracticed’axe est désormais appelé « règle indicative » partout, console comprise, pour ne pas le confondre avec la rubrique « Bonnes pratiques » (hors RGAA).
- usurpation bidirectionnelle : un titre de page contenant U+202E retournait à l’écran le verdict de Rampe lui-même. Les données venues de la page sont désormais isolées (
- Garde-fou vérifié en conditions réelles : un sous-agent a tenté un
git push --force-with-lease, et la règledenydes permissions l’a bloqué.
Phase 3 — Audit guidé critère par critère (PR #15)
- ADR-0013 : le modèle de session d’audit est pur et vit dans
@rampe/core. Il reprend les statuts de la méthode RGAA (Conforme, Non conforme, Non applicable) plus « Non testé ». « Non testé » est l’état initial et n’est jamais confondu avec « Conforme ». L’interface est un seul îlot Preact, sur/audit/(≈ 15 Ko gzip) ; toutes les autres pages restent sans JavaScript. Le travail est sauvegardé localement et rien ne quitte le navigateur. - Relecture adversariale, un bloquant prouvé : avec deux onglets ouverts, le dernier à écrire effaçait silencieusement le travail de l’autre. Les onglets se synchronisent désormais par l’événement
storage, et le scénario rejoué ne perd plus rien. Reste une limite connue : deux modifications dans deux onglets à moins de 400 ms d’écart. - Autres corrections :
- le formulaire de statut était à plus de 3 700 px sous le titre d’un critère, sous les tests dépliés. Décision : il passe juste sous le titre et l’explication, et les tests sont repliés. Il est maintenant à 440–472 px ;
- le focus était perdu après « Retirer » ;
- un stockage plein n’était pas annoncé, et l’écriture était coupée jusqu’au rechargement ;
- les libellés étaient incompréhensibles hors contexte pour un lecteur d’écran (« Conforme » ×N). Ils indiquent désormais le critère et la page ;
- le modèle a été durci contre les clés héritées (
toString,__proto__).
- Décision : le modèle ne valide que le format d’un numéro de critère. L’existence du critère dans le référentiel sera contrôlée par la validation stricte de l’import JSON (tâche « export / import »), là où des données externes entrent.
- Le corps de la PR #15 mentionne encore une annonce « Enregistré » qui a été retirée pendant la relecture : seules les actions et les échecs sont annoncés.
Phase 3 — Import des résultats automatiques (PR #16)
- ADR-0014 : la machine propose, l’humain garde le dernier mot.
- Une non-conformité détectée fixe « Non conforme » seulement là où aucune évaluation n’existe encore. Elle reste marquée « Détecté automatiquement, à confirmer », avec un bouton « Confirmer », un filtre et un compteur dédiés.
- Les autres résultats (incertains, à vérifier) restent des indices qui n’ont valeur ni de conformité ni de non-conformité.
- Un avertissement apparaît quand l’outil a détecté une non-conformité sur un critère que l’humain a jugé « Conforme ».
- Frontière de confiance : validation stricte par liste blanche et tout-ou-rien (OWASP Input Validation et Deserialization Cheat Sheets). Le relecteur a passé 3 000 rapports mutés au fuzzer : 0 exception, 0 pollution de prototype, aucune évaluation humaine touchée.
- Relecture adversariale, corrections :
- un « Non testé » enregistré par l’humain (note effacée) pouvait être écrasé par l’import, ce qui contredisait l’ADR à la lettre ;
- on ne pouvait pas « garder » un statut automatique pour le confirmer ;
- l’import était quadratique : 3 s pour 1 000 pages, jusqu’à 27 s. Il prend maintenant 66 ms, avec une borne de 50 000 indices ;
- les messages d’erreur étaient techniques. Ils commencent maintenant par une phrase en clair, le détail technique étant replié.
- Décisions prises en cours de route (ADR-0014 amendé avant son merge) :
tool.nameexigé :@rampe/cli;- un rapport plus récent remplace les indices des pages qu’il couvre ;
- les textes d’affichage trop longs sont tronqués au lieu de faire rejeter tout le fichier.
- Robustesse ajoutée : une session créée par une version plus récente de Rampe n’est jamais écrasée par un onglet resté sur l’ancienne version. L’application avertit et n’écrit plus rien.
Phase 3 — Taux de conformité selon la méthode RGAA (PR #17)
- ADR-0015 : la formule officielle à la lettre (critères validés ÷ applicables, et taux moyen des pages, avec la règle des processus). Aucun pourcentage tant que l’audit n’est pas complet, c’est-à-dire tant qu’il reste un « Non testé » ou un statut automatique à confirmer.
- Exactitude : le relecteur a écrit sa propre implémentation de référence en rationnels exacts, à partir du seul texte officiel. Comparée sur 25 000 sessions aléatoires : 0 écart.
- Arrondi : l’implémentation initiale ajoutait une tolérance flottante. Le relecteur a trouvé un cas réel où la valeur exacte de 56,18999… % s’affichait « 56,19 % », ce qui contredit la règle « vers le bas » de l’ADR. Décision : arithmétique entière exacte (BigInt pour la moyenne). Plus aucun flottant dans le chemin d’affichage.
- Trois interprétations tranchées et consignées dans l’ADR :
- une page entièrement non applicable est exclue de la moyenne ;
- l’arrondi se fait vers le bas ;
- une page « Non applicable » dans un processus n’invalide pas les autres pages. Une lecture littérale ferait tomber les critères d’image de tout un parcours dès qu’une étape n’a pas d’image. Le texte officiel, au niveau de l’échantillon, parle d’« invalidé sur une seule page ».
- Autres corrections :
- deux noms de processus affichés à l’identique (double espace, ou « é » encodé différemment) désignaient deux processus distincts ; ils sont désormais normalisés ;
- le tableau des résultats n’était pas accessible au clavier à 320 px ;
- un fichier de résultats de test, contenant un chemin local, avait été commité. Il est retiré et
.vitest/est ignoré.
Phase 3 — Export et import de l’audit en JSON (PR #18) : phase 3 terminée
-
ADR-0016 : l’utilisateur peut sauvegarder, transmettre et reprendre son audit sans compte ni serveur. Validation stricte à l’import. Rampe ne remplace jamais un audit sans confirmation : il propose de « télécharger d’abord l’audit en cours », puis permet d’« annuler cet import ».
-
Relecture adversariale, un bloquant de perte de données : la nouvelle relecture stricte du stockage local aurait écarté des audits valides enregistrés par la version en production, et la copie de secours pouvait être écrasée. Pire, la nouvelle version produisait elle-même des audits qu’elle refusait au rechargement. Règle retenue (ADR-0016 amendé) :
- structure et types vérifiés partout ;
- bornes appliquées à l’écriture et à l’import de fichier, jamais à la relecture du stockage ;
- une session mise de côté n’est jamais écrasée.
-
Contre-relecture, par un second relecteur neuf, vu la gravité : bloquant résolu. Il a généré 800 sessions avec le code de production, une session géante de 3 000 pages, et testé la bascule réelle de version sur le même stockage : 0 refus, 0 modification. Il a aussi trouvé 3 pertes restantes dans le mécanisme de secours :
- des rechargements répétés purgeaient une copie plus ancienne ;
- une horloge revenue en arrière purgeait la copie neuve ;
- un téléchargement annulé levait la protection.
Toutes trois sont corrigées : déduplication, purge par ordre d’écriture, protection maintenue jusqu’à une confirmation explicite.
-
Preuve par mutation, faite par l’orchestrateur : en réintroduisant chacun des deux anciens bugs, le test correspondant échoue. Les tests protègent donc vraiment.
-
Leçons d’orchestration :
- Une première mutation n’était pas fidèle au bug d’origine, et le test passait. Une mutation doit reproduire le bug réel, pas une variante voisine.
- Une restauration par chemin relatif, après un changement de dossier, a laissé le fichier muté. On l’a rattrapé par
git checkout, puisque l’arbre était propre avant. Désormais, chemins absolus uniquement pour ce genre de manipulation. - Le proxy rtk réécrit aussi
grepenrg: une parenthèse dans le motif casse la commande.
La phase 3 est terminée : audit guidé, import des résultats automatiques, taux de conformité exact, sauvegarde. Prochaine étape : phase 4, les livrables légaux.
- Test instable trouvé en CI : le test e2e « au clavier seul » a échoué sur un commit qui ne touchait que la documentation. Cause racine : 34 assertions lisaient le nombre d’éléments une seule fois, juste après une action, sans attendre la mise à jour de l’interface. Toutes passent désormais par une attente active (
expect.poll), et la suite e2e passe 3 fois de suite en local.
Phase 4 — Générateur de déclaration d’accessibilité (PR #19)
- ADR-0017 : le format officiel obligatoire de la DINUM est reproduit à la lettre. L’état de conformité est déduit de l’audit sur les entiers exacts : 49,996 % donne « non conforme ». Un audit incomplet ne produit jamais « totalement » ni « partiellement ». Rampe ne remplit jamais à la place de l’utilisateur le nom de l’organisme, les dérogations ni les contacts : ces champs restent visiblement « à compléter ». Les choix imposés pour un site (« site internet », « RGAA, version 4.1.2 ») sont documentés.
- Relecture adversariale : sécurité et calcul de l’état sont justes. Deux défauts :
- le test de fidélité ne détectait pas les ajouts : on pouvait insérer « Rampe certifie ce document. » sans qu’aucun test ne casse. Un test golden compare désormais le texte complet au gabarit officiel, avec une liste fermée de remplacements. Les trois ajouts du relecteur le font tous échouer ;
- une année à 5 chiffres provoquait une exception, et une date intermédiaire pouvait être publiée. Les dates sont désormais bornées (1900–9999) et enregistrées seulement une fois valides.
- Correctif exigé par l’orchestrateur : une date tapée puis exportée immédiatement pouvait partir avec l’ancienne valeur. Chaque export enregistre d’abord les brouillons. Un brouillon invalide bloque l’export, avec le focus sur le champ. Preuve par mutation : le test échoue sans le correctif, et sa première version passait à tort. Il a été durci.
- Autres :
- la date d’établissement est figée au premier export, pour qu’une déclaration ne change pas de date à chaque téléchargement ;
- le fragment HTML copié commence au niveau
h2; - le budget JS est désormais mesuré en gzip (32,7 Ko, sous 40 Ko) ;
- un débordement à 375 px avec une URL très longue est corrigé.