The assigner's rule 8 waited for a key for every `requires`, while the plans named only the needs of handed modules: every new build of grafana, dnsmasq, mesh-knowledge, mesh-mail and the builders waited for a key nobody would make, and grafana, not handed, had no plan, so no route key and no route on route-proxy. catalogue.Keyed is the rule (a need a module answers is keyed when its consumer is handed or the provider's helper answers it), catalogue.Awaited the same rule from manifests for the assigner, and a module not handed now has a plan for what a helper answers of it. Handed modules' plans are unchanged. Quick fix: drop the missing-key check from rule 8. Thorough fix (chosen): one rule in mesh-sdk all three parts use, since the kind (three parts deciding the same set apart) already drifted once and hid failures as waits.
68 lines
3.0 KiB
Go
68 lines
3.0 KiB
Go
package catalogue
|
|
|
|
import "slices"
|
|
|
|
// The one rule of which provisions the seat mesh-provisioner keys and a want waits for (novox/hq ADR 0570 §1, §2, §4;
|
|
// issue 774). The plan composition puts a need in a consumer's plan by it, the holder of mesh-provisioner keys what the
|
|
// plans name, and the assigner's rule 8 waits for what Awaited answers: three parts, one rule, so they cannot drift
|
|
// again (on 2026-10-30 the assigner waited for every `requires` while the plans named only some, and every new build of
|
|
// grafana, dnsmasq, mesh-knowledge, mesh-mail and the builders waited for a key nobody would make).
|
|
//
|
|
// A need a module answers (not a record, not nothing) is keyed when its consumer is handed to the provisioner, or the
|
|
// provider's offer says the provider helper answers it. A need of a consumer not handed whose provider's helper does
|
|
// not answer it is still answered by the controller's composition: it is neither keyed nor waited for.
|
|
|
|
// HandedByManifest is whether a module is handed to the provisioner as far as its manifest says (Rendering.Handing
|
|
// without the machine's own words, and begin's): marked moved, not a held module's stub, with a template its build
|
|
// kept or an item.
|
|
func (m Manifest) HandedByManifest() bool {
|
|
return m.Moved && m.Handed != nil && !m.Stubbed && (len(m.Handed.Templates) > 0 || len(m.Items) > 0)
|
|
}
|
|
|
|
// Keyed is whether a need is a provision of the seat mesh-provisioner: a key, an entry in its consumer's plan, and a
|
|
// wait of the consumer's want. consumerHanded is whether the composition hands the consumer to the provisioner.
|
|
func Keyed(consumerHanded bool, n Needed) bool {
|
|
if n.ByRecord || n.Module == "" || n.From == "" {
|
|
return false
|
|
}
|
|
return consumerHanded || n.AnsweredByHelper
|
|
}
|
|
|
|
// Awaited is, of what consumer requires (not optionally), each provision Keyed answers yes for, judged from manifests
|
|
// alone, as the assigner reads them: providers answers the modules providing a provision. A provision is a need when a
|
|
// provider offers it to the mesh, or one on the consumer's machine serves facts about it (Resolve: one answered on the
|
|
// machine with nothing served binds nothing). It is keyed when the consumer is handed, or every provider's offer is
|
|
// answered by the helper: where the providers disagree, which one answers is the composition's, and nothing is waited
|
|
// for that might never be keyed. Sorted, each once.
|
|
func Awaited(consumer Manifest, providers func(provision string) []Manifest) []string {
|
|
var out []string
|
|
for _, r := range consumer.Requires {
|
|
if consumer.OptionalRequires[r] || slices.Contains(out, r) {
|
|
continue
|
|
}
|
|
by := providers(r)
|
|
if len(by) == 0 {
|
|
continue
|
|
}
|
|
need, helper := false, true
|
|
for _, p := range by {
|
|
for _, o := range p.Provides {
|
|
if o.Name != r {
|
|
continue
|
|
}
|
|
if o.At() == ScopeMesh || len(p.Serves[r]) > 0 {
|
|
need = true
|
|
}
|
|
}
|
|
if !p.AnsweredByHelperFor(r) {
|
|
helper = false
|
|
}
|
|
}
|
|
if need && (consumer.HandedByManifest() || helper) {
|
|
out = append(out, r)
|
|
}
|
|
}
|
|
slices.Sort(out)
|
|
return out
|
|
}
|