The controller ended by its unassignment (ADR 0590), so its seat, the grants seat's lease write and hand-back and placement's take-over from it serve nothing. The dependence check becomes strict (clause 5): a read of the lease, a claim, a require or the module itself is refused like any other declaration. held and artifacts-gone are the artifact sweep seat's (ADR 0571 §2). Issue 1126 B1, B2. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
144 lines
4.4 KiB
Go
144 lines
4.4 KiB
Go
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 <id>` or `tools <binary>`.
|
|
By string `json:"by,omitempty"`
|
|
Kind string `json:"kind"`
|
|
What string `json:"what"`
|
|
}
|
|
|
|
// onController says whether a name `<owner>.<rest>` 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
|
|
}
|