diff --git a/modules/mesh-config/README.md b/modules/mesh-config/README.md index 5ed62e898..99f368a43 100644 --- a/modules/mesh-config/README.md +++ b/modules/mesh-config/README.md @@ -46,7 +46,7 @@ names who gave it in `by`, or on the operator's Approve of a proposal. `action` `propose` (with `value`, or `clear`) judges the value as a set would, keeps it in `mesh-config_proposals`, and asks the operator under mesh-config's own name on the `operator-channel` seat (its own grant, from `uses`, and -its own cap of three open asks; the same change twice is refused, and a newer proposal for the same level and key +the router holds an asker's oldest ask back behind a fourth, no cap of its own; the same change twice is refused, and a newer proposal for the same level and key replaces the older). The ask says the level, the key and the value, exact where who answers is proven, and that, approved, it takes effect at once on every node it reaches; Approve and Decline are both at the level approve and each binds the proposal's level, key, value and the value it was shown against. On the answer mesh-config reads diff --git a/modules/mesh-config/cmd/mesh-config/proposals.go b/modules/mesh-config/cmd/mesh-config/proposals.go index d3e689dc9..e38bee873 100644 --- a/modules/mesh-config/cmd/mesh-config/proposals.go +++ b/modules/mesh-config/cmd/mesh-config/proposals.go @@ -641,8 +641,8 @@ func (c *Config) propose(call Call, action string) (Proposal, oc.Ask, []string, return fail("the change carries %s, which leaves the mesh nowhere, so the operator could not be shown what "+ "they approve; config holds no secret, and %s", refusal, AtTheTerminalInstead) } - // **Its own cap of open asks, and the same change once** (ADR 0277 §21); a newer proposal for the same place - // replaces an older one still open (§10). + // **The same change once** (ADR 0277 §21); a newer proposal for the same place replaces an older one still open + // (§10). No cap of open asks of its own: the router offers at most three and holds the oldest back (ADR 0666 §12). all, err := c.proposals() if err != nil { return Proposal{}, oc.Ask{}, nil, err @@ -662,10 +662,6 @@ func (c *Config) propose(call Call, action string) (Proposal, oc.Ask, []string, } open++ } - if open >= occ.MostOpen { - return fail("%d proposals already wait for the operator's answer, and mesh-config asks at most %d at once; "+ - "config's proposals lists them", open, occ.MostOpen) - } if why := approverReady(c.Asks); why != "" { return fail("%s; %s", why, AtTheTerminalInstead) } diff --git a/modules/mesh-config/cmd/mesh-config/proposals_test.go b/modules/mesh-config/cmd/mesh-config/proposals_test.go index e41c281d3..da09744a5 100644 --- a/modules/mesh-config/cmd/mesh-config/proposals_test.go +++ b/modules/mesh-config/cmd/mesh-config/proposals_test.go @@ -484,9 +484,10 @@ func TestAProposalIsJudgedAndRefusedBeforeTheOperatorIsAsked(t *testing.T) { } propose(t, c, Call{Key: "font-size", Value: 15.0, Node: "novox"}) propose(t, c, Call{Key: "agent-managed-settings", Value: map[string]any{"a": 1.0}}) + // A fourth is asked, never refused: the router holds the asker's oldest back (ADR 0666 §12). if _, err := c.Propose(Call{Action: "propose", Key: "width", Value: 400.0, Node: "g14", Module: "dunst", - Caller: "g", Why: "w"}); err == nil || !strings.Contains(err.Error(), "3 proposals already wait") { - t.Errorf("a fourth open ask: %v", err) + Caller: "g", Why: "w"}); err != nil { + t.Errorf("a fourth open ask was refused: %v", err) } if keys, _ := m.Keys(ValuesState); len(keys) != 1 { t.Errorf("proposals set %v", keys)