The operator wants a reviewed pull request merged without a session calling
the merge tool again after every recheck. The reviewer marks it ready (label
mesh/ready and a comment "ready at <full head sha>"); the forge's open-pulls
read carries the mark, and mesh-delivery merges through gitea_merge_pull_request
at that head, in a group's order once its composed check passed. A push after
the mark clears it; a failed check is said on the pull request and as a
stalled line.
mesh/merge-gate head 01d2ff7a46bc merged into trunk 2fe5601397ae — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 01d2ff7a46bc merged into trunk 2fe5601397ae — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The merge tool deletes the branch after merging; the forge then reads head.ref as refs/pull/<n>/head and only
head.label names the branch. pull.merged carried the pull ref, so the controller found no group for the merge,
cut mesh-catalog #251's walk at once and walked it before mesh-controller #271's, against the group's order.
The watch for unchecked heads counted any merge-check status as checked, pending
included, so a head left with a pending mesh/merge-gate, or never given
mesh/repo-check, waited unable to merge with nothing saying so. gitea_open_pulls
now gives each head status with its state and time, and the watch says a head
whose required check stays pending or unset past the delivery table's bound for
a check asked and not answered.
After merging #159 (issue 347): every /repos/<owner>/<name> the client builds
now takes its owner and name through one helper, whether they came from a
caller or from the forge's answer; the open-pulls fixture's shas are commits.
The confirmation review asked for the delivery domain's own vocabulary
instead of a provider standing. A gitea health check would need a `tools`
list (turning gitea's tools into seat verbs), a check of another kind
beside it, and would hold the forge's own deliveries at the first-node
gate; so the delivery's owner says it, with the word it already has.
- gitea_open_pulls (gitea): every open pull request from the forge itself,
with what its base requires and the statuses its head has.
- mesh-delivery asks it every five minutes and keeps its own first-seen
time per head (the forge's update time moves on every comment). A head
on a base requiring mesh/merge-gate OR mesh/repo-check (hq requires only
the second) with neither for ten minutes is a `stalled` line in state
`unannounced`, which the controller raises as delivery.<id>.stalled (D14);
H2 has nothing to close. Once announced it is a delivery of its own.
- The gitea-side watcher and its provider standing are gone.
The announcer read only the repositories whose update time moved since its
last pass, less a minute. Opening, reopening or retargeting a pull request
does not move a repository's update time, so a pull request opened more
than a minute after its push was never announced, never checked, and
nothing said so (mesh-sdk #14, 2026-10-09).
- Each pass also looks at every repository holding a pull request updated
since the floor, by the forge's own search; every ten minutes, or when the
search fails, at every repository.
- Every five minutes the forge is asked for every open pull request; one on
a base requiring mesh/merge-gate whose head has had none for ten minutes
is said as the forge failing that pull request's merge check (a provider
standing, ADR 0224), which the controller keeps as a condition, and is
recovered when a check arrives or it closes.
- The client refuses a pull request or issue number that is not one before
asking the forge (a misnamed tool argument sent pulls/NaN).