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}` |
|
| `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.
|
**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
|
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.
|
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
|
- ~~**Vérifier en navigateur tous les écrans touchés.**~~ ✅ **Fait le 2026-08-21** — voir
|
||||||
été regardé s'afficher. Formulaire livre réordonné, menu collant et plein écran, flèche de
|
`CLAUDE.md`, section « La 7ᵉ série vérifiée en navigateur ». Vingt-deux routes, à 320, 375 et
|
||||||
retour sur chaque branche, actions en tête des fiches série et revue, édition d'un numéro,
|
1280 px. Les huit lots se comportent comme décrit, et **trois défauts** que les 618 tests ne
|
||||||
deux sections de la liste d'envies, page « À propos ». Les services et l'API sont couverts par
|
pouvaient pas voir en sont sortis : l'arbre des séries débordait de 8 px à 320 px (`min-width`
|
||||||
618 tests ; le rendu ne l'est par rien.
|
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
|
- **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é :
|
é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.
|
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.
|
// Timeout court : une source lente ne doit pas bloquer la cascade, l'appelant bascule sur la suivante.
|
||||||
var timeoutSources = TimeSpan.FromSeconds(10);
|
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 =>
|
builder.Services.AddHttpClient<IBnfClient, BnfClient>(http =>
|
||||||
{
|
{
|
||||||
http.BaseAddress = new Uri(BnfClient.UrlBase);
|
http.BaseAddress = new Uri(BnfClient.UrlBase);
|
||||||
@@ -67,7 +80,7 @@ builder.Services.AddScoped<IIsbnLookupService, IsbnLookupService>();
|
|||||||
// le SSRF.
|
// le SSRF.
|
||||||
builder.Services.AddHttpClient<IServiceCouvertures, ServiceCouvertures>(http =>
|
builder.Services.AddHttpClient<IServiceCouvertures, ServiceCouvertures>(http =>
|
||||||
{
|
{
|
||||||
http.Timeout = timeoutSources;
|
http.Timeout = timeoutRelaisCouvertures;
|
||||||
http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)");
|
http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)");
|
||||||
})
|
})
|
||||||
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
|
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
|
||||||
|
|||||||
@@ -1080,9 +1080,16 @@ body {
|
|||||||
|
|
||||||
/* Un ISBN se relit chiffre à chiffre : une chasse fixe évite de confondre 1 et l,
|
/* 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. */
|
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 {
|
.code-isbn {
|
||||||
font-family: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace;
|
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
|
/* 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;
|
gap: 0.5rem;
|
||||||
min-height: 2.25rem;
|
min-height: 2.25rem;
|
||||||
padding: 0.2rem 0;
|
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,
|
.arbre-plier,
|
||||||
|
|||||||
Reference in New Issue
Block a user