Record a push that only moves recorded builds as the person's word, not a repair (hq issue 301)
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

A recorded build moves only by a person's push (ADR 0242), so that push is
the word its upgrade policy asks for; S15 counted it as a repair and wanted a
healer for split-dns, words and uplink-verbs. The push now reads what it
carries before it is recorded and says so in its kind, and the ten pushes of
2026-10-07 are named so their three warnings clear on the next tick.
This commit is contained in:
jochen
2026-10-08 00:12:23 +02:00
parent db953e7da8
commit e92a3fe237
5 changed files with 383 additions and 3 deletions
+35 -3
View File
@@ -36,6 +36,9 @@ type handActVerb struct {
Decision string
// DecidedFor limits Decision to these causes; empty, it holds for every act of the verb.
DecidedFor []string
// DecidedWhen limits Decision to the acts it answers true for: what the controller read the act to
// be from what it did (a push's kind), never a word the person gave.
DecidedWhen func(link.HandAct) bool
}
// causeLeakedInLogs is the cause a rotation after a value was printed into a log gives.
@@ -52,8 +55,10 @@ const causeDrill = "drill"
// listed without a decision, counts, so a new verb is a repair until its entry says otherwise.
var handActVerbs = []handActVerb{
// Repairs: each repeated is a healer the mesh lacks. A push by hand is exactly what roll-out by
// default (ADR 0236) exists to end.
{Verb: "push"},
// default (ADR 0236) exists to end — except a push that only moved builds a `record` policy held for
// a person's word (ADR 0242), which the push itself reads from what it carried (recorded_push.go).
{Verb: "push", Decision: "a recorded build moves only by a person's push: that push is the word its " +
"upgrade policy asks for (ADR 0242)", DecidedWhen: pushedRecorded},
{Verb: "plans stop"},
{Verb: "plans close"},
// A walk started by a person instead of its delivery's owner (novox/hq ADR 0239): the owner down, or
@@ -93,7 +98,8 @@ func personsDecision(a link.HandAct) bool {
if v.Verb != a.Verb {
continue
}
return v.Decision != "" && (len(v.DecidedFor) == 0 || slices.Contains(v.DecidedFor, a.Cause))
return v.Decision != "" && (len(v.DecidedFor) == 0 || slices.Contains(v.DecidedFor, a.Cause)) &&
(v.DecidedWhen == nil || v.DecidedWhen(a))
}
return false
}
@@ -153,6 +159,19 @@ func (f handActFlags) record(ctx context.Context, verb string, args []string) {
}
act := link.HandAct{Verb: verb, Args: args, Why: strings.TrimSpace(*f.why),
Cause: strings.TrimSpace(*f.cause), Condition: strings.TrimSpace(*f.condition)}
// A push naming one machine says whether it only moves recorded builds (novox/hq issue 301):
// read from what it carries, before it is sent.
if verb == "push" && len(args) == 1 && !strings.HasPrefix(args[0], "-") {
switch carried, why, err := recordedPushOf(ctx, args[0]); {
case err != nil:
fmt.Fprintf(os.Stderr, "whether this push only moves recorded builds could not be read, so it is "+
"recorded as a push by hand: %v\n", err)
case len(carried) > 0:
act.Kind, act.Carried = link.KindRecordedBuilds, carried
default:
fmt.Printf("a push by hand, not of recorded builds only: %s\n", why)
}
}
err := onTheBus(func(conn *nats.Conn) error {
written, err := link.RecordHandAct(ctx, conn, act)
act = written
@@ -162,6 +181,12 @@ func (f handActFlags) record(ctx context.Context, verb string, args []string) {
fmt.Fprintf(os.Stderr, "this act by hand could NOT be recorded in the hand-act log, and is done anyway: %v\n", err)
return
}
if act.Kind == link.KindRecordedBuilds {
fmt.Printf("recorded as %s in the hand-act log: a push of recorded builds (%s) by %s, because %q "+
"— the person's word their upgrade policy asks for, which no healer is wanted for\n", act.ID,
strings.Join(act.Carried, "; "), act.By, act.Why)
return
}
fmt.Printf("recorded as %s in the hand-act log: %s, because %q (cause: %s)\n", act.ID, act.By, act.Why, act.Cause)
}
@@ -244,6 +269,13 @@ func handActCommand(ctx context.Context, args []string) error {
fmt.Printf(", condition %s", a.Condition)
}
fmt.Println(")")
if pushedRecorded(a) {
carried := strings.Join(a.Carried, "; ")
if carried == "" {
carried = recordedBefore[a.ID]
}
fmt.Printf(" a push of recorded builds, no repair: %s\n", carried)
}
}
if len(repeated) > 0 {
causes := make([]string, 0, len(repeated))