Give each asking of a merge ask its own id, and add the have phase removed (issues 1370, 1369)
mesh/merge-gate head ba684e54976b merged into trunk 5786ba190c69 — pass: group fix/r3e-before-the-gate composed: every machine composes with the change as …
mesh/repo-check head ba684e54976b merged into trunk 5786ba190c69 beside mesh-host#121@150fadfe — pass: its merge-check.sh passed, each part in its toolchai…
mesh/delivery delivered
mesh/delivery-group group fix/r3e-before-the-gate delivered: every member is delivered

The router drops an ask under an id it keeps as a redelivery, so a gate that writes the same group's ask again at unchanged heads was never heard. Ask gains Asking; AskingID gives the first asking the old id and later ones their own. PhaseRemoved lets the node-engine say a module left its node.
This commit is contained in:
2026-10-20 01:18:49 +00:00
parent 5786ba190c
commit ba684e5497
4 changed files with 107 additions and 4 deletions
+21 -2
View File
@@ -119,6 +119,18 @@ func AskID(askKey string) string {
return string(readable) + "-" + hex.EncodeToString(sum[:])[:12]
}
// AskingID is the id of the asking-th writing of the ask at askKey. Asking 0 and 1 give AskID(askKey), so the first
// asking's id is unchanged; asking n of 2 or more gives the AskID form of askKey + "." + n, so each asking has an id
// of its own (at most 64 bytes, ending in the 12 hex digits of the hash of that whole string) and the router, which
// drops an ask under an id it keeps as a redelivery, takes each as new and an answer to an earlier asking is never
// taken for a later one.
func AskingID(askKey string, asking int) string {
if asking < 2 {
return AskID(askKey)
}
return AskID(askKey + "." + strconv.Itoa(asking))
}
func checkOwedAct(act string) (kind, context string, err error) {
kind, context, hasContext := strings.Cut(act, "=")
switch kind {
@@ -274,15 +286,22 @@ type Ask struct {
Group string `json:"group"`
Heads []Head `json:"heads"`
Ask asks.Ask `json:"ask"`
// Asking counts the times the gate wrote this group's ask at these heads: 0 or 1 for the first, n for the n-th.
// The router drops an ask whose id it has already kept as a redelivery, so each asking has its own id
// (AskingID); the first asking's id is unchanged and the field is omitted for it.
Asking int `json:"asking,omitempty"`
}
func (a Ask) check() error {
if a.Asking < 0 {
return fmt.Errorf("delivery: the ask's asking %d is negative", a.Asking)
}
key, err := MergeAskKey(a.Group, a.Heads)
if err != nil {
return fmt.Errorf("delivery: an ask needs its group and at least one pull request's head: %w", err)
}
if want := AskID(key); a.Ask.ID != want {
return fmt.Errorf("delivery: the ask's id %q is not %q, the id its group and heads give", a.Ask.ID, want)
if want := AskingID(key, a.Asking); a.Ask.ID != want {
return fmt.Errorf("delivery: the ask's id %q is not %q, the id its group, heads and asking %d give", a.Ask.ID, want, a.Asking)
}
if len(a.Ask.Options) == 0 {
return fmt.Errorf("delivery: the ask has no option")