Keep the client filling secrets and reading the controller's assignments until the lease write; plans for held modules; warrant says yes

Review round 3 (issue 1954): the node-engine of today writes ${secret:} as given and the new one fills only
provision keys, so the client fills secrets this release; plans exist only for modules with a want, so a
module without a seat plan is read from the controller's assignment and never leaves for want of one, and
the holder composes held modules at the build they run; the SDK's provider lets go only on "yes".
This commit is contained in:
2026-10-30 00:25:12 +01:00
parent 9cb177cae6
commit fc66555ecc
13 changed files with 465 additions and 111 deletions
@@ -103,6 +103,13 @@ func (h *Holder) ComposeNode(ctx context.Context, node string) (Composed, error)
if err != nil {
return out, err
}
// A module held on the node with no want (the bus on the control-node) is composed at the build its have says it
// runs, so it has a plan too and its client keeps filling it (review of 2026-10-30).
for module, fp := range h.runningOn(node) {
if _, ok := wanted[module]; !ok {
wanted[module] = fp
}
}
atWants, err := h.Compose(ctx, node, wanted)
if err != nil {
return out, fmt.Errorf("the plans of %s cannot be composed: %w", node, err)
@@ -266,6 +273,30 @@ func (h *Holder) wantedOn(node string) (map[string]string, error) {
return out, nil
}
// runningOn is the fingerprint each module's have on a node says it runs, by module: what a module held without a want
// is composed at.
func (h *Holder) runningOn(node string) map[string]string {
out := map[string]string{}
keys, err := h.Store.Keys(HaveRead)
if err != nil {
return out
}
for _, k := range keys {
n, module, isNode, err := delivery.ParseHaveKey(k)
if err != nil || isNode || n != node {
continue
}
e, err := h.Store.Get(HaveRead, k)
if err != nil || e == nil {
continue
}
if have, err := delivery.DecodeHave(e.Value); err == nil && have.FP != "" {
out[module] = have.FP
}
}
return out
}
// writePlans writes each plan that differs and removes the node's plans of modules no longer composed there.
func (h *Holder) writePlans(node string, plans map[string]catalogue.Plan, out *Composed) error {
var problems []error
@@ -589,10 +620,12 @@ func (h *Holder) retired(key string, p provisions.Provision) (bool, string) {
// ---- the retiring ask ----------------------------------------------------------------------------------------------
// The options a retiring ask offers.
// The options a retiring ask offers. The chosen one is the warrant's option in the key, and a provider lets its entry go
// only on "yes" (mesh-sdk provider.go, the pass's retiring keys), so the approving option is "yes" (review of
// 2026-10-30: the holder wrote "approve", which no provider acted on).
const (
OptionApprove = "approve"
OptionDecline = "decline"
OptionApprove = "yes"
OptionDecline = "no"
)
// askLasts is how long a retiring ask stays open.
@@ -290,6 +290,10 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
if w := m.state(t, pg).Warrant; w == nil || w.Option != OptionApprove || !strings.Contains(w.By, "42") {
t.Fatalf("the warrant is not in the key: %+v", w)
}
// The word the SDK's provider lets an entry go on (provider.go): any other, and no provider ever retires it.
if w := m.state(t, pg).Warrant; w.Option != "yes" {
t.Fatalf("the warrant says %q, and a provider lets go only on \"yes\"", w.Option)
}
if said, _ := m.h.Rejudge(pg); said != "" || m.state(t, pg).State != provisions.Retiring {
t.Errorf("retired while the provider's entry stands: %q", said)
}
@@ -310,6 +314,30 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
}
}
// Review of 2026-10-30: a module held on a node with no want (the bus on the control-node) is composed at the build
// its have says it runs, so the holder writes it a plan and its client keeps filling it.
func TestAModuleHeldWithoutAWantIsComposedAtTheBuildItRuns(t *testing.T) {
m := newMesh()
fp := "src2:" + strings.Repeat("dd", 32)
m.s.write(t, HaveRead, "novox.nats", `{"v":1,"fp":"`+fp+`","phase":"running","health":"ok"}`)
m.s.write(t, HaveRead, "g14.dunst", `{"v":1,"fp":"src2:`+strings.Repeat("ee", 32)+`","phase":"running","health":"ok"}`)
var keptAt map[string]string
m.h.Compose = func(_ context.Context, node string, at map[string]string) (map[string]catalogue.Plan, error) {
if at != nil {
keptAt = at
return map[string]catalogue.Plan{"nats": {}}, nil
}
return nil, nil
}
c := m.compose(t, "novox")
if keptAt["nats"] != fp || len(keptAt) != 1 {
t.Fatalf("composed at %v, want nats at the build it runs and nothing of another node", keptAt)
}
if !slices.Contains(c.Plans, "novox.nats") {
t.Fatalf("no plan written for a module held without a want: %+v", c)
}
}
// The holder holds no ticker: it composes on change events alone (ADR 0570 clause 2; issue 1954 H1).
func TestTheHolderHoldsNoTimer(t *testing.T) {
files, _ := filepath.Glob("*.go")