package catalogue import ( "fmt" "slices" "sort" "strings" ) // **Nothing may name the controller** (novox/hq ADR 0590 clause 5, issue 1126): the controller ended by its unassignment // on 2026-11-02 and its code left the mesh, so a manifest that reads one of its states (its lease too), invokes one of its // verbs or tools, consumes or waits on one of its events, uses, claims or requires it, or is it, depends on nothing that // answers. ManifestRefusals runs the check over a repository's manifests, in the test each repository of manifests keeps // (mesh-catalog, mesh-delivery, mesh-tools); a later decision that places a controller again must first lift it. // EndedControllerName is the name the ended controller had, as its module and as its seat: no manifest may name it. const EndedControllerName = "mesh-controller" // The kinds of a declaration that names the controller. const ( DependsRead = "read" DependsInvoke = "invoke" DependsConsume = "consume" DependsUses = "uses" DependsWaits = "waits" DependsClaims = "claims" DependsRequires = "requires" DependsIs = "is" ) // Dependency is one declaration of a manifest that names the controller. type Dependency struct { Module string `json:"module"` // By is the account declaring it when it is not the module's own: `process ` or `tools `. By string `json:"by,omitempty"` Kind string `json:"kind"` What string `json:"what"` } // onController says whether a name `.` is the controller's. func onController(name string) bool { return strings.HasPrefix(name, EndedControllerName+".") } // invokesController says whether an invoke names a verb of the controller's seat or a tool of its module. `*` names none: // it is the console's grant to every tool. func invokesController(invoke string) bool { if seat, _, ok := SeatInvoke(invoke); ok { return seat == EndedControllerName } return onController(invoke) } // Dependencies are every declaration naming the controller in the manifests given, by module. func Dependencies(manifests map[string]Manifest) []Dependency { var out []Dependency add := func(module, by, kind, what string) { if d := (Dependency{Module: module, By: by, Kind: kind, What: what}); !slices.Contains(out, d) { out = append(out, d) } } for name, m := range manifests { if name == EndedControllerName || m.Module == EndedControllerName { add(name, "", DependsIs, EndedControllerName) } for _, r := range m.Reads { if onController(r) { add(name, "", DependsRead, r) } } for _, i := range m.Invokes { if invokesController(i) { add(name, "", DependsInvoke, i) } } for _, c := range m.Consumes { if onController(c) { add(name, "", DependsConsume, c) } } for _, w := range m.Waits { if onController(w) { add(name, "", DependsWaits, w) } } for _, u := range m.Uses { if u == EndedControllerName { add(name, "", DependsUses, u) } } for _, c := range m.Claims { if c.Name == EndedControllerName { add(name, "", DependsClaims, c.Name) } } for _, r := range m.Requires { if r == EndedControllerName || onController(r) { add(name, "", DependsRequires, r) } } for _, a := range m.BusAccounts() { by := "process " + a.ID if a.Tools { by = "tools " + a.ID } for _, i := range a.Bus.Invokes { if invokesController(i) { add(name, by, DependsInvoke, i) } } } } sort.Slice(out, func(i, j int) bool { a, b := out[i], out[j] if a.Module != b.Module { return a.Module < b.Module } if a.Kind != b.Kind { return a.Kind < b.Kind } if a.What != b.What { return a.What < b.What } return a.By < b.By }) return out } // ManifestRefusals is the check over a repository's manifests, by module name: one reason per declaration naming the // controller, none when it passes. None given fails it, since nothing read can hide a declaration. func ManifestRefusals(manifests map[string]Manifest) []string { if len(manifests) == 0 { return []string{"no manifest was read: with nothing read, nothing naming the controller can be judged absent"} } var out []string for _, d := range Dependencies(manifests) { who := d.Module if d.By != "" { who += " (" + d.By + ")" } out = append(out, fmt.Sprintf("%s declares %s %s: the controller ended by its unassignment and nothing may name it "+ "(ADR 0590 clause 5)", who, d.Kind, d.What)) } return out }