Sweep the Open Pull Requests Before Selecting the Next Item - #618
Conversation
The selection procedure checked that every open issue appears in this file and never asked the same of an open pull request, so a pull request whose blocker has passed is invisible to the one procedure that would have caught it. Nothing selects it, nothing closes it, and develop moves underneath it. Step 2 asks for a stated active blocker on every open pull request, stated where the pull request carries it rather than in a session that has ended, and active only while the thing it names is still true. It carries #591 as the evidence, which was parked correctly during the GitHub Actions outage of 2026-08-06 and came back twenty commits behind with six conflicting regions and an exit code that had come to mean something else. Measured against the live corpus before writing it, the way a checker's exemption is. One pull request is open, and the merge-bot takes a Dependabot pull request inside a minute, so the rule flags what it is for rather than crying wolf on the routine traffic. Amends "A Programmatic Reading of a Copilot Review" in the same change, recording the upstream ask for a machine-readable Copilot review schema as a place to watch rather than a dependency to wait on, since that cluster's whole question is whether anything but prose is on offer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR tightens the “select next item” procedure in TODO.md by adding an integrity check for open pull requests (not just open issues), ensuring lingering PRs remain visible and have an explicitly stated, still-active blocker before new work is chosen.
Changes:
- Add a new selection step that sweeps open pull requests for a stated active blocker before selecting new work.
- Update the “Programmatic Reading of a Copilot Review” cluster to include an upstream tracking reference (GitHub Community discussion).
- Add new reference links for the upstream discussion and PR #591.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Uh oh!
There was an error while loading. Please reload this page.
The finding is that "rather than output an integration infers meaning from" is missing its noun, so the clause names no alternative and the sentence stops meaning anything. It reads "rather than the human-facing prose an integration has to infer those from" now, which is the thing the upstream request is actually asking to be given something better than, and the thing this cluster exists to decide about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (2)
TODO.md:305
- Grammar: the clause "rather than output an integration infers meaning from" is missing a noun/connector (e.g., "prose output that"), which reads like a truncated sentence.
- **Issue** - None filed here, and the ask is filed upstream as [GitHub community discussion 204320][copilot-review-schema], which asks for a versioned machine-readable schema carrying severity, category, suggestion and resolution state, rather than the human-facing prose an integration has to infer those from. It is unanswered, so it is a place to watch rather than a dependency to wait on. The prose reader and its vetted inventory shipped under [#607][issue-607], which is the change this would supersede.
TODO.md:14
- Grammar: "rather than held" is missing a verb (should be "rather than being held"), which makes the new step harder to read.
2. Run `gh pr list --state open` and confirm every pull request it returns carries a **stated active blocker**, written where the pull request itself carries it rather than held in a session that has ended. A blocker is active only while the thing it names is still true, so a review round that has landed, a dependency that has merged, and an outage that has passed each stop being one, and what they leave behind is a forgotten pull request rather than a parked one. The remedy is to finish it, close it, or write the current blocker down, and it happens before selecting new work rather than after, because the cost is not the waiting. [#591][pr-591] was parked correctly during a GitHub Actions outage and came back three days later twenty commits behind `develop`, conflicting in six regions, and carrying an exit code that had come to mean something else in the meantime.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (2)
TODO.md:465
[pr-591]is defined under the "" link section, but it is a pull request link, not an issue. Splitting PR links into their own group keeps the link definitions consistent with the section headers and makes it easier to scan/maintain the reference list.
[issue-607]: https://github.com/ptr727/ProjectTemplate/issues/607
[pr-591]: https://github.com/ptr727/ProjectTemplate/pull/591
TODO.md:14
- Step 2 uses
gh pr list --state open, which will include bot PRs (e.g., Dependabot) whenever one happens to be open; those PRs typically do not carry a human-written "active blocker" statement, so the procedure can become impossible to satisfy at random times. Filter the list to human PRs (or explicitly exclude Dependabot) so the check matches the rule's intended working set.
2. Run `gh pr list --state open` and confirm every pull request it returns carries a **stated active blocker**, written where the pull request itself carries it rather than held in a session that has ended. A blocker is active only while the thing it names is still true, so a review round that has landed, a dependency that has merged, and an outage that has passed each stop being one, and what they leave behind is a forgotten pull request rather than a parked one. The remedy is to finish it, close it, or write the current blocker down, and it happens before selecting new work rather than after, because the cost is not the waiting. [#591][pr-591] was parked correctly during a GitHub Actions outage and came back three days later twenty commits behind `develop`, conflicting in six regions, and carrying an exit code that had come to mean something else in the meantime.
Two findings, both correct. The step demanded a stated blocker of every open pull request, and a bot pull request has nobody to write one, so the step became unsatisfiable whenever a Dependabot bump happened to be open. Read rather than excluded is the answer: its checks say what it waits on, an unfinished or failing one is its blocker, and a green one still open means the merge-bot did not take it, which is a finding this sweep should surface rather than filter away. Filtering was the other option and it loses that. The measurement behind the step says a Dependabot pull request merges inside a minute, so one sitting open is already the abnormal case. The pull request and discussion links moved out of the Issues group into their own, since a header that misnames what it holds is the same defect the entries under it are about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ptr727
commented
Aug 8, 2026
Answering both round 2 suppressed findings here, since a suppressed comment has no thread to resolve. Both accepted, both fixed in 97f3fa5.
Correct, and it is the better of the two halves of this finding. A step that cannot be satisfied is a step that gets skipped, and one that goes unsatisfiable on a timer nobody controls gets skipped permanently. I took the other remedy, though, because filtering loses the case worth having. A bot pull request is now read rather than excluded: nobody is there to write a blocker on one, and its checks already say what it waits on, so an unfinished or failing check is its stated blocker. A bot pull request sitting open with green checks means the merge-bot did not take it, and that is a finding this sweep should surface rather than something to filter out of view. The measurement behind the step supports reading them. #611 and #612 each went from opened to merged inside a minute, so a Dependabot pull request that is still open when the sweep runs is already the abnormal case rather than the routine one.
Correct. There are now three groups where there was one: Worth saying that this is the same defect as the entries under it, one level up: a header that misnames what it holds is a stated claim that quietly stopped being true, which is what the step this change adds exists to catch. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (1)
TODO.md:14
- Step 2 states that for bot PRs "its checks say what it waits on", but this repo’s own merge-bot/ruleset behavior can leave a bot PR OPEN with all checks green for reasons unrelated to checks (e.g.,
mergeStateStatus: BEHINDafter another bot PR merges, or auto-merge being disabled after a maintainer push; see GOVERNANCE.md:64-68). This makes the instruction misleading for the case it is meant to catch.
Reword the bot-PR clause to treat the blocker as “whatever gate keeps the PR open” (checks, approvals, merge state, conflicts, auto-merge disabled), rather than implying checks are sufficient.
2. Run `gh pr list --state open` and confirm every pull request it returns carries a **stated active blocker**, written where the pull request itself carries it rather than held in a session that has ended. A blocker is active only while the thing it names is still true, so a review round that has landed, a dependency that has merged, and an outage that has passed each stop being one, and what they leave behind is a forgotten pull request rather than a parked one. The remedy is to finish it, close it, or write the current blocker down, and it happens before selecting new work rather than after, because the cost is not the waiting. A bot pull request is read rather than excluded, since nobody is there to write a blocker on one and its checks say what it waits on, so an unfinished or failing check is its stated blocker and a green one sitting open means the merge-bot did not take it, which is the finding rather than the exemption. [#591][pr-591] was parked correctly during a GitHub Actions outage and came back three days later twenty commits behind `develop`, conflicting in six regions, and carrying an exit code that had come to mean something else in the meantime.
The finding is that the previous wording read the blocker off the checks alone, and this repository has two documented ways a bot pull request sits open with every check green: a merge state of BEHIND when a sibling bot pull request merges first, and auto-merge disabled by a maintainer push, both in GOVERNANCE.md "Branching Model". So the clause claimed the checks were sufficient and the sweep would have read green, concluded the merge-bot missed it, and reported the wrong thing on the two cases the repository already knows about. It now reads the blocker as whichever gate holds the pull request open, names those three, and keeps the merge-bot having missed it as what a pull request open under none of them means. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ptr727
commented
Aug 8, 2026
Answering the round 3 suppressed finding here, since a suppressed comment has no thread to resolve. Accepted, fixed in 9b45834.
Correct, and checked against the cited lines rather than accepted on the citation. So the previous wording was wrong in the direction that matters. It claimed the checks were sufficient, which means the sweep would have read green, concluded the merge-bot missed it, and reported the wrong cause on the two cases this repository has already written down. The clause now reads the blocker as whichever gate holds the pull request open, names those three, and keeps "the merge-bot missed it" as what a pull request open under none of them means. This is the third round on one paragraph, and each round has narrowed a claim that was broader than what I had checked. The first said every open pull request owes a written blocker, which no bot pull request can satisfy. The second said a bot's checks answer it. This one reads the gate. That progression is the same failure the step itself exists to catch, which is a statement that was true of the case in front of me and not of the population. |
Uh oh!
There was an error while loading. Please reload this page.
…request sweep (#619) Promotes `develop` to `main`, carrying two merged pull requests. ## What is being promoted - **[#591](#591 `07ed74a`, reading why a merge is blocked instead of reporting one word. `scripts/pr_review.py` gains the check rollup, the four stuck shapes it tells apart, and exit `44` for a review loop that closed against a check no waiting clears, plus the [`GOVERNANCE.md`](./GOVERNANCE.md) and runbook wording that says `BLOCKED` never names its own cause. - **[#618](#618 `dd5fc90`, the open pull request sweep in [`TODO.md`](./TODO.md)'s selection procedure, plus an amendment recording the upstream ask for a machine-readable Copilot review schema. ## The exit code, since it changed meaning between branches #591 was authored before the outage of 2026-08-06 and defined exit `42` for its check reading. #607, #608 and #613 took `42` for a round that read fewer files than the pull request changed, and `43` for a shape the reader does not know, while it sat. The forward-merge renumbered the check reading to **44** and ranked it under both: `43` says no field can be believed, `42` says part of the diff has no review, and only once those are clear is a wedged required check the thing worth reporting. `wait` returns the coverage and shape verdict where it has one and reads the checks only where it does not. ## Review state Both were reviewed and merged on their own pull requests, so this promotion carries no unreviewed change. #591 ran 18 rounds across its life, 5 of them after the revival, and #618 ran 5. Every finding was accepted except one on #614, which was declined with evidence and recorded under "Disproved Claims" in [`.github/copilot-instructions.md`](./.github/copilot-instructions.md). ## Why #591 was open long enough to need reviving It was parked correctly during the GitHub Actions major outage, with the reason written on the pull request, and the reason then expired quietly. Three days later it was 20 commits behind `develop`, conflicting in six regions, and carrying an exit code that meant something else. #618 is the procedural answer to that, and it is in this same promotion. ## Merge shape This is a promotion, so it merges as a **merge commit** rather than a squash, per [`GOVERNANCE.md`](./GOVERNANCE.md) "Branching Model". Its head is `develop` itself, so it must **not** be merged with `--delete-branch`.
Adds the missing half of the selection procedure's integrity check, and amends one cluster with an upstream reference.
The gap
Step 1 confirms every open issue appears in this file. Nothing asked the same of an open pull request, so a pull request whose blocker has passed is invisible to the one procedure that would catch it. Nothing selects it, nothing closes it, and
developmoves underneath it.#591 is the worked example and is carried in the step as its evidence. It was parked correctly on 2026-08-06, during a GitHub Actions major outage, with the reason written on the pull request. The reason then expired quietly. Three days later it was 20 commits behind
develop, conflicting in six regions, and its central exit code had come to mean something else, because #607, #608 and #613 had taken42for a different reading in the meantime.The failure is not specific to this repository. The same shape was reported on Blog, where two pull requests were left open through the same outage and a day of new work landed on top of them.
The rule
Step 2 asks that every open pull request carries a stated active blocker: stated where the pull request itself carries it rather than held in a session that has ended, and active only while the thing it names is still true. A landed review round, a merged dependency and a passed outage each stop being one, and what they leave is a forgotten pull request rather than a parked one. The remedy is to finish it, close it, or write the current blocker down.
Measured before writing, not after
The lesson this repository keeps relearning about checkers is to measure the live corpus before shipping a rule, so it flags what it is for rather than the routine traffic:
02:24to02:25)The merge-bot takes bot traffic inside a minute, so it never sits long enough to owe a blocker, and the rule's working set is the handful of human pull requests that actually linger.
Second disposition in this change
Amends "A Programmatic Reading of a Copilot Review". That cluster's open question is whether GitHub publishes anything but prose to read a Copilot review from, and its
Settledline records that the public API does not. The ask is now filed upstream as GitHub community discussion 204320, which requests a versioned machine-readable schema carrying severity, category, suggestion and resolution state. It is unanswered, so the entry records it as a place to watch rather than a dependency to wait on.Verification
prose_lint.pyclean includingsentence-split,editorconfig-checkerexit 0,markdownlint-cli20 issues across 44 files,TODO.mdat 497 of 497 CRLF lines. The renumbering was checked against the file's own cross-references, and the only one that names a position is step 1 calling itself first, which it still is.