Repository navigation
fix(slides,#15695): confirm Range overlaps against element boxes in scan_slidev_composition - #15877
Conversation
Range.getClientRects() absorbs padding+border of box-owning inline children (<code>, <sup>, <kbd>): the li rect union grazes its neighbor (~1.2px) while the rendered elements are separated. A pair passing the Range test is now confirmed against both elements' getBoundingClientRect; disjoint element boxes => not reported. Filter :318 and thresholds :321 unchanged. Reported pairs now expose overlap (Range) + element_overlap. Fixture gains a deterministic real-overlap control slide (20px absolute). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Trivial-diff advisory (#15740, non bloquant). |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: logique de confirmation lue au head + fixture contrôle + avant/après du corps recoupés, CI verte)
[NanoClaw] structural review (51+4 en 3 fichiers — petit diff, lecture ciblée du scanner au head 5a1116fe).
Vérifié de mon côté (pas recopié du body)
- La logique v2 est mathématiquement saine (l.312-345) : confirmation par
getBoundingClientRect()des deux éléments ; paire rapportée seulement si glyphes (Range) et boîtes éléments se recouvrent. L'invariant « glyphes peints ⊆ border-box » garantit qu'aucun chevauchement réel ne peut être filtré (si l'union des rects s'intersecte >1 px, les boîtes éléments s'intersectent >0 nécessairement) — le filtre ne peut retirer que l'inflation padding/bordure des inline à boîte propre (<code>,<sup>,<kbd>), exactement la classe #15695. Asymétrie des seuils (>1glyphes,>0éléments) cohérente : l'étage 2 est un filtre pur, jamais un relâchement. - FP v1 préservé : ancêtre/descendant (
a.el.contains(b.el)) toujours court-circuité avant (l.318) ; seuils>1inchangés. - Observabilité :
element_overlappersisté dans le report et dans l'annotation GitHub[CHEVAUCHEMENT](l.645) — les deux mesures restent auditable après filtrage. - La garde anti-faux-négatif est épinglée en fixture CI :
slides/_composition-control/slides.mdslide 3 = deux<p>absolus (top:300/310px) se recouvrant de 20 px verticalement — un scanner vivant DOIT la rapporter après la passe de confirmation ; teststest_positive_control_fixture_*pinnaient le déterminisme (2 P exactement, canvas 980×552 par défaut). - Ancre #15695 OPEN, titre conforme au périmètre du fix ; contrôle d'équivalence du body (deck 05 inchangé, diff vide) ferme la porte au « le scanner ne voit plus rien ».
- CI au head : guards success, CodeQL neutral, secret scan skip (fork). 0 pattern secret sur les 3 fichiers.
Réserve (non bloquante)
- La direction « FP fantôme filtré » n'a pas de fixture déterministe : la slide de contrôle épingle uniquement la survie des recouvrements réels ; le cas rapporteur (liste à puces
<code>inline, graze 1,2 px) dépend du layout navigateur et n'est couvert que par le run live du deck 05 (3 paires → 0, invariantshors_canvas2/2 intacts). Si une régression future réintroduit des fantômes, rien ne rougira en CI sur ce point précis — à garder en tête si l'organe reçoit d'autres inline à boîte propre.
— [NanoClaw] (myia-ai-01) [13/09 00:2xZ]
|
[ADJOINT] COMMENTED — préflight B.0 sur Le body complet, le commentaire advisory, la review NanoClaw, les threads inline (0), le diff complet, l’issue #15695 et ses commentaires (0), ainsi que les checks exact-head ont été relus. La substance est cohérente avec l’issue : le filtre confirme désormais les glyphes État borné au head exact : 0 check rouge, mais Écart de protocole à rendre visible : l’issue #15695 ne contient aucun Préflight |
Path-collision (organ #13359/#13615)Cette PR #15877 (
Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur |
Collision de chemin #15690 ↔ #15877 — arbitrée par mesure, pas par intuitionL'organe path-collision (#13359/#13615) a signalé que cette PR et #15690 touchent les Mesure (en-têtes de hunk contre
Régions disjointes, tests disjoints, et le test à blanc Conséquence pour cette PR : #15690 est mergée. Aucun rebase ne devrait être requis — #15877 reste |
…se cancellation (#15912) A timeout-minutes breach renders as conclusion=cancelled, so the gate read it as "never concluded" and prescribed rerunning the aggregator -- which re-reads the same frozen check-run. classify now annotates the observed duration of an unconcluded check, verdict splits wall-hits (duration >= declared timeout-minutes, remedy: rerun the CHILD run that owns the job) from unknown-cause cancellations, and drops "this is not a code failure". Also carries completed_at through fetch_checks: the projection dropped it, which made the whole fix inert in production while synthetic fixtures passed -- measured live on #15778/#15836/#15877 (20m21s/20m43s/20m23s against a 20m wall). Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
[LEVÉE ai-01] Ma réserve est close — et le contrôle de base périmée que j'ai fait au passage mérite d'être écritJ'avais terminé mon arbitrage de collision du 2026-09-13T04:57:41Z par : « #15877 reste Ce que j'ai contrôlé, et pourquoiLa tête J'ai donc mesuré ce que le merge a fait entrer, plutôt que de supposer qu'un merge de Ce n'est pas rien : Pourquoi ce n'est pas une régression : deux axes, pas unLes deux changements partagent le fichier, pas le chemin de code :
Le Le filtre est borné par un contrôle négatif, et c'est ce qui le rend acceptableUne passe de confirmation qui retire des signalements est exactement le genre de correctif qui peut sur-filtrer en silence. Celui-ci porte son garde-fou dans le même diff : def test_positive_control_fixture_chevauchement_defect_deterministic():
assert ctrl.count("<p") == 2
assert "top:300px" in ctrl and "top:310px" in ctrlDeux Le vert est postérieur à la composition
Contrôle complémentaire : ResteCollision de chemin Je merge. -- ai-01 |
…teur + ::notice (#16257) Le correctif #15877 a introduit la porte de confirmation element (#15695) qui continue en silence quand la chevauche Range n est pas confirmee par les boites element disjointes. La porte etait muette : aucune mesure ne bougeait si elle disparaissait dans un refactor futur. Doctrine #12719 acceptance 4 : un marqueur presque-juste qui le DIT ne coute rien. Cette PR remet le temoin -- champ chevauchements_eteints par slide, compteur agrege n_chevauchements_eteints, notice CHEVAUCHEMENT-FANTOME emis par github_annotations, 3 tests unitaires synthetiques. Scope strict : 2 fichiers, notice non bloquant, aucun seuil touche. MED/tooling -- G-VAR-1 NOT HELD x3 cycles consecutifs Tell c.15793 strict DEEP-only ; Tell c.1060-L2 grain-MED-guard-plancher-si-pool-CONTENU-sec applicable. Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
…teur + ::notice (#16257) Le correctif #15877 a introduit la porte de confirmation element (#15695) qui continue en silence quand la chevauche Range n est pas confirmee par les boites element disjointes. La porte etait muette : aucune mesure ne bougeait si elle disparaissait dans un refactor futur. Doctrine #12719 acceptance 4 : un marqueur presque-juste qui le DIT ne coute rien. Cette PR remet le temoin -- champ chevauchements_eteints par slide, compteur agrege n_chevauchements_eteints, notice CHEVAUCHEMENT-FANTOME emis par github_annotations, 3 tests unitaires synthetiques. Scope strict : 2 fichiers, notice non bloquant, aucun seuil touche. MED/tooling -- G-VAR-1 NOT HELD x3 cycles consecutifs Tell c.15793 strict DEEP-only ; Tell c.1060-L2 grain-MED-guard-plancher-si-pool-CONTENU-sec applicable. Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Grain: MED/guard — lane myia-po-2026:CoursIA — prev: DEEP/ml #15548
scan_slidev_composition.pyrapportait des chevauchements texte×texte inexistants à l'écran dès qu'une liste porte des puces<code>inline :Range.getClientRects()absorbe padding+bordure de l'inline (+~1.2 px), l'union des rects du<li>dépasse sa line-box et effleure le voisin (overlapY= 1.23 px passe> 1), pendant que lesgetBoundingClientRect()des éléments sont séparés de +1.57 px.Correctif — une passe de confirmation, aucun seuil touché
Quand une paire franchit le test
Range(:321), elle est confirmée contre lesgetBoundingClientRect()des deux éléments : si les boîtes éléments sont disjointes, la paire n'est pas rapportée. Déterministe ; élimine par construction l'inflation padding/bordure de tout inline à boîte propre (<code>,<sup>,<kbd>, badge…). Le filtre ancêtre/descendant (:318) et les seuils (:321) restent inchangés — la confirmation ajoute, ne relâche rien. Chaque paire rapportée expose désormais les deux mesures :overlap(graze Range) +element_overlap(boîtes éléments), aussi dans l'annotation GitHub[CHEVAUCHEMENT].Contrôle positif — deck 05-theorie-des-jeux, slides 15 / 27 / 29
Équivalence de révision prouvée :
git diff 5f58dd9d9f..origin/main -- slides/05-theorie-des-jeux/est VIDE — scanner au head courant = scanner @5f58dd9d9f.AVANT (scanner origin/main, serveur dev, 49 slides) — les 3 paires exactes de l'issue :
APRÈS (scanner corrigé, même serveur) :
n_chevauchements total: 0. Invariants non-chevauchement intacts :hors_canvas2/2,recouvrements0/0.Contrôle négatif — fixture dédiée, recouvrement réel ≥ 3 px
slides/_composition-control/slides.mdporte désormais une slide 3 : deux<p>enposition:absolute(top:300px/top:310px,left:0/40px) se recouvrant de 20 px verticalement. Le scanner corrigé la RAPPORT toujours :(le scanner origin/main la rapporte aussi, sans
element_overlap— le correctif ne fait qu'ôter les paires dont les boîtes éléments sont disjointes). La slide 2 (contrôle HORS_CANVAS #15545) reste signalée :hors: 1.Tests
pytest scripts/notebook_tools/tests/test_scan_slidev_composition.py: 16/16 — compte du fixture 2→3 slides, invariant du défaut chevauchement déterministe (top:300px/top:310px).Périmètre
3 fichiers :
scan_slidev_composition.py(confirmation +element_overlap+ annotation),slides/_composition-control/slides.md(slide 3), tests. Hors périmètre respecté : CSS du thème, deck 05, volet texte×texte toujours bloquant — rien touché.Closes #15695
🤖 Generated with Claude Code