mesh-conditions: observe node-tools' and claude-code's first views and the builder's publishing kinds
Their views findings were written and raised by nobody (ADR 0615 §6). The test finds every catalogue module writing a views finding in the tree, so a new writer cannot go unobserved; homes for publish-refused, publish-unanswered, seat-outcome-unread and family-not-heard. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -111,6 +111,14 @@ var Homes = map[string]Home{
|
||||
"floor-silent": {Source: "builder", Observer: builder},
|
||||
"old-form-held": {Source: "builder", Observer: builder},
|
||||
"tag-removal-not-done": {Source: "builder", Observer: builder},
|
||||
// The builder's publishing (design 51): a holder refused the publish, or said nothing past its bound (about the name);
|
||||
// a holder's outcome the builder cannot read (about the seat).
|
||||
"publish-refused": {Source: "builder", Observer: builder},
|
||||
"publish-unanswered": {Source: "builder", Observer: builder},
|
||||
"seat-outcome-unread": {Source: "builder", Observer: builder},
|
||||
// A consumer of a delivery part that stopped hearing an event family (ADR 0615 §5), cleared when it binds again: written
|
||||
// by each of the indexer, the assigner, the builder and the watchman in its own findings, so the kind has no one observer.
|
||||
"family-not-heard": {Source: "views", Why: "every delivery part whose consumer stopped hearing writes its own"},
|
||||
// The indexer's own (design 26, ADR 0625): a seat definition that does not parse, generated types out of step with
|
||||
// their definition, one seat defined by two repositories' trunks, a manifest accepted and not said.
|
||||
"seat-definition-unparsed": {Source: "indexer", Observer: indexer},
|
||||
|
||||
@@ -46,7 +46,9 @@ var Observers = []string{health.WatchmanModule, health.SelfCheckModule, health.H
|
||||
"mesh-watcher", "minio", "nfs-server", gitea, "mesh-build-go",
|
||||
// The builder's, the indexer's (asked of its read tool and followed by its views events, ADR 0615 §1) and the other
|
||||
// readers' of the indexer's and the assigner's state (the registry milestone's join).
|
||||
builder, indexer, "mesh-delivery-checker", "mesh-delivery-teller", "mesh-delivery-view", enrolment}
|
||||
builder, indexer, "mesh-delivery-checker", "mesh-delivery-teller", "mesh-delivery-view", enrolment,
|
||||
// The tool runner's and claude-code's own first views (views.UnansweredFinding in their findings, ADR 0615 §6).
|
||||
"node-tools", "claude-code"}
|
||||
|
||||
// The other states it reads, as `<module>.<name>`.
|
||||
const (
|
||||
|
||||
@@ -3,6 +3,10 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -11,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
)
|
||||
|
||||
@@ -279,7 +284,8 @@ func TestEveryControllerKindHasItsHome(t *testing.T) {
|
||||
"data-shrank": selfCheck, "retire-waiting": provisioner, "asks-undelivered": messenger,
|
||||
"image-missing": artifactStore, "build-failed": builder, "floor-silent": builder, "old-form-held": builder,
|
||||
"tag-removal-not-done": builder, "seat-definition-unparsed": indexer, "generated-types-out-of-step": indexer,
|
||||
"seat-defined-twice": indexer, "accepted-unsaid": indexer, "packages-token-refused": gitea} {
|
||||
"seat-defined-twice": indexer, "accepted-unsaid": indexer, "packages-token-refused": gitea,
|
||||
"publish-refused": builder, "publish-unanswered": builder, "seat-outcome-unread": builder} {
|
||||
if h, ok := Homes[kind]; !ok || h.Observer != observer || h.Carried {
|
||||
t.Errorf("%s's home is %+v", kind, h)
|
||||
}
|
||||
@@ -302,21 +308,60 @@ func TestEveryControllerKindHasItsHome(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// The readers' unanswered first view and the owners' views too large to say are every reader's and owner's own.
|
||||
for _, kind := range []string{"first-view-unanswered", "view-too-large"} {
|
||||
for _, kind := range []string{"first-view-unanswered", "view-too-large", "family-not-heard"} {
|
||||
if h := Homes[kind]; h.Observer != "" || h.Carried || h.Controller {
|
||||
t.Errorf("%s's home is %+v", kind, h)
|
||||
}
|
||||
}
|
||||
// Each module that writes a reader's unanswered first view (ADR 0615 §6) is read.
|
||||
for _, reader := range []string{watchman, "mesh-delivery-teller", enrolment, builder, "mesh-delivery-checker",
|
||||
"mesh-delivery-view", indexer, configModule, vaultModule, gitea} {
|
||||
// Each module that writes a reader's unanswered first view (ADR 0615 §6), or that a delivery part's consumer stopped
|
||||
// hearing, is read: the delivery parts and the tool runner by name (other repositories), and every catalogue module
|
||||
// whose code writes a views finding, found in the catalogue's tree, so a new writer cannot go unobserved.
|
||||
readers := []string{watchman, "mesh-delivery-teller", enrolment, builder, "mesh-delivery-checker", "mesh-delivery-view",
|
||||
indexer, delivery.AssignerModule, configModule, vaultModule, gitea, "node-tools"}
|
||||
readers = append(readers, viewFindingWriters(t, "../../..")...)
|
||||
for _, reader := range readers {
|
||||
if !slices.Contains(Observers, reader) {
|
||||
t.Errorf("the reader %s's findings are not read by the keeper", reader)
|
||||
}
|
||||
}
|
||||
// 19 of ADR 0564, the 63 of the table, plan-failed and stalled, mesh-config's four (design 32), the readers' unanswered
|
||||
// first view, the owners' view too large, the builder's four, the indexer's four and the package seats' token refused.
|
||||
if len(Homes) != 99 || carried != 37 {
|
||||
// And the builder's three publishing kinds and the delivery parts' family not heard: 103.
|
||||
if len(Homes) != 103 || carried != 37 {
|
||||
t.Errorf("the table holds %d kinds, %d carried", len(Homes), carried)
|
||||
}
|
||||
}
|
||||
|
||||
// viewFindingWriters are the catalogue modules (under modules) whose non-test Go code writes a views finding into its own
|
||||
// findings: views.UnansweredFinding, views.TooLargeFinding or views.OwnFindings.
|
||||
func viewFindingWriters(t *testing.T, modules string) []string {
|
||||
t.Helper()
|
||||
writes := regexp.MustCompile(`views\.(UnansweredFinding|TooLargeFinding|OwnFindings)\b`)
|
||||
var out []string
|
||||
entries, err := os.ReadDir(modules)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() || e.Name() == Module {
|
||||
continue
|
||||
}
|
||||
found := false
|
||||
_ = filepath.WalkDir(filepath.Join(modules, e.Name()), func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil || found || d.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
|
||||
return nil
|
||||
}
|
||||
if src, err := os.ReadFile(path); err == nil && writes.Match(src) {
|
||||
found = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if found {
|
||||
out = append(out, e.Name())
|
||||
}
|
||||
}
|
||||
if len(out) < 5 {
|
||||
t.Fatalf("found %d catalogue modules writing views findings in %s: the tree was not read (%v)", len(out), modules, out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
"mesh-delivery-teller.findings",
|
||||
"mesh-delivery-view.findings",
|
||||
"mesh-enrolment.findings",
|
||||
"node-tools.findings",
|
||||
"claude-code.findings",
|
||||
"mesh-healers.attempts",
|
||||
"node-engine.have"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user