หน้ารีโปของ GitHub แสดงค่า pushed_at ซึ่งเป็นเวลาที่อาจเปลี่ยนได้เมื่อมีการ push เข้าไปที่สาขาใดก็ตาม ทำให้ตัวเลขนี้อาจไม่ตรงกับคอมมิตล่าสุดบนสาขาเริ่มต้น (default branch) ได้ วันที่ของ default branch เป็นเพียงสัญญาณบอกความเคลื่อนไหวในการดูแลรีโป ไม่ได้หมายความว่านั่นคือโค้ดชุดเดียวกับที่แพ็กเกจเมเนเจอร์ติดตั้งเสมอไป
โดยปกติแล้ว package manager จะไปดึงอาร์ติแฟกต์จาก registry หรือเลือกเวอร์ชันของโมดูลมาติดตั้ง ดังนั้นการตรวจสอบครั้งนี้จึงแยกดู “ความเคลื่อนไหวของรีโป” กับ “อาร์ติแฟกต์ที่เผยแพร่” ออกจากกัน เพราะอย่างใดอย่างหนึ่งอาจยังใหม่อยู่ แต่อีกฝั่งหนึ่งล้าสมัยไปแล้ว
ผมจึงคัดรีโป 35 ตัวที่ยังโผล่ในคำแนะนำต่าง ๆ มาดู และอ่านตัวเลขที่ GitHub ไม่ได้แสดงไว้บนหัวหน้าเพจ นั่นคือวันที่ของคอมมิตล่าสุด บน default branch
ผลต่างนั้นมีจริง: 14 จาก 35 รีโปมี pushed_at ที่ใหม่กว่าคอมมิตล่าสุดบน default branch เกิน 180 วัน โดยมากที่สุดห่างกันถึง 1,802 วัน ตรวจพบว่ามีบอทเกี่ยวข้องแน่ชัดใน 3 จาก 14 กรณีดังกล่าว หลังตัดกรณีที่เป็นรีโป archived และกรองกิจกรรมของมนุษย์ออก เหลือกรณีบอทที่ยืนยันได้ 2 รายจากผู้เข้ารอบ 9 ราย สิ่งที่มีประโยชน์กว่าคือข้อเท็จจริงว่า “ความใหม่ของรีโป” กับ “ความใหม่ของอาร์ติแฟกต์ที่เผยแพร่” อาจแยกทางกันได้
วัดอะไร และวัดจากตรงไหน

อ้างอิงทางการ: GitHub repository API.
ตัวเลขทั้งหมดในบทความนี้อ่านมาจากคำตอบของ API แบบสด ระหว่างเวลา 15:44 ถึง 15:53 UTC ของวันที่ 2026-07-27 แล้วบันทึกแคชไว้ ชุดข้อมูล 35 แถว, รายชื่อรีโป, เรคคอร์ดที่สร้างแล้ว และสคริปต์ดึงข้อมูล/แปลงข้อมูลใน artifacts/ เก็บอินพุตและโค้ดที่ใช้ในการตรวจสอบทั้งหมดไว้ครบ
เก็บข้อมูลไว้ 4 หมวด แต่คำขอของ registry และ activity ไม่ได้ยิงแบบชุดคำสั่งเดียว 4 ครั้งเสมอไป:
GET /repos/{owner}/{repo}— ดาว,archived,pushed_at, ไลเซนส์,default_branch.GET /repos/{o}/{r}/commits?sha={default_branch}&per_page=1— คอมมิตล่าสุดบน default branch ใช้เป็นสัญญาณการดูแลรีโปGET /repos/{o}/{r}/activity?per_page=30— สำหรับทุกรีโปที่สองค่านี้ไม่ตรงกัน ดูว่าอะไรคือสิ่งที่ทำให้pushed_atขยับจริง ๆGET /repos/{o}/{r}/releasesรวมถึง registry ของ PyPI และ npm — ดูว่าอาร์ติแฟกต์ ถูกปล่อย ล่าสุดเมื่อไร ซึ่งสุดท้ายแล้วมีความสำคัญมากกว่าอย่างอื่น
staleness_days คือระยะเวลาที่ผ่านไปนับจากคอมมิตบน default branch จนถึงจุดเวลาที่อ้างอิง ความต่างระหว่าง pushed_at กับคอมมิตนั้นคือภาพลวงตา วัดเป็นจำนวนวัน ถ้าเกิน 180 วันจะถูกติดธง
มีสองหลักการที่ควรพูดตรง ๆ เพราะมันเปลี่ยนผลลัพธ์จริง
การระบุแพ็กเกจยืนยันแล้วเท่านั้น ไม่เคยเดาเอา แพ็กเกจที่ README เอ่ยถึงรีโปหนึ่งตัว ไม่ได้แปลว่าเป็นแพ็กเกจของรีโปนั้นจริง ๆ การจับคู่ทุกกรณีต้องยืนยันจากฟิลด์โครงสร้าง เช่น repository/project_urls ของ registry เอง หรือ manifest ที่คอมมิตไว้ในรีโป มีถึง 6 การจับคู่ที่ดูเข้าท่าแต่ไม่ผ่านเงื่อนไขนี้ และจำนวนดาวน์โหลดของพวกมันจึง ไม่ถูกนับรวม อย่างตั้งใจ
หนึ่งในกรณีที่ถูกปฏิเสธนั้นอธิบายกติกานี้ได้ดีที่สุด curl-cffi มียอดดาวน์โหลด 35,763,529 ครั้งต่อเดือน และจากระยะไกลดูเหมือนจะเป็นไบนดิง Python ของ lwthiker/curl-impersonate — รีโปที่เหมือนไม่มีใครแตะมา 875 วัน ถ้าเอาไปนับรวม ตัวเลขจะใหญ่กว่า newspaper3k ถึง 44 เท่า แต่ก็จะผิด เพราะ metadata บน PyPI ของ curl-cffi ชี้ไปที่ lexiforest/curl_cffi ซึ่งเป็นโปรเจ็กต์อีกตัวที่ยังดูแลอยู่ และปล่อยเวอร์ชันล่าสุดเมื่อ 2026-04-03 ตัวเลขที่น่าตื่นที่สุดในที่นี้กลับเป็นตัวเลขที่ผิด
กรณีที่ 7 ยิ่งแปลกกว่า: steel-dev/steel-mcp-server ระบุ @steel-dev/mcp-server ไว้ใน package.json ของตัวเอง แต่ npm ตอบกลับ 404 แปลว่าไม่เคยถูกเผยแพร่ ดังนั้นจะพูดว่า “ยังถูกติดตั้งอยู่” ไม่ได้เลย
ถ้าเอาตัวเลขมาไม่ได้ ก็ต้องบอกตรง ๆ ว่าเอาไม่ได้ เครื่องมือ Go, JVM, .NET และ PHP ไม่มีตัวตนบน PyPI หรือ npm จึงถูกระบุเป็น N/A (no PyPI/npm package) — ไม่ใช่ศูนย์ และจาก 35 รีโป มี 17 ตัวที่ไม่มี GitHub Releases เลย ก็ถูกบันทึกว่า none ไม่ใช่ข้อมูลหาย
ฟิลด์เหล่านี้ตั้งใจไม่ถูกรวมเป็นคะแนน “สุขภาพรวม” คะแนนเดียว เพราะ default branch ที่เก่า, สาขาย่อยที่ยังใหม่, GitHub Release ที่ไม่มี, และ registry artifact ที่เก่า เป็นคำถามคนละแบบ ข้อมูลระดับแถวดูได้จากชุดข้อมูล 35 แถว พร้อม อินพุตของรีโป และ เรคคอร์ดที่สร้างแล้ว อ่านมันเป็นสัญญาณคัดกรองเพื่อชี้ว่าควรตรวจอะไรต่อ ไม่ใช่โหวต 4 เสียงว่าจะตายแล้วหรือยัง
ข้อแม้ของการสุ่มตัวอย่าง บอกไว้ก่อน
นี่คือรายชื่อที่คัดขึ้นมาเองจากเครื่องมือที่ผมสงสัยว่ากำลังอาศัยชื่อเสียงกินต่ออยู่ มันไม่ใช่ตัวอย่างแบบสุ่มของระบบนิเวศงานสแครปปิง และคำว่า “31 จาก 35 ล้าสมัย” ก็ไม่ใช่อัตราของทั้งระบบนิเวศ — มันใกล้จะเป็นตัววัดว่าผมเลือกได้ดีแค่ไหนมากกว่า ผลลัพธ์ที่น่าสนใจจริง ๆ ไม่ใช่จำนวนที่ล้าสมัย แต่คือแม้แต่ในตัวอย่างที่เลือกมา เพื่อ ให้เห็นปรากฏการณ์นี้ กลไกเฉพาะที่ผมทดสอบกลับอธิบายได้เพียงบางส่วน และยังยืนยันแบบชัดเจนได้ไม่กี่รายด้วย
ภาพลวงตานั้นมีจริง และนี่คือเคสที่เลวร้ายที่สุด
sjdirect/abot เป็น crawler บน .NET ที่มี 2,308 ดาว GitHub รายงานว่ามีการ push เมื่อ 2026-07-17 ซึ่งคือ 10 วันก่อนวันที่อ้างอิง แต่ default branch ถูกแตะครั้งล่าสุดเมื่อ 2021-08-09
นั่นคือช่องว่าง 1,802 วัน ห้าปีเต็ม หัวหน้าเพจบอกเหมือนเพิ่งสัปดาห์ที่แล้ว
จาก 35 รีโป มี 14 ตัวที่ช่องว่างเกิน 180 วัน:
| รีโป | ช่องว่าง (วัน) | default branch ถูกแตะล่าสุด | pushed_at |
|---|---|---|---|
sjdirect/abot | 1,802 | 2021-08-09 | 2026-07-17 |
dragnet-org/dragnet | 1,520 | 2021-05-09 | 2025-07-08 |
paquettg/php-html-parser | 1,376 | 2020-11-01 | 2024-08-09 |
seomoz/simhash-py | 1,159 | 2020-03-12 | 2023-05-15 |
internetarchive/wayback | 1,039 | 2021-04-27 | 2024-03-01 |
Rhizome-Conifer/conifer | 1,013 | 2023-10-12 | 2026-07-22 |
kohlschutter/boilerpipe | 856 | 2015-08-30 | 2018-01-03 |
scrapinghub/splash | 819 | 2022-05-05 | 2024-08-02 |
tomnomnom/waybackurls | 756 | 2022-04-05 | 2024-05-01 |
geziyor/geziyor | 689 | 2024-08-12 | 2026-07-02 |
crawlab-team/crawlab | 488 | 2024-10-09 | 2026-02-10 |
ArchiveTeam/wpull | 468 | 2023-01-16 | 2024-04-29 |
yasserg/crawler4j | 396 | 2020-10-03 | 2021-11-04 |
apache/any23 | 381 | 2022-06-03 | 2023-06-20 |
14 ใน 35 เป็นเรื่องจริง ควรรู้ไว้ และ ยังเป็นเพียงส่วนน้อยของตัวอย่างที่คัดมาเพราะต้องการให้เจอเรื่องนี้
ยืนยันว่ามีบอทในรีโปที่ถูกตั้งธง 3 ราย — และเหลือ 2 รายหลังกรองแล้ว
เวอร์ชันเล่าต่อ ๆ กันมักจะโทษ dependabot ก่อนเสมอ ผมตรวจโดยดึง activity feed ของแต่ละรีโปที่ถูกตั้งธง และจัดประเภททุก ref ที่ถูก push หลัง คอมมิตล่าสุดบน default branch คำว่า “หลัง” สำคัญมาก เพราะ event ที่เกิดก่อนคอมมิตล่าสุดไม่ได้บอกอะไรเกี่ยวกับสิ่งที่ทำให้ช่องว่างขยาย และถ้านับทั้ง feed ก็เท่ากับเปลี่ยนคำถามไปเงียบ ๆ
ยืนยันว่าเกิดจากบอท ตามวิธีนับหลังคอมมิต: 3 ราย scrapinghub/splash (4 จาก 4 event หลังคอมมิตอยู่บน dependabot/pip/*), geziyor/geziyor (5 จาก 5 อยู่บน dependabot/go_modules/*), apache/any23 (16 จาก 16 อยู่บน dependabot/maven/*) กรณีหลัง any23 ถูก archived อย่างเป็นทางการ จึงไม่ถูกนับเข้าเซตที่กรองแล้ว ทำให้เหลือ 2 ราย ที่ยืนยันว่าเป็นบอทและผ่านเงื่อนไขอื่นครบ
ผิดไปเลย: 2 ราย และทั้งคู่กลับน่าสนใจกว่าเรื่องบอท
ช่องว่าง 1,520 วันของ dragnet-org/dragnet มาจากมนุษย์ที่ push สาขาชื่อ mp/py3.10 — เป็นพอร์ต Python 3.10 ที่ไม่ได้ merge ใครบางคนพยายามดันมันต่อแล้วก็หยุด นั่นไม่ใช่เสียงรบกวนจากระบบอัตโนมัติที่ไปดันเวลาให้เพี้ยน แต่มันคือบันทึกที่เห็นได้ชัดและลงวันที่ไว้แล้วของความพยายามกู้โครงการที่ไม่สำเร็จ ถ้าจะพูดตรง ๆ นี่อาจเป็นสัญญาณที่มีประโยชน์ที่สุดในทั้งชุดข้อมูล และกรอบเล่าแบบ “dependabot ทำ” จะลบมันหายไปเลย
ผสมกัน และใหญ่กว่าทั้งสองแบบ: 2 ราย crawlab-team/crawlab มี 12,250 ดาว — มากเป็นอันดับสองในตัวอย่าง — และมีช่องว่าง 488 วันบน main activity feed ของมันมีทั้งสาขา dependabot และ 24 ครั้งที่มนุษย์ push หลังคอมมิต โดยทั้งหมดไปที่ develop และ test ผู้ใช้ที่อ่านหัวหน้าเพจจะเห็นกุมภาพันธ์ 2026 แล้วคิดว่ายังมีชีวิต ผู้ใช้ที่อ่าน main จะเห็นตุลาคม 2024 แล้วคิดว่าตาย ทั้งสองอย่างผิด การพัฒนาย้ายออกจาก default branch ซึ่งเป็นสิ่งที่โปรเจ็กต์ทำกันได้ และสรุปแบบย่อของ GitHub ก็ไม่มีทางเล่าเรื่องนี้ได้ sjdirect/abot ก็เป็นกรณีผสมอีกตัว: push ที่ทำให้ pushed_at กลายเป็นหัวเรื่องนั้นมาจาก dependabot จริง แต่มีมนุษย์ push upgrade1 ในปี 2024 จึงหลุดจากเซตที่กรองในภายหลัง
Rhizome-Conifer/conifer เป็นเคสกำกวม และตอนแรกผมอ่านผิด default branch ของมันคือ main ไม่ใช่ master และ main เงียบมาตั้งแต่ 2023-10-12 — event เดียวที่เกิดบน main ใน feed คือการ สร้างสาขา ในเดือนมกราคม 2025 ซึ่งสอดคล้องกับการเปลี่ยนชื่อสาขา ขณะเดียวกันมีบัญชีเดียวที่ push ไปที่ conifer-twilight และ twilight/read-only เมื่อ 2026-07-22 ซึ่งคือ 5 วันก่อนวันที่อ้างอิง นั่นคือกิจกรรมของมนุษย์จริง แต่คำว่า “ยังมีการพัฒนาอยู่” ก็ยังแรงเกินกว่าหลักฐานที่ ref เหล่านี้บอก สิ่งที่พูดได้แน่และยังคุ้มจะพูดคือ: ช่องว่าง 1,013 วันนี้ไม่ใช่เสียงบอท และก็ยังไม่ใช่หลักฐานว่าถูกทิ้งร้างด้วยเช่นกัน
ไม่ทราบสาเหตุ: 7 ราย php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull และ crawler4j ต่างก็มีช่องว่างที่ยืนยันได้ แต่ activity feed กลับ ว่างเปล่า
คำอธิบายที่ชวนให้เชื่อที่สุดคือการเก็บข้อมูลย้อนหลังของ GitHub activity feed อาจไม่ยาวพอ แต่แคชข้อมูลขัดแย้งกับข้อสันนิษฐานนี้ในหลายกรณี เหตุการณ์ที่เก่าที่สุดใน response ทั้ง 123 ชุดคือ 2023-03-10 และใน 7 รายนี้มี 5 ตัวที่ pushed_at อยู่ภายในช่วงเวลาดังกล่าวอย่างสบาย ๆ: php-html-parser 2024-08-09, wpull 2024-04-29, waybackurls 2024-05-01, internetarchive/wayback 2024-03-01, simhash-py 2023-05-15 ไม่ว่าอะไรจะเป็นตัวผลักเวลาเหล่านี้ มันควรจะอยู่ใน feed แต่กลับไม่อยู่ การเก็บข้อมูลย้อนหลังอธิบายได้แค่ boilerpipe (2018) และ crawler4j (2021) เท่านั้น
ดังนั้นถ้าจะพูดอย่างซื่อสัตย์ คำอธิบายที่เหลืออยู่บางกว่าคำสรุปสวย ๆ มาก: สำหรับ 7 รีโปนี้ ช่องว่างเป็นข้อเท็จจริงที่ยืนยันได้ แต่สาเหตุยังไม่ถูกพิสูจน์ — endpoint ไม่ส่งอะไรกลับมาเลย และสำหรับ 5 ราย ผมบอกไม่ได้ว่าทำไม “dependabot ทำ” เป็นเพียงข้อสันนิษฐานสำหรับทั้ง 7 ราย
เมื่อนับรวมจาก 14 รีโปที่ถูกตั้งธง:
สาเหตุของ pushed_at ที่ดูใหม่เกินจริง | รีโป | รายชื่อ และหลักฐานที่ใช้ |
|---|---|---|
| ยืนยันว่าเกิดจากบอท | 3 | scrapinghub/splash (4 จาก 4 post-commit events อยู่บน dependabot/pip/*), geziyor/geziyor (5 จาก 5 อยู่บน dependabot/go_modules/*), apache/any23 (16 จาก 16 อยู่บน dependabot/maven/*) — any23 ถูก archived จึงเหลือ 2 ราย ที่ผ่านเงื่อนไขอื่นครบ |
| ผสมกัน ทั้งบอทและมนุษย์ | 2 | crawlab-team/crawlab (มีทั้งสาขา dependabot และ 24 ครั้งที่มนุษย์ push หลังคอมมิต ไปที่ develop และ test), sjdirect/abot (push ที่ทำให้หัวเรื่อง pushed_at มาจาก dependabot จริง แต่มีมนุษย์ push upgrade1 ในปี 2024) |
| ผิดชัดเจน — งานของมนุษย์ ไม่มีสาขาบอทเลย | 2 | dragnet-org/dragnet (3 event หลังคอมมิต, 0 รายการบนสาขาบอท) — มนุษย์ push mp/py3.10 ซึ่งเป็นพอร์ต Python 3.10 ที่ยังไม่ merge Rhizome-Conifer/conifer (30 event หลังคอมมิต, 0 รายการบนสาขาบอท) — บัญชีเดียว push ไปที่ conifer-twilight และ twilight/read-only เมื่อ 2026-07-22 ส่วนจะ “ถูกทิ้งร้าง” หรือไม่ยังคลุมเครือดังที่บอกไว้ด้านบน แต่สิ่งที่ไม่คลุมเครือคือไม่มีบอทดัน pushed_at |
| ยังพิสูจน์ไม่ได้ — activity feed ว่าง | 7 | php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull, crawler4j |
ผลรวมแถวได้ 14 พอดี แต่ละแถวบอกว่าอะไรเป็นตัวขยับ pushed_at ไม่ได้ยืนยันแยกเดี่ยว ๆ ว่าโปรเจ็กต์ถูกทิ้งร้างหรือไม่
อะไรที่รอดจากฟิลเตอร์ทั้งหมด และคำว่า “รอด” หมายถึงอะไร
ข้อกล่าวหาเดิมต้องมี 4 อย่างพร้อมกัน: ล้าสมัยเกินหนึ่งปี, pushed_at ดูใหม่เกินจริงเกิน 180 วัน, ไม่ถูก archive, และไม่มีสัญญาณว่าความใหม่เกิดจากงานของมนุษย์ มี 9 จาก 35 ตัวที่ผ่านครบทั้งสี่ข้อ และนี่คือรายชื่อ พร้อมข้อยกเว้นที่สำคัญที่สุด 2 ราย:
| รีโป | ผ่านครบทั้งสี่ข้อ? | หลักฐานเชิงบวกว่าบอทเป็นตัวทำให้ค่าพอง |
|---|---|---|
splash | ใช่ | ใช่ — 4 จาก 4 post-commit events อยู่บน dependabot/pip/* |
waybackurls | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
crawler4j | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
geziyor | ใช่ | ใช่ — 5 จาก 5 อยู่บน dependabot/go_modules/* |
php-html-parser | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
boilerpipe | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
wpull | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
internetarchive/wayback | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
simhash-py | ใช่ | ไม่มีหลักฐานทั้งสองทาง |
any23 | ไม่ใช่ — archived | ใช่ — 16 จาก 16 อยู่บน dependabot/maven/* ซึ่งเป็นการยืนยันที่แรงที่สุดในทั้งออดิท |
abot | ไม่ใช่ — ในเรคคอร์ดมีการ push ของมนุษย์ (upgrade1, 2024) | ผสมกัน — push ที่ทำให้หัวเรื่อง pushed_at ดูใหม่มาจาก dependabot จริง |
ตัวเลขนี้ต้องมีคำอธิบายกำกับที่ฟิลเตอร์ใส่ลงไปไม่ได้ มีเพียง 2 จาก 9 — splash และ geziyor — ที่มีหลักฐานเชิงบวกว่าบอทเป็นคนดันค่าพอง อีก 7 ตัวผ่านเงื่อนไขข้อที่สี่เพราะไม่มีหลักฐานไปทางใดทางหนึ่ง พวกมันเป็นเคสที่ข้อกล่าวหา “ยังรอดอยู่” ไม่ใช่เคสที่พิสูจน์ข้อกล่าวหานั้น และกรณี any23 ซึ่งเป็นการยืนยันที่แรงที่สุดในทั้งออดิทที่ 16 จาก 16 dependabot events กลับถูกตัดออกเพราะรีโปถูก archived
สังเกตด้วยว่า abot เคสห่าง 1,802 วัน ไม่ได้ อยู่ใน 9 ตัวนั้น เพราะในเรคคอร์ดมี human push อยู่ ทำให้มันไม่ผ่านเงื่อนไขข้อที่สี่ — ภาพลวงตาที่อลังการที่สุดในชุดข้อมูลกลับไม่ใช่ตัวอย่างบริสุทธิ์ของกลไกที่มันสื่อ
สำหรับ 21 จาก 35 GitHub บอกความล้าสมัยตรงไปตรงมา
นี่คือข้อค้นพบที่ทำลายสมมติฐานของผมมากที่สุด 14 รีโปมีช่องว่างเป็นศูนย์พอดี และอีก 7 ตัวอยู่ต่ำกว่า 180 วัน สำหรับ 21 จาก 35 ตัว pushed_at ก็คือคอมมิตล่าสุดบน default branch จริง ๆ GitHub ไม่ได้ปิดบังอะไร
รวมตัวที่ดูเหมือนตายที่สุดไว้ด้วย:
| รีโป | ดาว | ความล้าสมัย (วัน) | ช่องว่าง |
|---|---|---|---|
Janpot/microdata-node | 57 | 1,866 | 0 |
1e0ng/simhash | 1,037 | 1,606 | 21 |
ekzhu/SetSimilaritySearch | 603 | 1,384 | 0 |
GerbenJavado/LinkFinder | 4,431 | 834 | 0 |
hakluke/hakrawler | 5,099 | 582 | 0 |
lavague-ai/LaVague | 6,388 | 551 | 0 |
my8100/scrapydweb | 3,411 | 522 | 0 |
getomni-ai/zerox | 12,258 | 432 | 0 |
scrapinghub/frontera | 1,332 | 415 | 0 |
BuilderIO/gpt-crawler | 22,374 | 384 | 0 |
BuilderIO/gpt-crawler มี 22,374 ดาว และหัวหน้าเพจบอกแบบเดิมมาตั้งแต่ 2025-07-07 ไม่มีอะไรถูกปกปิด และจำนวนการติดตั้งยังคงเกิดขึ้นต่อไป
นั่นบังคับให้ข้อกล่าวหาลดรูปลงเหลือเรื่องที่แคบกว่า: GitHub ทำให้มองความล้าสมัยไม่ชัดในส่วนน้อยของกรณี แต่ในส่วนใหญ่กลับบอกตรง ๆ ขณะเดียวกันการติดตั้งยังดำเนินต่อไป สาเหตุที่ติดตั้งต่อคือสิ่งที่ข้อมูลชุดนี้ตอบไม่ได้ — ตัวเลขที่นี่นับจำนวนการติดตั้ง ไม่ได้นับการตัดสินใจ แต่การเปลี่ยน UI ก็ไม่ได้แก้กลุ่มหลัง ซึ่งเป็นกลุ่มที่ใหญ่กว่า
ความเคลื่อนไหวของรีโปกับอาร์ติแฟกต์ที่เผยแพร่ อาจไม่ไปทางเดียวกัน
แถวที่เด่นที่สุดในชุดข้อมูลทำลายกรอบความคิดเดิมไปเลย
codelucas/newspaper — 15,126 ดาว — ยัง active อยู่ คอมมิตล่าสุดบน default branch อยู่วันที่ 2026-07-21 เมื่อเทียบกับวันที่อ้างอิง 2026-07-27 และเป็นคอมมิตของผู้ดูแลโครงการ ทุกการตรวจระดับรีโปผ่านหมด
แพ็กเกจที่ทุกคนติดตั้งคือ newspaper3k 0.2.8 ซึ่งเผยแพร่เมื่อ 2018-09-28 — เก่าไป 2,858 วัน — แต่ยังมียอดดาวน์โหลด 813,513 ครั้งต่อเดือน
default branch ยังใหม่ แต่ artifact บน PyPI ไม่ได้ปล่อยเวอร์ชันใหม่มาตั้งแต่ปี 2018 สิ่งนี้พิสูจน์ได้ว่า release มีช่องว่าง ไม่ได้บอกว่าทำไมแพ็กเกจถึงไม่ปล่อย หรือ pipeline เสียหรือไม่ และนี่คือความเสี่ยงแบบที่การเช็กจากรีโปอย่างเดียวจะมองไม่เห็น เพราะสิ่งที่ pip install newspaper3k ดึงไปใช้จริงคือ registry artifact
พอมองแพ็กเกจแทนรีโป รูปแบบนี้ก็โผล่เต็มไปหมด ใน 17 แพ็กเกจที่ยืนยันการจับคู่กับรีโปแล้ว 16 ตัวมีการปล่อยเวอร์ชันล่าสุดนานเกินหนึ่งปี และ 16 ตัวนั้นคิดเป็นราว 2.28 ล้านการติดตั้งต่อเดือน จากทั้งหมด 2.30 ล้าน:
| แพ็กเกจ | ติดตั้ง/เดือน | เผยแพร่ล่าสุด | อายุแพ็กเกจ (วัน) |
|---|---|---|---|
newspaper3k | 813,513 | 2018-09-28 | 2,858 |
tls-client | 790,305 | 2024-02-02 | 905 |
simhash | 317,615 | 2022-03-03 | 1,606 |
microdata-node | 204,025 | 2020-05-11 | 2,267 |
@modelcontextprotocol/server-puppeteer | 127,232 | 2025-05-12 | 440 |
extract-thinker | 10,927 | 2025-06-09 | 412 |
SetSimilaritySearch | 7,984 | 2022-10-11 | 1,384 |
frontera | 4,709 | 2019-04-05 | 2,669 |
zerox | 3,303 | 2025-05-20 | 432 |
scrapydweb | 1,163 | 2025-02-16 | 525 |
lavague | 606 | 2024-08-05 | 720 |
splash | 333 | 2020-06-16 | 2,231 |
dragnet | 213 | 2019-04-16 | 2,658 |
@builder.io/gpt-crawler | 137 | 2025-01-23 | 549 |
lmnr-index | 120 | 2025-06-05 | 416 |
simhash-py | 113 | 2017-03-22 | 3,413 |
tls-client สมควรได้บรรทัดของตัวเอง: 790,305 installs ต่อเดือน จากรีโปที่เงียบมา 905 วัน ในหมวดที่การอัปเดตให้ทันคือหน้าที่หลักทั้งหมดของเครื่องมือ ตัวอย่าง TLS ของเบราว์เซอร์เปลี่ยนตลอดเวลา ไลบรารีที่หยุดตามตั้งแต่ต้นปี 2024 ก็เลยทำงานอยู่บนสมมติฐานของต้นปี 2024
มีข้อควรระวังสองข้อกับตารางนี้ ตัวเลขดาวน์โหลดจาก registry รวมทั้ง CI, mirror และไม่ได้ตัดซ้ำอะไรเลย ดังนั้นมันคือปริมาณการติดตั้ง ไม่ใช่คนใช้ และหน้าต่างเวลาที่ใช้ก็ไม่ได้จบวันเดียวกัน — ของ npm ใกล้ 2026-07-24 ส่วน pypistats อิงเวลาตอนดึงข้อมูล — ดังนั้นยอดรวมจึงเป็นผลรวมของช่วงเวลาที่เหลื่อมกันเล็กน้อย และควรอ่านว่า “ประมาณ 2.28 ล้าน” ไม่ใช่ตัวเลขเป๊ะ ๆ ถึงหลักสุดท้าย
ชื่อที่ชนกันซึ่งควรรู้ไว้
internetarchive/wayback คือ Java OpenWayback ที่ตายแล้ว เงียบมา 1,916 วัน ส่วน wayback บน PyPI เป็น คนละโปรเจ็กต์กันทั้งหมด — edgi-govdata-archiving/wayback — และยังแข็งแรงดี โดยปล่อย 0.5.1 เมื่อ 2026-06-19 ห้าสัปดาห์ก่อนวันที่อ้างอิง ชื่อเหมือนกัน แต่สถานะตรงกันข้าม และไม่เกี่ยวข้องกันเลย นี่เป็นหนึ่งใน 6 การจับคู่ที่ถูกปฏิเสธ และเป็นกรณีที่มีโอกาสทำให้ผู้ใช้จริงพลาดได้มากที่สุด: ค้นชื่อเดียวกันจะเจอทั้งคู่ แต่บนหน้าใดก็ตามไม่ได้บอกเลยว่าคุณเจออันไหน
ยังติดตั้งอยู่ 127,232 ครั้งต่อเดือน แม้ถูก archived และ deprecated
มี 6 รีโปในตัวอย่างที่มี archived: true ซึ่ง GitHub แสดงเป็นแถบเต็มหน้ากว้าง ตอนแรกผมคิดว่านี่พิสูจน์ว่าคนเมินคำเตือนที่แสดงออกโต้ง ๆ แต่แคชข้อมูลบอกว่าความจริงแย่กว่านั้น
อ้างอิงทางการ: npm download-count API documentation.
อ้างอิงทางการ: npm's deprecation documentation.
@modelcontextprotocol/server-puppeteer มียอดติดตั้ง 127,232 ครั้งต่อเดือน มาจาก modelcontextprotocol/servers-archived แต่ฟิลด์ repository บน npm ของมันเป็น null — ไม่มีลิงก์จากหน้าแพ็กเกจกลับไปยังรีโป ดังนั้นแถบ archived ไม่ใช่สิ่งที่คนติดตั้งจะข้ามไปเจอได้จริง คนส่วนใหญ่ที่ดึงแพ็กเกจนี้จึงแทบไม่มีทางไปเห็นรีโปต้นทางตั้งแต่แรก
สิ่งที่ npm ประกาศจริง ๆ คือสถานะ deprecated เวอร์ชันล่าสุดของแพ็กเกจมี deprecated: "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." ซึ่ง npm จะแสดงในเทอร์มินัลตอนติดตั้ง ดังนั้นคำเตือนถูกส่งถึงที่ที่ผู้ใช้ใช้งานอยู่จริง แต่ก็ยังมีการติดตั้งต่อไปอีก 127,232 ครั้งต่อเดือน นี่เป็นข้อค้นพบที่แรงกว่าเรื่องแถบ banner และชี้ไปคนละจุด: สัญญาณไม่ได้หายไป แต่ถูกส่งเข้าไปในกองข้อความระหว่างติดตั้งที่ไม่มีอะไรบังคับให้คนอ่าน
browserbase/mcp-server-browserbase แสดงภาพของการปิดโปรเจ็กต์แบบชัดเจน: คอมมิตสุดท้ายบน default branch เมื่อ 2026-07-20 มีข้อความตรงตัวว่า "Mark repository as archived and unmaintained (#198)" ผู้ดูแลโครงการประกาศไว้ ลงวันที่ไว้ และติดธงใน API แล้ว การติดตั้ง 20,389 ครั้งของมันควรอ่านอย่างระมัดระวัง เพราะหน้าต่างเวลาของ npm คือ 2026-06-25 ถึง 2026-07-24 ดังนั้น 26 จาก 30 วันนั้นเกิดขึ้นก่อนคอมมิตที่ประกาศ archived ตัวเลขนี้จึงเป็นความต้องการก่อนประกาศเป็นส่วนใหญ่ ไม่ใช่การเมินคำเตือนว่าเกิดขึ้นหลังจากนั้น สิ่งที่จะเกิดต่อจากนี้ยังบอกไม่ได้จากสแนปช็อตนี้ และผมอยากดูซ้ำอีกครั้งในอีกหนึ่งเดือนก่อนจะสรุปอะไร
57 ดาว, 204,025 installs ต่อเดือน
Janpot/microdata-node มี 57 ดาว แต่กลับมียอดดาวน์โหลด 204,025 ครั้งต่อเดือน จาก release วันที่ 2020-05-11
เมื่อเทียบกับปริมาณใน registry แล้ว microdata-node มีตัวตนบนรีโปน้อยมาก อัตราส่วนการติดตั้งต่อดาว 3,579 ต่อ 1 สอดคล้องกับการถูกใช้ผ่าน dependency อื่น, การรันใน CI ซ้ำ ๆ, mirror หรือการที่เครื่องดึงไปใช้โดยตรง ออดิทนี้ไม่ได้ดึง dependency graph มา และจึงเลือกคำอธิบายใดคำอธิบายหนึ่งไม่ได้
แถวนี้เป็นสัญญาณให้ตรวจว่ามีการใช้งานทางอ้อมหรือไม่ แต่การพิสูจน์ transitive use ต้องใช้ reverse dependency หรือ lockfile evidence ซึ่งออดิทนี้ไม่ได้เก็บมา
ล้าสมัย ไม่ได้แปลว่าเสีย
ออดิทที่ซื่อสัตย์ต้องพูดให้ชัดว่า ทั้งหมดนี้ไม่ได้วัดว่าอะไรพังอยู่หรือไม่ มันวัดว่าใครยังอยู่หรือเปล่า
บางตัวก็แค่เสร็จงานแล้วจริง ๆ SetSimilaritySearch ใช้อัลกอริทึมความคล้ายกันของเซต ซึ่งไม่ได้เสื่อมตามเวลา simhash คือกระดาษวิชาการปี 2007 และอัลกอริทึมดึงเนื้อหาของ boilerpipe ทำงานในปี 2026 แบบเดียวกับปี 2015 — ไม่ว่าวันนี้จะอ่านหน้าเว็บยุคใหม่ได้แม่นแค่ไหน โค้ดมันก็ไม่ได้ไถลหายไปใต้เท้าคุณ
สิ่งที่เสื่อมคือทุกอย่างที่ฝั่งปลายทางมันขยับอยู่ตลอด:
- Browser automation — Chrome ออกเวอร์ชันใหม่ทีไรก็พังได้
- HTTP client ที่เลียนแบบพฤติกรรมเบราว์เซอร์ — เบราว์เซอร์เปลี่ยน แล้วไลบรารีที่ค้างอยู่ก็ไม่เหมือนของจริงอีกต่อไป;
tls-clientอยู่ในหมวดนี้ - parser เฉพาะเว็บไซต์และกฎดึงข้อมูลรายเว็บ — เว็บรีดีไซน์แต่ละครั้งคือบั๊ก
- อะไรก็ตามที่ครอบ third-party API — ผู้ให้บริการเปลี่ยน schema แล้วคุณจะรู้ตอน production
- อะไรก็ตามที่ครอบ LLM — deprecation ของโมเดลมาเร็วกว่าสิ่งอื่นในรายการนี้ทั้งหมด
ดังนั้น “ล้าสมัย 1,606 วัน” จึงเป็นเหตุฉุกเฉินสำหรับบางหมวด แต่แทบไม่เกี่ยวอะไรกับยูทิลิตีแฮชบางชนิด การทดสอบการพังไม่ได้ถูกทำที่นี่ และไม่มีการอ้างว่าเคยทดสอบ การจัดกลุ่ม dependency ของคุณเองตามหมวดที่มันอยู่แทบไม่เสียค่าใช้จ่าย และช่วยได้มากกว่าดูแค่ตัวเลขความล้าสมัยอย่างเดียว
4 การตรวจที่ตอบคำถามจริง ๆ

ไม่มีข้อไหนคือ header ของรีโป
| # | การตรวจ | อ่านจากไหน | จับอะไรได้ |
|---|---|---|---|
| 1 | คอมมิตล่าสุดบน default branch | GET /repos/{owner}/{repo}/commits?sha={default_branch}&per_page=1 | ตัวเลขที่ไม่ได้แสดงให้คุณเห็น |
| 2 | ครั้งล่าสุดที่อาร์ติแฟกต์ถูกปล่อย | pypi.org/pypi/{pkg}/json หรือ registry.npmjs.org/{pkg} → เวอร์ชันล่าสุดและวันที่อัปโหลด | นี่แหละที่จับ newspaper3k ได้ ซึ่งข้อ 1 จับไม่ได้แน่ ๆ และระหว่างอ่านข้อมูลนี้ให้ดูฟิลด์ deprecated ของ npm ด้วย ซึ่งคือวิธีที่ @modelcontextprotocol/server-puppeteer ประกาศตัวเอง |
| 3 | ธง archived | ฟิลด์หนึ่งใน response ของ repo ชัดเจนและฟรี | แต่ช่วยได้ก็ต่อเมื่อคุณเข้าถึง repo ได้จริง ซึ่งแพ็กเกจที่ repository: null ไม่เปิดทางนั้นให้คุณ |
| 4 | ช่องว่างระหว่างข้อ 1 กับ 2 | — (คำนวณจากสองข้อข้างบน) | รีโปที่คอมมิตใหม่ แต่ออกรีลีสครั้งสุดท้ายเมื่อสามปีก่อน เป็นความล้มเหลวอีกแบบหนึ่งจากรีโปที่แค่เงียบเฉย ๆ: หมายความว่าผู้ดูแลยังอยู่ แต่ไม่ปล่อยของแล้ว นั่นคือการตัดสินใจที่ต้องดูให้ครบ ไม่ใช่สัญญาณแดงในตัวมันเอง กฎเดียวกันนี้ใช้ย้อนกลับกับ crawlab ด้วย: ต้องเช็กว่าการทำงานย้ายไปสาขาที่ไม่ใช่ default branch ก่อนจะสรุปอะไร |
ใช้การตรวจ 1, 2 และ 3 เป็นการคัดกรองด่วนก่อน แล้วค่อยไล่ต่อเมื่อ metadata ของรีโปไม่มี, การจับคู่แพ็กเกจกับรีโปคลุมเครือ, activity ย้ายไปสาขาที่ไม่ใช่ default branch, หรือ registry artifact แยกทางกับรีโป ข้อจำกัดของ GitHub แบบไม่ยืนยันตัวตนและความหน่วงของ registry ทำให้ไม่ควรสัญญาว่าจะได้คำตอบในหนึ่งวินาที
ถ้าการตรวจเจอของเก่าในหมวดที่เคลื่อนตัวเร็ว เครื่องมือทางเลือกแบบที่ยังดูแลอยู่ในพื้นที่นี้มีบันทึกไว้ในการทดสอบของเราเอง: Trafilatura สำหรับงานดึงเนื้อหาที่ dragnet และ boilerpipe เคยทำ, Scrapy หรือ Crawlee สำหรับเฟรมเวิร์ก crawl, Crawl4AI และ Firecrawl สำหรับงานดึงข้อมูลที่เน้น LLM, และ Scrapling ในจุดที่ความทนทานสำคัญ รายงาน open-source scraper pillar ของเราตามสภาพรวมของเครื่องมือสายนี้ไว้ด้วย ทั้งหมดนั้นเป็นรีวิวของเราเอง ดังนั้นควรวิ่ง 4 การตรวจนี้ด้วยตัวคุณเองก่อนเชื่อคำแนะนำใด ๆ รวมถึงของเราด้วย
ข้อจำกัดของข้อมูลชุดนี้
- การคัดเลือกตัวอย่าง เลือกมือมาเพราะสงสัยว่าจะถูกทิ้งร้าง ไม่ได้สุ่มมาจากทั้งระบบนิเวศ จึงอ่านเป็นอัตรารวมของทั้งวงการไม่ได้
- ไม่มีการทดสอบการพัง เครื่องมือทั้ง 35 ตัวนี้ไม่ได้ถูกนำไปรันบนเว็บจริง ความล้าสมัยคือสัญญาณด้านการดูแล ไม่ใช่คำตัดสินด้านการใช้งาน
- ตัวเลขดาวน์โหลดรวมเครื่องด้วย CI, mirror, ไม่มีการตัดซ้ำ และหน้าต่างเวลาที่ไม่จบวันเดียวกัน ตัวเลขคือปริมาณการติดตั้ง ไม่ใช่ผู้ใช้ และไม่ใช่การตัดสินใจ
- สาเหตุที่ไม่รู้ 7 ราย ยังไม่รู้ activity feed ไม่คืนอะไรกลับมา และใน 5 จาก 7 ราย การเก็บข้อมูลย้อนหลังไม่อธิบายได้ ปล่อยช่องว่างไว้ดีกว่าใส่คำเดายอดนิยมลงไป
staleness_daysใช้วันที่ของ committer ถ้าประวัติถูกเขียนใหม่หรือ backdate จะทำให้ตัวเลขเพี้ยน ไม่พบหลักฐานแบบนั้น แต่การไม่พบไม่ใช่สิ่งเดียวกับการไม่มี- อ้างอิง ณ วันเดียว 2026-07-27 รีโปหลายตัวคงเปลี่ยนไปแล้วตอนคุณอ่าน โดยเฉพาะ
newspaperที่คอมมิตสม่ำเสมอ รัน 4 การตรวจใหม่ อย่าอ้างวันที่ของผม
เมื่อบริการแบบ managed เปลี่ยนรูปแบบของความเสี่ยงนี้
ทุกการตรวจในบทความนี้มีอยู่ก็เพราะถ้าคุณใช้ไลบรารีที่โฮสต์เอง คุณเป็นเจ้าของความล้าสมัยนั้นเอง ถ้า HTTP client ที่ค้างเวอร์ชันเริ่มทำตัวไม่เหมือนเบราว์เซอร์ปัจจุบัน นั่นคือ incident ของคุณ ไม่ว่าจะโผล่มากลางวันหรือกลางคืน
หมายเหตุผู้เขียน: Thunderbit คือผลิตภัณฑ์สแครปปิงแบบ managed ของเรา บริการแบบ managed จะโยนภาระการดูแลบางส่วนไปให้ผู้ให้บริการ แต่ coverage, เวลาในการตอบสนอง, lock-in และความต่อเนื่องของผู้ให้บริการก็กลายเป็นส่วนหนึ่งของโมเดลความเสี่ยงด้วยเช่นกัน บทความออดิทรีโปนี้ไม่ได้ประเมิน Thunderbit
ข้อแลกเปลี่ยนที่ซื่อสัตย์คือ คุณสละสิทธิ์ในการอ่านซอร์สโค้ด ปักเวอร์ชัน และแก้เองตอนตีสอง สำหรับทีมที่ต้องดูแลสแครปเปอร์อยู่แล้ว เส้นทางโอเพนซอร์สมักเป็นตัวเลือกที่ถูกต้อง — และ 4 การตรวจนี้คือวิธีทำให้มันเป็น “การตัดสินใจ” ไม่ใช่ “การคาดเดา”
ลองใช้ Thunderbit สำหรับดึงข้อมูลเว็บ
สรุปสั้น ๆ
ผมสร้างลิสต์นี้ขึ้นมาเพื่อพิสูจน์ว่า GitHub ซ่อนการถูกทิ้งร้างไว้ แต่ภาพลวงตามีจริงใน 14 จาก 35 รีโป และเคสที่แรงที่สุดคือ sjdirect/abot ซึ่งแสดงว่าเพิ่งมีการ push สัปดาห์ที่แล้ว แต่ default branch ค้างมาตั้งแต่ปี 2021 ทำให้เกิดช่องว่าง 1,802 วัน
แต่กลไกนั้นแคบกว่าที่เรื่องเล่าบอกไว้ 9 รีโปผ่านครบทุกเงื่อนไขของข้อกล่าวหา และมีเพียง 2 จาก 9 — splash และ geziyor — ที่มีหลักฐานเชิงบวกว่าบอทเป็นคนทำให้ตัวเลขพอง ที่เหลือผ่านเพราะไม่มีหลักฐานยืนยันในทางใดทางหนึ่ง สองรีโปที่ถูกตั้งธงเป็นกรณีของมนุษย์พยายามฟื้นโปรเจ็กต์แล้วไม่สำเร็จ หนึ่งตัวคือ crawlab ที่มี 12,250 ดาวและเพียงย้ายการพัฒนาไป develop สำหรับอีก 7 ราย activity feed ว่าง และการเก็บข้อมูลย้อนหลังอธิบายไม่ได้ 5 ราย จึงต้องถือว่ายังพิสูจน์สาเหตุไม่ได้ มากกว่าเดาเอา และสำหรับ 21 จาก 35 รีโป GitHub บอกความล้าสมัยได้ตรงไปตรงมา
เคสที่แย่ที่สุดในชุดข้อมูลกลับผ่านการตรวจระดับรีโปทุกข้อ codelucas/newspaper ถูกคอมมิตเมื่อ 2026-07-21; newspaper3k ที่ปล่อยล่าสุดเมื่อ 2018-09-28 ยังถูกติดตั้ง 813,513 ครั้ง ในเดือนนั้น ในทั้งตัวอย่างนี้ 16 แพ็กเกจที่มี release เก่าเกินหนึ่งปีคิดเป็นราว 2.28 ล้านการติดตั้งต่อเดือน
เริ่มจากตรวจวันที่คอมมิตบน default branch, วันที่ปล่อยเวอร์ชันใน registry, ธง archived และฟิลด์ deprecation ของ npm ก่อนเสมอ จากนั้นค่อยตรวจการระบุแพ็กเกจ-รีโป และการพัฒนาในสาขาที่ไม่ใช่ default branch ก่อนสรุปผล
ลองใช้ Thunderbit สำหรับดึงข้อมูลเว็บ Get Started Free
คำถามที่พบบ่อย
pushed_at คืออะไร และทำไมไม่ควรแปลว่า “อัปเดตล่าสุด”?
pushed_at คือฟิลด์ของ GitHub API ที่อยู่เบื้องหลังเวลา activity บนหน้ารีโป และมันจะรีเฟรชเมื่อมีการ push เข้าไปที่สาขาใดก็ตาม คอมมิตล่าสุดบน default branch เป็นเพียงสัญญาณด้านการดูแลรีโปหนึ่งแบบ ขณะที่ package manager ปกติจะติดตั้งอาร์ติแฟกต์จาก registry หรือเวอร์ชันโมดูลที่ resolve แล้ว ในออดิทนี้ 14 จาก 35 รีโปมีวันที่ของ GitHub สองค่านี้ห่างกันเกิน 180 วัน
มันคือ dependabot เสมอไปไหมที่ดันตัวเลขนี้ให้ดูใหม่?
ไม่ใช่ และนี่กลายเป็นจุดที่อ่อนที่สุดของเรื่องเล่าทั่ว ๆ ไป ถ้านับเฉพาะ event ที่เกิด หลัง คอมมิตล่าสุดบน default branch จะยืนยันได้ว่าเป็นบอทใน 3 จาก 14 รีโปที่ถูกตั้งธง (splash 4 จาก 4, geziyor 5 จาก 5, any23 16 จาก 16) อีก 2 รายผิดชัดเจน: ช่องว่างของ dragnet มาจากมนุษย์ที่ push พอร์ต Python 3.10 ที่ยังไม่ merge อีก 2 รายเป็นแบบผสม รวมถึง crawlab ที่มี human push 24 ครั้งไปที่ develop และ test ขณะที่ main แทบไม่ขยับ และสำหรับอีก 7 ราย activity feed ไม่คืนอะไรกลับมาเลย จึงยังพิสูจน์สาเหตุไม่ได้ — การเก็บข้อมูลย้อนหลังอธิบายได้แค่ 2 จาก 7 รายเท่านั้น
รีโปที่ล้าสมัยแปลว่าเครื่องมือเสียเสมอไปไหม?
ไม่ใช่จากหลักฐานในชุดนี้ — ไม่มีตัวไหนถูกเอาไปรันบนเว็บจริง ความล้าสมัยมีความสำคัญตามความเร็วของเป้าหมาย: browser automation, HTTP client ที่เลียนแบบเบราว์เซอร์, parser เฉพาะเว็บ และ wrapper ของ API/LLM เสื่อมเร็ว ขณะที่ไลบรารีเชิงอัลกอริทึมอย่าง SetSimilaritySearch หรือ simhash อาจเก่าเป็นปี ๆ แล้วยังใช้ได้ดี tls-client คือเคสที่คมที่สุดในตัวอย่างนี้ ด้วย 790,305 installs ต่อเดือนจากรีโปที่เงียบ 905 วัน
รีโปอาจ active แต่แพ็กเกจข้างในยังตายอยู่ได้อย่างไร?
นั่นคือ codelucas/newspaper และเป็นสิ่งที่ออดิทนี้พบว่ามีผลกระทบมากที่สุด default branch ของมันถูกคอมมิตเมื่อ 2026-07-21 ไม่กี่วันก่อนวันที่อ้างอิง แต่ newspaper3k บน PyPI ปล่อยล่าสุดเป็น 0.2.8 เมื่อ 2018-09-28 — ห่างกัน 2,858 วัน — และยังถูกดาวน์โหลด 813,513 ครั้งต่อเดือน การตรวจระดับรีโปผ่านหมด แต่อาร์ติแฟกต์ที่คุณติดตั้งอยู่เก่าแปดปีเสมอ เช็กวันที่เผยแพร่ล่าสุดของ registry แยกจาก commit log ทุกครั้ง
รีโป archived ช่วยแก้ปัญหานี้ไหม? GitHub แสดงแบนเนอร์อยู่แล้ว
ไม่เสมอไป และ @modelcontextprotocol/server-puppeteer คือเหตุผล repository บน npm ของมันเป็น null จึงไม่มีลิงก์จากแพ็กเกจไปยังรีโป archived และไม่มีแบนเนอร์ให้ข้ามด้วยซ้ำ สิ่งที่ npm ส่งให้จริง ๆ คือสตริง deprecated ของแพ็กเกจ — "Package no longer supported" — ที่พิมพ์ตอนติดตั้ง และยังมีการติดตั้ง 127,232 ครั้งต่อเดือน ผ่านข้อความนั้นไป browserbase/mcp-server-browserbase ประกาศปิดตัวอย่างชัดเจนในคอมมิตสุดท้าย ส่วนยอดติดตั้ง 20,389 ครั้งของมันส่วนใหญ่เกิดก่อนคอมมิตนั้น จึงบอกอะไรได้ไม่มากทั้งสองทาง
จะเช็ก dependency ของตัวเองอย่างรวดเร็วได้อย่างไร?
เริ่มจากวันที่คอมมิตบน default branch, วันที่ปล่อยเวอร์ชัน/อัปโหลดใน registry, ฟิลด์ deprecation ของ npm และธง archived ของรีโป จากนั้นยืนยันการจับคู่แพ็กเกจ-รีโป ตรวจสาขาที่ไม่ใช่ default branch เมื่อ activity ไม่ตรงกัน และใช้ dependency graph หรือ lockfile ก่อนจะบอกว่าการพึ่งพานั้นเป็นทางอ้อม ชื่อที่ชนกัน เช่น โปรเจ็กต์ wayback ของ Java กับ PyPI ที่ไม่เกี่ยวกัน ยิ่งทำให้การไล่ระดับตรวจแบบนี้จำเป็น


