Skip to content

fix(slides): scan_slidev_composition rapporte des chevauchements fantomes sur toute liste portant des puces <code> inline #15695

Description

@myia-ai-01

Défaut

scan_slidev_composition.py rapporte des chevauchements texte×texte inexistants à l'écran dès qu'une liste porte des puces <code> inline — c'est-à-dire sur n'importe quel slide de formule. Trois lanes ont mesuré indépendamment la même chose sur #15661 et les trois ont conclu qu'il n'y avait rien à voir :

Slide Paire rapportée myia-ai-01 (captures @5× DPI) myia-po-2026 (QA vision) myia-po-2025:CoursIA-2
15 [170, 1] boîtes élément séparées de +1.57 px VISUAL-OK 0 intersection de glyphes
27 [348, 1] +1.57 px VISUAL-OK 5 intersections, 0 de glyphes
29 [189, 1] +1.56 px VISUAL-OK 4 intersections, 0 de glyphes

Coût mesuré : trois lanes mobilisées sur une QA visuelle d'un défaut qui n'existe pas, et une PR (#15661) retenue le temps de le démontrer. L'organe est par ailleurs utile — ce n'est pas une demande de le désarmer.

Cause — le seuil est juste en dessous de l'inflation qu'il doit absorber

Les deux gardes existantes ne sont pas en cause et ne doivent pas être touchées :

  • scripts/notebook_tools/scan_slidev_composition.py:318 filtre déjà l'ancêtre/descendant (a.el.contains(b.el)) — « FP structurel v1 ». Ici la paire n'est pas en relation de containment : c'est un <li> de niveau 2 (x=76, imbriqué dans le <li> précédent) contre le <li> de premier niveau suivant (x=56). contains() rend false, à raison.
  • :321 exige overlapX > 1 && overlapY > 1.

Le défaut est que overlapY vaut 1.23 px, donc passe > 1 — puis Math.round() (:326) le rend comme le 1 des paires [170, 1]. Ces 1.23 px ne sont pas un chevauchement : ils viennent de

/* slides/theme-ia101/styles/index.css:142-148 */
code { … padding: 2px 6px; border: 1px solid #E0C8C8; }

La puce de code inline est plus haute que sa line-box, et Range.getClientRects() (:290) absorbe padding + bordure : l'union des rects du <li> dépasse sa line-box d'environ 1.2 px et effleure le rect du voisin. Ce qui ne laisse que ~1.5 px de marge réelle à absorber vient de deux réglages légitimes — slides/theme-ia101/layouts/dense.vue (.dense ul > li { margin-bottom: 1px }) et slides/05-theorie-des-jeux/style.css (line-height: 1.3; margin: 0.1em 0).

Le tell décisif : sur les trois paires, les rects de Range se chevauchent de 1.23 px pendant que les getBoundingClientRect() des éléments sont séparés de +1.57 px. Les deux instruments se contredisent, et c'est le second qui dit la vérité du rendu.

Correctif demandé — une passe de confirmation, pas un seuil relevé

Relever le seuil overlapY à 2 ou 3 px ferait taire ces trois cas et rendrait l'organe aveugle aux vrais chevauchements fins. Le correctif qui tient est une seconde lecture :

quand une paire franchit le test Range de :321, la confirmer contre les getBoundingClientRect() des deux éléments ; si ceux-ci ne se chevauchent pas, ne pas rapporter la paire.

C'est déterministe, ça ne change aucun seuil, et ça élimine par construction toute inflation de padding/bordure d'un enfant inline — <code>, mais aussi <sup>, <kbd>, un badge, n'importe quel inline à boîte propre.

Acceptance — un contrôle positif et un contrôle négatif

Les deux sont exigés. Un correctif qui ne livre que le premier est indiscernable d'un organe muet.

  1. Positif : sur slides/05-theorie-des-jeux/slides.md au merge de Fix: deck 05-theorie-des-jeux — 16 -> 0 slide hors canvas (#14888) #15661 (5f58dd9d9f), les slides 15, 27 et 29 rapportent 0 chevauchement texte×texte. Coller la sortie avant (3 paires) et après (0).
  2. Négatif — obligatoire : un cas de chevauchement réel (fixture dédiée, deux blocs en position:absolute qui se recouvrent de ≥3 px) reste rapporté après correctif. Coller la sortie. Sans ce contrôle, le correctif n'est pas recevable.
  3. Le filtre :318 (FP v1) et les seuils :321 restent inchangés — le correctif ajoute une confirmation, il ne relâche rien.
  4. La paire rapportée expose les deux mesures (graze Range et séparation élément) dans son détail, pour qu'un futur lecteur n'ait pas à refaire les captures @5× que ce dossier a coûtées.

Hors périmètre

Note de routage

Ce défaut est dans mon instrument : c'est moi qui ai posé le gate visuel que trois lanes ont dû satisfaire. Le grain est de genre guard, donc META — il ne tient pas le plancher G-VAR-1 de la lane qui le prend, et ne doit pas être pris comme plat principal.

Activity

  1. jsboige commented on Sep 13, 2026

    @jsboige
    Owner

    [CLAIMED] lane myia-po-2023:CoursIA -- scan_slidev_composition: passe de confirmation getBoundingClientRect sur les paires franchissant le test Range (pas de relèvement de seuil) + contrôles positif (slides 15/27/29 @ 5f58dd9) et négatif (vrai chevauchement toujours rapporté) -- 2026-09-13T07:2xZ

  2. jsboige commented on Sep 13, 2026

    @jsboige
    Owner

    [DELIVERED] #15695 — myia-po-2023:CoursIA 2026-09-13T07:35Z

    PR #15930 — porte de confirmation élément dans scan_slidev_composition.py (seconde lecture, aucun seuil relevé).

    • Positif (deck 05, serveur live, main 2233ed8) : slides 16/29/31/48 → 0 rapportée, 4 éteintes comptées (notice CHEVAUCHEMENT-FANTOME) — signatures byte-identiques aux paires de l'issue ([170,1], [348,1], [189,1] + [691,1] apparue depuis), index dérivés +1/+2 par l'évolution du deck après 5f58dd9.
    • Négatif (fixture dédiée, deux blocs position:absolute, recouvrement réel ≥3px) : toujours rapportée — overlap [545, 21] el [580, 4].
    • Filtre :318 et seuils :321 inchangés en substance ; paire rapportée porte les deux mesures (overlap + element_overlap).
    • Tests : 11 passed (8 + 3 nouveaux).
  3. added a commit that references this issue on Sep 14, 2026
  4. added a commit that references this issue on Sep 15, 2026
  5. added a commit that references this issue on Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority-mediumNEEDS_IMPROVEMENT strategies

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions