// Command noplacement refuses what the repository path of placement left behind (novox/hq ADR 0567 §10, §12). // // Placement, which module runs on which node, is bus state held by the seat mesh-placement; no file of the // catalogue says it, and no manifest reads it from the delivery indexer, which no longer keeps it. It refuses: // // 1. a `placement` directory (or file) at the root of the catalogue; // // 2. a `particulars` file at the root (the mesh's node names come from the checker's run, §16); // // 3. a manifest naming a state, stream, event or bucket of the indexer's placement (`mesh-delivery-indexer.placement…` // or `mesh-delivery-indexer_placement…`) in any string value, such as `reads`. // // go run . // // Exits 1 on a finding. package main import ( "encoding/json" "fmt" "os" "path/filepath" "sort" "strings" ) // Prefixes are the names of the indexer's placement parts; a manifest string starting with one names them. var Prefixes = []string{"mesh-delivery-indexer.placement", "mesh-delivery-indexer_placement"} // Findings is every refusal in the catalogue at root, sorted. func Findings(root string) ([]string, error) { var out []string if _, err := os.Lstat(filepath.Join(root, "placement")); err == nil { out = append(out, "placement: the repository holds no placement; it is bus state of the seat mesh-placement (novox/hq ADR 0567 §10)") } if _, err := os.Lstat(filepath.Join(root, "particulars")); err == nil { out = append(out, "particulars: the repository lists no node names; the checker hands them to the check (novox/hq ADR 0567 §16)") } manifests, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json")) if err != nil { return nil, err } sort.Strings(manifests) for _, file := range manifests { raw, err := os.ReadFile(file) if err != nil { return nil, err } var doc any if err := json.Unmarshal(raw, &doc); err != nil { return nil, fmt.Errorf("%s: %w", file, err) } module := filepath.Base(filepath.Dir(file)) for _, s := range named(doc, nil) { out = append(out, fmt.Sprintf("%s: names %q, which the indexer no longer keeps; placement is the seat mesh-placement's (novox/hq ADR 0567 §12)", module, s)) } } return out, nil } // named collects the strings of a decoded manifest that start with one of the Prefixes. func named(v any, into []string) []string { switch v := v.(type) { case string: for _, p := range Prefixes { if strings.HasPrefix(v, p) { return append(into, v) } } case []any: for _, e := range v { into = named(e, into) } case map[string]any: for _, e := range v { into = named(e, into) } } return into } func main() { if len(os.Args) != 2 { fmt.Fprintln(os.Stderr, "usage: noplacement ") os.Exit(2) } found, err := Findings(os.Args[1]) if err != nil { fmt.Println(err) os.Exit(1) } for _, f := range found { fmt.Println(f) } if len(found) > 0 { os.Exit(1) } fmt.Println("no placement directory, and no manifest reads the indexer's placement") }