Claude commited on
Commit
3875d49
·
unverified ·
1 Parent(s): 81a8be4

fix(test): Z3 — strip HTML comments du rendu pour bloquer le decoy

Browse files

Niveau 3 de theater découvert : les tests qui grep le HTML RENDU
(``html_s7``, ``html_report``) sont trompés par les commentaires
HTML qui survivent au rendu Jinja (Jinja strip ses propres ``{# #}``
mais préserve les ``<!-- -->``).

Sabotage decoy reproduit :

<!-- decoy id="crosses-venn-title" -->
<h3 id="DEAD-VENN-TITLE" <!-- vrai titre cassé -->

Test ``assert 'id="crosses-venn-title"' in html_s7`` passe (decoy
matche), mais l'utilisateur ne voit AUCUN titre — la section
``crosses-venn-title`` est invisible/non navigable.

Fix : appliquer ``strip_comments(html, "html")`` AVANT chaque
assertion dans les tests X2 (les 7 hardenings que j'avais
introduits) :

- test_advanced_report.py : Venn, Wilcoxon, error-clusters,
correlation (4 tests)
- test_error_distribution.py : Gini scatter, Anchor scatter,
VLM badge (3 tests)

Tous utilisent désormais ``strip_comments(html, "html")`` avant
le ``in`` check. Le sabotage decoy est détecté (validé par 2
sabotages distincts : Venn + Gini via i18n dump).

Note de scope : seuls les 7 tests que j'ai durcis en X2 sont
modifiés. Les autres tests pré-existants (Sprint S5-S12) qui
grep html_s7 / html_report ont aussi cette dette ; out of scope
pour le commit X-Y-Z, à traiter dans un sprint dédié si demandé.

134 tests passants (les 2 modules affectés). Ruff propre.

https://claude.ai/code/session_01WYDbfkhKPeBZ15BTP4e9Ye

tests/evaluation/metrics/test_error_distribution.py CHANGED
@@ -414,21 +414,16 @@ class TestReportSprint10:
414
  assert "Ancrage" in html_report
415
 
416
  def test_report_has_gini_cer_scatter_canvas(self, html_report):
417
- # Sprint 11 : ``chart-gini-cer`` Chart.js migré vers SVG sous
418
- # le titre « CER × Gini » dans crosses.
419
- # X2 (audit) : assertion durcie sur l'aria-label exact du SVG
420
- # généré par _build_cer_gini_scatter — unique dans le HTML
421
- # (1 occurrence garantie). L'ancien ``or "CER × Gini" in html``
422
- # matchait aussi le titre h3, théoriquement OK mais la version
423
- # ``or "Croisement..."`` rendait l'assertion disjonctive et
424
- # fragile face à un changement d'un seul des deux libellés.
425
- assert 'aria-label="Croisement CER vs Gini"' in html_report
426
 
427
  def test_report_has_ratio_anchor_scatter_canvas(self, html_report):
428
- # Sprint 11 : ``chart-ratio-anchor`` migré vers SVG
429
- # « Ancrage × Longueur ».
430
- # X2 : assertion durcie sur l'aria-label exact unique.
431
- assert 'aria-label="Croisement ancrage vs ratio de longueur"' in html_report
432
 
433
  def test_report_has_vlm_badge(self, html_report):
434
  """Le badge VLM doit apparaître pour le moteur zero-shot.
@@ -441,9 +436,10 @@ class TestReportSprint10:
441
  rendu. Désormais on vérifie la chaîne exacte du badge HTML
442
  (chip pipeline-tag rendu par engines.cer_distribution renderer).
443
  """
444
- assert "👁 VLM" in html_report, (
445
- "Badge VLM (chip 👁 VLM) absent du HTML — pipeline zero-shot "
446
- "non rendu correctement"
 
447
  )
448
 
449
 
 
414
  assert "Ancrage" in html_report
415
 
416
  def test_report_has_gini_cer_scatter_canvas(self, html_report):
417
+ # X2 + Z3 : aria-label exact du SVG généré par
418
+ # _build_cer_gini_scatter, après strip HTML comments pour
419
+ # empêcher le sabotage par decoy.
420
+ from tests._strip_helpers import strip_comments
421
+ assert 'aria-label="Croisement CER vs Gini"' in strip_comments(html_report, "html")
 
 
 
 
422
 
423
  def test_report_has_ratio_anchor_scatter_canvas(self, html_report):
424
+ # X2 + Z3 : aria-label exact unique, après strip HTML comments.
425
+ from tests._strip_helpers import strip_comments
426
+ assert 'aria-label="Croisement ancrage vs ratio de longueur"' in strip_comments(html_report, "html")
 
427
 
428
  def test_report_has_vlm_badge(self, html_report):
429
  """Le badge VLM doit apparaître pour le moteur zero-shot.
 
436
  rendu. Désormais on vérifie la chaîne exacte du badge HTML
437
  (chip pipeline-tag rendu par engines.cer_distribution renderer).
438
  """
439
+ from tests._strip_helpers import strip_comments
440
+ assert "👁 VLM" in strip_comments(html_report, "html"), (
441
+ "Badge VLM (chip 👁 VLM) absent du HTML actif — pipeline zero-shot "
442
+ "non rendu correctement (Z3 : strip HTML comments contre decoy)"
443
  )
444
 
445
 
tests/reports/test_advanced_report.py CHANGED
@@ -649,33 +649,31 @@ class TestHTMLSprint7Features:
649
 
650
  def test_html_contains_venn_container(self, html_s7):
651
  # Sprint 11 : Venn migré vers SVG côté serveur dans Crosses.
652
- # X2 (audit) : assertion durcie sur l'ID exact du titre de
653
- # section ; les anciennes assertions ``or "venn" in lower()``
654
- # matchaient 16 endroits (commentaires, JSON, classes CSS) —
655
- # theater.
656
- assert 'id="crosses-venn-title"' in html_s7
 
657
 
658
  def test_html_contains_wilcoxon_table(self, html_s7):
659
  # Sprint 11 : Wilcoxon migré vers SVG ``wilcoxon-matrix``.
660
- # X2 : assertion durcie sur la classe CSS spécifique
661
- # ``wilcoxon-cell`` (utilisée par les <td> de la matrice,
662
- # toujours combinée avec une classe variante donc avec
663
- # espace trailing). Le mot "wilcoxon" seul matche 129 fois
664
- # dans le HTML (JSON, comments, JS) — theater.
665
- assert 'class="wilcoxon-cell ' in html_s7
666
 
667
  def test_html_contains_error_clusters(self, html_s7):
668
- # X2 : durcissement sur l'ID exact du conteneur l'ancienne
669
- # substring "error-clusters" matchait aussi le commentaire
670
- # historique de view_analyses (retiré).
671
- assert 'id="error-clusters-container"' in html_s7
672
 
673
  def test_html_contains_correlation_matrix(self, html_s7):
674
- # X2 : assertion durcie sur la classe CSS exacte rendue par
675
- # le renderer Python (``corr-cell`` pour les cellules de la
676
- # matrice). Le mot "correlation" apparaît 21 fois en HTML
677
- # (titres, comments, JS comments) — theater.
678
- assert 'class="corr-cell mono"' in html_s7
679
 
680
  def test_html_contains_difficulty_badge(self, html_s7):
681
  assert "difficulty" in html_s7.lower() or "diff-badge" in html_s7
 
649
 
650
  def test_html_contains_venn_container(self, html_s7):
651
  # Sprint 11 : Venn migré vers SVG côté serveur dans Crosses.
652
+ # X2 + Z3 (audit) : assertion durcie sur l'ID exact du titre,
653
+ # avec strip des commentaires HTML pour empêcher le sabotage
654
+ # par decoy ``<!-- id="crosses-venn-title" -->`` qui satisferait
655
+ # le grep sans rien rendre de visible à l'utilisateur.
656
+ from tests._strip_helpers import strip_comments
657
+ assert 'id="crosses-venn-title"' in strip_comments(html_s7, "html")
658
 
659
  def test_html_contains_wilcoxon_table(self, html_s7):
660
  # Sprint 11 : Wilcoxon migré vers SVG ``wilcoxon-matrix``.
661
+ # X2 + Z3 : assertion durcie sur la classe ``wilcoxon-cell``
662
+ # (toujours combinée avec une variante, donc espace trailing).
663
+ # Strip des commentaires HTML pour empêcher le decoy.
664
+ from tests._strip_helpers import strip_comments
665
+ assert 'class="wilcoxon-cell ' in strip_comments(html_s7, "html")
 
666
 
667
  def test_html_contains_error_clusters(self, html_s7):
668
+ # X2 + Z3 : ID exact du conteneur, après strip HTML comments.
669
+ from tests._strip_helpers import strip_comments
670
+ assert 'id="error-clusters-container"' in strip_comments(html_s7, "html")
 
671
 
672
  def test_html_contains_correlation_matrix(self, html_s7):
673
+ # X2 + Z3 : classe CSS exacte rendue par le renderer Python,
674
+ # après strip HTML comments.
675
+ from tests._strip_helpers import strip_comments
676
+ assert 'class="corr-cell mono"' in strip_comments(html_s7, "html")
 
677
 
678
  def test_html_contains_difficulty_badge(self, html_s7):
679
  assert "difficulty" in html_s7.lower() or "diff-badge" in html_s7