diff --git a/wizard-work/ledger/python_org_repos_top50.csv b/wizard-work/ledger/python_org_repos_top50.csv new file mode 100644 index 0000000..7ed8e7a --- /dev/null +++ b/wizard-work/ledger/python_org_repos_top50.csv @@ -0,0 +1,51 @@ +rank,repo,owner,description,language,stars,forks,open_issues,updated_at +1,cpython,python,The Python programming language,Python,77750,38313,9417,2026-10-23T06:26:43Z +2,mypy,python,Optional static typing for Python,Python,20695,3347,3224,2026-10-23T00:30:27Z +3,typeshed,python,"Collection of library stubs for Python, with static types",Python,5135,2113,407,2026-10-23T04:08:08Z +4,peps,python,Python Enhancement Proposals,reStructuredText,5029,1819,63,2026-10-22T15:59:15Z +5,devguide,python,The Python developer's guide,Python,2112,1060,105,2026-10-23T06:24:34Z +6,typing,python,Python static typing home. Hosts the documentation and a user help forum.,Python,1785,303,231,2026-10-23T00:57:03Z +7,pythondotorg,python,Source code for python.org,Python,1667,708,22,2026-10-21T15:40:07Z +8,asyncio,python,asyncio historical repository,,1083,179,86,2026-10-23T02:29:41Z +9,pyperformance,python,Python Performance Benchmark Suite,Python,1041,205,76,2026-10-22T02:11:40Z +10,typing_extensions,python,Backported and experimental type hints for Python,Python,590,152,23,2026-10-20T21:17:15Z +11,python-docs-zh-cn,python,Simplified Chinese translation of the Python documentation,,468,106,6,2026-10-19T11:28:05Z +12,python-docs-es,python,Spanish translation of the Python documentation.,Python,373,414,441,2026-10-20T14:22:42Z +13,pymanager,python,The Python Install Manager (for Windows),Python,358,74,30,2026-10-23T05:42:17Z +14,python-docs-fr,python,Mirroir de https://git.afpy.org/AFPy/python-docs-fr,,355,255,1,2026-10-17T12:23:33Z +15,python-docs-zh-tw,python,Traditional Chinese (zh-tw) translation of the Python Documentation,Python,285,228,44,2026-10-15T20:32:21Z +16,typed_ast,python,Modified fork of CPython's ast module that parses `# type:` comments,C,234,52,1,2026-08-27T10:32:57Z +17,raspberryio,python,Source code for raspberry.io,Python,229,37,19,2026-08-27T10:32:52Z +18,steering-council,python,Communications from the Steering Council,Makefile,182,35,11,2026-10-21T20:51:35Z +19,python-docs-pt-br,python,Brazilian Portuguese translation of the Python Documentation,Python,165,42,17,2026-10-17T19:08:22Z +20,mypy_extensions,python,Extensions for mypy,Python,155,41,8,2026-08-29T16:07:41Z +21,planet,python,Configuration for Python planets,Python,144,197,33,2026-08-27T10:32:26Z +22,importlib_metadata,python,Library to access metadata for Python packages,Python,142,100,17,2026-10-22T22:43:48Z +23,bedevere,python,A bot to help identify missing information for CPython pull requests,Python,140,64,15,2026-10-21T18:37:46Z +24,python-docs-tr,python,Turkish Translation of the Python Documentation,Python,128,47,34,2026-10-12T09:06:41Z +25,psf-salt,python,PSF infrastructure configuration,Hurl,125,68,44,2026-10-22T14:49:24Z +26,tzdata,python,Python package wrapping the IANA time zone database,Python,121,27,6,2026-10-20T17:43:29Z +27,pycon-code-of-conduct,python,pycon code of conduct,,119,91,7,2026-10-02T15:15:25Z +28,miss-islington,python,πŸπŸ’β›πŸ€– - A bot for backporting and merging CPython pull requests,Python,116,43,4,2026-10-21T13:44:06Z +29,pythoncapi-compat,python,The pythoncapi-compat project can be used to write a C extension supporting a wide range of Python versions with a single code base.,C++,112,41,2,2026-10-16T08:08:12Z +30,core-workflow,python,Issue tracker for CPython's workflow,Python,104,57,9,2026-08-27T10:32:09Z +31,python-docs-fa,python,Farsi (Persian) translation of the official Python documentation,Python,104,19,11,2026-10-23T05:29:32Z +32,python-docs-theme,python,Sphinx theme for Python documentation,CSS,91,79,13,2026-10-17T08:27:16Z +33,the-knights-who-say-ni,python,CLA enforcement bot for Python organization projects,Python,86,33,0,2026-09-18T23:32:31Z +34,docsbuild-scripts,python,Scripts for building the documentation on docs.python.org,Python,84,70,8,2026-10-22T12:36:08Z +35,python-docs-id,python,Terjemahan Bahasa Indonesia untuk Dokumentasi Python,Python,82,26,5,2026-10-22T00:27:22Z +36,python-docs-ko,python,Korean translation of the Python documentation,,78,56,378,2026-10-14T08:40:48Z +37,python-docs-ja,python,Japanese Translation of the Python Documentation,Python,75,38,1,2026-10-21T10:05:59Z +38,importlib_resources,python,Backport of the importlib.resources module,Python,74,51,10,2026-10-21T20:41:18Z +39,cherry-picker,python,πŸπŸ’β› Utility script for backporting/cherry-picking CPython changes from master into one of the maintenance branches.,Python,66,47,13,2026-10-06T18:00:06Z +40,release-tools,python,Scripts for making (C)Python releases,Python,64,48,26,2026-10-22T20:47:47Z +41,buildmaster-config,python,Configuration for buildbot.python.org,Python,61,62,10,2026-10-21T21:49:41Z +42,python-docs-pl,python,Polskie tΕ‚umaczenie dokumentacji Pythona,Python,60,16,6,2026-10-22T10:26:03Z +43,typing-council,python,Decisions by the Python Typing Council,,57,2,4,2026-10-15T14:13:32Z +44,docs-community,python,Community management for documentation contributors and the Docs Workgroup,Makefile,55,28,22,2026-10-09T20:31:08Z +45,community-starter-kit,python,Collection of resources for Python community organizers,Python,52,22,3,2026-09-09T01:53:00Z +46,psf-chef,python,Chef configuration and cookbooks for the Python Software Foundation,Ruby,47,33,1,2026-08-27T10:32:28Z +47,getpython3.com,python,getpython3.com page and resources.,CSS,46,14,8,2026-09-07T02:12:33Z +48,codespeed,python,A fork of Codespeed that includes the instances run at https://speed.python.org/ and https://speed.pypy.org,Python,40,21,11,2026-08-27T10:32:06Z +49,blurb_it,python,`blurb add` over the internet,Python,33,22,9,2026-10-22T01:00:02Z +50,prebuilt-cpython,python,Repository for discussing/planning prebuilt binaries of CPython,Python,33,9,5,2026-10-22T23:57:44Z diff --git a/wizard-work/ledger/verify_python_org_repos.py b/wizard-work/ledger/verify_python_org_repos.py new file mode 100644 index 0000000..da60445 --- /dev/null +++ b/wizard-work/ledger/verify_python_org_repos.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Verify the finished GitHub `python` org repos table (evidence test). + +Input: /root/.hermes/wizard-outputs/ledger/python_org_repos_top50.csv +Output: PASS line + exit 0, or FAIL + exit 1. + +Checks: + A. Schema/handshake of the stored CSV (exact header, 50 rows, unique + repo names, ranks 1..50, integer counts >= 0, stars non-increasing). + B. Stored top-50 equals a fresh fetch of the live GitHub API + (independent source provenance, not the extractor's own output). +""" +import csv +import json +import sys +import urllib.request + +CSV_PATH = "/root/.hermes/wizard-outputs/ledger/python_org_repos_top50.csv" +ORG = "python" +PER_PAGE = 100 +N_TOP = 50 +EXPECTED_HEADER = ["rank", "repo", "owner", "description", "language", + "stars", "forks", "open_issues", "updated_at"] +HEADERS = { + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "ledger-verify-python-org-repos/1.0", +} + + +def fetch_repos(): + page, all_repos = 1, [] + while True: + url = "https://api.github.com/orgs/%s/repos?per_page=%d&page=%d" % (ORG, PER_PAGE, page) + req = urllib.request.Request(url, headers=HEADERS) + with urllib.request.urlopen(req, timeout=30) as r: + all_repos.extend(json.loads(r.read())) + link = r.getheader("Link") or "" + if 'rel="next"' not in link: + break + page += 1 + return all_repos + + +def main(): + try: + with open(CSV_PATH, newline="", encoding="utf-8") as f: + reader = csv.DictReader(f) + header = reader.fieldnames + rows = list(reader) + except Exception as e: + print("FAIL A: cannot read CSV: %s" % e) + sys.exit(1) + + if header != EXPECTED_HEADER: + print("FAIL A: header mismatch: %r" % (header,)) + sys.exit(1) + if len(rows) != N_TOP: + print("FAIL A: expected %d rows, got %d" % (N_TOP, len(rows))) + sys.exit(1) + + names = [r["repo"] for r in rows] + if len(set(names)) != N_TOP: + print("FAIL A: duplicate repo names") + sys.exit(1) + if [int(r["rank"]) for r in rows] != list(range(1, N_TOP + 1)): + print("FAIL A: ranks not contiguous 1..%d" % N_TOP) + sys.exit(1) + for r in rows: + for c in ("stars", "forks", "open_issues"): + try: + v = int(r[c]) + except (TypeError, ValueError): + print("FAIL A: %s not an integer: %r" % (c, r[c])) + sys.exit(1) + if v < 0: + print("FAIL A: %s < 0: %s" % (c, v)) + sys.exit(1) + stars = [int(r["stars"]) for r in rows] + if stars != sorted(stars, reverse=True): + print("FAIL A: stars not sorted non-increasing") + sys.exit(1) + + # Source provenance: recompute the top-50 from a fresh live fetch. + live = fetch_repos() + live_sorted = sorted(live, key=lambda r: (-int(r.get("stargazers_count") or 0), + r["full_name"] or "")) + live_top = live_sorted[:N_TOP] + stored_top = [(r["repo"], int(r["stars"]), r["updated_at"]) for r in rows] + live_top_t = [(r["name"], int(r["stargazers_count"] or 0), r["updated_at"]) + for r in live_top] + if stored_top != live_top_t: + print("FAIL B: stored table differs from a fresh live API fetch") + sys.exit(1) + + print("OK: %d rows verified against a fresh live GitHub API fetch (%d total repos fetched)" + % (len(rows), len(live))) + sys.exit(0) + + +if __name__ == "__main__": + main()