No build reaches a machine without a gate; a release plan walks what waits (hq ADR 0236)

A send carries the machine's whole declaration, so at the switch to roll the next send of
anything would have carried the old default's backlog, unjudged, to every machine. A gated
send now carries and judges everything waiting on its machine; every other send is refused
or leaves the machine; a release plan walks what waits one machine at a time, the control
node last, and one that fails holds the next until a person releases it.
This commit is contained in:
jochen
2026-10-06 19:14:25 +02:00
parent 41f7b2c152
commit 2bfa6ae4a0
15 changed files with 1163 additions and 40 deletions
+32
View File
@@ -1,6 +1,7 @@
package main
import (
"slices"
"context"
"crypto/sha256"
"encoding/hex"
@@ -466,6 +467,28 @@ func pushCommand(ctx context.Context, args []string) error {
which, len(asked), strings.Join(asked, ", "))
}
// **A whole-mesh push sends no build a gate has not seen** (novox/hq ADR 0236): a machine where one
// waits is left, named, for the release plan — `push <node>` still sends one machine by a person's word.
if len(args) == 0 {
f, err := readMoveFacts(ctx, inv)
if err != nil {
return err
}
var kept []string
for _, n := range asked {
moves, err := machineMoves(ctx, open, f, n, false)
if err != nil {
return err
}
if len(moves) > 0 {
fmt.Printf(" %s is left: %d build(s) wait there for a gate, which a release plan sends one machine "+
"at a time (`upgrade backlog` lists them; `push %s` sends it by name)\n", n, len(moves), n)
continue
}
kept = append(kept, n)
}
asked = kept
}
// **The bus is replaced only as a planned step** (novox/hq ADR 0236, to-be 45 §8): a machine whose bus
// would move is not sent by a push — named, it is refused; otherwise it is left and said.
busKept, err := busHeld(ctx, inv, asked)
@@ -1030,7 +1053,16 @@ func sendToEach(ctx context.Context, open *stores, names []string) ([]string, er
if err != nil {
return nil, err
}
added := ""
if behind && !slices.Contains(names, holder) {
added = holder
}
names = brokerFirst(names, holder, behind)
// **No build moves on a machine without a gate** (novox/hq ADR 0236): a send outside its scope that
// would carry one is refused, said with what waits; the bus's machine added for its user list is left.
if names, err = ungatedIn(ctx, open, names, added); err != nil {
return nil, err
}
// Held from composing to sending (novox/hq ADR 0100); a caller that holds them already —
// converge, which flips the node and then sends it — is not made to wait on itself.