Episode 02 said this site’s research and requirement stages never ran. That was true on 13 October. On 26 October, both ran.
What ran
The estate has a skill that moves a product through the stages before a build: brief, research, requirement, decision and spec. Each stage opens a pull request against a records repository and writes one line to an audit ledger. Two lines from 26 October belong to this site:
| Time (UTC) | Stage | Record | Tier | Result |
|---|---|---|---|---|
| 14:19 | research | where-the-published-record-comes-from |
1 | merged |
| 16:34 | requirement | the-record-is-complete-and-names-its-source, status proposed |
1 | merged |
Both were Tier 1, so the gate let the agent merge them without me. The forge records the agent as the account that opened and merged each one. The first deploy was on 8 September. The research ran 48 days later.
The question the research asked
The brief asks what the published record is derived from. The research compared three sources: the site’s pull request history, the audit ledger, and the delivery records in this repository. It recommended the pull request history, which the record page already reads. The ledger is a file on one machine, outside version control, so a build cannot read it. Its lines name no actor, and every pull request link in it points at a private address.
The research also listed a risk:
The page reads at most 100 closed pull requests. The repo is at #67. At the current rate the cap is reached within weeks, and the page then omits changes with no error.
The requirement turned that risk into something a test can check: “the record lists every merged change to the site repository, in merge order, and none is missing.”
The risk had already happened
On 29 October I checked the research against the forge.
The record page asked the forge for 100 pull requests. The forge returns at most 50 items in any list, whatever a request asks for. That limit is a forge setting, and the code did not read it. So each build received 50 closed pull requests and dropped the rest. On 29 October it received #18 to #67.
| Source | Merged changes | Unprovable |
|---|---|---|
| The forge | 66 | 10 |
| The live record page | 49 | 0 |
The page was missing changes #1 to #17. Those include the 10 from before the agent had its own identity, which the page exists to show as unprovable. Its heading still said “Every change that built this site”.
The research had the right risk and the wrong number. It read the limit in the request, not the limit in the response. The cap was not weeks away. It was passed on 12 October, when the 51st pull request closed. The next deploy was on 13 October, the day the series launched with episodes 01 to 03. Every build from that day was incomplete.
Why nothing objected
The record page fails closed. If the forge cannot be reached, the build fails rather than publish a list that looks complete. That design expected one kind of failure: no answer.
A capped list is a different failure. The forge answered with a success code and 50 valid items. Each check on the page passed, because each check tested the items it received. The forge also sends the total count in a response header. The code never read it, so nothing compared what it had with what existed.
The fix
Pull request #70 changes the read:
- it asks for each list page by page until a page comes back empty, so the forge’s limit does not matter;
- it compares the number it read with the total the forge reports, and fails the build if they differ.
One test reads a stub forge that holds 120 pull requests and returns 50, then 30, at a time. Another checks that a wrong or missing total fails the build. Both fail on the old code. I merged the fix on 3 November. That day the live record listed 71 merged changes, from #73 down to #1, with 10 unprovable.
In one case the fix does not do what the requirement asks. The requirement says that a record which cannot be read in full states that it is incomplete. The fix fails the build instead, so the last complete record stays live. One of the two has to change. That is a decision, and the decision and spec stages have not run for this requirement.
What the late stages showed
Episode 02 said the missing stages would ask the questions the build could not ask for itself. Run late, they did. The research asked where the record comes from, and the requirement turned “every change” into a test.
They also showed a limit of reading. The research read the code and believed it. One request to the forge settings found what 16 days of builds had not.
Next
The requirement is still proposed. It asks for more than this fix: the record should name the brief version that sets each change’s tier, and it should publish no private address. Those wait for the decision and spec stages.