`pushed_at` de GitHub a induit en erreur pour 14 dépôts sur 35 ; des bots ont été confirmés dans trois cas

Dernière mise à jour le August 14, 2026
`pushed_at` de GitHub a induit en erreur pour 14 dépôts sur 35 ; des bots ont été confirmés dans trois cas
Résumé IA

La page d’un dépôt GitHub expose pushed_at, un horodatage qui peut évoluer lorsqu’une branche reçoit un push. Il peut donc diverger du dernier commit sur la branche par défaut. La date de la branche par défaut est un signal de maintenance du dépôt ; elle ne correspond pas forcément au code installé par un gestionnaire de paquets. Les gestionnaires de paquets résolvent généralement des artefacts de registre ou des versions de modules. C’est pourquoi cette analyse vérifie séparément l’activité du dépôt et l’artefact publié : l’un peut être à jour pendant que l’autre est obsolète. J’ai donc passé au crible 35 dépôts qui apparaissent encore dans des recommandations, et j’ai relevé le chiffre que GitHub n’affiche pas dans l’en-tête : la date du commit le plus récent sur la branche par défaut.

La page d’un dépôt sur GitHub affiche pushed_at, un horodatage qui peut changer dès qu’une branche reçoit un push. Il peut donc différer de la date du dernier commit sur la branche par défaut. Or, la date de la branche par défaut est un bon indicateur de la maintenance du dépôt ; elle ne correspond pas forcément au code installé via un gestionnaire de paquets.

Les gestionnaires de paquets résolvent en général des artefacts de registre ou des versions de modules. C’est pourquoi cette analyse vérifie séparément l’activité du dépôt et l’artefact publié : l’un peut être à jour pendant que l’autre est obsolète.

J’ai donc passé au crible 35 dépôts qui apparaissent encore dans des recommandations, et j’ai relevé le chiffre que GitHub n’affiche pas dans l’en-tête : la date du commit le plus récent sur la branche par défaut.

L’écart est bien réel : 14 des 35 dépôts affichent un pushed_at situé à plus de 180 jours après le dernier commit de la branche par défaut, avec un maximum de 1 802 jours. Des bots sont formellement confirmés dans trois de ces 14 cas ; après exclusion des dépôts archivés et des cas où une activité humaine est avérée, il reste deux cas de bots confirmés parmi neuf candidats. Le constat le plus utile est surtout celui-ci : la fraîcheur du dépôt et celle de l’artefact publié peuvent diverger.

Ce qui a été mesuré, et sur quoi

System diagram: What was measured, and on what

Référence officielle : API des dépôts GitHub.

Chaque chiffre ci-dessous a été lu dans une réponse API live entre 15:44 et 15:53 UTC le 2026-07-27, puis mis en cache. Le jeu de données à 35 lignes, la liste des dépôts, les lignes construites ainsi que les scripts de récupération et de génération dans artifacts/ conservent les données d’audit et le code de transformation.

Quatre catégories de données ont été collectées ; les requêtes au registre et à l’activité étaient conditionnelles, et non une séquence uniforme de quatre appels :

  • GET /repos/{owner}/{repo} — étoiles, archived, pushed_at, licence, default_branch.
  • GET /repos/{o}/{r}/commits?sha={default_branch}&per_page=1 — le dernier commit de la branche par défaut, utilisé comme signal de maintenance du dépôt.
  • GET /repos/{o}/{r}/activity?per_page=30 — pour chaque dépôt où les deux dates divergent, ce qui a réellement fait bouger pushed_at.
  • GET /repos/{o}/{r}/releases ainsi que les registres PyPI et npm — la date de dernière publication de l’artefact, qui s’avère plus importante que l’une ou l’autre.

staleness_days correspond au temps écoulé entre le commit de la branche par défaut et le moment de référence. L’écart entre pushed_at et ce commit constitue l’illusion, mesurée en jours. Tout ce qui dépasse 180 jours est signalé.

Deux précisions méthodologiques ont changé les résultats.

L’attribution des paquets a été vérifiée, jamais déduite. Le fait qu’un README mentionne un dépôt ne prouve pas que ce dépôt est bien celui du paquet. Chaque correspondance a dû être confirmée par un champ structuré — l’entrée repository/project_urls du registre, ou un manifeste commité dans le dépôt. Six correspondances plausibles ont échoué à ce test, et leurs volumes de téléchargement ne sont volontairement pas attribués.

L’un de ces rejets mérite à lui seul la règle. curl-cffi totalise 35 763 529 téléchargements par mois et ressemble, de loin, au binding Python de lwthiker/curl-impersonate — un dépôt inactif depuis 875 jours. L’attribuer aurait produit un chiffre quarante-quatre fois supérieur à celui de newspaper3k, et ce chiffre aurait été faux : les métadonnées PyPI de curl-cffi pointent vers lexiforest/curl_cffi, un projet distinct, activement maintenu, dont la dernière publication date du 2026-04-03. Le chiffre le plus spectaculaire ici était le mauvais.

Un septième cas est plus étrange encore : steel-dev/steel-mcp-server déclare @steel-dev/mcp-server dans son propre package.json, mais npm renvoie une 404. Le paquet n’a jamais été publié ; on ne peut donc pas dire qu’il soit « encore installé ».

Quand un chiffre ne pouvait pas être obtenu, c’est indiqué. Les outils Go, JVM, .NET et PHP n’ont pas de présence sur PyPI ou npm, et portent donc la mention N/A (no PyPI/npm package) — jamais zéro. Dix-sept des 35 dépôts n’ont aucune GitHub Release ; cela est noté none, et non comme donnée manquante.

Ces champs ne sont volontairement pas réduits à un seul « score de santé ». Une branche par défaut obsolète, une branche secondaire récente, l’absence de release GitHub et un artefact de registre ancien répondent à des questions différentes. Les preuves ligne par ligne sont disponibles dans le jeu de données à 35 lignes, avec les entrées de dépôt et les enregistrements construits. Il faut les lire comme des signaux de triage qui orientent le contrôle suivant, et non comme quatre votes sur le fait qu’un projet soit vivant ou non.

La limite de l’échantillon, d’emblée

Il s’agit d’une liste constituée à la main, de dépôts que je soupçonnais de vivre sur leur réputation. Ce n’est pas un échantillon aléatoire de l’écosystème du scraping, et « 31 sur 35 sont obsolètes » n’est pas un taux de l’écosystème — c’est surtout une mesure de la qualité de ma sélection. Le vrai résultat intéressant n’est pas le nombre de dépôts obsolètes. C’est que, même sur un échantillon choisi pour ce phénomène, le mécanisme précis que je testais n’explique qu’une minorité des cas, et ne peut être confirmé positivement que dans encore moins de cas.

L’illusion est réelle, et voici son pire cas

sjdirect/abot, un crawler .NET avec 2 308 étoiles. GitHub affiche un push daté du 2026-07-17, dix jours avant la date de référence. Pourtant, la branche par défaut n’a pas bougé depuis le 2021-08-09.

L’écart est de 1 802 jours. Cinq ans. L’en-tête dit « la semaine dernière ».

Quatorze des 35 dépôts présentent un écart supérieur à 180 jours :

DépôtÉcart (jours)Dernier mouvement sur la branche par défautpushed_at
sjdirect/abot1 8022021-08-092026-07-17
dragnet-org/dragnet1 5202021-05-092025-07-08
paquettg/php-html-parser1 3762020-11-012024-08-09
seomoz/simhash-py1 1592020-03-122023-05-15
internetarchive/wayback1 0392021-04-272024-03-01
Rhizome-Conifer/conifer1 0132023-10-122026-07-22
kohlschutter/boilerpipe8562015-08-302018-01-03
scrapinghub/splash8192022-05-052024-08-02
tomnomnom/waybackurls7562022-04-052024-05-01
geziyor/geziyor6892024-08-122026-07-02
crawlab-team/crawlab4882024-10-092026-02-10
ArchiveTeam/wpull4682023-01-162024-04-29
yasserg/crawler4j3962020-10-032021-11-04
apache/any233812022-06-032023-06-20

Quatorze sur trente-cinq. C’est réel, utile à savoir, et cela reste une minorité d’un échantillon choisi pour contenir ce phénomène.

Des bots sont confirmés sur trois dépôts signalés — et deux restent après filtrage

La version populaire de cette histoire cite presque toujours dependabot. J’ai vérifié en récupérant le flux d’activité de chaque dépôt signalé et en classant chaque ref poussée après le dernier commit de la branche par défaut. Ce « après » est essentiel : les événements antérieurs au dernier commit ne disent rien de ce qui a gonflé l’écart, et compter tout le flux change silencieusement la question.

Confirmé comme piloté par un bot, selon la méthode post-commit : trois cas. scrapinghub/splash (4 événements sur 4 post-commit sur dependabot/pip/*), geziyor/geziyor (5 sur 5 sur dependabot/go_modules/*), apache/any23 (16 sur 16 sur dependabot/maven/*). L’un de ces trois, any23, est officiellement archivé, donc il n’entre jamais dans l’ensemble filtré — il reste donc deux cas confirmés qui satisfont aussi toutes les autres conditions.

Totalement faux : deux cas, et les deux sont plus intéressants que l’histoire du bot.

L’écart de 1 520 jours de dragnet-org/dragnet provient d’un humain qui a poussé une branche appelée mp/py3.10 — un port Python 3.10 jamais fusionné. Quelqu’un a essayé de le faire avancer puis s’est arrêté. Ce n’est pas du bruit automatisé qui gonfle un horodatage ; c’est un enregistrement visible et daté d’une tentative de sauvetage qui a échoué. On peut même dire que c’est le signal le plus utile de tout le jeu de données, et que le cadrage « dependabot l’a fait » l’aurait effacé.

Mixte, et plus important que l’un ou l’autre : deux cas. crawlab-team/crawlab compte 12 250 étoiles — le deuxième dépôt le plus étoilé de l’échantillon — et affiche un écart de 488 jours sur main. Son flux contient des branches dependabot et 24 pushes post-commit effectués par des humains, tous vers develop et test. Un lecteur qui se fie à l’en-tête voit février 2026 et pense que le projet va bien ; un lecteur qui ne regarde que main voit octobre 2024 et pense qu’il est mort. Les deux se trompent. Le développement a été déplacé hors de la branche par défaut, ce que font certains projets et que la vue récapitulative de GitHub ne permet pas d’exprimer. sjdirect/abot est l’autre cas mixte : le push qui a fixé son pushed_at mis en avant venait bien de dependabot, mais un humain a poussé upgrade1 en 2024, ce qui le fait sortir de l’ensemble filtré plus tard.

Rhizome-Conifer/conifer est le cas ambigu, et je l’ai d’abord mal lu. Sa branche par défaut est main, pas master, et main n’a plus bougé depuis le 2023-10-12 — le seul événement main du flux est la création d’une branche en janvier 2025, cohérente avec un renommage. En parallèle, un seul compte a poussé vers conifer-twilight et twilight/read-only le 2026-07-22, cinq jours avant la date de référence. C’est une vraie activité humaine, mais « activement développé » va au-delà de ce que les refs prouvent : un seul contributeur, sur des branches nommées read-only, est au moins aussi compatible avec une fermeture progressive gérée qu’avec un développement continu. Ce que l’on peut dire est plus étroit, mais reste important : l’écart de 1 013 jours n’est pas du bruit de bot, et ce n’est pas non plus une preuve d’abandon.

Inconnu : sept cas. php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull et crawler4j présentent tous un écart vérifié, mais un flux d’activité qui revient vide.

L’explication la plus tentante serait la rétention — le flux d’activité de GitHub ne remonte pas indéfiniment. Le cache contredit cette hypothèse pour la plupart d’entre eux. L’événement le plus ancien dans ces 123 réponses date du 2023-03-10, et cinq des sept ont un pushed_at largement à l’intérieur de cette fenêtre : php-html-parser 2024-08-09, wpull 2024-04-29, waybackurls 2024-05-01, internetarchive/wayback 2024-03-01, simhash-py 2023-05-15. Quoi que ce soit qui ait déplacé ces horodatages aurait dû apparaître dans le flux, et ce n’est pas le cas. La rétention n’explique que boilerpipe (2018) et crawler4j (2021).

La formulation honnête est donc plus mince qu’une explication élégante : pour sept dépôts, l’écart est un fait vérifié mais sa cause n’est pas établie — l’endpoint n’a rien renvoyé, et pour cinq d’entre eux je ne peux pas dire pourquoi. Dire « dependabot l’a fait » serait une hypothèse pour les sept.

Bilan, sur les 14 dépôts signalés :

Cause du pushed_at artificiellement gonfléDépôtsLesquels, et sur quelles preuves
Confirmé comme piloté par un bot3scrapinghub/splash (4 événements sur 4 post-commit sur dependabot/pip/*), geziyor/geziyor (5 sur 5 sur dependabot/go_modules/*), apache/any23 (16 sur 16 sur dependabot/maven/*) — any23 est archivé, ce qui laisse deux cas satisfaisant aussi toutes les autres conditions
Mixte, bot et humain2crawlab-team/crawlab (branches dependabot plus 24 pushes post-commit par des humains, tous vers develop et test), sjdirect/abot (le push ayant fixé son pushed_at mis en avant venait bien de dependabot, mais un humain a poussé upgrade1 en 2024)
Totalement faux — travail humain, aucune branche de bot2dragnet-org/dragnet (3 événements post-commit, 0 sur une branche de bot) — un humain poussant mp/py3.10, un port Python 3.10 non fusionné. Rhizome-Conifer/conifer (30 événements post-commit, 0 sur une branche de bot) — un seul compte poussant conifer-twilight et twilight/read-only le 2026-07-22. Que conifer soit abandonné reste ambigu, comme indiqué plus haut ; ce qui ne l’est pas, c’est qu’aucun bot n’a gonflé son pushed_at
Non établi — flux d’activité vide7php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull, crawler4j

Les lignes totalisent 14. Elles classent ce qui a déplacé pushed_at ; elles n’établissent pas, à elles seules, qu’un projet est abandonné.

Ce qui survit au filtre complet, et ce que « survivre » signifie

La thèse initiale exige quatre conditions à la fois : obsolescence de plus d’un an, pushed_at gonflé de plus de 180 jours, dépôt non archivé, et aucune preuve que l’inflation provient d’un travail humain. Neuf des 35 candidats remplissent ces quatre conditions, listés ici avec les deux exclusions les plus importantes :

DépôtRemplit les quatre ?Preuve positive que des bots ont gonflé l’indicateur
splashouioui — 4 sur 4 événements post-commit sur dependabot/pip/*
waybackurlsouiaucune dans un sens ou dans l’autre
crawler4jouiaucune dans un sens ou dans l’autre
geziyorouioui — 5 sur 5 sur dependabot/go_modules/*
php-html-parserouiaucune dans un sens ou dans l’autre
boilerpipeouiaucune dans un sens ou dans l’autre
wpullouiaucune dans un sens ou dans l’autre
internetarchive/waybackouiaucune dans un sens ou dans l’autre
simhash-pyouiaucune dans un sens ou dans l’autre
any23non — archivéoui — 16 sur 16 sur dependabot/maven/*, la confirmation la plus forte de tout l’audit
abotnon — son historique contient un push humain (upgrade1, 2024)mixte — le push qui a fixé son pushed_at mis en avant venait bien de dependabot

Ce chiffre mérite une précision que le filtre ne peut pas porter. Seuls deux des neuf — splash et geziyor — apportent une preuve positive que des bots ont provoqué l’inflation. Les sept autres remplissent la quatrième condition parce qu’aucune preuve ne va dans un sens ou dans l’autre. Ce sont des cas que la thèse survit à l’examen, pas des cas qui la confirment. Et la confirmation la plus solide de tout l’audit, any23 avec 16 événements dependabot sur 16, est exclue parce que le dépôt est archivé.

Notez aussi que abot, le cas à 1 802 jours, ne figure pas parmi ces neuf. Son historique contient un push humain ; il échoue donc la quatrième condition — l’illusion la plus spectaculaire du jeu de données n’est pas un exemple pur du mécanisme qu’elle illustre.

Pour 21 dépôts sur 35, GitHub a signalé l’obsolescence sans détour

Voici le résultat qui a le plus fragilisé ma thèse. Quatorze dépôts ont un écart exactement nul, et sept autres restent sous 180 jours. Pour 21 des 35 candidats, pushed_at correspond bien au dernier commit de la branche par défaut. GitHub ne cache pas tout.

Y compris certains des cas les plus morts de l’échantillon :

DépôtÉtoilesObsolescence (jours)Écart
Janpot/microdata-node571 8660
1e0ng/simhash1 0371 60621
ekzhu/SetSimilaritySearch6031 3840
GerbenJavado/LinkFinder4 4318340
hakluke/hakrawler5 0995820
lavague-ai/LaVague6 3885510
my8100/scrapydweb3 4115220
getomni-ai/zerox12 2584320
scrapinghub/frontera1 3324150
BuilderIO/gpt-crawler22 3743840

BuilderIO/gpt-crawler a 22 374 étoiles et son en-tête dit la même chose depuis le 2025-07-07. Rien n’est caché, et le volume d’installations continue.

Cela réduit la thèse à quelque chose de plus précis : GitHub masque l’obsolescence dans une minorité de cas, et dans la majorité il la dit clairement pendant que les installations continuent malgré tout. Pourquoi elles continuent dépasse ce que ces données peuvent expliquer — ici, les chiffres comptent des installations, pas des décisions. Mais aucune modification d’interface ne règle le second groupe, qui est le plus important.

L’activité du dépôt et l’artefact publié peuvent diverger

La ligne la plus frappante du jeu de données casse complètement le cadrage.

codelucas/newspaper — 15 126 étoiles — est actif. Son dernier commit sur la branche par défaut date du 2026-07-21, pour une date de référence fixée au 2026-07-27, et il a été rédigé par le mainteneur. Tous les contrôles au niveau du dépôt sont au vert.

Le paquet que tout le monde installe est newspaper3k 0.2.8, publié le 2018-09-28. Il a donc 2 858 jours, et il totalise 813 513 téléchargements par mois.

La branche par défaut est à jour, alors que l’artefact PyPI n’a plus été publié depuis 2018. Cela prouve un écart de publication, mais pas pourquoi le paquet n’a pas été publié ni si la chaîne de publication est cassée. C’est exactement le genre de risque qu’un contrôle de maintenance limité au dépôt manquerait, puisque c’est l’artefact du registre qui est normalement installé après pip install newspaper3k.

Dès qu’on regarde les paquets plutôt que les dépôts, le schéma apparaît partout. Parmi les 17 paquets dont l’attribution au dépôt a pu être vérifiée, 16 ont été publiés pour la dernière fois il y a plus d’un an, et ces 16 représentent environ 2,28 millions d’installations par mois sur 2,30 millions au total :

PaquetInstallations/moisDernière publicationÂge du paquet (jours)
newspaper3k813 5132018-09-282 858
tls-client790 3052024-02-02905
simhash317 6152022-03-031 606
microdata-node204 0252020-05-112 267
@modelcontextprotocol/server-puppeteer127 2322025-05-12440
extract-thinker10 9272025-06-09412
SetSimilaritySearch7 9842022-10-111 384
frontera4 7092019-04-052 669
zerox3 3032025-05-20432
scrapydweb1 1632025-02-16525
lavague6062024-08-05720
splash3332020-06-162 231
dragnet2132019-04-162 658
@builder.io/gpt-crawler1372025-01-23549
lmnr-index1202025-06-05416
simhash-py1132017-03-223 413

tls-client mérite sa propre ligne : 790 305 installations par mois pour un dépôt inactif depuis 905 jours, dans une catégorie où rester à jour est précisément la mission.

Deux précautions à propos de ce tableau. Les téléchargements de registre incluent les exécutions CI et les miroirs, et ne dédupliquent rien : ils mesurent donc un volume d’installation, pas des humains. Et les fenêtres roulantes n’ont pas la même date de fin — celles de npm se terminent proche du 2026-07-24, celles de pypistats sont relatives au moment de la collecte — si bien que le total est la somme de mois légèrement décalés, à lire comme « environ 2,28 millions » et non au chiffre près.

La collision de noms qu’il faut connaître

internetarchive/wayback est l’ancien OpenWayback en Java, inactif depuis 1 916 jours. wayback sur PyPI est un autre projetedgi-govdata-archiving/wayback — et il se porte bien, avec une publication de la version 0.5.1 le 2026-06-19, soit cinq semaines avant la date de référence. Même nom, état opposé, aucun lien. C’était l’une des six attributions rejetées, et c’est celle qui risque le plus de piéger un utilisateur réel : une recherche par nom affiche les deux, et rien sur l’une ou l’autre page n’indique clairement lequel vous avez trouvé.

Archivé, déprécié, et encore installé 127 232 fois par mois

Six dépôts de l’échantillon portent archived: true, que GitHub affiche sous forme de bannière sur toute la largeur. Ma première lecture était que cela prouvait que les gens ignorent les avertissements visibles. Le cache montre que l’histoire est pire que cela.

Référence officielle : documentation de l’API des téléchargements npm.

Référence officielle : documentation de la dépréciation npm.

@modelcontextprotocol/server-puppeteer totalise 127 232 installations par mois à partir de modelcontextprotocol/servers-archived. Mais son champ repository npm vaut null — il n’existe donc aucun lien entre la page du paquet et le dépôt archivé, et aucun bandeau à contourner. La plupart des personnes qui récupèrent ce paquet n’avaient tout simplement aucun chemin menant à ce dépôt.

Ce que npm publie, en revanche, c’est la dépréciation. La dernière version du paquet contient deprecated: "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." — message que npm affiche dans le terminal lors de l’installation. L’avertissement est donc bien transmis, à l’endroit exact où se trouve l’utilisateur, et 127 232 installations par mois continuent malgré tout. C’est un résultat plus fort que celui de la bannière, et il pointe ailleurs : le signal n’est pas absent, il arrive au milieu d’une sortie d’installation que rien n’oblige à lire.

browserbase/mcp-server-browserbase montre à quoi ressemble un arrêt propre : son dernier commit sur la branche par défaut, le 2026-07-20, dit littéralement « Mark repository as archived and unmaintained (#198) ». Les mainteneurs l’ont annoncé, daté et signalé dans l’API. Ses 20 389 installations méritent toutefois une lecture prudente — la fenêtre npm va du 2026-06-25 au 2026-07-24, donc 26 de ces 30 jours précèdent le commit d’archivage. Ce chiffre reflète donc surtout une demande antérieure à l’annonce, pas une quelconque défiance à son égard. Ce qui se passe ensuite est réellement inconnu à partir de cet instantané, et j’attendrais une nouvelle lecture un mois plus tard avant d’affirmer quoi que ce soit.

57 étoiles, 204 025 installations par mois

Janpot/microdata-node a 57 étoiles et affiche 204 025 téléchargements par mois pour une publication datée du 2020-05-11.

Avec seulement 57 étoiles, microdata-node a une visibilité de dépôt très faible au regard de son volume sur le registre. Son ratio installations/étoile de 3 579 pour 1 est compatible avec un usage transitif, des exécutions CI répétées, des miroirs ou une consommation directe par des machines. Cet audit n’a pas récupéré d’arbre de dépendances et ne peut pas trancher entre ces explications.

Cette ligne invite à inventorier l’exposition indirecte, mais prouver l’usage transitif exige des preuves de dépendance inverse ou de lockfile que cet audit n’a pas collectées.

Obsolète ne veut pas dire cassé

Un audit honnête doit le dire : rien ici ne mesure si quelque chose est cassé. Cela mesure si quelqu’un est encore là.

Certaines de ces bibliothèques sont simplement terminées. SetSimilaritySearch implémente des algorithmes de similarité d’ensembles ; ils ne « pourrissent » pas. simhash renvoie à un article de 2007. L’algorithme d’extraction de contenu de boilerpipe fonctionne en 2026 comme en 2015 — quelle que soit sa précision face aux pages modernes, le code ne vous échappe pas en se dégradant sous vos pieds.

Ce qui se dégrade, c’est tout ce qui dépend d’un objectif mouvant de l’autre côté :

  • L’automatisation de navigateur — chaque version de Chrome peut la casser.
  • Le comportement d’un client HTTP qui imite les navigateurs — les navigateurs changent, et une bibliothèque figée cesse de suivre ; tls-client entre dans cette catégorie.
  • Les parseurs spécifiques à un site et les règles d’extraction par site — chaque refonte est un bug.
  • Tout ce qui enveloppe une API tierce — le fournisseur modifie le schéma et vous le découvrez en production.
  • Tout ce qui enveloppe un LLM — les dépréciations de modèles vont plus vite que tout cela.

Ainsi, « 1 606 jours d’obsolescence » est une alerte de niveau maximal pour une catégorie, et presque sans importance pour un utilitaire de hachage. Aucune casse n’a été testée ici et aucun tel constat n’est avancé ; classer vos propres dépendances selon leur catégorie vous coûte zéro et vous apporte davantage que le seul chiffre d’obsolescence.

Les quatre vérifications qui répondent vraiment à la question

System diagram: The four checks that actually answer the question

Aucune n’est l’en-tête du dépôt.

#VérificationOù la lireCe qu’elle détecte
1Le dernier commit sur la branche par défautGET /repos/{owner}/{repo}/commits?sha={default_branch}&per_page=1Le chiffre qui n’est pas affiché.
2La dernière publication de l’artefactpypi.org/pypi/{pkg}/json ou registry.npmjs.org/{pkg} → dernière version et date d’envoiC’est ce qui attrape newspaper3k, et la vérification 1 ne le fera jamais. Tant qu’on y est, regarde le champ deprecated de npm, c’est ainsi que @modelcontextprotocol/server-puppeteer se signale.
3Le drapeau archivedUn champ dans la réponse du dépôt, sans ambiguïté et gratuitUtile seulement si tu as atteint le dépôt, ce que les paquets avec repository: null ne permettent pas.
4L’écart entre 1 et 2— (dérivé des deux précédents)Un dépôt avec des commits récents et une release vieille de trois ans n’est pas le même problème qu’un dépôt simplement froid : cela signifie que le mainteneur est là, mais ne publie plus. C’est une décision à prendre en connaissance de cause, pas un signal d’alarme en soi. La même logique vaut à l’inverse pour crawlab : vérifiez si le travail a migré vers une branche non par défaut avant de conclure quoi que ce soit.

Exécute les vérifications 1, 2 et 3 comme triage rapide. Puis escalade quand les métadonnées du dépôt sont absentes, que l’attribution du paquet est ambiguë, que l’activité s’est déplacée vers une branche non par défaut, ou que l’artefact du registre diverge du dépôt. Les limites GitHub non authentifiées et la latence des registres rendent une promesse à la seconde peu réaliste.

Si une vérification révèle quelque chose de froid dans une catégorie où la dynamique change vite, les alternatives maintenues dans ce domaine sont documentées dans nos propres tests : Trafilatura pour l’extraction de contenu que dragnet et boilerpipe faisaient auparavant, Scrapy ou Crawlee pour les frameworks de crawling, Crawl4AI et Firecrawl pour l’extraction orientée LLM, et Scrapling quand la robustesse compte. Notre page pilier sur les scrapers open source suit l’ensemble plus large. Ce sont des avis de première main ; fais toi-même les quatre vérifications avant de faire confiance à une recommandation, y compris la nôtre.

Limites de ces données

  • Sélection de l’échantillon. Choisie à la main sur suspicion d’abandon. Aucun taux d’écosystème n’en découle.
  • Aucun test de casse. Aucun des 35 outils n’a été exécuté sur un site live. L’obsolescence est un signal de maintenance, pas un verdict fonctionnel.
  • Les téléchargements incluent des machines. CI, miroirs, pas de déduplication, et fenêtres qui n’ont pas la même date de fin. Volume d’installation, pas utilisateurs, et pas décisions.
  • Sept causes inconnues restent inconnues. Le flux d’activité n’a rien renvoyé, et pour cinq des sept la rétention ne l’explique pas. Mieux vaut laisser la case vide que la remplir avec le soupçon le plus répandu.
  • staleness_days utilise les dates du committer. Un historique réécrit ou antidaté le fausserait. Rien de tel n’a été détecté, ce qui n’est pas la même chose que l’absence de tel phénomène.
  • Une seule date de référence. 2026-07-27. Plusieurs de ces dépôts auront bougé au moment où tu liras ceci — newspaper en particulier commite régulièrement. Rejoue les quatre vérifications ; ne cite pas mes dates.

Ce qu’un service géré change dans l’équation

Chaque contrôle ici existe parce qu’avec une bibliothèque auto-hébergée, l’obsolescence t’appartient. Si un client HTTP figé cesse de se comporter comme un navigateur actuel, c’est ton incident, à l’heure où il apparaît.

Note de l’auteur : Thunderbit est notre produit de scraping géré. Un service géré transfère une partie de la responsabilité de maintenance à un fournisseur, mais la couverture, le temps de réponse, le verrouillage propriétaire et la continuité du fournisseur deviennent alors une partie du modèle de risque. Thunderbit n’a pas été évalué dans cet audit de dépôts.

Le compromis honnête : tu perds la possibilité de lire le code source, d’épingler une version et de corriger toi-même à 2 heures du matin. Pour une équipe qui maintient déjà des scrapers, l’open source est souvent le bon choix — les quatre vérifications sont là pour en faire une décision, pas une hypothèse.

Essayer Thunderbit pour l’extraction de données web

En bref

J’ai constitué une liste pour prouver que GitHub cachait l’abandon. L’illusion est bien réelle pour 14 dépôts sur 35, et spectaculaire dans un cas : sjdirect/abot affiche un push datant de la semaine dernière alors que sa branche par défaut est figée depuis 2021, soit un écart de 1 802 jours.

Mais le mécanisme est plus étroit que l’histoire. Neuf dépôts remplissent toutes les conditions exigées par la thèse, et seuls deux de ces neufsplash et geziyor — apportent une preuve positive que des bots ont gonflé l’indicateur ; pour les autres, l’absence de preuve suffit à franchir le seuil. Deux dépôts signalés correspondent à des humains qui essaient de relancer un projet sans y parvenir. L’un d’eux, crawlab, compte 12 250 étoiles et a simplement déplacé le développement vers develop. Pour sept dépôts, le flux d’activité est resté vide et la rétention n’explique pas cinq de ces cas ; la cause n’est donc pas établie, seulement supposée. Et pour 21 des 35 dépôts, GitHub a signalé l’obsolescence avec exactitude.

Le pire cas du jeu de données passe pourtant tous les contrôles au niveau du dépôt. codelucas/newspaper a été commité le 2026-07-21 ; newspaper3k, dont la dernière publication date du 2018-09-28, est sorti 813 513 fois ce mois-là. Sur l’ensemble de l’échantillon, 16 paquets avec des publications vieilles de plus d’un an représentent environ 2,28 millions d’installations par mois.

Vérifie d’abord le dernier commit sur la branche par défaut, la date de dernière publication du registre, le drapeau d’archive et le champ de dépréciation npm. Puis clarifie l’attribution paquet-vers-dépôt et l’éventuel développement hors branche par défaut avant de conclure.

Essayer Thunderbit pour l’extraction de données web Get Started Free

FAQ

Qu’est-ce que pushed_at et pourquoi ne veut-il pas dire « dernière mise à jour » ? pushed_at est le champ de l’API GitHub derrière l’horodatage d’activité affiché sur la page du dépôt, et il se met à jour dès qu’un push touche n’importe quelle branche. Le dernier commit sur la branche par défaut est un indicateur de maintenance du dépôt, alors que les gestionnaires de paquets installent généralement des artefacts du registre ou des versions de modules résolues. Dans cet audit, 14 des 35 dépôts présentaient plus de 180 jours d’écart entre ces deux dates GitHub.

Est-ce toujours dependabot qui gonfle cet horodatage ? Non, et c’est ce qui s’est révélé être le maillon le plus faible du récit populaire. En ne comptant que les événements survenus après le dernier commit de la branche par défaut, des bots sont confirmés dans 3 des 14 dépôts signalés (splash 4 sur 4, geziyor 5 sur 5, any23 16 sur 16). Pour 2 cas, c’est carrément faux : l’écart de dragnet provient d’un humain ayant poussé un port Python 3.10 non fusionné. Deux autres sont mixtes, dont crawlab, où 24 pushes humains sont allés vers develop et test pendant que main restait figée. Et pour 7 cas, le flux d’activité n’a rien renvoyé, donc la cause n’est pas établie — la rétention n’explique que deux de ces sept.

Un dépôt obsolète veut-il dire que l’outil est cassé ? Pas d’après ces éléments — rien ici n’a été exécuté sur un site live. L’obsolescence compte à proportion de la vitesse d’évolution de la cible : l’automatisation de navigateur, les clients HTTP qui imitent les navigateurs, les parseurs spécifiques à un site et les wrappers d’API/LLM vieillissent vite, alors que des bibliothèques algorithmiques comme SetSimilaritySearch ou simhash peuvent avoir plusieurs années et rester parfaitement valables. tls-client est le cas le plus frappant de l’échantillon, avec 790 305 installations par mois pour un dépôt inactif depuis 905 jours.

Comment un dépôt peut-il être actif alors que le paquet est mort ? C’est le cas de codelucas/newspaper, et c’est l’élément le plus important de cet audit. Sa branche par défaut a été commité le 2026-07-21, quelques jours avant la date de référence, mais newspaper3k sur PyPI a été publié pour la dernière fois en 0.2.8 le 2018-09-28 — soit 2 858 jours — et continue à générer 813 513 téléchargements par mois. Les contrôles au niveau du dépôt sont tous positifs ; l’artefact que tu installes a huit ans. Vérifie toujours la dernière date de publication du registre séparément du journal des commits.

Les dépôts archivés règlent-ils le problème ? GitHub affiche une bannière. Pas de façon fiable, et @modelcontextprotocol/server-puppeteer montre pourquoi. Son champ npm repository vaut null, donc il n’y a aucun lien depuis le paquet vers le dépôt archivé et aucun bandeau à ignorer. Ce que npm affiche réellement, c’est la chaîne deprecated du paquet — « Package no longer supported » — au moment de l’installation, et 127 232 installations par mois passent malgré tout. browserbase/mcp-server-browserbase a annoncé proprement son arrêt dans son dernier commit ; ses 20 389 installations sont surtout antérieures à ce commit, donc elles n’indiquent pas grand-chose dans un sens ou dans l’autre.

Comment vérifier rapidement mes propres dépendances ? Commence par la date du dernier commit sur la branche par défaut, la date de version/publication du registre, le champ de dépréciation npm et le drapeau archived du dépôt. Vérifie ensuite l’attribution paquet-vers-dépôt, inspecte les branches non par défaut lorsque l’activité diverge, et utilise des graphes de dépendances ou des lockfiles avant de qualifier une exposition de transitive. Des collisions de noms, comme les projets Java et PyPI wayback sans lien entre eux, rendent cette escalade indispensable.

Ke
Ke
CTO chez Thunderbit | Data Scientist senior et expert en ML Forte d’une expérience de près de dix ans en machine learning et en data science, Ke Shen est diplômé de Columbia University et ancien Data Scientist senior chez Walmart Labs. Grâce à une expertise approfondie, reconnue par ses pairs, en Python, R, Java et statistiques, il partage des analyses éprouvées sur le passage d’algorithmes d’IA complexes de la théorie à une architecture prête pour la production.
Table des matières
Thunderbit · Agent IA de données web

Extrayez des données de n'importe quelle page en 1 clic

Approuvé par plus de 250 000 utilisateurs
formule gratuite disponible
De la page web au tableur
Décris ce dont tu as besoin — l'agent IA de Thunderbit l'extrait et l'exporte vers Excel, Google Sheets, Airtable ou Notion. Gratuit pour commencer.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week