From 323b50676bdbab3c33e67b1645853698a3832927 Mon Sep 17 00:00:00 2001 From: mathieu Date: Fri, 21 Aug 2026 17:44:00 +0200 Subject: [PATCH] =?UTF-8?q?Regarde=20enfin=20les=20=C3=A9crans=20s'affiche?= =?UTF-8?q?r,=20et=20trouve=20ce=20que=20618=20tests=20taisaient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La 7ᵉ série s'était close sur un aveu : aucun écran n'avait été regardé. Balayage des vingt-deux routes à 320, 375 et 1280 px. Les huit lots tiennent leurs promesses ; trois défauts en sortent, qu'aucun test ne pouvait voir. L'arbre des séries débordait de 8 px à 320 px : sa ligne est elle-même un élément de flex, et « min-width: auto » lui interdisait de rétrécir. C'est mot pour mot la leçon du lot M, non appliquée à cet étage de la cascade. L'ISBN à tirets faisait défiler toute la fiche — 395 px pour un écran de 320. « white-space: nowrap » y annulait le « word-break » dont le dd est muni justement pour cela. Le défaut de CSS était déjà le bon comportement : une ligne quand il y a la place, une coupure au tiret sinon. Le troisième est le sérieux : le relais de couvertures rendait 404 une fois sur trois sur une couverture qui existe. archive.org extrait l'image d'un ZIP à la volée et met 5 à 15 s, le délai coupait à 10. Rien n'était alors mis en cache, donc CORS puis relais se rejouaient à chaque affichage — le défaut même que ce relais existe pour corriger. Un 404 ne prouve rien ici, par construction : le relais répond 404 à tout refus pour ne pas être un oracle. Il a désormais son propre délai, personne n'attendant derrière un cache qui se remplit en tâche de fond. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 98 ++++++++++++++++++++++++++++++ IDEES.md | 19 ++++-- MaBibli.Api/Program.cs | 15 ++++- MaBibli.Client/wwwroot/css/app.css | 14 ++++- 4 files changed, 139 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3298d48..dfa309b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3058,3 +3058,101 @@ n'affirme rien — comparer avec `RangDesEnvies`, qui avait dû reconduire un or | `GET /api/version` avec `-p:Version=0.4.1 -p:MaBibliDateBuild=…` | `{"numero":"0.4.1","publiee":true}` | **618 tests au vert** (506 au début de la série), aucun avertissement de compilation. + +## La 7ᵉ série vérifiée en navigateur — trois défauts, tous invisibles aux tests (2026-08-21) + +La série Q à Y s'était close sur un aveu : « **aucun** écran n'a été regardé s'afficher ». Le +balayage l'a été le 2026-08-21, à **320, 375 et 1280 px**, sur les vingt-deux routes de +l'application. Les 618 tests ne pouvaient rien en dire — ils couvrent les services et l'API, pas +la mise en page ni le réseau réel. + +⚠️ **Le panneau du navigateur d'automatisation ne compose pas d'image** : aucune capture d'écran +n'est possible ici. Ce n'est pas un obstacle, et c'est même instructif — la vérification s'est +faite sur la **géométrie réelle** (`getBoundingClientRect`, `scrollWidth`) et les styles calculés, +qui prouvent un débordement de 8 px qu'un œil sur une capture aurait laissé passer. + +### Ce que la vérification a confirmé + +| Lot | Vérifié | +|---|---| +| Q | ordre titre → type → thèmes → auteurs → rôles → reste ; les rôles n'apparaissent **qu'à deux auteurs** | +| R | à 375 px menu **plein écran** (375×812, `fixed`, focalisé, Échap ferme) ; à 1280 px rangée collante sous un en-tête `sticky top:0` | +| S | remontée d'un cran sur **cinq branches** éprouvées, et l'arrêt au catalogue : `/revues/3/edition → /revues/3 → /revues → / → /` | +| T | actions à droite sur la ligne du titre à 1280 px (bord droit commun) ; elles passent à la ligne à 375 px, ce qui est la bonne dégradation | +| U | champ « Nombre de pages (facultatif) » en `` | +| W | actions en tête, ISSN à tiret, numéros du plus récent au plus ancien, **sans date en dernier** ; l'édition d'un numéro rouvre bien ses articles joints par « ; », « Ukraine, deux ans après » restant entier | +| X | deux sections, « 2 livres et 2 revues en envie », « Éditer » sur chacune | +| Y | manuel, contact, version (« version de développement », dit honnêtement), licence AGPL v3 | + +Toutes les routes du client (`@page`) figurent bien dans la table de `RemonteeRoutes` — contrôle +refait à la main, la table étant explicite et rien ne garantissant en machine qu'on n'en oublie +pas une. + +### ⚠️ Défaut 1 — l'arbre des séries débordait de 8 px à 320 px + +`.arbre-ligne` est elle-même un **élément de flex** (son `
  • ` l'est), et `min-width: auto` lui +interdisait de descendre sous sa largeur intrinsèque : un titre de sous-série indenté poussait le +compte « 0 sur 2 tomes » à 328 px sur un écran de 320. + +C'est **mot pour mot la leçon du lot M**, déjà écrite ici — « le point qui fait tenir la ligne à +320 px n'est pas le `flex` mais `min-width: 0` » — simplement non appliquée à ce composant-là. +`.arbre-titre` l'avait, la **ligne** ne l'avait pas. La règle vaut à chaque étage de la +cascade de flex, pas au seul étage où l'on a été mordu. + +### ⚠️ Défaut 2 — l'ISBN à tirets faisait défiler toute la fiche + +`.code-isbn` portait `white-space: nowrap`. Un ISBN en monospace mesure **147 px**, là où la +colonne des valeurs de la fiche en offre 111 à 375 px et **56 à 320 px** : le code débordait sa +colonne, et avec lui la page entière — **395 px de contenu pour un écran de 320**. + +⚠️ Deux choses à retenir, au-delà du symptôme : + +- **Une règle tardive annulait un garde-fou délibéré.** `.fiche-champs dd` porte `min-width: 0` + et `word-break: break-word` *précisément* pour cela ; `nowrap`, plus spécifique, les défaisait + sur la seule valeur qui en avait besoin. +- **Le défaut de CSS était déjà le bon comportement.** Sans `nowrap`, le code tient sur une ligne + quand il y a la place (vérifié à 1280 px) et ne se coupe **qu'à un tiret** quand il n'y en a + pas — le tiret étant le seul endroit où une coupure se relit. Deux lignes à 375 px, trois à + 320 px : c'est le prix, et il est sans commune mesure avec une page qui défile de travers. + +Décidé avec l'utilisateur. Les deux autres pistes ont été écartées : donner sa pleine largeur à +la ligne ISBN **ne suffit pas à 320 px** (144 px disponibles pour 147 nécessaires), et réduire la +police rendrait illisible, sur le petit écran, un code qu'on y recopie chez le libraire. + +### ⚠️ Défaut 3 — le relais de couvertures rendait 404 sur une couverture qui existe + +Le plus sérieux des trois, et le seul qu'aucune inspection du code n'aurait donné. + +`GET /api/couvertures` partageait le délai de 10 s des sources bibliographiques. Or les +couvertures OpenLibrary aboutissent sur `archive.org`, qui les **extrait d'une archive ZIP à la +volée** : mesuré le 2026-08-21, 5,6 s / 14,9 s / 5,5 s en amont, et **8,3 s → 200, 7,3 s → 200, +10,003 s → 404** à travers le relais. Une fois sur trois, l'image existante était déclarée +introuvable. + +⚠️ **La conséquence n'est pas une image manquante, elle est cumulative** : un 404 signifie que +rien n'est rangé en IndexedDB, donc que le client rejoue CORS **puis** relais à *chaque* affichage +de la fiche — exactement le défaut que ce relais existe pour corriger, et que CLAUDE.md notait +comme réglé (« l'erreur CORS n'apparaît qu'une fois par couverture et par appareil »). + +⚠️ **Et il était indistinguable d'une URL inconnue**, par construction : tout refus du relais +répond 404 pour ne pas faire de lui un oracle. Cette règle reste juste, mais elle a un revers à +connaître — **le 404 ne prouve rien**, et un défaut du relais ne se diagnostique qu'en le +chronométrant. C'est la même leçon que « Robert A. Harper » : une source intermittente produit +exactement les symptômes d'une source lacunaire. + +**Correction : un délai propre au relais, `timeoutRelaisCouvertures` = 30 s.** Les deux appels +n'ont pas le même témoin — un lookup ISBN fait patienter quelqu'un devant un formulaire, d'où les +10 s et la bascule sur la source suivante ; le relais remplit un cache **en tâche de fond**, et +abandonner n'y fait rien gagner, cela perd la couverture. La lecture reste bornée à 5 Mio. +Vérifié après correction : **cinq appels sur cinq en 200**, 49 153 octets. + +### Ce que le balayage n'a PAS trouvé + +Aucun débordement horizontal sur les vingt-deux routes, aux trois largeurs, après correction. +Aucune erreur de console autre que les erreurs CORS attendues (première tentative directe avant +repli sur le relais, documentée). 618 tests toujours au vert. + +⚠️ **La base de développement a été garnie pour l'occasion** — un cycle de deux sous-séries et +cinq tomes, une revue à trois numéros, deux envies de livres et deux de revues. Sans elle, la +moitié des écrans de la série s'affichait vide et ne prouvait rien. Elle est restée en place : +le prochain balayage en aura le même besoin. diff --git a/IDEES.md b/IDEES.md index 3dd5a83..5364f94 100644 --- a/IDEES.md +++ b/IDEES.md @@ -707,11 +707,20 @@ Aux items déjà ouverts plus haut — **A5** (alléger les couvertures), **K1** couverture), **N2** (stocker l'URL finale après redirections), les **homonymes**, **OpenLibrary en second rideau** et l'**EAN-2 à confirmer en kiosque** — la série du 2026-08-21 en ajoute trois. -- **Vérifier en navigateur tous les écrans touchés.** ⚠️ C'est le plus important : **aucun** n'a - été regardé s'afficher. Formulaire livre réordonné, menu collant et plein écran, flèche de - retour sur chaque branche, actions en tête des fiches série et revue, édition d'un numéro, - deux sections de la liste d'envies, page « À propos ». Les services et l'API sont couverts par - 618 tests ; le rendu ne l'est par rien. +- ~~**Vérifier en navigateur tous les écrans touchés.**~~ ✅ **Fait le 2026-08-21** — voir + `CLAUDE.md`, section « La 7ᵉ série vérifiée en navigateur ». Vingt-deux routes, à 320, 375 et + 1280 px. Les huit lots se comportent comme décrit, et **trois défauts** que les 618 tests ne + pouvaient pas voir en sont sortis : l'arbre des séries débordait de 8 px à 320 px (`min-width` + manquant sur la ligne — la leçon du lot M, non appliquée à cet étage), l'ISBN à tirets faisait + défiler toute la fiche (`white-space: nowrap` annulant le garde-fou de `.fiche-champs dd`), et + surtout **le relais de couvertures rendait 404 une fois sur trois** sur une couverture qui + existe, `archive.org` mettant 5 à 15 s là où le délai coupait à 10. + + ⚠️ Ce que l'exercice a montré au-delà des trois correctifs : **le rendu ne se vérifie pas à + l'œil**. Le débordement de 8 px n'était visible que par `scrollWidth`, et le 404 intermittent du + relais que par un chronométrage — aucune capture d'écran n'aurait donné l'un ni l'autre. La + bonne question n'est pas « est-ce que ça ressemble à quelque chose ? » mais « qu'est-ce que la + géométrie et le réseau disent réellement ? ». - **Réordonner les envies de revues.** Elles ont un `Rang` et une section à elles, mais aucun écran pour les déplacer — les livres, eux, ont `/souhaits/ordre`. Le besoin n'est pas constaté : la section est courte par nature. À faire le jour où elle ne l'est plus. diff --git a/MaBibli.Api/Program.cs b/MaBibli.Api/Program.cs index 6e39083..c48880d 100644 --- a/MaBibli.Api/Program.cs +++ b/MaBibli.Api/Program.cs @@ -36,6 +36,19 @@ builder.Services.AddScoped(http => { http.BaseAddress = new Uri(BnfClient.UrlBase); @@ -67,7 +80,7 @@ builder.Services.AddScoped(); // le SSRF. builder.Services.AddHttpClient(http => { - http.Timeout = timeoutSources; + http.Timeout = timeoutRelaisCouvertures; http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)"); }) .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler diff --git a/MaBibli.Client/wwwroot/css/app.css b/MaBibli.Client/wwwroot/css/app.css index 26c5c11..39e2cb3 100644 --- a/MaBibli.Client/wwwroot/css/app.css +++ b/MaBibli.Client/wwwroot/css/app.css @@ -1080,9 +1080,16 @@ body { /* Un ISBN se relit chiffre à chiffre : une chasse fixe évite de confondre 1 et l, 0 et O, et rend les tranches séparées par des tirets alignées d'une ligne à l'autre. */ +/* ⚠️ PAS de « white-space: nowrap » ici, et ce n'est pas un oubli. Un ISBN à tirets mesure + 147 px en monospace, là où la colonne des valeurs de la fiche n'en offre que 111 à 375 px et + 56 à 320 px : « nowrap » le faisait déborder, et avec lui TOUTE la page — 395 px de contenu + pour un écran de 320, mesuré le 2026-08-21. Il annulait au passage le « word-break » dont + « .fiche-champs dd » est justement muni pour cela. + Le défaut de CSS est exactement ce qu'on veut : le code tient sur une seule ligne quand il y + a la place, et ne se coupe qu'à un tiret quand il n'y en a pas — le tiret étant le seul + endroit où une coupure se relit. */ .code-isbn { font-family: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace; - white-space: nowrap; } /* Titre d'écran et son bouton de réglages sur la même ligne : le bouton « Filtrer » du @@ -1173,6 +1180,11 @@ body { gap: 0.5rem; min-height: 2.25rem; padding: 0.2rem 0; + /* ⚠️ Même piège qu'au lot M : la ligne est elle-même un élément de flex (son
  • l'est), + et « min-width: auto » lui interdit de descendre sous sa largeur intrinsèque. Sans cette + ligne, un titre de sous-série indenté pousse le compte « 0 sur 2 tomes » hors de l'écran + et fait défiler la page horizontalement (mesuré à 320 px : 328 px de large). */ + min-width: 0; } .arbre-plier,