Assemble merges in a rolling window and walk each batch once (hq ADR 0276, issue 362)
mesh/merge-gate pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without …
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request

Every merge opened a walk and the next merge of the branch superseded it: two
catalogue merges 18 s apart left a walk no delivery held, and the operator
started it by hand 58 minutes later. A merge now joins the open batch, kept in
the store (migration 0089), which is cut into one walk when no merge came for
merge-window (90 s) or at merge-window-at-most (10 min): one commit per
repository, the latest of its branch, with every file the batch's merges
changed. One walk at a time; a started walk is never superseded, a waiting one
is folded into the next. The walk names every merge it answers on the wire
(delivery.merges, taken_over_by, batch). A failed walk walks its earlier merges
alone, newest first, until one is delivered. A delivery group's order becomes
tier edges inside the walk. plans shows the batch assembling; S18 and S19
bound its waits; S16 names the merges a waiting walk answers.
This commit is contained in:
jochen
2026-10-10 13:20:04 +02:00
parent 8a53532d89
commit 96fc4209d3
24 changed files with 2110 additions and 563 deletions
+8 -1
View File
@@ -53,6 +53,8 @@ type signalFacts struct {
plansErr error
// waits are the walks waiting for their delivery's word (S16, novox/hq ADR 0239).
waits []waitFacts
// batches are the batches not yet cut (S18, S19, novox/hq ADR 0276).
batches []batchFacts
loop loopFacts
loopErr error
@@ -159,6 +161,8 @@ type waitFacts struct {
since time.Time
// modules are the modules the walk moves, as a person names the delivery.
modules []string
// merges are the merges it answers (novox/hq ADR 0276), as the deliveries to read are found.
merges []inventory.PlanMerge
}
type loopFacts struct {
@@ -326,6 +330,9 @@ func (w *watchdogs) gather(ctx context.Context) *signalFacts {
f.machines, f.machinesErr = w.gatherMachines(ctx, inv, now)
f.bus, f.busErr = gatherBus(ctx, inv)
f.plans, f.waits, f.plansErr = gatherPlans(ctx, inv, now, f.bus.heldByTheBus())
if f.plansErr == nil {
f.batches, f.plansErr = gatherBatches(ctx, inv, now)
}
f.loop, f.loopErr = w.gatherLoop()
f.mergesPassed, f.merges, f.mergesErr = watchedMerges.last()
if f.mergesErr == nil && !f.mergesPassed.IsZero() && now.Sub(f.mergesPassed) > 3*mergeCatchUpEvery {
@@ -480,7 +487,7 @@ func gatherPlans(ctx context.Context, inv *inventory.Inventory, now time.Time, b
// S16's, whatever mesh-delivery says or does not say.
if p.Waiting() {
waits = append(waits, waitFacts{id: p.ID, repository: p.Repository, commit: p.Commit,
awaits: p.Delivery.Awaits, since: p.Created, modules: planModules(p)})
awaits: p.Delivery.Awaits, since: p.Created, modules: planModules(p), merges: p.Delivery.Merges})
continue
}
_, paused := pausedWaiting(p, pause, now)