overfetch : audit des requêtes

Auditez comment une application frontend communique avec son backend et produisez un rapport classé, étayé par des preuves, des amplifications de requêtes avec des correctifs concrets — lectures N+1 par ligne, doubles récupérations, temporisateurs de poll empilés, fraîcheur nulle, invalidation globale, cascades séquentielles, pagination « tout récupérer », sur-récupération, gaspillage de tentatives.

Qu'est-ce que overfetch : audit des requêtes ?

Ce skill permet de réaliser un audit systématique des requêtes réseau d'une application frontend. Il génère un rapport classé par sévérité identifiant les amplifications de requêtes (lectures N+1, duplications, polling excessif, cascades, etc.) avec des preuves, une cause racine, un correctif et le delta attendu. Il prend en charge les applications utilisant TanStack Query, SWR, Apollo et RTK Query, et peut fonctionner en mode statique ou avec des captures live (HAR, Playwright, DevTools). Le processus inclut une analyse de couverture, un scan statique, une vérification manuelle des candidats et une capture live pour valider les comptes réels. Le rapport inclut une table des non-findings, des décisions produit en suspens et les limites de l'audit.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/alii13/overfetch/tree/HEAD

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait overfetch : audit des requêtes ?

Vous produisez un rapport sur lequel quelqu'un agira : une liste classée des façons dont cette application fait plus de requêtes que nécessaire pour ses écrans, chacune avec une preuve, un correctif et le nombre cible à atteindre. Le rapport n'est utile que si chaque constatation survit à un lecteur sceptique, donc la méthode ci-dessous consacre l'essentiel de ses efforts à la vérification et à dire clairement ce qui a et n'a pas été vérifié.

Ce que vous livrez

Un rapport en Markdown (modèle dans references/report-template.md) avec :

  1. Périmètre et preuves : quel arbre, quel commit, quelles captures.
  2. Couverture : chaque route, chunk lazzy et site de données conditionnel, et lesquels ont été lus dans le code uniquement vs. exercés dans une capture.
  3. Constatations classées par la façon dont le nombre de requêtes croît, chacune avec fichier:ligne ou preuve de capture, cause racine, motif de correctif, delta attendu, effort.
  4. Non-constatations : les motifs que vous avez vérifiés et exclus, avec la raison. Cela évite à la personne suivante de réinvestiguer.
  5. Décisions produit en suspens et demandes backend : des choses qui nécessitent un humain ou un changement d'API, pas un correctif client.
  6. Limites : ce que l'audit n'a pas pu mesurer.

Proposez ensuite d'implémenter les correctifs, un PR par constatation, par sévérité décroissante. Ne commencez pas à corriger pendant l'audit.

Principes

Un résultat de regex est un candidat, pas une constatation. scripts/static_scan.py lit du texte. Il ne peut pas faire la différence entre une barre d'onglets de 3 lignes et un tableau de 3 000 lignes, ou entre une invalidation racine délibérée après une importation en masse et une invalidation paresseuse. Lisez le code derrière chaque candidat que vous avez l'intention de signaler. Dites ce que vous avez lu.

Mesuré bat déclaré. Une capture de l'application en cours d'exécution est la vérité sur les nombres de requêtes ; le code est la vérité sur le pourquoi. Les commentaires, la documentation et les anciens enregistrements d'audit sont des déclarations. Quand un document dit « frais pendant 60 secondes » et que le code dit staleTime: Infinity, signalez le code, notez la contradiction et enregistrez le hash du commit que vous avez lu.

Connaissez la sémantique réelle de la bibliothèque avant de l'accuser. Les erreurs qui coûtent le plus sont des affirmations confiantes mais erronées : « le cache déduplique ceci » alors que les clés diffèrent, « le polling s'arrête en inactivité » alors qu'il s'arrête seulement quand l'onglet est caché, « trois appelants, trois récupérations par minute » alors que la bibliothèque resynchronise les temporisateurs de même clé et partage la récupération. references/library-facts.md contient les faits pour TanStack Query, SWR, Apollo et RTK Query, avec le chemin source vérifié pour chacun. Lisez la section pour la bibliothèque utilisée avant d'écrire une phrase sur le cache ou le polling, et quand une affirmation décide d'une constatation, ouvrez le code source de la bibliothèque installée et confirmez-la.

Classez par croissance, pas par nombre. Une lecture qui évolue avec le nombre de lignes, de composants montés ou avec le temps est pire qu'une duplication fixe. La grille de sévérité ci-dessous concerne la classe de croissance.

La couverture a un dénominateur. Une capture ne voit que le code qui s'est chargé pendant son exécution : les routes visitées, les boîtes de dialogue et les onglets ouverts, les drapeaux activés, les états renvoyés par le backend. Les chunks lazzy, les écrans conditionnels et les chemins d'erreur sont exactement là où se cachent les bugs de requêtes, car personne ne les regarde pendant le développement. Donc chaque audit commence par la surface complète (coverage_map.py), chaque « pas de problème » est limité à ce qui a été couvert, et le rapport indique quelles parties ont été exercées en direct et lesquelles ont seulement été lues.

Dites ce qui va bien. Une pré-récupération au survol qui est une lecture dédupliquée par ligne est une non-constatation. Écrivez-la comme telle. Un rapport qui ne liste que les problèmes fait se demander au lecteur ce qui a été oublié.

Les nombres viennent de quelque part. Chaque nombre du rapport fait référence à un fichier de capture ou à un chemin de code. N'inventez pas « 6+ » ou « environ 100 » par intuition ; si vous ne pouvez pas mesurer, dites « non mesuré » et donnez la formule (lignes × lectures par ligne).

Flux de travail

Informez l'utilisateur à l'avance du temps nécessaire. Un audit statique seul d'une application de taille moyenne prend 15 à 30 minutes de lecture. L'ajout de captures live ajoute 15 à 45 minutes selon le nombre de parcours importants.

1. Périmètre

  • Trouvez les racines de l'application et la bibliothèque de données dans package.json (le scan les affiche toutes deux). Monorepos : scannez chaque application séparément.
  • Trouvez la couche de données : les fabriques de clés de requête, les modules de transport/service, la construction de QueryClient (ou la configuration SWR, le client Apollo, createApi de RTK). Lisez d'abord les valeurs par défaut ; elles définissent la base de référence par rapport à laquelle chaque constatation est mesurée.
  • Listez les écrans importants : généralement la route d'atterrissage après la connexion, la liste la plus active, et tout écran laissé ouvert pendant des heures (un shell, un moniteur). Demandez à l'utilisateur si ce n'est pas évident ; sinon, choisissez ces trois-là et dites-le.
  • Enregistrez le commit : git rev-parse HEAD. Chaque ligne du rapport fait référence à cette révision.
  • Décidez si une capture live est possible : un serveur de développement en cours d'exécution plus un navigateur que vous pouvez piloter, ou un HAR que l'utilisateur possède déjà. Si aucun des deux, l'audit est statique uniquement, et le rapport doit le dire dans son premier paragraphe.

2. Carte de couverture

python3 <skill-dir>/scripts/coverage_map.py <app-root> --format md --out coverage.md

C'est le dénominateur. Elle liste chaque route (routeurs basés sur les fichiers pour TanStack Router, Next.js, Remix, SvelteKit et SolidStart ; routeurs définis par le code via leurs littéraux de chemin ; fichiers d'entrée sinon), chaque frontière import() dynamique avec les lectures derrière elle, chaque module de données conditionné par un drapeau, une plateforme, une permission ou une vérification d'environnement, chaque littéral de chemin d'endpoint dans le code source, et les modules de données qu'aucune route n'atteint. Elle s'exécute en quelques secondes sur une application de 2 000 fichiers.

Utilisez-la de trois manières :

  • Pour planifier. Le plan de capture en bas nomme les routes avec le plus de sites de lecture, les chunks lazzy à déclencher et les conditions à activer/désactiver. Utilisez-le pour choisir les parcours à l'étape 6 au lieu de deviner.
  • Pour délimiter le scan. Une constatation dans un module qu'aucune route n'atteint est soit du code mort, soit atteint par quelque chose que la carte ne peut pas résoudre. Vérifiez avant de le qualifier de vivant.
  • Pour boucler la boucle. Après la capture, relancez-la avec les captures ; elle marque les routes visitées, les modules et chunks lazzy chargés (exactement, pour une capture sur serveur de développement), les modules conditionnés qui ont été exécutés et les chemins d'endpoint apparus :
python3 <skill-dir>/scripts/coverage_map.py <app-root> --har home.har --har library.har --visited home.har.visited.txt --format md

Répétez les captures jusqu'à ce que les routes et chunks lazzy avec le plus de sites de lecture soient couverts, ou indiquez pourquoi ils ne le sont pas (pas de données de fixture, nécessite un rôle que vous n'avez pas, plateforme que vous ne pouvez pas exécuter).

3. Scan statique

python3 <skill-dir>/scripts/static_scan.py <app-root> --format md --out scan.md
python3 <skill-dir>/scripts/static_scan.py <app-root> --format json --out scan.json

Le scan est rapide (environ dix secondes pour 2 000 fichiers) et nécessite seulement Python 3.9+. Il émet des candidats avec une sévérité, une confiance, le détecteur qui a déclenché, fichier:ligne, pourquoi c'est important, le motif de correctif et une instruction « vérifier d'abord ». Lisez scan.md en entier ; le JSON est pour le scripting et le harnais d'évaluation.

Ajoutez --exclude pour les arbres générés que les valeurs par défaut manquent, --min-confidence medium quand la liste est longue et que vous voulez un premier passage serré.

4. Vérifier les candidats

Passez en revue les candidats dans cet ordre : P0 par confiance, puis P1, puis le reste. Pour chacun que vous conservez, vous devez avoir ouvert le fichier et être capable de répondre :

  • Quel est le multiplicateur par ligne ou par observateur, et quelles sont ses limites ? (Un .map sur une énumération fixe n'est pas du N+1. Un nombre de lignes provenant d'une liste paginée l'est.)
  • Le cache l'absorbe-t-il déjà ? (Même clé, entrée chaude, lectures enabled: false, un parent qui a déjà récupéré l'objet.)
  • Existe-t-il un endpoint de lot ou de projection que le client pourrait utiliser à la place ? Lisez le client API ou la spécification OpenAPI. Si aucun n'existe, le correctif est une demande backend, et la constatation reste avec la mention « bloqué par backend ».
  • Quel est le motif de correctif, par son nom, dans references/catalog.md ?

Éliminez les candidats qui échouent à ces vérifications et conservez ceux que vous éliminez et qu'un lecteur soulèverait plausiblement : ils vont dans le tableau des non-constatations avec une raison d'une ligne.

L'entrée du catalogue pour chaque détecteur liste les conditions spécifiques de non-constatation. Lisez-la pour chaque identifiant de détecteur qui apparaît dans le scan ; elle est organisée par les mêmes identifiants.

5. Vérifications transversales que le scanner ne peut pas faire

Celles-ci nécessitent de la lecture, pas du grep. Faites-les toutes ; la plupart des audits en trouvent au moins une.

  • Canonicité des clés. Choisissez les cinq endpoints les plus lus et trouvez chaque clé de requête qui lit chacun d'eux. Deux clés pour une lecture signifient deux entrées de cache et deux récupérations. Cherchez particulièrement les lectures de liste sous différentes projections (complète vs. seulement les noms) et les différences de périmètre (org vs. espace de travail) qui ne sont pas réellement des données différentes.
  • Récupérations en vol partagées. Deux composants montés dans la même trame avec la même clé partagent une seule requête seulement si la clé est identique à ce moment-là. Les clés construites à partir d'un état qui se stabilise un tick plus tard (un identifiant qui arrive d'une autre requête) produisent deux récupérations : une avec undefined, une réelle. Vérifiez les portes enabled sur les clés dépendantes.
  • Fraîcheur par surface. Faites un tableau de staleTime par famille de données (identité, listes, détails, statut en direct) et comparez avec la vitesse à laquelle chacune change réellement. Le bug habituel est une valeur globale unique qui ne convient à rien.
  • Propriété du polling. Pour chaque option de poll dans un hook partagé ou une fabrique d'options, listez les composants qui peuvent être montés en même temps et la clé que chacun utilise. Dans SWR et Apollo, chaque instance exécute son propre temporisateur et les récupérations se multiplient à moins qu'elles n'atterrissent dans une fenêtre de déduplication. Dans TanStack Query, les temporisateurs redémarrent à chaque mise à jour de requête et partagent une récupération, donc les observateurs de même clé coûtent une récupération par intervalle le plus court ; l'empilement apparaît entre clés ou clients, et la constatation est la propriété de la cadence. Dans RTK Query, un temporisateur par entrée de cache s'exécute à l'intervalle le plus court.
  • Focus et visibilité. Qu'est-ce qui déclenche les re-récupérations au focus sur cette plateforme ? Un shell de bureau (Tauri, Electron) câble souvent le focus de la fenêtre du système d'exploitation, ce qui se déclenche bien plus souvent que la visibilité de l'onglet. Quels polls s'arrêtent quand l'onglet est caché, et lesquels continuent de s'exécuter pendant que l'utilisateur est inactif sur un écran visible ?
  • Plafond de concurrence. Y a-t-il un limiteur pour les lectures en éventail, et quel est-il ? Notez qu'un limiteur de 6 en vol n'est pas une limite de 6 requêtes par seconde ; n'écrivez pas l'un pour l'autre.
  • Contrat de pagination. Pour les collections à total inconnu, le client s'arrête-t-il quand une page revient avec moins d'éléments, ou continue-t-il jusqu'à une page vide ? Vérifiez les tailles de page par rapport à ce que l'écran peut afficher.
  • Tentatives. Que fait le client sur 403/404/422 ? La valeur par défaut de la bibliothèque réessaie trois fois ; un N+1 de 100 lignes avec un bloc interdit devient 400 requêtes.
  • Persistance. Si le cache est persisté (IndexedDB, localStorage, un magasin natif), quel est le maxAge, qu'est-ce qui le casse lors du déploiement, et le magasin est-il par plateforme ? Un cache persisté change ce que « chargement à froid » signifie dans une capture ; dites lequel vous avez mesuré.
  • Mutations. Pour les cinq écritures les plus courantes, qu'est-ce qui est invalidé ? Les invalidations racines après une petite écriture sont la découverte habituelle.

6. Capture live

Si vous pouvez exécuter l'application ou si l'utilisateur vous a donné une capture, obtenez des nombres. references/capture.md contient les parcours à exécuter, la matrice d'états (vide, peuplé, erreur, lent, hors ligne, inactif, caché, conditionné, cache froid et chaud), comment capturer (HAR DevTools, Playwright, le scripts/capture.mjs fourni, ou le journal de requêtes de l'application), et comment garder les captures comparables.

Choisissez les parcours à partir du plan de la carte de couverture, pas par habitude. Préférez le serveur de développement quand vous pouvez l'exécuter : ses captures nomment chaque module chargé, donc la carte peut dire exactement quels chunks lazzy et modules conditionnés ont été exécutés. Relancez ensuite la carte avec les captures (étape 2) et capturez les lacunes ou listez-les sous Limites.

Une capture montre ce qui s'est passé, jamais pourquoi. Dans un audit basé uniquement sur des captures, tempérez chaque clause causale là où elle se trouve (« compatible avec deux clés de requête », « probablement un remontage »), pas une fois dans un avertissement en haut : les lecteurs citent des phrases isolées, et un « parce que » non tempéré voyage sans son avertissement.

Quand vous n'avez qu'une capture prise par quelqu'un d'autre, vous ne pouvez pas voir ce qu'elle a manqué à partir de la seule capture. Dites-le, listez ce qu'une session unique manque habituellement (routes non visitées, boîtes de dialogue et onglets non ouverts, variantes de drapeaux et de rôles, états d'erreur et vides, comportement en inactivité et onglet caché), et recommandez les captures qui combleraient les lacunes.

python3 <skill-dir>/scripts/har_analyze.py capture.har --format md --out capture.md

Il rapporte les requêtes API par page, les bursts par ligne sur un même modèle de chemin, le polling avec le nombre de temporisateurs empilés par clé, les doublons dans une fenêtre (avec le hash du corps pour les POST), les chaînes séquentielles, les erreurs répétées et les réponses les plus volumineuses. Les ressources statiques sont exclues ; utilisez --ignore pour les hôtes de télémétrie.

Deux choses à garder à l'esprit lors de la lecture :

  • Un POST vers la même URL deux fois est un doublon uniquement si le hash du corps correspond. Si les corps n'ont pas été capturés, l'outil dit « non vérifié » ; rapportez-le ainsi.
  • Une chaîne séquentielle est une cascade uniquement si la requête ultérieure n'avait besoin de rien de la précédente. L'outil trouve la forme ; vous confirmez la dépendance dans le code.

7. Réconcilier

Associez chaque constatation statique à une preuve de capture lorsque la capture couvre cet écran. En cas de désaccord, la capture l'emporte pour les comptes et le code l'emporte pour la cause. Quand une capture montre une amplification qu'aucun candidat n'explique, lisez le code jusqu'à ce que ce soit le cas ; c'est généralement un problème de canonicité de clé ou de clé dépendante de l'étape 4.

Si le dépôt contient un audit antérieur ou un document de performance, vérifiez chacune de ses affirmations qui touchent à vos constatations par rapport au code à ce commit, et listez les contradictions dans le rapport. Les affirmations obsolètes sont la façon dont le même bug est « corrigé » deux fois.

8. Classer et écrire

Utilisez la grille :

SévéritéClasse de croissanceFormes typiques
P0Croît sans plafond : avec les lignes, avec les observateurs montés ou avec le tempsRequête par ligne sur une liste paginée, temporisateurs de poll par instance dans un hook partagé (SWR, Apollo, fait maison), invalidation à chaque frappe, intervalle non effacé
P1Multiplicateur fixe sur un chemin chaudstaleTime 0 sur une liste que chaque écran lit, re-récupération à chaque focus, récupération pilotée par effet sans cache, requête de pagination toujours chargée, sérialisation forcée via un état de mutation, invalidation groupée d'une famille de clés entière
P2Déchets qui ne croissent pas mais s'accumulentDonnées non lues récupérées via une projection large, préchargement d'une modale jamais ouverte (déclenchée par un hover qui ne mène pas au clic), récupération avant que le cache soit chaud, dépendance sur un écran en lecture pour la fraîcheur d'un autre (re-récupération cascade), visiteur de graphe toujours chargé
P3Bruit perturbateur faibleRequête de type-pouraudit (.headers, préflight de déploiement), fetch à partir d'un nœud de module (toujours chargé même si inutilisé), point de terminaison de configuration chargé plusieurs fois lors d'un changement de thème

Chaque constatation a son entrée dans le references/catalog.md ; lisez-la pour vous assurer que le motif correspond avant d'écrire.

9. Rapport

Le modèle est à references/report-template.md. Lisez-le avant de commencer l'étape 2 ; il façonne ce que vous collectez.

Scripts

Tous sont dans le même répertoire que ce fichier. Exécutez-les à partir du répertoire racine de l'application cible, pas d'ici.

scripts/
  coverage_map.py   # Construit la carte de couverture
  static_scan.py    # Candidats regex + heuristiques
  har_analyze.py    # Analyse les captures HAR
  capture.mjs       # Script de capture Playwright

Références

Les fichiers ici ne sont pas de la théorie. Lisez-les avant de les utiliser.

references/
  report-template.md    # Modèle avec en-tête, tableaux, exemples
  catalog.md            # Catalogue des motifs de constatation avec sévérité, delta et conditions de non-constatation
  library-facts.md      # Sémantique de cache : TanStack Query, SWR, Apollo, RTK Query ; chaque entrée vérifiée par rapport à la source à un commit donné
  capture.md            # Parcours de capture, matrice d'états, instructions d'outil

Skills associés