ASA Compass · entrée K-47 · session hotel-saint-michel-97 · 1er septembre 2026

Passer d'un fichier par chose à un rendu à la demande : ce que le prototype mesure

Un Worker Cloudflare et une base D1 rendent, à la requête, l'index, la page d'une collection et la page d'une pièce. Le site actuel n'a pas été touché. Les chiffres ci-dessous disent chaque fois sur quel geste ils ont été pris.

Le montage tient, et il règle les trois murs d'un coup. Le catalogue entier (16 150 collections, 1 891 551 pièces) tient dans une base D1 de 376 Mo, sous le plafond du plan gratuit, avec trois fichiers déployés au lieu de 18 575. Une page de collection froide répond en 98 ms depuis Montréal, une page de pièce en 137 ms, et l'une comme l'autre en 52 ms dès qu'elle est en cache. Un robot reçoit du HTML complet, un 404 quand la page n'existe pas, un 503 quand la base est absente.

Ce que la mesure a trouvé et que la question ne posait pas : le budget gratuit de 100 000 requêtes par jour est celui du compte, partagé avec le Worker qui sert les images. Ce sont les vignettes, pas les pages, qui fixeront le jour où Karl paie, et c'est déjà vrai du site statique. La bascule ne change pas ce jour-là ; elle change ce que coûte le catalogue quand il grossit : rien.

Recommandation : basculer, par paliers, en commençant par les pages de pièces, qui n'existeront jamais en statique et que K-48 exige. Rester sur le plan gratuit ; le premier dollar (5 $ US par mois) se justifie le jour où /sante ou le tableau de bord montre le compte à 100 000 requêtes par jour, et il achète 10 millions de requêtes par mois et 10 Go de base.

1. Ce qui a été bâti, et ce qui ne l'a pas été

Un dossier séparé, rendu-demande/, avec son Worker (asa-compass-rendu), sa base D1 et ce projet Pages. Le Worker lit la base et compose le HTML avec le CSS du site, extrait tel quel d'une page engendrée. Il sert :

Pas bâti, volontairement : le portefeuille, le Portfolio, le marché, les propriétés ARC-69 et la rareté (la session K-48 les produit ; la page-pièce leur réserve la place et le dit). Le prototype est en anglais comme le site.

Les trois nombres, nommés

K-47 demandait de distinguer ce que la sonde connaît, ce que le site retient, ce que le site publie. La base du prototype les sépare en tables :

collections, ce que la sonde connaît
16 150
familles adressables par une limace
14 554
dont 2 222 publiées aujourd'hui, qui regroupent 3 818 collections de la base
pièces, une page chacune
1 891 551
ventes rattachées
50 568

2. Les quatre mesures

Mesure 1 · Le référencement : ce qu'un robot voit

Geste : curl avec l'agent Googlebot/2.1 sur /c/algokitten et /a/201269711, depuis Montréal, le 1er septembre à 12 h 40 UTC ; script robot.sh.

Ce que Google exigeCe que le prototype rend
un code 200 et du HTML lisible sans exécuter de script200, 26 347 octets pour la collection, 7 114 pour la pièce, zéro balise <script>, 49 liens internes dans le HTML de la collectionoui
un titre, une description, un canoniqueprésents, canonique absolu sur l'adresse du Workeroui
une og:image absolue (défaut de K-44 sur 2 231 pages)absolue, vers la vignette du cache de médiasréglé par construction
un temps de réponse court (Google : « responses over two seconds can cause Googlebot to reduce its crawling frequency »)page froide 98 à 137 ms en médiane, 270 ms au pire sur 81 pagesoui
un sitemap tenu à jour (Google : « Keep your sitemaps up to date »)index de 49 fichiers rendu depuis la base, 40 000 adresses par fichier, XML valide (xmllint), 3,5 Mo le plus grosoui, et il ne peut pas se périmer : il lit la base
un 404 quand la page n'existe pas (Google : « a 404 status code is a strong signal not to crawl that URL again »)404 avec une page, noindex ; le site actuel rend l'accueil en 200réglé
pas de « soft 404 » (page vide en 200)une base absente rend un 503 avec Retry-After, jamais une page vide en 200oui
que Cloudflare ne bloque pas le robotaucun défi, aucun en-tête cf-mitigated, cf-cache-status: HIT sur la seconde visiteoui

Ce que cette mesure ne prouve pas, et il faut le dire : qu'une page soit effectivement indexée par Google. Cela ne se mesure que dans la Search Console, sur un domaine, après des semaines. Le prototype vit sur workers.dev, un sous-domaine partagé que Google traite avec réserve. Ce qui est prouvé, c'est que rien dans le montage ne manque à ce que Google demande à une page statique : le HTML servi à un robot est identique à celui servi à un visiteur, et il est plus complet que celui du site actuel, dont la page-pièce a.html se remplit en JavaScript côté navigateur et n'offre donc rien à un robot.

Mesure 2 · Le temps de la première visite, et celui d'une page en cache

Geste : 81 adresses tirées au hasard (l'index, 25 familles publiées, 15 non publiées, 40 pièces), chacune demandée à froid avec ?froid=1 (le Worker saute le cache et interroge la base) puis à chaud (adresse normale, servie par le cache de bordure), par curl depuis Montréal, le 1er septembre entre 12 h 45 et 13 h 05 UTC, après les deux correctifs de la section 4. Script mesurer.sh, relevé mesures-apres-correctif.csv. Le temps « base » vient de l'en-tête Server-Timing écrit par le Worker autour de son lot de requêtes D1.

Pagefroide, médianefroide, p90dont base D1en cache, médianeen cache, p90
collection (n = 40)98 ms123 ms41 ms52 ms74 ms
pièce (n = 40)137 ms173 ms81 ms52 ms76 ms
index (n = 1)167 ms97 ms48 ms
pire cas : page 6 250 de la famille de 614 133 pièces (?apres=23982241-897151367)142 ms52 ms

Pourquoi la base coûte 41 ms pour une requête qui s'exécute en 0,3 ms : la base D1 vit dans la région ENAM (les réponses portent served_by_colo: ORD, Chicago), et le Worker s'exécute là où est le visiteur (ici YUL, Montréal). Chaque page froide paie un aller-retour Montréal-Chicago par lot de requêtes ; la page-pièce en fait deux (la pièce, puis ses voisines), d'où ses 81 ms. Un visiteur d'Europe paierait un aller-retour plus long sur sa première visite d'une page, et seulement sur celle-là.

Où ce modèle peut décevoir, et ce qu'on y a vu : le cache de bordure est par centre de données (Cloudflare : « the contents of the cache do not replicate outside of the originating data center »). Une page chaude à Montréal est froide à Paris. Sur un catalogue de 1,9 million de pages et un trafic modeste, la plupart des visites seront donc des visites froides, et c'est le chiffre froid, 98 à 137 ms, qui compte. Il reste sous ce que le site statique offre pour sa page-pièce, qui doit interroger l'indexeur public depuis le navigateur avant d'afficher quoi que ce soit.

Temps CPU, relevé par wrangler tail sur quatre requêtes : 3 ms pour une collection froide, 1 ms pour une pièce froide, 4 ms pour l'index froid, 0 ms en cache. Le plan gratuit permet 10 ms par invocation.

Mesure 3 · Le coût, sur des scénarios posés

Sources tarifaires, lues le 1er septembre 2026 sur developers.cloudflare.com/workers/platform/pricing, …/workers/platform/limits et …/d1/platform/limits. Plan gratuit : 100 000 requêtes par jour pour le compte, 10 ms de CPU par invocation, D1 limitée à 500 Mo par base et 5 millions de lignes lues par jour ; « Requests to static assets are free and unlimited ». Au-delà, Cloudflare rend l'erreur 1027 jusqu'à minuit UTC. Plan Workers Paid : 5 $ US par mois, 10 millions de requêtes incluses puis 0,30 $ le million, 30 millions de ms CPU incluses puis 0,02 $ le million, D1 à 10 Go par base, 25 milliards de lignes lues incluses puis 0,001 $ le million.

Mesures d'unités, sur la campagne ci-dessus : une page de collection froide lit 33 lignes D1 en médiane (163 au p90, 2 581 pour AOWL, une famille de trois séries que la base doit trier entière) ; une page de pièce en lit 16 (438 au pire) ; l'index froid en lit 35 573 parce qu'il compte le catalogue. Une page en cache ne lit rien, mais compte quand même une requête Worker : sur workers.dev, le Worker s'exécute avant de répondre depuis le cache. Chaque vignette affichée est une requête au Worker du cache de médias, sur le même compte.

Les scénarios posés (hypothèses explicites : 30 % des pages vues par des visiteurs sont froides ; 60 % des pages vues sont des collections ; un robot voit toujours une page froide ; une page de collection montre 48 vignettes sur le prototype, 8 à 12 sur le site actuel : on retient 48, le pire) :

Scénariopages / jour+ vignettes / jourlignes D1 / jourplan gratuitsi plan payant
A · aujourd'hui : 200 visiteurs, 6 pages, 3 000 pages de robots4 20034 560457 000tient5,00 $
B · le catalogue trouve son public : 2 000 visiteurs, 8 pages, 20 000 de robots36 000460 8001,1 Mles vignettes dépassent6,47 $
C · 10 000 visiteurs, 8 pages, 20 000 de robots100 0002,3 M1,7 Mdépasse23,64 $
D · pointe de robots : 2 000 visiteurs et 100 000 pages de robots116 000460 8003,5 Mdépasse7,19 $
E · gros trafic : 50 000 visiteurs, 8 pages, 100 000 de robots500 00011,5 M7,0 Mdépasse110,18 $

Le point de bascule, en visiteurs par jour : sur les pages seules, le palier gratuit tient jusqu'à environ 10 000 visiteurs par jour à 8 pages. En comptant les vignettes servies par le Worker de médias, il tient jusqu'à environ 420 visiteurs par jour. Le second chiffre est le vrai, et il vaut déjà pour le site statique. Le premier dollar est l'abonnement de 5 $ US par mois ; les scénarios B et D, plausibles, restent entre 5 et 8 $. Un plan Pages supérieur (plafond à 100 000 fichiers) ne déplace qu'une date et ne couvre jamais les pièces ; le même abonnement de 5 $ donne aussi bien la limite Pages relevée que les Workers, D1 à 10 Go et Time Travel à 30 jours. Aucun abonnement n'a été engagé ni aucune ressource payante créée par cette session.

Ce qui ferait sortir les vignettes du compte : servir le seau R2 directement (adresse publique r2.dev ou un domaine sur le seau), sans passer par un Worker. R2 n'a pas de frais de sortie. Cela appartient au périmètre du cache de médias, aujourd'hui sans propriétaire ; c'est signalé, pas fait.

Ce que coûte la croissance du catalogue, dans ce modèle : zéro requête, zéro fichier. Seule la taille de la base bouge. Les 376 Mo mesurés laissent 124 Mo sous le plafond gratuit de 500 Mo, soit environ 600 000 pièces de plus au tarif de 200 octets la ligne ; les années 2023 et suivantes ne tiendraient donc pas sur le plan gratuit sans amincir les lignes (l'adresse du créateur, 58 octets, se répète 1,9 million de fois) ou sans passer à 10 Go. C'est l'endroit où le plan gratuit finira par céder, et il le dira : l'import refuse au-delà du plafond.

Mesure 4 · Quand la base ne répond pas

Geste : deux pannes simulées dans le Worker, ?panne=base (D1 refuse) et ?panne=lente (D1 ne répond jamais), sur une page jamais rendue, puis sur la même page après un rendu, le 1er septembre à 12 h 42 UTC. Ce sont les chemins de défaillance du Worker qui sont mesurés, pas une panne réelle de D1 : personne ne peut en déclencher une.

SituationRéponsedélai
base qui refuse, page jamais rendue503, page d'explication, Retry-After: 120, x-rendu: panne62 ms
base muette, page jamais rendue503, coupée par le délai de garde de 4 s au lieu d'attendre sans fin4 055 ms
base qui refuse, page déjà rendue une fois200, la dernière copie connue, x-rendu: secours, x-panne qui dit pourquoi, Cache-Control: no-store71 ms
/sante, base qui refuse503 en JSON avec le motif
/sante, base présente mais table des pièces vide (mesuré avant l'import)500 en JSON : « la pièce témoin 201269711 manque »125 ms

Est-ce acceptable ? Un site statique ne tombe jamais ; celui-ci tombe avec sa base, mais il tombe en le disant. Une page déjà vue dans ce centre de données survit sept jours à la panne (copie de secours en cache) ; une page jamais vue rend un 503 que Google traite comme temporaire (« 5xx and 429 server errors prompt Google's crawlers to temporarily slow down with crawling ») et que le visiteur lit comme une explication, pas comme une page blanche. La dégradation est donc franche et réversible. Ce qu'elle n'est pas : invisible. C'est ce que K-49 demande.

Deux limites de cette protection : la copie de secours est par centre de données et ne couvre que ce qui y a déjà été demandé ; et D1 étant gérée par Cloudflare, ses pannes se confondent avec celles des Workers, qui abattraient aussi le site statique.

3. Les trois murs, revus avec les chiffres

MurSite statique, plan gratuit (20 000 fichiers)Site statique, plan payant (100 000 fichiers, depuis le 23 janvier 2026)Rendu à la demande
1 · aujourd'hui, 18 575 fichiers dont 15 314 d'img/ jamais servis93 %. Retirer img/ ramène à 16 %.19 %3 fichiers
2 · le catalogue complet, environ 23 500 fichiersfranchi avant d'y arriver24 %, tient, mais 3 Go de HTML à téléverser à chaque régénération3 fichiers, 376 Mo de base, import en 217 s
3 · les pièces, 1 891 551 pages, exigées par K-48jamaisjamais : 100 000 est dix-neuf fois trop petitrendues, 137 ms à froid, sitemap de 49 fichiers

La correction de la prémisse compte : K-47 disait « limite dure de 20 000 » et c'est vrai du plan gratuit, sur lequel Karl se trouve ; le plan payant la porte à 100 000 (variable PAGES_WRANGLER_MAJOR_VERSION=4 à poser dans le projet). Cela recule le mur 2 d'un ordre de grandeur et ne fait rien au mur 3. Payer pour le statique déplace une date ; le rendu à la demande supprime la variable.

4. Ce que la mesure a corrigé en chemin

Deux formes de requête, écrites naturellement, coûtaient des centaines de milliers de lignes lues, l'unité que D1 facture. Elles sont mesurées sur la plus grosse famille (D01-39, 614 133 pièces) avec wrangler d1 execute --json, qui rend meta.rows_read :

Formelignes luesForme retenuelignes lues
pagination LIMIT 48 OFFSET 300000300 048curseur (round, id) > (?, ?) … LIMIT 4849
page 12 000 par ?page=, mesurée sur le Worker1 152 013 en 855 msmême page par ?apres=112 en 52 ms
voisines par round < ? OR (round = ? AND id < ?) avec paramètres liés, depuis le Worker614 146(round, id) < (?, ?)7

Sans ces deux correctifs, huit visites de pièces de cette seule famille auraient épuisé les 5 millions de lignes quotidiennes du plan gratuit. Avec, la campagne complète des 81 pages a lu 40 000 lignes. La leçon vaut pour tout ce qui s'écrira sur cette base : mesurer les lignes lues de chaque requête avant de la garder, la commande est dans le LISEZMOI.md.

5. Les deux défauts que la bascule règle, prouvés, et un troisième

6. Jugé à l'aune de K-49 : tenable par une seule personne ?

Le critère : ce qui demande une intervention manuelle régulière est une dette mortelle ; six mois sans Karl ; échouer bruyamment.

Ce qui, aujourd'hui, demande KarlDans ce montage
régénérer et republier le site à chaque changement de catalogue (3 261 fichiers, 1 Go)disparaît : une ligne écrite dans la base est en ligne à la requête suivante
régénérer pour changer un réglage par défaut (K-43, K-51)disparaît : c'est une ligne de la table etat
surveiller que le déploiement n'a pas dépassé une limite de fichiersdisparaît : trois fichiers
s'apercevoir qu'une page manque (aucun 404)disparaît : le 404 existe, et le balayage de K-44 peut enfin compter
s'apercevoir que la donnée vieillit/sante rend un 500 avec le texte « la donnée a N jours : le rafraîchissement ne tourne plus » au-delà de 45 jours, et un 503 si la base manque. Un contrôle externe gratuit (UptimeRobot ou équivalent, à brancher par Karl) lui écrit à sa place
voir venir la limite du plan gratuitreste à faire : Cloudflare rend l'erreur 1027 au-delà de 100 000 requêtes par jour, bruyamment mais tard. Le tableau de bord montre la consommation ; /sante ne la connaît pas
réimporter la base quand la sonde a tourné217 s, une commande, mais une commande. Doit devenir l'étape finale automatique de reconstruire.sh, sinon c'est une intervention

Le solde est net : le montage supprime quatre interventions régulières et en laisse deux, qui existent déjà sous d'autres formes. Ce qu'il ajoute de fragile, c'est une dépendance à D1, gérée par Cloudflare comme le sont déjà Pages, R2 et le Worker du marché ; pas un serveur, pas un indexeur, pas une équipe.

7. La base devient la source vivante du site : ce que cela demande

Si la bascule est retenue, catalogue.sqlite cesse d'être un fichier de travail qu'on régénère et la base D1 cesse d'être un essai : ce que les visiteurs voient en dépend. Elle entre donc dans ce qui ne se recalcule pas sans coût. Ce que le prototype a mesuré et ce qui est proposé :

8. Ce que cette session signale sans le faire

9. La recommandation, par paliers

  1. Retirer img/ (chantier). Gratuit, immédiat, achète le temps du reste.
  2. Basculer la page-pièce sur le rendu à la demande, en premier : elle n'existe pas en statique, K-48 la réclame, et c'est celle qui gagne le plus au référencement puisque la version actuelle n'offre rien à un robot. Le site statique continue de servir tout le reste ; seule /a/{id} est routée vers le Worker (Pages sait déléguer un chemin à un Worker).
  3. Basculer les collections et l'index, avec les réglages de K-43 et K-51 en paramètres, et le sitemap rendu depuis la base.
  4. Faire de l'import D1 l'étape finale de reconstruire.sh, puis du rafraîchissement incrémental un Worker planifié qui écrit dans D1 et dans un journal R2.
  5. Brancher un contrôle externe sur /sante, qui écrit à Karl quand la base tombe ou quand la donnée a plus de 45 jours.
  6. Rester sur le plan gratuit tant que le compte n'approche pas 100 000 requêtes par jour ; le jour venu, le premier dollar est 5 $ US par mois, et il relève d'un coup Workers, D1 (10 Go) et Pages (100 000 fichiers).

Ce qui appartient à Karl : décider de basculer ; décider du plan ; décider si les vignettes sortent du Worker. Rien de tout cela n'a été fait.

10. Ce que ce rapport ne prouve pas

Annexe · Ce qui a été fait, dans l'ordre, avec les temps

base D1 asa-compass-rendu créée, région ENAM
catalogue.sqlite copié en local : 17 s (l'export sur le disque externe n'avait rien produit en 6 min)
exporter.py : 16 150 collections, 14 554 familles, 50 568 ventes, 1 891 551 pièces en 19 fichiers : 20 s
import familles + collections + état : 14 s · ventes : 9 s (après réduction à 120 lignes par ordre)
import des pièces : 19 lots de 100 000, 9 à 15 s chacun, 217 s au total, 3,79 M lignes écrites
taille finale de la base : 376 Mo (plafond gratuit : 500 Mo)
campagne de 81 pages à froid puis à chaud : deux fois, avant et après correctifs
sauvegarde complète wrangler d1 export : 92 s, 578 Mo, 68 Mo compressés
captures Chrome sans fenêtre : index, collection, pièce, 404, mobile 375 × 667

Les relevés bruts (mesures.csv, mesures-apres-correctif.csv), les scripts et la marche à suivre pour tout rejouer sont dans rendu-demande/ sur le disque de Karl.