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
jschoubben merged 3 commits from fix/1275-group-hands-every-member into main 2026-10-25 19:28:34 +00:00
Member

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..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 0c216d99d0

## 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
mesh-tools added 3 commits 2026-10-25 17:40:12 +00:00
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.
Gate takes a merge learnt after the fact as past: no trunk move, the forge's time, never source.main (issue 1275, review round 2)
mesh/delivery held for a person: merged without a passing check: only a person decides what follows
mesh/check pass 0c216d99d0c0 on 9d9dfda19b7e | unit 2181 run, 2147 kept, 5 skipped | integration 2203 run, 2166 kept, 9 skipped | over bound: unit, in…
0c216d99d0
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.
Author
Member

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@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`.
jschoubben merged commit 9d9dfda19b into main 2026-10-25 19:28:34 +00:00
jschoubben deleted branch fix/1275-group-hands-every-member 2026-10-25 19:28:34 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#480