Lighthouse

Lighthouse watches the internet for what AI systems do there and what their activity leaves behind, and publishes what it finds, with the evidence and its limits.

Studies LH013

LH013 study brief

Brief, written before any outcome of its weeks was read, 29 September 2026.

study: LH013 edition: 0.1 status: fixed; waiting for data. The study may read counts only when the eligibility condition below is met, and not before 13 October 2026. Until then nothing of its weeks is read, and no week already read may stand in for them. date opened: 2026-09-29 written by: the driving session of 29 September 2026 in Claude Code, model Opus 5.5 (claude-opus-5-5, as reported by its harness), which also corrected LH012's record to version 0.3 the same day; no research agent was dispatched. Read before the snapshot by the release reviewer of the same day (Fable 5.1, notes/R-0017.md), whose edits are to the eligibility check, the resource ceiling's arithmetic and the description of country_code, and touch no measure, threshold, field or week; the driving session then restated the eligibility condition and said how the number of cells carrying half is computed; and, after the reader-and-inference review of the same day (notes/R-0018.md), added the version profile (measure 4), its test and the note on resolver walks, before the snapshot and before any count of W1 or W2 was read grounded at: repository commit 89d4aa7 (LH012 record version 0.2), with LH012's record at version 0.3 in the same working tree issue: #15 (JKershaw/lighthouse); programme.md, Next, checkpoint of 29 September 2026

Question

Over the two weeks after LH012's, 28 September to 11 October 2026, do the 37 libraries' shares of downloads on older versions, and the part of those older downloads that came from Pythons no newer release supports, hold at the values LH012 read for 21 to 27 September; how much of each library's downloads falls in the single largest combination of the fields the download log reports; and does the flat, walk-like shape of some libraries' older downloads by version hold?

A combination of reported fields is called a cell here. A cell is not a machine, an owner or a population: many unrelated machines can share one, one machine can fall in several (for example, with two Pythons), and a cell that holds its share from week to week has not been shown to be the same machines. A large cell can also be an installer's search rather than installations: a resolver that fetches each version it tries counts every one as a download. This study measures how concentrated downloads are in cells, and the shape of each library's older downloads by version, and whether those hold; it does not identify who or what makes them, and it does not test why older versions are downloaded.

What the writer already knows of the outcome, disclosed

  • Everything in LH012's record (version 0.3), which the writer corrected: for 21 to 27 September 2026 (W0), a median 37.3 per cent of a project's downloads were of versions below its reference release R0 (pyjwt 20.0 to pydantic-core 99.3), each project's P and its class, and the post hoc readings: on 23 September 62.2 per cent of boto3's downloads reported Python 3.9, 99.4 per cent of those pip, Linux, glibc and no CI flag; over W0 64.7 per cent of boto3's downloads reported Python 3.9, 95.4 per cent of those were of versions below 1.42.97, and boto3 was fetched 7.51 times as often as botocore on Python 3.9 against 2.94 times over all Pythons.
  • The reader-and-inference review's reading of W0, made after LH012's release (post hoc; notes/R-0018.md; studies/LH012/review/r0018_*): the count-by-version profiles of boto3's, aiobotocore's and grpcio-status's older downloads are flat for long runs below each Python's edge (boto3 on Python 3.9: 49 of the 50 versions below 1.42.97 between 882,481 and 905,092 downloads; flatness 0.001), the shape a resolver's walk leaves; walk-shaped fetches were 78.9 per cent of boto3's older downloads, 84.2 of aiobotocore's and 17.1 per cent of the 37 projects' pooled. Measure 4 and its test below are fixed from that reading, on weeks it did not read.
  • No count for any day from 28 September 2026 on has been read by Lighthouse. LH012 read the most recent day ClickPy held on 29 September at 06:19 UTC (28 September), not its counts; its review's live re-reads were of W0 and earlier days (notes/R-0016.md).
  • The writer's expectation, from the size of these libraries' daily downloads and not from any count of the new weeks: that older shares move by a few points from week to week. That is a prior, not a finding.

Population, unit and reuse

  • Projects. LH012's 37 projects, all of them (studies/LH011/data/releases.csv, as LH012 used it).
  • Unit. The project. Pooled figures are reported beside per-project ones, never in their place. Intervals are percentile intervals over 10,000 resamples of projects with replacement, seed 20260929.
  • Reuse, disclosed. LH012's frame, reference releases (studies/LH012/data/reference.csv), definitions and scripts, and its retained W0 tables (studies/LH012/data/analysis/week.csv, python.csv) as the baseline. The new weeks are days no study has read, so this is a repetition in time on new data, not a replication on new projects.

The weeks, and when the study may run

  • W0: 21 to 27 September 2026, LH012's week. Not reread, except the check below.
  • W1: Monday 28 September to Sunday 4 October 2026. W2: Monday 5 to Sunday 11 October 2026. UTC days. Both are fixed now and cannot be replaced by other weeks.
  • Eligibility condition. The study may begin reading counts when the most recent day ClickPy's per-day tables hold is 12 October 2026 or later, so that 11 October, the last day of W2, is not the most recent, possibly incomplete day. This is checked with LH012's coverage query (the first and last day held per table and project, studies/LH012/data/clickpy_last_day_by_table.csv), which returns no count. Once it is met, and before any count is read, the days held per project over W1 and W2 are listed (project and date only, from pypi_downloads_per_day, which also returns no count); a day of W1 or W2 not held for a project is that project's gap day under Missing evidence, not a reason to wait longer. ClickPy held the day before on 29 September, so the condition is expected to be met from about 13 October 2026.
  • If it is not met. A session that finds the condition unmet reads nothing of W1 or W2 and leaves this study waiting. If ClickPy still does not hold 12 October 2026 by 31 October 2026, the study is recorded as blocked by its source in programme.md and issue #15, and its weeks are not replaced.
  • Check of the baseline. Before any count of W1 or W2 is read, W0's daily totals for the 37 projects are read once from pypi_downloads_per_day_by_version and compared with LH012's retained totals, because ClickPy re-ingests days it finds wrong. A project whose W0 total differs by more than 2 per cent has its W0 comparisons reported as unknown. This reads totals already read, as a check, not a new outcome.

Measures

LH012's definitions hold unless stated here (studies/LH012/brief.md, "The read week and the reference release", "Sources and events", "The three explanations and their traces" for P, and "Missing evidence").

  1. Older share O. For each project and week, downloads of versions below LH012's R0 over all downloads, from pypi_downloads_per_day_by_version, with versions at or above R0 (including any uploaded since) "at or newer", and pre-releases above R0 and versions PyPI does not list "other". R0 is held fixed so that the same versions are compared across weeks.
  2. Python exclusion P. LH012's P, lower and upper estimates, at R0, from pypi_downloads_per_day_by_version_by_python, with admission recomputed for each day of W1 and W2 from PyPI's metadata at the read (a version at or above R0 uploaded during the weeks can admit a Python and end its exclusion). P is a count of fetches from Pythons that no version at or above R0 admits: fetches that could not have been of R0 or later. It is not an account of why they were of the versions they were.
  3. Concentration C. For each project and week, the share of its downloads in its largest cell of six fields of pypi.pypi: python_minor, installer, system, libc.lib, ci and country_code; beside it C5, the same without country_code (LH012's descriptor fields plus the Python minor). Each is reported with the cell's values and with the number of cells that together carry half of the project's downloads, counted from the largest cell down and reported as "more than 1,000" beyond 1,000. Both are computed server-side, the second with a running sum over the cells ordered by size, so that each query returns a few rows a project, never the full grouping, which passes the demo user's 10,000-row limit; queries are split by project and by day where one would pass a limit.
  4. Version profile. For each project, week and Python minor with at least 1,000,000 older downloads and at least twelve older versions below its start, the count-by-version profile of older downloads, newest first from the start, which is the highest version below R0 that the Python admits (for an excluded Python, its edge; for an admitted one, the version just below R0). Its flatness is the median, over the consecutive pairs among the first hundred versions after the start, of the absolute change in count from one version to the next as a share of the first of the pair; the profile is walk-shaped when flatness is below 0.05. Its plateau mass is the sum, over the versions after the start, of each version's count capped at one and a half times the median count of the nine versions centred on it. Per project and week, the walk-shaped plateau mass is reported as a share of older downloads, and pooled. These are the definitions of studies/LH012/review/r0018_walkshare.py, fixed here as they stand. Read from the by-Python table the study already reads, at no extra query.
  5. Secondary, described only. O and P at each week's own reference release by LH012's rule (the highest non-pre-release, not wholly yanked, first uploaded on or before the week's first day less 31 days: 28 August for W1, 4 September for W2), which is the baseline a watch would compute week by week and which moves when R moves; C and C5 over older downloads only.

What the fields are (read before this brief was fixed): installer, system, libc.lib and ci are what the client reports, with the meanings LH011 and LH012 read in pip 26.2.1's and uv 0.12.8's source (pip and uv send ci true only when a build variable is set, else nothing, which ClickPy stores as false); python_minor is the client's reported Python, as LH012 describes; country_code is a country code carried in each download's log line, which linehaul's log parser passes through unchanged (linehaul-cloud-function, linehaul/events/parser.py, read 29 September 2026 at 10:18 UTC, and again by the review at 10:31 UTC); which service assigns it to the requesting address is stated on neither page read, and that it is the package index's content network is general knowledge, not a source here (the package index's BigQuery page, https://docs.pypi.org/api/bigquery/, read at 10:18 UTC, names the table and says it is filled by linehaul, and says nothing of the field). A country is where an address is placed, which for a cloud machine, a proxy or a mirror is not where anyone is.

Tests and conventions (fixed now)

  • O holds for a project when its O in W1 and in W2 is each within 5 percentage points of its O in W0.
  • P holds for a project when its class by LH012's convention (accounts for most, undetermined, cannot be the main reason, with "accounts for little" inside "cannot") is the same in W1 and W2 as in W0.
  • C holds for a project when its C in W2 is within 5 points of its C in W1 and the largest cell has the same values in both weeks; C5 the same. W0's cells were not read with these fields, and they are not read now.
  • Across projects, for O, P, C and C5: the number and share of projects with a known outcome that hold, with its interval. "As a rule" when at least three quarters hold, "for most projects" above one half, "for some projects" otherwise; these labels stay in the record, and a piece gives the numbers.
  • Tests of LH012's post hoc readings, one each: boto3's share of downloads reporting Python 3.9 is above one half in both W1 and W2 (W0: 64.7 per cent); the ratio of boto3's to botocore's fetches on Python 3.9 is at least twice the ratio over all Pythons in both weeks (W0: 7.51 against 2.94); and more than three quarters of boto3's Python 3.9 downloads are of versions below 1.42.97, the highest boto3 whose Requires-Python admits 3.9, in both weeks (W0: 95.4 per cent). Whichever way they come out, they say whether a pattern holds, not who makes it.
  • The walk, one test: boto3's Python 3.9 profile below 1.42.97 is walk-shaped (flatness below 0.05) in both W1 and W2 (W0: 0.001). Beside it, described only: the walk-shaped share of each project's older downloads in W1 and W2 against W0's (studies/LH012/review/r0018_walkshare.txt), and the depths at which boto3's 3.9 profile steps down.
  • Number of comparisons: 37 projects times two weeks for O, 37 for P, 37 for C and 37 for C5 (185 per-project readings), four across-project summaries, three tests of LH012's post hoc readings and one of the walk; the version profiles are described, not tested. Anything else read after counts are seen is labelled post hoc with its number of comparisons.

Sources

ClickPy's public SQL (user demo, anonymous): pypi_downloads_per_day_by_version, pypi_downloads_per_day_by_version_by_python and pypi.pypi, for W1 and W2, and the W0 totals check; PyPI's JSON API for the 37 projects' versions uploaded since LH012's read (Requires-Python for admission, upload times, yanking), read after the eligibility check and before any count. Every query and request is logged with its time, as LH012's were. BigQuery is not read.

Missing evidence

As LH012: unknown stays unknown and is never counted as a negative. Downloads with no Python reported enter P only through its lower and upper estimates. A day that is a gap by LH011's rule is left out of that project's week and named; with more than two gap days in a week, that project's measures for the week are unknown. A cell with an empty field is a cell like any other, with its empty values reported.

Resource ceiling

  • ClickPy: at most 300 queries and 30 billion rows read in all, by ClickHouse's own statistics. Expected use is about 20 billion, most of it two passes of pypi.pypi, one a week, each computing C, C5 and their older-only secondary together (about 9.4 billion rows a pass, by LH012's brief); a second pass a week would take the total to about 40 billion, over the ceiling, so the passes are combined, or the study stops at the ceiling with the unread part stated.
  • PyPI JSON: at most 300 requests.
  • Documentation: at most 5 page reads. One is fixed now: the package index's own statement of what its download table counts, read before any count, since whether requests for PEP 658 metadata files are counted decides whether newer pips' walks can appear in the log. pip's NEWS.rst was read for this brief on 29 September 2026 at 11:12 UTC (https://raw.githubusercontent.com/pypa/pip/main/NEWS.rst): its resolver has tried versions in turn by default since 20.3 (30 November 2020), and since 22.3 (15 October 2022) it reads PEP 658 metadata files instead of downloading each candidate, where the index offers them.
  • About six dollars of the research agent's own model spend at list rates. Anonymous reads only; no key or token is read.

Stopping condition

Close when O and P for W1 and W2, C and C5 for W1 and W2, the version profiles, and the four tests are read for all 37 projects, or at a ceiling, with the unread part stated. The question, the weeks, R0, the measures, the fields, the thresholds and the conventions are not changed after any count of W1 or W2 is read; a later change is a dated amendment, labelled post hoc if made after counts were seen.

What would leave it inconclusive

  • The eligibility condition not met by 31 October 2026.
  • Fewer than 25 projects with a known O in both weeks, or with their W0 totals confirmed.
  • ClickPy's tables disagreeing: if a project's weekly total in the by-Python table differs from the per-version table's by more than 2 per cent, its P is described only, as in LH012.
  • Whatever it finds, it cannot say who or what makes a cell's downloads, which installer versions make a walk-shaped profile, or why older versions are downloaded; that a walk-shaped profile is a resolver's walk stays an interpretation.

Overlap with earlier studies

The projects, R0, the definitions and the W0 baseline are LH012's, and through it LH011's. The four tests re-measure readings made after LH012's counts, three by its writer and one by the reader review of its piece, on weeks neither read. No project, repository or release outside LH012's frame is read.

Intended output

LH013.md (version 0.1), sources.md, data/ with the read logs and every query result the analysis uses, scripts/ adapted from LH012's with an offline replay, a line in investigations/software-updates.md, and a piece only if the record earns one.

  • Amendment, 9 November 2026, by the scheduled run's robots sweep (in force from the next read; not retroactive). The keeper decided on 8 November 2026 that Lighthouse obeys robots.txt as its own agent and as whatever runs it (AGENTS.md, Rules that matter; scripts/robots_rules.py, scripts/robots_tokens.json). The gate is scripts/robots_gate.py, which reads each host's robots.txt once per run. Every read goes through scripts/common.py's curl helper (ClickPy, PyPI JSON, docs.pypi.org and raw.githubusercontent.com, through collect.py and collect_counts.py), which now asks the gate first; a URL not allowed is not requested and its row in data/read_log.csv has the status "not fetched: ..." with the deciding group and rule, a missing reading and never a negative. For ClickPy the endpoint URL is checked. The documentation stage keeps no file for a page not fetched. scripts/preflight.py, which posts to ClickPy directly, asks the gate for the endpoint first and stops, logging "not fetched", if it is not allowed. The User-Agent now carries Lighthouse's token (Mozilla/5.0 (compatible; Lighthouse-research/1.0; +https://lighthouse.harbour.cat)), and email addresses are withheld from ClickPy results and documentation pages before they are written. Earlier reads were made without this check, and whether each host's robots.txt allowed them on those days was not checked. Read 1 is done; this applies to any further read under this brief or the installer brief that uses these scripts.

From studies/LH013/brief.md in the repository, last changed 9 November 2026.