Gate: hand every member of an approved group in pin order, settle pull requests closed on the forge, and say a stopped pass as a condition (issue 1275)
#480
Merged
jschoubbenmerged 3 commits from fix/1275-group-hands-every-member into main2026-10-25 19:28:34 +00:00
Met a second time on 2026-10-25 18:02: the operator approved group fix/puller-wakes-on-capacity (mesh-sdk #80, mesh-catalog #479); the gate handed only mesh-catalog #479 (the member that pins the sdk, so the wrong order), mesh-sdk #80 waited for ever, and nothing told the operator. Causes: ready.go kept the literal "delivering" after release 6 renamed the group state to "merging"; members were ordered by id; the half-merged line's only reader (the controller's self-check D14) was deleted in release 6. Kind: code acting on a word another part no longer says or reads.
What
Group states are named constants, with a test that every decision uses them; groupMayMerge allows ready and merging.
Members are handed in pin order: mesh-sdk first, then members that change no go.mod/go.sum, then those that do (empty or truncated path lists rank last).
A held group resumes on the forge's status event, not a 30 s timer.
The gate raises its stalled lines as conditions on the operator-channel seat (key mesh-delivery-gate.delivery..stalled; urgent for a half-merged or held group, AC4/AC6), keeps what it raised in a new state bucket conditions, arms a timed look for every time-bound line, and never clears a condition before the forge's open list is read since start or while its head still waits.
A delivery whose pull request is missing from a complete open list is read from the forge by number and settled: closed -> PullClosed; merged -> merged late (LearntLate), at the forge's merged_at, moving no other delivery's trunk and never source.main. The gitea tool gitea_commit_statuses returns merged_at.
After delivery
Pull requests closed long ago (de-spiegel #4, mesh-controller #203) are settled and raise nothing. Four old D14 conditions in the controller's own list stay: a controller fix (issue 1275 note 10). Check the gate's log says a condition 'is said to the operator' and that the operator channel holds it.
Tests
One table test of 12 cases (TestAnApprovedGroupIsHandedWholeInItsOrderAndAStopIsSaid) replacing an older test: no new top-level test (gate 183 unit, 5 integration). gofmt, go vet with and without -tags integration, go test -race pass; the TypeScript change compiled by the reviewer in a scratch copy. Recovery mode: no try; merge by hand, AFTER mesh-controller #465 runs.
## Why
Met a second time on 2026-10-25 18:02: the operator approved group fix/puller-wakes-on-capacity (mesh-sdk #80, mesh-catalog #479); the gate handed only mesh-catalog #479 (the member that pins the sdk, so the wrong order), mesh-sdk #80 waited for ever, and nothing told the operator. Causes: ready.go kept the literal "delivering" after release 6 renamed the group state to "merging"; members were ordered by id; the half-merged line's only reader (the controller's self-check D14) was deleted in release 6. Kind: code acting on a word another part no longer says or reads.
## What
- Group states are named constants, with a test that every decision uses them; groupMayMerge allows ready and merging.
- Members are handed in pin order: mesh-sdk first, then members that change no go.mod/go.sum, then those that do (empty or truncated path lists rank last).
- A held group resumes on the forge's status event, not a 30 s timer.
- The gate raises its stalled lines as conditions on the operator-channel seat (key mesh-delivery-gate.delivery.<id>.stalled; urgent for a half-merged or held group, AC4/AC6), keeps what it raised in a new state bucket `conditions`, arms a timed look for every time-bound line, and never clears a condition before the forge's open list is read since start or while its head still waits.
- A delivery whose pull request is missing from a complete open list is read from the forge by number and settled: closed -> PullClosed; merged -> merged late (LearntLate), at the forge's merged_at, moving no other delivery's trunk and never source.main. The gitea tool gitea_commit_statuses returns merged_at.
## After delivery
Pull requests closed long ago (de-spiegel #4, mesh-controller #203) are settled and raise nothing. Four old D14 conditions in the controller's own list stay: a controller fix (issue 1275 note 10). Check the gate's log says a condition 'is said to the operator' and that the operator channel holds it.
## Tests
One table test of 12 cases (TestAnApprovedGroupIsHandedWholeInItsOrderAndAStopIsSaid) replacing an older test: no new top-level test (gate 183 unit, 5 integration). gofmt, go vet with and without -tags integration, go test -race pass; the TypeScript change compiled by the reviewer in a scratch copy. Recovery mode: no try; merge by hand, AFTER mesh-controller #465 runs.
Issue: issue 1275 (notes 8-10).
Reviewed-by: reviewer-gate@shanks at 0c216d99d0c0e920d5e680300b37b707a31ee274
Met again 2026-10-25: group fix/puller-wakes-on-capacity was merged half. Three causes in the gate:
- The next member's turn compared the group's state with "delivering", a word GroupState no longer says
since release 6 renamed it "merging" (ready.go groupTurnToMerge). Once the first member's merge was heard
from the forge the group read merging, and the second member waited for ever. Group states are now named
constants, the turn goes on in ready and merging (groupMayMerge), and a test holds every word to it.
- Members merged in id order, so mesh-catalog went before the mesh-sdk commit it pins. membersOf now orders
by mergeRank: mesh-sdk first, then members that change no go.mod or go.sum, then those that do.
- No condition was raised: the controller's self-check that read `stalled` went with release 6
(mesh-controller dc456d56). The gate now says its stalled lines as conditions itself on the
operator-channel seat (ADR 0437 §9) after every look, clears those listed no more, and keeps which it
raised in its new bucket conditions. A held group's line says "half merged" when a member merged.
A pass held for a required status no longer retries on a timer: the status turning success is the event
that asks the merge again.
The conditions the gate now says would otherwise be wrong three ways:
- A pull request closed or merged on the forge with no event heard stayed ready here for days (de-spiegel #4,
closed 2026-10-17) and would raise a condition. After a complete read of the open list (shorter than the
forge tool's 1000), each delivery not final whose pull request is missing is read from the forge and taken as
its close or merge; a merge learnt so does not move source.main, as it is undated and could move it back.
- A line that comes due on the clock (a state's bound, the author's bound, an answered refusal, an
out-of-date refusal turning urgent after 10 minutes) waited for an unrelated event. The gate now asks a look
at the earliest such time.
- After a restart the heads waiting on the forge start their bound again, so their conditions were cleared and
raised again later. A condition is cleared only once the open list was read since start, and not while the
forge still shows its head open and waiting.
Also: an empty path list ranks with a truncated one in the merge order, and a seat that keeps refusing
conditions is retried on the clock 10 looks in a row, then at events only, said once in the log.
A pull request found merged only by its absence from the open list went through PullMerged, which moved every
other open delivery of its repository back to an old trunk (ready ones to proposed, composed checks out of
date), dated the merge now, and so let a later catch-up write the old commit into source.main. pullMerged now
takes such a merge as late: its own delivery is merged and its group closed, no other trunk moves, its time is
the forge's or none, and LearntLate keeps it out of source.main in finish, settleForgeMerges and the catch-up.
The gitea tool gitea_commit_statuses now answers the pull request's merged_at, and the gate reads a gone pull
request by its number alone, so a deleted branch does not fail the read.
Deliverynovox/mesh-catalog@0c216d99d0c0 — held since 2026-10-25T19:28:35Z
Held for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
Source — source.main moved to novox/mesh-catalog@9d9dfda19b. Whether it reached the machines is mesh-delivery-view's, derived from source.main, the wants and the haves.
Transitions
2026-10-25 17:40 (new) → proposed (announced): novox/mesh-catalog#480's head announced
2026-10-25 18:00 proposed → rejected (refused): a verdict names this commit and the trunk's head as its trunk commit, and the gate failed or could not run, or the repository's own check failed
2026-10-25 19:28 rejected → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides what follows
The commit's note under refs/notes/mesh-plan keeps every transition of this change up to its merge: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@0c216d99d0c0` — **held** since 2026-10-25T19:28:35Z
Held for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
**Source** — source.main moved to novox/mesh-catalog@9d9dfda19b7e. Whether it reached the machines is `mesh-delivery-view`'s, derived from `source.main`, the wants and the haves.
**Transitions**
- 2026-10-25 17:40 (new) → proposed (announced): novox/mesh-catalog#480's head announced
- 2026-10-25 18:00 proposed → rejected (refused): a verdict names this commit and the trunk's head as its trunk commit, and the gate failed or could not run, or the repository's own check failed
- 2026-10-25 19:28 rejected → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides what follows
The commit's note under `refs/notes/mesh-plan` keeps every transition of this change up to its merge: `git log --notes=mesh-plan`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
Met a second time on 2026-10-25 18:02: the operator approved group fix/puller-wakes-on-capacity (mesh-sdk #80, mesh-catalog #479); the gate handed only mesh-catalog #479 (the member that pins the sdk, so the wrong order), mesh-sdk #80 waited for ever, and nothing told the operator. Causes: ready.go kept the literal "delivering" after release 6 renamed the group state to "merging"; members were ordered by id; the half-merged line's only reader (the controller's self-check D14) was deleted in release 6. Kind: code acting on a word another part no longer says or reads.
What
conditions, arms a timed look for every time-bound line, and never clears a condition before the forge's open list is read since start or while its head still waits.After delivery
Pull requests closed long ago (de-spiegel #4, mesh-controller #203) are settled and raise nothing. Four old D14 conditions in the controller's own list stay: a controller fix (issue 1275 note 10). Check the gate's log says a condition 'is said to the operator' and that the operator channel holds it.
Tests
One table test of 12 cases (TestAnApprovedGroupIsHandedWholeInItsOrderAndAStopIsSaid) replacing an older test: no new top-level test (gate 183 unit, 5 integration). gofmt, go vet with and without -tags integration, go test -race pass; the TypeScript change compiled by the reviewer in a scratch copy. Recovery mode: no try; merge by hand, AFTER mesh-controller #465 runs.
Issue: issue 1275 (notes 8-10).
Reviewed-by: reviewer-gate@shanks at
0c216d99d0Delivery
novox/mesh-catalog@0c216d99d0c0— held since 2026-10-25T19:28:35ZHeld for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
Source — source.main moved to novox/mesh-catalog@9d9dfda19b. Whether it reached the machines is
mesh-delivery-view's, derived fromsource.main, the wants and the haves.Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.