Regarde enfin les écrans s'afficher, et trouve ce que 618 tests taisaient
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 `<input number>` |
|
||||
| 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 `<li>` 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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
+14
-1
@@ -36,6 +36,19 @@ builder.Services.AddScoped<IFournisseurUtilisateur, FournisseurUtilisateurSsowat
|
||||
// Timeout court : une source lente ne doit pas bloquer la cascade, l'appelant bascule sur la suivante.
|
||||
var timeoutSources = TimeSpan.FromSeconds(10);
|
||||
|
||||
// ⚠️ Le relais de couvertures a son PROPRE délai, et bien plus long. Ce n'est pas une largesse :
|
||||
// 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 ci-dessus, et la bascule sur la source suivante. Le relais, lui,
|
||||
// remplit un cache en tâche de fond : personne n'attend derrière, et abandonner ne fait pas
|
||||
// gagner du temps, cela perd la couverture.
|
||||
//
|
||||
// Mesuré le 2026-08-21 : les couvertures OpenLibrary aboutissent sur `archive.org`, qui les
|
||||
// EXTRAIT D'UNE ARCHIVE ZIP à la volée et met 5 à 15 s. À 10 s, le relais répondait 404 une fois
|
||||
// sur trois — indistinguable, pour l'appelant, d'une URL inconnue. L'image n'était alors jamais
|
||||
// mise en cache, et le client rejouait CORS puis relais à CHAQUE affichage : exactement le
|
||||
// défaut que ce relais existe pour corriger.
|
||||
var timeoutRelaisCouvertures = TimeSpan.FromSeconds(30);
|
||||
|
||||
builder.Services.AddHttpClient<IBnfClient, BnfClient>(http =>
|
||||
{
|
||||
http.BaseAddress = new Uri(BnfClient.UrlBase);
|
||||
@@ -67,7 +80,7 @@ builder.Services.AddScoped<IIsbnLookupService, IsbnLookupService>();
|
||||
// le SSRF.
|
||||
builder.Services.AddHttpClient<IServiceCouvertures, ServiceCouvertures>(http =>
|
||||
{
|
||||
http.Timeout = timeoutSources;
|
||||
http.Timeout = timeoutRelaisCouvertures;
|
||||
http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)");
|
||||
})
|
||||
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
|
||||
|
||||
@@ -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 <li> 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,
|
||||
|
||||
Reference in New Issue
Block a user