Phase 4 — Schéma pluriannuel et plan d’action (PR #20)
- ADR-0018 : la DINUM n’impose pas de format, seulement 14 volets. Rampe est donc un guide de rédaction qui suit cette liste officielle mot pour mot (golden vérifié par l’empreinte git du fichier source). Aucun texte de politique n’est écrit à la place de l’organisme. Le plan d’action est pré-rempli depuis l’audit : chaque critère non validé y devient une action, avec une priorité et une année cible fixées par l’utilisateur. La synchronisation est idempotente, et une non-conformité ne peut jamais disparaître en silence : un retrait reste visible, et un critère redevenu validé est marqué, pas supprimé.
- Cause racine du test instable trouvée : le même test e2e avait échoué deux fois en CI, la première fois à tort imputé aux seules lectures uniques. Le relecteur a prouvé un défaut du produit, présent depuis la PR #18 : après la fermeture de la boîte de dialogue, l’application rendait le focus au champ fichier en retard, et pouvait le voler à un utilisateur déjà passé ailleurs au clavier. Son « Annuler cet import » ouvrait alors le sélecteur de fichier. Désormais, le focus n’est rendu que s’il n’est nulle part ailleurs. Preuve : un test déterministe, qui échoue sans le correctif. La suite e2e passe 5 fois sur 5, et la CI au premier passage.
- Le budget JS était mesuré sur un build de développement (
NODE_ENV=testimposé par Vitest), qui embarquaitjsxDEVet les chemins absolus de la machine. Le verdict dépendait même de l’emplacement du checkout. Il est désormais mesuré sur le build de production : 37,5 Ko gzip, soit 2,5 Ko de marge, et non 60 octets comme on le croyait. J’ai donc annulé ma décision de charger les sections à la demande : la mesure juste l’a rendue inutile. - Autres corrections :
- un report d’action faisait écrire au bilan « Aucune action n’était prévue », ce qui était faux. Les années d’origine sont désormais conservées, y compris pour les reports multiples ;
- les liens Markdown sont limités à http(s) et mailto, et c’est documenté ;
- la mention « Rampe vous aide seulement à le structurer » ne figure plus dans les documents publiés, où « vous » ne désignait plus personne.
La phase 4 est terminée. Ce qui reste dans la roadmap demande, pour l’essentiel, une action d’Alexandre (comptes, dépense, mentions légales), sauf l’extension navigateur (code local) et l’audit de Rampe par Rampe.
Phase 5 — Extension navigateur (PR #21)
- ADR-0019 : un clic analyse l’onglet courant, y compris derrière une connexion, et le rapport JSON s’importe dans l’audit guidé. Deux permissions seulement (
activeTab,scripting) : aucun accès aux sites, à l’historique ni aux cookies. Aucune donnée ne quitte le navigateur : la CSPdefault-src 'none'bloque même les connexions, et axe-core est embarqué. Le code est testé de bout en bout dans un vrai Chromium avec l’extension chargée, et une archive.zipest produite par la CI. - Relecture adversariale : rien de bloquant. L’extension tient face à une page hostile grâce au monde isolé, même si la page redéfinit
window.axeou casse les prototypes. Elle donne exactement les mêmes résultats que la CLI. Corrections apportées :- débordement du panneau ;
- focus perdu après l’analyse ;
- PDF « audités » avec de fausses non-conformités ;
- jetons secrets dans le fragment de l’URL gardés dans le rapport, désormais retirés, avec un avertissement avant partage ;
- absence de délai maximal d’analyse ;
- erreurs brutes en anglais.
- Taille :
popup.jspasse de 450 à 189 Ko, grâce à un point d’entrée léger de@rampe/coresans glossaire ni méthodologies, pour des résultats identiques. - Site : le champ d’import devient « Importer un rapport automatique (CLI ou extension, JSON) ».
- À surveiller : le test « navigation pendant l’analyse » dépend du temps que met axe. Il passe 3 fois sur 3, mais à la première instabilité, il faudra en chercher la cause racine.
- Découverte majeure de la relecture : la CLI en production pouvait être trompée. Elle exécutait axe dans le contexte JavaScript de la page, et une page hostile lui faisait afficher « Aucune non-conformité » avec le code de sortie 0. C’est traité dans la PR #22 (ADR-0020).
- La publication dans les magasins reste ⛔ (compte Mozilla ; 5 $ pour Chrome).
Sécurité — La CLI ne peut plus être trompée par la page qu’elle audite (PR #22, ADR-0020)
- Défaut en production, découvert pendant la relecture de l’extension : la CLI exécutait axe-core dans le contexte JavaScript de la page. Une page hostile redéfinissait
window.axeou cassait les prototypes, et faisait afficher « Aucune non-conformité » avec le code de sortie 0. - Correctif : axe-core s’exécute dans un monde isolé créé par CDP (
Page.createIsolatedWorld). Le DOM y est partagé, mais pas les objets JavaScript de la page. Le mécanisme est étendu à toute lecture de la page par la CLI, y compris la collecte de l’échantillon qu’une page piège pouvait fausser (fausse page « accessibilité »). - Relecture adversariale, un second bloquant : il restait un canal ouvert,
postMessage. axe interroge les iframes par messagerie, et une page hostile répondait à leur place pour faire disparaître toutes ses non-conformités (code 0). Correctif :axe.run(…, { iframes: false }). C’est cohérent, puisque Rampe n’analyse pas les iframes : toute réponse d’un cadre serait forgée. Le correctif s’applique à la CLI et à l’extension, déjà en ligne et touchée elle aussi, via une constante partagée dans@rampe/core. - Preuves : chaque page piège donne exactement les résultats du témoin honnête. Par mutation, les tests de la CLI et de l’extension échouent dès qu’on retire l’isolation ou l’option. La sortie est identique à
mainsur toutes les fixtures et sur deux sites publics. Le relecteur a aussi vérifié que l’isolation tient face aux prototypes, globaux et surcharges d’instance remplacés en masse. - Limites documentées dans l’ADR :
- une page qui détecte l’automatisation (
navigator.webdriver) et corrige ses défauts pour le robot ne peut pas être démasquée par un audit automatique ; - le Shadow DOM fermé est invisible pour axe ;
- les iframes ne sont pas analysées.
- une page qui détecte l’automatisation (
- Leçon : une mutation lancée avant de commiter a effacé, par
git checkout --, du travail non commité. Il a été réécrit. Désormais : commit d’abord, mutation ensuite (règle déjà dansCLAUDE.md, rappelée ici).
Phase 6 — Rampe audite Rampe à chaque PR (PR #23, ADR-0021 §1)
-
Le gate : à chaque PR et à chaque push sur
main, le site est construit, servi en local et audité par la vraie CLI en mode strict. La moindre non-conformité, le moindre rattachement incertain ou point à vérifier bloque le merge et le déploiement, sans aucune liste d’exceptions. Il comporte trois passages :- toutes les pages construites (137) en thème clair ;
- les mêmes en thème sombre ;
- l’échantillon méthodologique en affichage étroit (375 px).
Il dure environ 4 minutes en CI.
-
Résultat : le site de Rampe a 0 résultat automatique sur ses 137 pages. Le relecteur a vérifié que l’audit regarde vraiment le contenu (1 576 nœuds analysés sur
/audit/, 3 959 sur le glossaire), et que le site publié donne le même résultat. -
La relecture a fait élargir le gate, qui ne voyait d’abord que 11 pages, en thème clair, à l’état chargé. Le gate élargi a aussitôt trouvé une vraie non-conformité : en 375 px, un tableau du cockpit défilait sans pouvoir être atteint au clavier. C’est corrigé.
-
Nouvelles options de la CLI :
--theme clair|sombre,--largeur <px>,--strict. -
Partage de couverture, documenté : le gate couvre les pages chargées, et les tests e2e couvrent les états interactifs de l’audit guidé (sections 2 et 5 vérifiées explicitement). Chaque élargissement est prouvé par mutation : un contraste insuffisant en sombre seulement, ou une image sans alternative dans un état interactif, fait échouer le test correspondant.
Phase 6 — Infrastructure de l’auto-évaluation (PR #24, ADR-0022)
- Infrastructure :
- fragments d’évaluation par thématique (
docs/audit-rampe/evaluations/<n>.json), validés strictement : forme canonique, UTF-8 strict, critère et page existants, justification qui cite un test, pas de date future ; - construction déterministe de
session.json, importable dans l’audit guidé ; - vérification en CI que la session est à jour ;
- dans le cockpit : l’avancement (0 / 1 166 évaluations), et le taux seulement une fois l’évaluation complète.
- fragments d’évaluation par thématique (
- Relecture adversariale, un bloquant d’honnêteté : une fois importée, l’auto-évaluation de l’IA se lisait comme un audit humain, et la déclaration générée annonçait le pourcentage sans aucune mention d’IA.
- Le relecteur estimait que la décision revenait à Alexandre. Par délégation (ADR-0001), je l’ai tranchée dans l’ADR-0022 : la session porte l’attribution de l’évaluateur (
evaluatedBy, session v5). Partout où le résultat apparaît, la mention apparaît aussi : bandeau permanent, « Résultat », déclaration (champ verrouillé), actions du schéma. - Seule une action explicite et réversible, « Je reprends cet audit à mon compte », retire l’attribution.
- Le relecteur estimait que la décision revenait à Alexandre. Par délégation (ADR-0001), je l’ai tranchée dans l’ADR-0022 : la session porte l’attribution de l’évaluateur (
- Autres corrections : des clés en double dans un fragment (
"status":"NC","status":"C") étaient acceptées en silence. La forme canonique l’empêche désormais. Le nombre de pages du cockpit est maintenant compté réellement, au lieu d’être codé en dur ; le gate a d’ailleurs révélé qu’il manquait une page. - Prochaine étape : l’auto-évaluation elle-même, soit 1 166 évaluations par des agents évaluateurs, puis les corrections jusqu’à 100 %.
Phase 6 — Auto-évaluation complète de Rampe : état initial honnête (PR #25)
- 1 166 évaluations, soit 106 critères sur 11 pages, menées par 5 agents évaluateurs IA en parallèle. Ils ont suivi les méthodologies officielles test par test : mesures de contraste refaites dans les deux thèmes, parcours au clavier de l’audit guidé, validateur W3C Nu, arbre d’accessibilité Chromium. Leurs limites sont écrites dans les notes (pas de lecteur d’écran réel, jugements de pertinence portés par une IA).
- Contre-évaluation indépendante d’environ 150 entrées choisies là où l’erreur était la plus probable : environ 96 % d’accord, et aucun « conforme » de complaisance. En revanche, des notes recopiées d’une page à l’autre affirmaient des faits faux, par exemple « aucun
<progress>» sur un cockpit qui en contient 7, ce qui avait produit de faux « non applicable ». 541 notes ont été réécrites à partir de mesures refaites, et les 1 166 notes sont désormais toutes distinctes. - Arbitrages consignés (délégation ADR-0001, chaque note concernée le signale) :
- le titre de la page du journal ne reflète pas son contenu, donc non conforme ;
- critère 8.7 appliqué strictement : les mots anglais courants (« commit », « merge », « build »…) exigent un
lang, et seuls les noms propres et titres d’œuvres en sont exemptés. Assouplir la règle pour améliorer le chiffre aurait été de la complaisance.
- Résultat publié tel quel : taux global 76,56 %, taux moyen 90,7 %, avec 43 non-conformités. Le cockpit les affiche avec la mention « auto-évaluation par IA, non certifiée ».
- Suite : corriger chaque non-conformité, puis faire réévaluer les critères concernés par un agent neuf. Défauts à corriger :
- un second système de navigation (plan du site) ;
- le menu balisé en liste ;
- les étiquettes des boutons radio ;
- les annonces et le focus de l’audit guidé ;
- les contrôles inopérants sans JavaScript ;
- le
<style>injecté dans le corps ; - les termes anglais ;
- les titres du journal ;
- le contraste des boutons ;
- le titre de tableau ;
- les citations ;
autocomplete.
Corrections — Audit guidé conforme (PR #26)
- Non-conformités de l’auto-évaluation corrigées sur
/audit/, chacune prouvée par mutation :- 11.1 : chaque bouton radio a son
<label for>; - 11.13 :
autocomplete; - 7.1 : le nom accessible de chaque bouton correspond à son intitulé visible ;
- 7.2 : sans JavaScript, aucun contrôle inopérant n’est affiché ;
- 7.3 : le focus est replacé ;
- 7.5 : une région
role="status"et une régionrole="alert", aux états séparés, sans double annonce ; - 3.3 : les bordures des boutons passent de 1,26:1 à 6,59:1 ;
- 9.4 : les citations sont balisées en
<q cite>.
- 11.1 : chaque bouton radio a son
- La relecture a fait revenir au rendu serveur : le rendu vide avant hydratation provoquait un saut de mise en page, et le gate n’auditait plus les contrôles. Les contrôles sont désormais masqués sans JavaScript par un
<noscript><style>. CLS mesuré : 0. - Elle a aussi trouvé la cause racine d’un test instable de la CLI, qui était un vrai bug : sous charge, une navigation pendant l’analyse faisait attribuer les défauts d’une page à la page suivante. C’est traité dans une PR dédiée.