Release review of the software-update piece and the front page that carries it
Findings
This is the release gate for a new piece, articles/where-a-software-update-went.md, its illustration, and the front page that carries it (README.md above the horizontal rule). The reviewer read the dispatch prompt, AGENTS.md and R-0003, then the piece once straight through as a newcomer would, then sentence by sentence against studies/LH002/LH002.md at version 0.2, its brief and cohort file, and the twenty-one tables in studies/LH002/data/. Every figure in the piece was checked against a table and not only against the write-up, since the record's Corrections entry shows the write-up once disagreed with its own tables: the lags, the pin history, the release intervals, the commit and release counts, the author classes, the line totals and the archive coverage were recomputed from the CSV timestamps and counts with a short Python script, and every x position in the illustration was recomputed from the table times on the axis the SVG declares. The SVG was rendered with cairosvg at 1600 pixels wide and looked at. Nothing was fetched from the internet: the piece claims nothing that the record and its tables do not carry, and the record is the study's own reading of 26 September 2026. The verdict is that the piece can be released after one must-fix, a stale version number in its colophon, and that the front page can be released as it stands, with one should-fix that the release commit can take. Everything else is a should-fix of a clause or a note.
The piece, sentence by sentence, against the record and its tables. Line numbers are the piece's.
| Piece passage | Checked against | As the record has it? |
|---|---|---|
| Line 3: "At 18:26 UTC on 8 April 2026, a maintainer of a public Python project changed a single requirement"; "exactly version 1.26.0" to "exactly 1.27.0, published six days before" | data/propagation_candidates.csv: R03, commit 35601f7b30, 2026-04-08T18:26:34Z, pyproject.toml ==1.26.0 to ==1.27.0, one package changed in the commit; data/pypi_releases_in_window.csv: mcp 1.27.0 at 2026-04-02T14:48:07Z, 6.15 days before (derived) |
Yes. The author is in the record's "unknown" class, an address with no bot marker; "maintainer" is the record's own word in its Answer, and the account made 24 of R03's 26 window commits (data/authors_pseudonymous.csv) |
| Line 3: "At 18:49 the project put out a release of its own, and anyone who installed that release would have got the new version of the library along with it" | data/pypi_releases_in_window.csv: lean-lsp-mcp 0.26.0 at 18:49:02Z, 22 minutes 28 seconds after the commit (derived; the figure the record's Corrections entry fixed); Findings: "Anyone installing either version received that exact release ... (interpretation)" | Yes; "would have got" keeps the record's label |
| Line 5: "The records show where the new version went; they do not show why, and they connect none of it to software anyone was running" | Answer: "the public record shows where it went but not why"; "The records connect nothing to running software. No source read says which version of the library anyone installed or ran" | Yes |
| Line 11: 1.27.0 chosen "because no other release came within four weeks of it on either side"; ten projects, "26 March to 22 April 2026"; "We settled on the ten before reading anything they did, and read their history on 26 September, five months later" | brief.md Scope: 1.26.0 on 24 January, 1.27.1 on 8 May; window 2026-03-26 to 2026-04-22; cohort fixed before collection; record header: read 2026-09-26, "not live observation" | Yes; 22 April to 26 September is 157 days |
| Line 13: the registry "gives the minute: 14:48 UTC on 2 April"; the library's history "keeps no time for the tag"; the archive "can place it only between its visits of 25 March and 6 April" | Findings, first paragraph; data/software_heritage_coverage.json: visit 2026-03-25T09:45:56Z without the tag, 2026-04-06T22:44:02Z with it; data/tags_in_window.csv has no R00 row, as the record says | Yes. The minute was read through Open Source Insights, which reports the registry's time; the colophon says so (finding 5) |
| Line 15: "four of the nine"; pin "six days after"; "1,482 commits"; lockfile "eleven days after"; history begins 4 April, "two days after the release", pin "on 14 April"; "the last day" | data/propagation_candidates.csv lags 147.6 h (6.15 d), 263.2 h (10.96 d), 49.5 h (2.06 d), 273.4 h, 488.2 h, each recomputed from its timestamp and matching; data/repo_summary.csv R06 1,482 commits; R02's commit at 22 April 23:02 UTC, inside a window that closes at 23:59:59 | Yes |
| Line 15: "Those moves took five commits, out of 2,508"; "two stayed pinned to 1.26.0, two still had 1.26.0 in their lockfiles at the end, and one did not use the library" | five distinct hashes in the candidates table; data/headline_figures.csv 2,508; data/mcp_state_window_start_end.csv: R05 and R08 ==1.26.0 at start and end, R01 and R07 lock 1.26.0 at end, R09 none; data/repo_day.csv: no mcp change for R09 in the window |
Yes |
| Line 17: "Seven of the nine were drawn from the projects that a public dependency index lists as users of the new version" | brief.md: frame A seven, frame B two; Limits: "The cohort is selected on uptake" | Yes |
| Line 21: the version number and the order of events "settles which came first. It does not show that the release prompted the move" | Answer: "That proves which came first; it does not show that the release prompted the change (interpretation)" | Yes |
| Line 23: "None of the moves was made by an identified bot; an automated dependency updater did make eight commits across the ten projects in those weeks, and none of them touched mcp" | candidates table: author classes unknown or human account throughout; data/authors_pseudonymous.csv: B01 two commits in R00, six in R05; data/lockfile_changes.csv: the R05 bot commits leave mcp at 1.26.0 | Yes; the eight are in two of the ten (finding 4) |
| Line 23: "no author address on the library's commits turns up on any of the nine projects' commits, though one person using two addresses would slip past that test" | data/shared_identities_with_library.csv: non-bot identities shared, 0 for all nine; Findings: "one person with two addresses would be missed" | Yes |
| Line 23: "moved its pin to the newest release of the library eighteen times since August 2025, half of those times within about three days of the release; this time it took six" | data/R03_mcp_pin_history.csv: 18 rows where the exact pin equals the newest release at the commit, the first on 2025-08-01; lags 0.2 to 22.0 days, median 3.2, nine of the 18 at or under 2.6 days; the window's move 6.2 days (all reproduced). One exact pin, 5f8b320c77, went back from 1.18.0 to 1.17.0 and is rightly not among the 18 | Yes |
| Line 23: "one of 23 locked versions that changed in a single commit, half an hour before one of its 35 releases in the four weeks" | data/lockfile_changes.csv: 3b4fa3d1b0, packages_moved 23; data/pypi_releases_in_window.csv: dartlab 0.9.11 at 14:27:53Z, 30 minutes 35 seconds later; 35 R06 rows, counted | Yes |
| Line 23: "one of five written in one commit to hold steady the versions that another of its dependencies pulls in" | data/manifest_dependency_changes.csv: 9e7430aef2 pins fastmcp, httpx, mcp, pydantic and xerparser exactly, five in one commit; the purpose is the record's reading of the commit message and is in no table | The count yes; the purpose rests on the record's sentence (finding 3) |
| Line 23: "The fourth was a first adoption" | candidates table: R02 380974f3e0, mcp>=1.0.0 added, lockfile resolves 1.27.0; data/mcp_state_window_start_end.csv: R02 none at start |
Yes |
| Line 25: "Two of the commits do carry a line in which their author declares that an AI coding tool was involved. That is the author's own statement" | Findings: "R04's pin and R04's first GitHub commit, carry a trailer"; data/repo_day.csv: R04 on 4 April six commits, six with a trailer, on 14 April one commit, one with a trailer; data/ai_tool_trailers.csv: R04, claude, 9 | Yes, as far as the tables reach |
| Line 35: "The dependency index lists the opening project's release among those that depend on 1.27.0, and the project's next release, two days later, still requires exactly that version" | Findings: 0.26.0 listed; data/depsdev_graphs_window_start_end.csv: R03 at window end, 0.26.1, ==1.27.0, resolved 1.27.0; 0.26.1 published 2026-04-10T14:52:14Z, one day twenty hours after 0.26.0 |
Yes; the dependents list itself is not a retained table |
| Line 37: the busy project's release "half an hour after its lockfile moved"; requirement "still said only '1.0 or later' at the end"; "As we understand Python packaging, an installer does not read the lockfile of a project it installs" | data/depsdev_graphs_window_start_end.csv: R06 0.9.19, >=1.0; Findings: "(interpretation, following Python packaging's ordinary behaviour, not checked against dartlab's installers)" |
Yes; the hedge matches the label |
| Line 39: today's index resolves open ranges to "releases of the library from September 2026. Only the exact pins still resolve to what they did in April" | the same table: R01, R04 and R07 to 2.2.0, R06 to 1.30.0 and 2.2.0; Findings: both published 7 September 2026; R03, R05 and R08 resolve to their pins | Yes |
| Line 41: "We think this gap is built in" | Limits: "The gap is structural (interpretation)" | Yes, with "we think" |
| Line 43: "One project's move happened before its history on GitHub begins; its earlier release points to a repository on another site, which we did not read" | Findings: "(interpretation for 'happened out of view')"; data/depsdev_source_repo_links.csv: R04 1.1.0, gitlab.com; Limits: not read | Firmer than the label (finding 2) |
| Line 43: "one project pushed twice to a branch that has since been deleted" | data/gharchive_hour_vs_git.csv: R05, two push events, heads reachable from no ref, both retrievable by hash | Yes |
| Line 43: the archive "holds the history of five of the ten projects, but of none of the four that moved" | data/software_heritage_coverage.json: R00, R05, R07, R08 and R09 archived with window-end heads; R02, R03, R04 and R06 not | Yes |
| Colophon: the five sources; the GH Archive hour "from 14:00 to 14:59 UTC on 2 April 2026"; "read on 26 September 2026, between about 12:55 and 13:40 UTC" | record header; data/gharchive_2026-04-02-14_summary.json created_min and created_max | Yes |
| Colophon: "our study record of the neighbourhood, version 0.1, 26 September 2026" | LH002.md header: "version: 0.2"; "corrected the same day as version 0.2 (see Corrections)" | No (finding 1) |
| Colophon: "the coding tool that the two commits name is Claude"; "nothing in the study used the library" | data/ai_tool_trailers.csv: every trailer names claude; record header, overlaps disclosed | Yes |
The illustration, mark by mark, on the axis the SVG declares (x = 252 + 18.5 px per UTC day from 26 March 00:00):
| Mark | SVG | Table time | Recomputed x | Agrees? |
|---|---|---|---|---|
| Axis and ticks | 252, 381.5, 511, 640.5, 770 | 26 March, 2, 9 and 16 April at 00:00, 23 April 00:00 | 252, 381.5, 511, 640.5, 770 | Yes; the right edge labelled "22 Apr" is the end of 22 April, right for a window closing at 23:59:59 |
| Release line | 392.9 | 2026-04-02T14:48:07Z | 392.9 | Yes |
| Row 1 dot | 506.7 | 2026-04-08T18:26:34Z | 506.7 | Yes |
| Row 2 dot | 595.8 | 2026-04-13T13:57:18Z | 595.8 | Yes |
| Row 3 ring and hatch end | 431.1 | 2026-04-04T16:20:04Z | 431.1 | Yes |
| Row 3 dot | 603.6 | 2026-04-14T00:09:17Z | 603.6 | Yes |
| Row 4 dot | 769.3 | 2026-04-22T23:02:10Z | 769.3 | Yes |
| Row 5 text and the band | "two pins and two lockfiles ended on 1.26.0; one did not use the library"; "Which version anyone installed or ran: in no public source we read" | data/mcp_state_window_start_end.csv; Limits | Yes |
The front page, sentence by sentence, against the piece and the record:
| README.md passage | Checked against | As the piece or record has it? |
|---|---|---|
| Line 3, the title and link; line 11, the link | Piece line 1; the file exists | Identical title, correct path |
| Line 5: "On 8 April 2026 a public Python project moved to the newest version of mcp, a library that AI agents use, and less than half an hour later put out a release of its own that would hand that version to anyone who installed it" | Piece line 3; 22 minutes 28 seconds | Yes |
| Line 5: "four weeks of public records around the library and nine projects that depend on it"; "into four of them"; "where it went but not why, and connected none of it to software anyone was running" | Piece line 5 | Yes |
| Line 5: "to the point where every public record we read stops: the machines where software is installed" | Piece line 45 | Yes |
| Lines 7 and 9, the alt text and caption | Piece lines 27 and 29 | Identical (by diff) |
| Line 15: "The software neighbourhood above is the first thing we have read with our own hands" | studies/LH000/observations.md: two host readings by hand on 25 September 2026; the table's own rows 4 and 5, "Ours", since 25 and 26 September; the LH002 collection began at 12:55 UTC on 26 September | True of the wider internet, not of everything on the page (finding 8) |
| Line 15: "we fetched its raw public records ourselves and counted them, and every table and script is kept in the record" | Method; studies/LH002/data/ (21 tables) and scripts/ (8 scripts) | Yes |
| Line 21, the new row: "ten projects around one library over twenty-eight days in March and April 2026"; "reading git, the package registry, Open Source Insights, Software Heritage and one hour of GH Archive"; "Read on 26 September 2026" | Record header, observation period and instruments; brief.md Sources and access | Yes |
| Line 29: the next question, the registry's "public record of downloads, by version and by the tool that did the installing"; "a download is not a program running"; record first "what they cover and how mirrors and build caches distort them" | LH002.md Next, second entry: "PyPI's public download records by version and installer are the nearest candidate for the taken side, though they measure downloads, not running code"; "its known distortions (mirrors, CI caches)"; programme.md LH005 | Supported (finding 9 on one phrase) |
| Line 29: "The programme holds the questions we are asking and the order we take them in" | programme.md: Answered, Next (LH005, then LH001), Questions after these | Yes |
| Every link above the rule, and the piece's | Tested for existence: all fourteen relative targets resolve; no link carries an anchor, so no programme.md anchor is at stake | Yes |
The piece
-
Must fix. Line 49, the colophon. "our study record of the neighbourhood, version 0.1, 26 September 2026" names an edition the record has left behind. The record's header reads "version: 0.2" and "date: 2026-09-26; corrected the same day as version 0.2 (see Corrections)", and its Corrections entry says what changed: the interval between the pin commit and the project's own release, 23 minutes to 22. The correction was made in the same commit that drafted the piece (1c31791), and the piece already uses the corrected figure ("At 18:49"). A reader who follows the colophon to version 0.1 finds a record that disagrees with the piece by a minute, and the rule for a colophon is that it links the record at its version; the released survey piece already carries a stale record version, which R-0003 finding 16 left for a correction. One number: "version 0.2, 26 September 2026".
-
Should fix. Line 43. "One project's move happened before its history on GitHub begins" is firmer than the record's label. The record says "The move to 1.27.0 happened in a history that the GitHub record does not hold ... (interpretation for 'happened out of view')", and the tables allow another reading: the lockfile could have been resolved in the making of that first commit, on 4 April, in which case the move happened at the edge of the visible history rather than before it. The piece's line 15 has it exactly ("already held the new version in its first commit there"); line 43 should not say more. "One project's move is nowhere in its history on GitHub, which begins with the new version already in place; its earlier release points to a repository on another site, which we did not read."
-
Note. Line 23. "one of five written in one commit to hold steady the versions that another of its dependencies pulls in". The five exact pins are in data/manifest_dependency_changes.csv. The purpose is the record's reading of the commit's message, which no table retains and this review could not see. The record states it without a table cite; the piece follows. "written in one commit which, its message says, was to hold steady ..." would place the claim. No change required.
-
Note. Line 23. "eight commits across the ten projects". The eight are in two of the ten, the library and one dependent (data/authors_pseudonymous.csv, B01). "Across" reads as spread; "in two of the ten projects" is exact and costs nothing.
-
Note. Line 13. "The Python Package Index ... gives the minute". The study read the minute from Open Source Insights, which reports the registry's publication time (Findings, first paragraph). The colophon says so in the same breath: "Open Source Insights, for ... the publication times the Python Package Index records". No change needed.
-
Note. Line 35. "That is a second step, visible from end to end in public records". The record labels the second hop an interpretation. What is observed is the chain, pin commit to release to a registry requirement of
==1.27.0; what is interpreted is that installers received it, and the piece carries that part as "would have received". The sentence is within the label. -
Note. The colophon at release. The form matches the two released pieces: sources with dates, the record linked, the method in a sentence, who wrote it, the review line, version and date, corrections, the Lighthouse line, and the interest disclosed (Claude in the trailers, Claude writing the piece). What the release act adds, as it did for the released pieces: "edited by" if the driver edits, the review link in place of "pending", "Version 1.0, released 26 September 2026", the released form of the corrections line, the Draft label off the byline, and a line in releases.md.
-
Note, on the record rather than the piece. The record's figures against its own tables. Every figure the piece uses was reproduced (the table above), and so were the record's totals the piece does not use: 271 observed and 143 active repository-days, 9.25 and 4.22 commits a day, 13, 1,625 and 870 by author class, the 8,065,850 and 7,632,433 lines outside lockfiles and 77,205 and 39,128 within them, 24 trailers, 83 tags, 74 releases, 50 tags for R06, nine days missing for R04, and the GH Archive scenario (672 files, 23,935,256,352 bytes, 0.49 hours). No second error of the kind the Corrections entry records was found. One rounding: "a window of thirteen days" between the archive's visits of 25 March 09:45 and 6 April 22:44 is twelve days and thirteen hours; the piece gives the dates, not the count.
The illustration
- Note. The dates, times and marks agree with the tables, and the caption says what the figure shows. Every position recomputes to the tenth of a pixel from the table times (second table above). The rendered figure is legible: five labelled rows, the release as a vertical line with its time, the hatch for the days before R04's history begins, the ring for "already holds it", the dashed band beneath. No line joins the release to any move, which is the record's point about order and cause, and the desc says so. The caption is one line and matches the piece's argument. The alt text in the piece and the front page is the SVG's desc in substance.
The front page
-
Should fix. Line 15. "The software neighbourhood above is the first thing we have read with our own hands" is contradicted by the table two lines below it. Rows 4 and 5 are "Ours" since 25 and 26 September, the Harbour export and the host sampler, and LH000 took two host readings by hand on 25 September; all predate the LH002 collection of 26 September, 12:55 UTC. The claim is true of the wider internet, which is what the paragraph means ("Until now, almost everything we knew came through other people's instruments"), and one clause makes it so: "The software neighbourhood above is the first thing beyond our own machine that we have read with our own hands". The same phrase sits below the rule at line 37 ("Its first reading with its own hands") and in AGENTS.md line 9; the driver may align them.
-
Note. Line 29. "whether it can connect a release to the machines that took it". Download records count downloads by version and installer; they identify no machine. The record's Next says "connect a release to installation" and the programme's LH005 "connect a software release to its installation". "To the installations that took it" would ask the question the record asks. It is a question, not a claim, and the sentence goes on to say a download is not a program running.
-
Note. The standfirst, the row and the links are right. Every sentence of the standfirst is in the piece; the new row's subject, instrument and date are the record's header; the alt text and caption are the piece's by diff; every link above the rule resolves, and none carries an anchor into programme.md. "The record" links the study directory rather than the write-up, which suits a row that speaks of tables and scripts.
The piece and the front page
-
Note. The class of claim that needs a person. Nothing in the piece or on the front page says harm is happening now or names a system as compromised. The piece reads four moves as ordinary maintenance and says so with "we read"; the AI trailers are reported as the authors' own statements and not weighed; the dependents are unnamed; the library is named as its public address. Nothing is irreversible outside the repository.
-
Note. The piece keeps the rules. No person's name or handle: none in the piece, the SVG or the front page (searched for all ten namespaces and package names). No dependent named: none; the library, mcp, is named, which the rules allow. No internal reference in the prose: the only "study", "record" and "LH002" are in the colophon, where the link to the record belongs. One idea a reader could say back: public records show where a change went, not why, and not whether anyone ran it. The opening is a moment, a maintainer's commit at 18:26 UTC. The verbs are honest: "the records show", "nothing we read records a reason", "we read all four as", "as we understand", "we think". The Draft label is on the byline and the review line reads "pending"; neither was touched. British spellings throughout; no em or en dash in the piece, the SVG or the front page (by code-point count). Read silently for rhythm twice; nothing trips.
Verdict
- articles/where-a-software-update-went.md: release after finding 1, the record's version in the colophon, 0.1 to 0.2. Finding 2 should go in the release commit; findings 3 to 8 are notes. Every figure traces to a table and reproduces; every interpretation is carried with the record's hedge, except the one clause in finding 2.
- articles/where-a-software-update-went-timeline.svg: release as it stands (finding 9).
- README.md above the rule: release as it stands. Finding 10 is a one-clause should-fix the driver can take in the release commit; findings 11 and 12 are notes. The standfirst says only what the piece says, the row is accurate, the next question is the record's second Next entry and the programme's LH005, and every link resolves.
- Nothing in the piece or the front page falls into the class of claim that AGENTS.md reserves for a person (finding 13).
What the review could not check
- The commit messages: the purpose of R04's five pins (finding 3), the "dependency-update wording" classes, and the exact two commits that carry trailers. The clones are not retained; the day totals in data/repo_day.csv are consistent with the record.
- Open Source Insights' dependents list naming lean-lsp-mcp 0.26.0 under 1.27.0, and git's date for the release commit (2026-03-24T22:24:47Z); neither is a retained table. The archive file holds the release commit's hash.
- No public source was fetched. The piece claims nothing the record does not, and the record is the study's reading of 26 September; a fetch today would show the forge as it stands later, which is a different reading.
- The scripts were not re-run against fresh clones (1.1 GB and the network). Every derived figure was recomputed from the retained tables instead, and all agreed.
- The SVG was rendered with cairosvg, not in a browser. Reading aloud was a silent read, twice.
- The review's own cost is not measured here; the driver prices it from the transcript.
From notes/R-0004.md in the repository, last changed 26 September 2026.