fix9b2-4: the view's build usage finds a seat's holder with mesh-sdk's seatlist.HolderOf, no lookup of its own

Builds: design 47 G A-126, A-82 (the view part of fix9-6 70e5845b taken in with the manifest tests' reader of fix9-1 09839e5d, which the view's tests need)
This commit is contained in:
2026-11-12 01:23:47 +01:00
parent e69f55468c
commit 418bf4f54f
7 changed files with 175 additions and 47 deletions
@@ -15,12 +15,15 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient/enginereads"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate"
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/busretry"
"git.novox.be/novox/mesh-sdk/go/seatdef"
"git.novox.be/novox/mesh-sdk/go/seatlist"
"git.novox.be/novox/mesh-sdk/go/views"
)
@@ -405,6 +408,15 @@ func ownersRead(ask func(key string, body any) (json.RawMessage, error)) view.Re
GraphState: indexer("indexer_read_graph")}
}
// holderOf is a seat's holder as mesh-sdk's seatlist.HolderOf answers it (design 47 G A-126): false while the seat has none or
// the seat list cannot be read.
func holderOf(ask func(key string, body any) (json.RawMessage, error)) func(seat string) (string, bool) {
return func(seat string) (string, bool) {
module, err := seatlist.HolderOf(ask, seat)
return module, err == nil
}
}
func main() {
r := ownersRead(stdio.Ask)
r.Builds, r.HavesState = read(stdio.State("mesh-delivery-builder.builds")), read(stdio.State("node-engine.have"))
@@ -416,16 +428,28 @@ func main() {
r.ProvisionsState = read(stdio.State(view.ProvisionsRead))
r.BuildLog = stdio.Log(builds.BuildLogRead).Since
r.Pending = pendingOf
// The build modules are no names (design 47 G A-82): the build seats on the seat list, each held by the module the seat
// list names for it; the seat list and its two tools are wired once by mesh-sdk (§204).
gate := seatlist.NewPart("view", []string{stdio.AnyPerson, "node-tools", "mesh-healers"})
go func() {
<-stdio.Served()
gate.Follow(seatlist.StdioBus(), nil, func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] "+f+"\n", a...) })
}()
seats := buildrun.NewBuildSeats(func() map[string]seatdef.Definition {
if rd := gate.Reader(); rd != nil {
return rd.Definitions()
}
return nil
}, holderOf(stdio.Ask))
u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")),
Steps: map[string]view.StateRead{}, Pauses: map[string]view.StateRead{}, Backlog: backlogOf(socket())}
for _, lang := range buildstep.AskLanguages {
module, _ := buildstep.BuildModuleOf(lang)
u.Steps[lang] = read(stdio.State(module + "." + view.StepsState))
u.Pauses[lang] = read(stdio.State(module + "." + buildstep.PausesState))
}
Seats: seats,
StepsOf: func(seat string) view.StateRead { return read(stdio.State(seat + "." + view.StepsState)) },
PausesOf: func(seat string) view.StateRead { return read(stdio.State(seat + "." + buildstep.PausesState)) },
Backlog: backlogOf(socket())}
// view_first_views and view_first_view_again: where the view's process stands with its first views of the indexer's and
// the assigner's states (ADR 0615 §6), and a re-read by hand.
tools := append(Tools(r, u), views.StatusTools(viewstate.ViewModule, "view_first_views", "view_first_view_again", stdio.State(views.StatusState), meshhandactsclient.Recorder{Ask: stdio.Ask}, time.Now)...)
tools := append(Tools(r, u), gate.Tools()...)
tools = append(tools, views.StatusTools(viewstate.ViewModule, "view_first_views", "view_first_view_again", stdio.State(views.StatusState), meshhandactsclient.Recorder{Ask: stdio.Ask}, time.Now)...)
if err := stdio.Serve("", tools); err != nil {
fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] %v\n", err)
os.Exit(1)
@@ -3,6 +3,7 @@ package main
import (
"crypto/ed25519"
"encoding/json"
"errors"
"fmt"
"mesh-delivery-view/internal/view"
"reflect"
@@ -20,6 +21,7 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/busretry"
"git.novox.be/novox/mesh-sdk/go/keys"
"git.novox.be/novox/mesh-sdk/go/seatlist"
)
type fake map[string]string
@@ -625,3 +627,26 @@ func manifestReadsAsksEveryNode(t *testing.T) {
t.Errorf("node_manifest_reads = %+v", rows)
}
}
// Design 47 G A-82, A-74: a build seat's holder is the module the seat mesh-module-assigner's verb assignments names for it with
// the seats, and none while the seat has no holder or the list cannot be read.
func TestABuildSeatsHolderIsTheOneTheSeatListNames(t *testing.T) {
var asked []string
ask := func(key string, _ any) (json.RawMessage, error) {
asked = append(asked, key)
return json.RawMessage(`{"seats":[{"seat":"node-build-go","scope":"node","holders":[{"module":"acme-go","node":"n1"}]},{"seat":"node-build-node","scope":"node","holders":[]}]}`), nil
}
holder := holderOf(ask)
if m, ok := holder("node-build-go"); !ok || m != "acme-go" {
t.Errorf("the holder of node-build-go = %q, %v; want acme-go", m, ok)
}
if m, ok := holder("node-build-node"); ok {
t.Errorf("a seat with no holder has %q", m)
}
if len(asked) != 2 || asked[0] != seatlist.HolderKey() {
t.Errorf("asked %v; want the seat mesh-module-assigner's assignments", asked)
}
if _, ok := holderOf(func(string, any) (json.RawMessage, error) { return nil, errors.New("down") })("node-build-go"); ok {
t.Error("a seat list that cannot be read names a holder")
}
}
+1
View File
@@ -16,6 +16,7 @@ require (
git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-delivery/modules/mesh-delivery-assigner/asks v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-sdk/go v0.0.0-00010101000000-000000000000
@@ -21,6 +21,7 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
buildseats "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
"git.novox.be/novox/mesh-delivery/sdk/buildrun"
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
)
@@ -50,9 +51,11 @@ const (
// UsageReader reads what build_usage answers from.
type UsageReader struct {
// Steps and Pauses are each build module's states by language (go, node, image).
Steps map[string]StateRead
Pauses map[string]StateRead
// Seats are the build seats, each by the acting rule that builds, with the module holding it on the seat list (design 47 G
// A-82): no build module is named here. StepsOf and PausesOf read a build seat's steps and pauses through the seat.
Seats *buildseats.BuildSeats
StepsOf func(seat string) StateRead
PausesOf func(seat string) StateRead
// Resolved is mesh-config's resolved values (<node>.<module>.<key>); Haves the node-engine's have.
Resolved StateRead
Haves StateRead
@@ -209,6 +212,16 @@ func (u UsageReader) Usage() UsageAnswer {
note := func(f string, a ...any) { ans.Notes = append(ans.Notes, fmt.Sprintf(f, a...)) }
tries := u.tries(now, &ans, note)
// The build seats once for this answer: each asks the seat list for its holder (design 47 G A-82).
buildSeats := u.Seats.All()
buildSeatOfModule := func(module string) buildseats.BuildModule {
for _, m := range buildSeats {
if m.Module == module && module != "" {
return m
}
}
return buildseats.BuildModule{}
}
seats := map[string]map[string]*SeatUsage{} // node -> language -> seat
seat := func(node, lang string) *SeatUsage {
if seats[node] == nil {
@@ -217,9 +230,13 @@ func (u UsageReader) Usage() UsageAnswer {
if s := seats[node][lang]; s != nil {
return s
}
name, _ := buildstep.BuildSeat(lang)
module, _ := buildstep.BuildModuleOf(lang)
s := &SeatUsage{Seat: name, Module: module, Running: RunningUsage{ByKind: map[string]int{}}, LeftRunning: []StepUsage{}, EndedStale: []StepUsage{}, Steps: []StepUsage{}}
var bm buildseats.BuildModule
for _, m := range buildSeats {
if m.AskLanguage() == lang {
bm = m
}
}
s := &SeatUsage{Seat: bm.Seat, Module: bm.Module, Running: RunningUsage{ByKind: map[string]int{}}, LeftRunning: []StepUsage{}, EndedStale: []StepUsage{}, Steps: []StepUsage{}}
seats[node][lang] = s
return s
}
@@ -233,10 +250,8 @@ func (u UsageReader) Usage() UsageAnswer {
} else {
var want []string
for _, k := range keys {
for _, lang := range buildstep.AskLanguages {
if m, _ := buildstep.BuildModuleOf(lang); strings.HasSuffix(k, "."+m) {
want = append(want, k)
}
if _, module, _ := strings.Cut(k, "."); buildSeatOfModule(module).Seat != "" {
want = append(want, k)
}
}
raws, err := u.Haves.values(want)
@@ -256,8 +271,8 @@ func (u UsageReader) Usage() UsageAnswer {
}
for k, h := range haves {
node, module, _ := strings.Cut(k, ".")
lang := strings.TrimPrefix(module, "mesh-build-")
s := seat(node, lang)
bm := buildSeatOfModule(module)
s := seat(node, bm.AskLanguage())
s.Phase, s.Holds = string(h.Phase), h.Phase == nodeengineclient.PhaseRunning
}
@@ -310,19 +325,27 @@ func (u UsageReader) Usage() UsageAnswer {
}
for key := range unreadable {
node, module, _ := strings.Cut(key, ".")
seat(node, strings.TrimPrefix(module, "mesh-build-"))
bm := buildSeatOfModule(module)
seat(node, bm.AskLanguage())
}
// Every node with a resolved capacity is listed, so "is this node eligible" is answered for it.
for key := range resolved {
node, module, _ := strings.Cut(key, ".")
seat(node, strings.TrimPrefix(module, "mesh-build-"))
bm := buildSeatOfModule(module)
seat(node, bm.AskLanguage())
}
if len(buildSeats) == 0 {
note("no build seat is known from the seat definitions and the seat list, so no steps or pauses are read")
}
// The steps of each build module.
steps := map[string]map[string][]usageStep{} // node -> language -> steps
for _, lang := range buildstep.AskLanguages {
module, _ := buildstep.BuildModuleOf(lang)
sr, ok := u.Steps[lang]
if !ok || sr.Keys == nil || sr.Get == nil {
for _, bm := range buildSeats {
lang, module := bm.AskLanguage(), cmpOr(bm.Module, bm.Seat)
var sr StateRead
if u.StepsOf != nil {
sr = u.StepsOf(bm.Seat)
}
if sr.Keys == nil || sr.Get == nil {
note("the steps of %s are not readable here", module)
continue
}
@@ -379,10 +402,13 @@ func (u UsageReader) Usage() UsageAnswer {
// Pauses: paused.<node> of each module; and capacity.<node>, the capacity the module says it judges by.
paused := map[string]bool{} // <node>.<language>
judged := map[string]buildstep.Capacity{}
for _, lang := range buildstep.AskLanguages {
module, _ := buildstep.BuildModuleOf(lang)
pr, ok := u.Pauses[lang]
if !ok || pr.Get == nil {
for _, bm := range buildSeats {
lang, module := bm.AskLanguage(), cmpOr(bm.Module, bm.Seat)
var pr StateRead
if u.PausesOf != nil {
pr = u.PausesOf(bm.Seat)
}
if pr.Get == nil {
note("the pauses of %s are not readable here, so none is said paused", module)
continue
}
@@ -422,7 +448,8 @@ func (u UsageReader) Usage() UsageAnswer {
for _, node := range nodes {
nu := NodeUsage{Node: node, Seats: []SeatUsage{}, Said: []string{},
CPU: "not on the bus: the disk-load module keeps no state; " + node + "/disk-load.cpu_top reads it (the build modules' share among its units)"}
for _, lang := range buildstep.AskLanguages {
for _, bm := range buildSeats {
lang := bm.AskLanguage()
s := seats[node][lang]
if s == nil {
continue
@@ -696,3 +723,11 @@ func sumMedian(d []int64) (sum, median int64) {
}
return sum, s[(len(s)-1)/2]
}
// cmpOr is the first of two names that is not empty.
func cmpOr(a, b string) string {
if a != "" {
return a
}
return b
}
@@ -4,6 +4,8 @@ import (
"encoding/json"
"errors"
"fmt"
buildseats "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
"git.novox.be/novox/mesh-sdk/go/seatdef"
"strconv"
"strings"
"testing"
@@ -82,8 +84,19 @@ func usageFixture() UsageReader {
"shanks.mesh-config.other": `{"value":"x"}`,
"g14.mesh-build-node.capacity": `{"node":"g14","module":"mesh-build-node","key":"capacity","source":"unreadable"}`,
}),
Steps: map[string]StateRead{"go": states(goSteps), "node": states(map[string]string{}), "image": states(map[string]string{})},
Pauses: map[string]StateRead{"go": states(map[string]string{"paused.ace": `{"v":1,"paused":true,"by":"lead@shanks","at":"2026-10-26T09:00:00Z"}`}), "node": states(nil), "image": states(nil)},
Seats: buildSeatsOf(),
StepsOf: func(seat string) StateRead {
if seat == "node-build-go" {
return states(goSteps)
}
return states(map[string]string{})
},
PausesOf: func(seat string) StateRead {
if seat == "node-build-go" {
return states(map[string]string{"paused.ace": `{"v":1,"paused":true,"by":"lead@shanks","at":"2026-10-26T09:00:00Z"}`})
}
return states(nil)
},
Tries: states(map[string]string{
"try-" + strconv.FormatInt(at("11:29").UnixNano(), 10): `{"id":"try-1","repository":"novox/mesh-sdk","head":"h","trunk":"t","state":"pass","asks":["` + tryAsk + `"]}`,
"try-" + strconv.FormatInt(at("11:58").UnixNano(), 10): `{"id":"try-2","repository":"novox/mesh-delivery","head":"h","trunk":"t","state":"running","started":"2026-10-26T11:58:00Z"}`,
@@ -167,7 +180,7 @@ func TestBuildUsageAnswersEveryNodesUseFromTheStates(t *testing.T) {
// Nothing readable: each state is named in a note, the backlog's refusal too, and nothing is said held.
none := UsageReader{Now: func() time.Time { return usageNow }, Backlog: func() ([]BacklogRow, error) { return nil, errors.New("no socket") }}.Usage()
notes := strings.Join(none.Notes, " | ")
for _, want := range []string{"have is not readable", "capacity unknown to this tool: mesh-config's resolved values are not readable", "steps of mesh-build-go are not readable", "tries are not readable", "did not answer: no socket"} {
for _, want := range []string{"have is not readable", "capacity unknown to this tool: mesh-config's resolved values are not readable", "no build seat is known", "tries are not readable", "did not answer: no socket"} {
if !strings.Contains(notes, want) {
t.Errorf("the notes %q do not say %q", notes, want)
}
@@ -196,8 +209,8 @@ func TestBuildUsageAnswersEveryNodesUseFromTheStates(t *testing.T) {
// Issue 1806's follow-up: the module on shanks says it judges by 1 of mesh-config's 2 (its build CPU bounds it); the
// seat says the module's capacity and why. And issue 1890: a running try that names its asks is said with them.
u = usageFixture()
u.Pauses["go"] = states(map[string]string{"capacity.shanks": `{"v":1,"effective":1,"configured":2,"quota-from":"the cpu.max of /meshyield.slice","quota-cores":6,"cores-per-step":6,"by-cpu":1,"why":"1, bounded by the CPU","at":"2026-10-26T11:00:00Z"}`,
"capacity.ace": `{"v":1,"effective":2,"configured":3,"why":"stale: mesh-config says 2 now"}`})
setPauses(&u, "node-build-go", states(map[string]string{"capacity.shanks": `{"v":1,"effective":1,"configured":2,"quota-from":"the cpu.max of /meshyield.slice","quota-cores":6,"cores-per-step":6,"by-cpu":1,"why":"1, bounded by the CPU","at":"2026-10-26T11:00:00Z"}`,
"capacity.ace": `{"v":1,"effective":2,"configured":3,"why":"stale: mesh-config says 2 now"}`}))
u.Tries = states(map[string]string{"try-" + strconv.FormatInt(at("11:58").UnixNano(), 10): `{"id":"try-2","repository":"novox/mesh-delivery","head":"h","trunk":"t","state":"running","asks":["` + tryAsk0 + `"],"steps":[{"ask":"` + tryAsk0 + `","node":"shanks","state":"running","phase":"unit: tests of 3 packages"}]}`})
bound := u.Usage()
sc := seatOf(t, bound, "shanks", "node-build-go")
@@ -208,13 +221,13 @@ func TestBuildUsageAnswersEveryNodesUseFromTheStates(t *testing.T) {
t.Errorf("a module's word older than mesh-config's value is not taken: %+v", sa)
}
// The operator, 2026-10-26: outside its build hours the seat takes nothing new, and says so.
u.Pauses["go"] = states(map[string]string{"capacity.shanks": `{"v":1,"effective":0,"configured":2,"build-hours":"18:00-06:00 CET","outside-hours":true,"why":"0, outside its build hours 18:00-06:00 CET until 18:00 (otherwise 2)","at":"2026-10-26T11:00:00Z"}`})
setPauses(&u, "node-build-go", states(map[string]string{"capacity.shanks": `{"v":1,"effective":0,"configured":2,"build-hours":"18:00-06:00 CET","outside-hours":true,"why":"0, outside its build hours 18:00-06:00 CET until 18:00 (otherwise 2)","at":"2026-10-26T11:00:00Z"}`}))
if so := seatOf(t, u.Usage(), "shanks", "node-build-go"); so.Capacity != 0 || !so.OutsideHours || so.Eligible == nil || *so.Eligible ||
so.WhyNot != "outside its build hours 18:00-06:00 CET on shanks: it takes nothing new until they open" {
t.Errorf("a seat outside its build hours: %+v", so)
}
// A build-hours value the module cannot read: it builds at any hour, and the seat says the value and why.
u.Pauses["go"] = states(map[string]string{"capacity.shanks": `{"v":1,"effective":2,"configured":2,"build-hours-fault":"the build hours \"shanks=18:00-6\": \"6\" is not a time HH:MM","why":"2; at any hour, because its build hours cannot be read","at":"2026-10-26T11:00:00Z"}`})
setPauses(&u, "node-build-go", states(map[string]string{"capacity.shanks": `{"v":1,"effective":2,"configured":2,"build-hours-fault":"the build hours \"shanks=18:00-6\": \"6\" is not a time HH:MM","why":"2; at any hour, because its build hours cannot be read","at":"2026-10-26T11:00:00Z"}`}))
if sf := seatOf(t, u.Usage(), "shanks", "node-build-go"); sf.BuildHours != "any hour" || !strings.Contains(sf.BuildHoursFault, "shanks=18:00-6") || sf.Eligible == nil || !*sf.Eligible {
t.Errorf("a seat whose build hours cannot be read: %+v", sf)
}
@@ -225,3 +238,25 @@ func TestBuildUsageAnswersEveryNodesUseFromTheStates(t *testing.T) {
}
var tryAsk0 = stepID(at("11:58"), "a00010")
// buildSeatsOf is the build seats as the seat definitions and the seat list give them (design 47 G A-82): the seats whose
// acting rule builds, each held by the module the seat list names.
func buildSeatsOf() *buildseats.BuildSeats {
rule := func(on string) seatdef.Definition {
return seatdef.Definition{Acts: []seatdef.ActingRule{{Step: seatdef.StepBuild, On: on}}}
}
defs := map[string]seatdef.Definition{"node-build-go": rule("go"), "node-build-node": rule("typescript"), "node-build-image": rule(seatdef.OnKindImage)}
holders := map[string]string{"node-build-go": "mesh-build-go", "node-build-node": "mesh-build-node", "node-build-image": "mesh-build-image"}
return buildseats.NewBuildSeats(func() map[string]seatdef.Definition { return defs }, func(seat string) (string, bool) { h, ok := holders[seat]; return h, ok })
}
// setPauses replaces what one build seat's pauses read.
func setPauses(u *UsageReader, seat string, st StateRead) {
prev := u.PausesOf
u.PausesOf = func(s string) StateRead {
if s == seat {
return st
}
return prev(s)
}
}
+5 -3
View File
@@ -106,7 +106,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
if m.Module != "mesh-delivery-view" {
t.Errorf("module = %q", m.Module)
}
want := []string{"mesh-build-go.pauses", "mesh-build-go.steps", "mesh-build-image.pauses", "mesh-build-image.steps", "mesh-build-node.pauses", "mesh-build-node.steps", "mesh-conditions.conditions", "mesh-config.resolved", "mesh-delivery-builder.build-log", "mesh-delivery-builder.builds", "mesh-delivery-checker.tries", "mesh-delivery-gate.asks", "mesh-delivery-gate.source", "mesh-delivery-teller.answers", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-provisioner.provisions", "mesh-vault.signers", "node-engine.have"} // no reads of the indexer's or the assigner's states (ADR 0615 §1, DLV-M4); view_tiers reads the module graph and the provisioner's keys (ADR 0603 §6); view_status reads the keeper's conditions and the healers' attempts (1952/V1); build_usage reads the build modules' steps and pauses, mesh-config's capacities and the checker's tries; 1168/AC1, 1241/AC4, 1345/AC3, 1297/B8, B9
want := []string{"mesh-conditions.conditions", "mesh-config.resolved", "mesh-delivery-builder.build-log", "mesh-delivery-builder.builds", "mesh-delivery-checker.tries", "mesh-delivery-gate.asks", "mesh-delivery-gate.source", "mesh-delivery-teller.answers", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-provisioner.provisions", "mesh-vault.signers", "node-build-go.pauses", "node-build-go.steps", "node-build-image.pauses", "node-build-image.steps", "node-build-node.pauses", "node-build-node.steps", "node-engine.have"} // the build seats' states by seat, never a build module (design 47 G A-82); // no reads of the indexer's or the assigner's states (ADR 0615 §1, DLV-M4); view_tiers reads the module graph and the provisioner's keys (ADR 0603 §6); view_status reads the keeper's conditions and the healers' attempts (1952/V1); build_usage reads the build modules' steps and pauses, mesh-config's capacities and the checker's tries; 1168/AC1, 1241/AC4, 1345/AC3, 1297/B8, B9
got := slices.Clone(m.Reads)
slices.Sort(got)
if !reflect.DeepEqual(got, want) {
@@ -124,7 +124,9 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
"mesh-delivery-indexer.indexer_read_graph", "mesh-delivery-indexer.indexer_read_heard", "mesh-delivery-indexer.indexer_pending",
"mesh-delivery-indexer.indexer_read_packages", "mesh-delivery-indexer.indexer_read_predefined", "mesh-delivery-indexer.indexer_read_taken",
"seat:mesh-catalog.revision", // ADR 0663: the modules are the catalog half's, read through the seat's verb revision, never the indexer's
"seat:mesh-catalog.seat-definitions", // design 47 G A-82, §204: the build seats are read from the seat list
"seat:mesh-hand-acts.hand-act", // the join: its first view asked again by hand is a hand act (views.StatusTools)
"seat:mesh-module-assigner.assignments", // A-82: the holder of each build seat
"seat:node-engine.manifest-reads"}; !reflect.DeepEqual(m.Invokes, want) { // ADR 0618 §3: node_manifest_reads asks the node-engine seat's verb of every node; 1585/T24: view_tiers asks indexer_pending, a verb edge (ADR 0614 §2)
t.Errorf("invokes = %v, want %v", m.Invokes, want)
}
@@ -139,7 +141,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
t.Errorf("version = %q, want 0.1", m.Version)
}
if want := []string{"mesh-conditions.findings-asked", "mesh-delivery-assigner.views.asks", "mesh-delivery-assigner.views.assignments", "mesh-delivery-assigner.views.wants",
"mesh-catalog.catalog-revision", "mesh-delivery-indexer.views.candidates", "mesh-delivery-indexer.views.taken"}; !reflect.DeepEqual(m.Consumes, want) {
"mesh-catalog.catalog-revision", "mesh-catalog.seat-definition-changed", "mesh-catalog.seat-definition-removed", "mesh-delivery-indexer.views.candidates", "mesh-delivery-indexer.views.taken"}; !reflect.DeepEqual(m.Consumes, want) {
t.Errorf("consumes = %v, want %v", m.Consumes, want)
}
// The one event the view says: a source revision is delivered (1906/D9, ADR 0539 §17), derived by it from the wants and the haves.
@@ -164,7 +166,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
}
// The two read tools of the indexer's modules (issue 1562), carried by a bundle the runtime launches; the indexer
// itself serves no tool (ADR 0437 §4). Carrying them gives the tool runner read access to every bucket the view reads.
if want := []string{"view_status", "indexer_module", "indexer_modules", "indexer_candidate", "indexer_candidates", "indexer_predefined", "indexer_config_candidates", "indexer_packages", "builder_build", "builder_builds", "builder_history", "assigner_wants", "assigner_want", "assigner_differences", "node_haves", "node_trusts", "build_usage", "view_reach", "indexer_module_history", "indexer_heard", "view_tiers", "view_first_views", "view_first_view_again", "node_manifest_reads"}; !reflect.DeepEqual(m.Tools, want) {
if want := []string{"view_status", "indexer_module", "indexer_modules", "indexer_candidate", "indexer_candidates", "indexer_predefined", "indexer_config_candidates", "indexer_packages", "builder_build", "builder_builds", "builder_history", "assigner_wants", "assigner_want", "assigner_differences", "node_haves", "node_trusts", "build_usage", "view_reach", "indexer_module_history", "indexer_heard", "view_tiers", "view_first_views", "view_first_view_again", "node_manifest_reads", "view_seat_list", "view_seat_list_again"}; !reflect.DeepEqual(m.Tools, want) {
t.Errorf("tools = %v, want %v", m.Tools, want)
}
// D-11: the holders and buckets the view names are its manifest's (no contract names a holder, novox/hq ADR 0634 §1): a
+13 -7
View File
@@ -27,7 +27,9 @@
"view_tiers",
"view_first_views",
"view_first_view_again",
"node_manifest_reads"
"node_manifest_reads",
"view_seat_list",
"view_seat_list_again"
],
"emits": [
"delivered",
@@ -56,6 +58,8 @@
"mesh-delivery-assigner.views.assignments",
"mesh-delivery-assigner.views.wants",
"mesh-catalog.catalog-revision",
"mesh-catalog.seat-definition-changed",
"mesh-catalog.seat-definition-removed",
"mesh-delivery-indexer.views.candidates",
"mesh-delivery-indexer.views.taken"
],
@@ -73,16 +77,18 @@
"mesh-delivery-indexer.indexer_read_predefined",
"mesh-delivery-indexer.indexer_read_taken",
"seat:mesh-catalog.revision",
"seat:mesh-catalog.seat-definitions",
"seat:mesh-hand-acts.hand-act",
"seat:mesh-module-assigner.assignments",
"seat:node-engine.manifest-reads"
],
"reads": [
"mesh-build-go.pauses",
"mesh-build-go.steps",
"mesh-build-image.pauses",
"mesh-build-image.steps",
"mesh-build-node.pauses",
"mesh-build-node.steps",
"node-build-go.pauses",
"node-build-go.steps",
"node-build-image.pauses",
"node-build-image.steps",
"node-build-node.pauses",
"node-build-node.steps",
"mesh-config.resolved",
"mesh-delivery-builder.build-log",
"mesh-delivery-builder.builds",