Merge pull request 'Issue 347: a pull request opened after its push is never checked, and nothing says so' (#247) from issues/347-a-pull-request-opened-after-its-push-is-never-checked into main
This commit was merged in pull request #247.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-09
|
||||
located-in: [mesh-catalog (modules/gitea, the announcer in index.ts and the client; modules/mesh-delivery, saying it), mesh-controller (its words)]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 347. A pull request opened after its push is never checked, and nothing says so
|
||||
|
||||
## Symptom
|
||||
|
||||
On 2026-10-09 a pull request on the SDK's repository (opened at 10:11 UTC, its branch pushed at 10:03) had no
|
||||
`mesh/merge-gate` and no `mesh/repo-check` status twenty minutes later, while four pull requests opened in the
|
||||
same minutes on other repositories were checked within three. `mesh-delivery.checks` answered "no status" for it,
|
||||
and no condition, log line or status said why. The pull request could not merge, because its base requires both
|
||||
statuses, and nothing in the mesh knew it existed.
|
||||
|
||||
The same day a call of the forge module's `gitea_get_pull_request` with a misnamed argument asked the forge for
|
||||
`pulls/NaN`.
|
||||
|
||||
## Why it is an issue
|
||||
|
||||
- **Work is silently never checked.** The forge's announcer is the only way the mesh learns of a pull request's
|
||||
head (to-be 45 §9). A pull request it misses waits for ever, with no status and no condition: failure is not
|
||||
loud, the worst kind.
|
||||
- **The cause, measured by the review of ADR 0272.** Each pass of the announcer (`pollPulls`, modules/gitea
|
||||
index.ts) reads only the repositories whose update time moved since its last pass, less a minute's margin
|
||||
(`movedSince`, issue 250). A push moves a repository's update time; opening, reopening or retargeting a pull
|
||||
request does not. So a pull request opened more than about a minute after its branch was pushed is in a
|
||||
repository the announcer skips, on every pass, until something else is pushed there.
|
||||
- **A number that is not one reaches the forge.** A tool's numeric argument read under the wrong name is `NaN`,
|
||||
and the client asked the forge about it rather than refusing.
|
||||
|
||||
## Acceptance test (the operator's view)
|
||||
|
||||
A pull request I open on a protected branch, whenever I open it after pushing its branch, has a merge check within a
|
||||
minute. If one ever has none for ten minutes — on a branch that requires `mesh/merge-gate` or only `mesh/repo-check` —
|
||||
the mesh tells me which pull request, as a condition. A tool asked
|
||||
with a pull request number that is not one refuses and says why.
|
||||
|
||||
## The fix
|
||||
|
||||
In the forge module (mesh-catalog, `modules/gitea`):
|
||||
|
||||
1. Each pass also looks at every repository holding a pull request updated since the floor, found by the forge's
|
||||
own search of open pull requests by their own update time; and every ten minutes, or when the search fails, it
|
||||
looks at every repository (a sweep).
|
||||
2. Every five minutes the delivery's owner (`mesh-delivery`) asks the forge itself for every open pull request
|
||||
(`gitea_open_pulls`), never what the announcer remembers. A head on a base that requires the merge check —
|
||||
`mesh/merge-gate` **or `mesh/repo-check`**, since this repository requires only the second — with neither on it
|
||||
for ten minutes since the owner first saw it so (its own time: the forge's update time moves on every comment)
|
||||
is a delivery held past its bound: a `stalled` line in state `unannounced`, which the controller raises as
|
||||
`delivery.<id>.stalled` like any other, with words that say to push a new commit. The delivery domain's own
|
||||
word, chosen over a provider standing and over a health check of the forge: that check would need a `tools`
|
||||
list (turning the forge's tools into seat verbs) and a check of another kind beside it, and would hold the
|
||||
forge's own deliveries at the first-node gate.
|
||||
3. The client refuses a pull request or issue number that is not a whole number above zero before it asks.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- `test/announcing.test.ts` (modules/gitea): a pull request opened two minutes after its push, with the last pass
|
||||
thirty seconds after that, is in a repository the pass looks at; without its own update time nothing is looked at
|
||||
(the fault, held as a case); a sweep and the first pass look at every repository. Every open pull request is read
|
||||
with its base's required statuses and its head's. `pulls/NaN`, `0` and `1.5` are refused and the forge is never
|
||||
asked. Each fails on the commit before the fix.
|
||||
- `unchecked_test.go` (modules/mesh-delivery): a head on a base requiring only `mesh/repo-check`, with no check,
|
||||
is a stalled `unannounced` line after ten minutes, counted from when the owner first saw it; one with a check,
|
||||
on a base requiring none, announced, closed, or behind a forge that cannot be asked is not said or not changed.
|
||||
- `TestAnUnannouncedPullRequestSaysToPushANewCommit` (mesh-controller): the condition's words say to push a new
|
||||
commit, never to stop or release a delivery that does not exist.
|
||||
- Live, after delivery: the next pull request opened later than a minute after its push has its statuses within a
|
||||
minute; `mesh-controller.conditions` shows none for it.
|
||||
Reference in New Issue
Block a user