CAT-RD1..RD10: the readers use mesh-sdk's views.Reader, say an unanswered first view in their own findings (mesh-conditions observes them) and record a re-read through mesh-hand-acts

This commit is contained in:
2026-11-04 12:23:37 +01:00
parent 5adb8e1fea
commit d8e8c258a6
29 changed files with 113 additions and 70 deletions
@@ -13,7 +13,7 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
"artifactstoretools/internal/registry"
)
@@ -29,7 +29,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
"artifactstoretools/internal/registry"
)
@@ -11,7 +11,6 @@ package main
import (
"context"
"encoding/json"
"fmt"
"os"
"time"
@@ -20,7 +19,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
)
func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) }
@@ -31,7 +30,7 @@ func main() {
Run: ExecRunner,
UID: os.Getuid(),
}
v := &views.Reader{Module: "artifact-store-tools", Logf: logf, Findings: viewFindings{}}
v := &views.Reader{Module: "artifact-store-tools", Logf: logf, Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}}
v.Follow(delivery.AssignerModule, "wants", WantsTool)
v.Follow(delivery.IndexerModule, "manifests", ManifestsTool)
h := &Holder{Bus: runtimeBus{views: v}, Door: DoorAt(os.Getenv("MESH_ARTIFACT_STORE_ADDRESS_FILE")), Listed: s.View,
@@ -51,12 +50,3 @@ const (
WantsTool = delivery.AssignerModule + ".assigner_read_wants"
ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests"
)
// viewFindings writes the holder's finding of a first view unanswered into its own state findings.
type viewFindings struct{}
func (viewFindings) Put(key string, value []byte) error {
_, err := stdio.State(FindingsState).Put(key, json.RawMessage(value))
return err
}
func (viewFindings) Delete(key string) error { return stdio.State(FindingsState).Delete(key) }
@@ -1,8 +1,8 @@
package main
import (
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/views"
"context"
"encoding/json"
+4 -2
View File
@@ -562,7 +562,8 @@
],
"state": [
"bound",
"announced"
"announced",
"findings"
],
"reads": [
"mesh-provisioner.plans",
@@ -575,7 +576,8 @@
"mesh-delivery-gate.source"
],
"invokes": [
"mesh-delivery-indexer.indexer_read_modules"
"mesh-delivery-indexer.indexer_read_modules",
"seat:mesh-hand-acts.hand-act"
],
"consumes": [
"mesh-delivery-indexer.views.modules"
@@ -15,6 +15,8 @@ var Kept = []announce.State{
{Name: "keys", Readable: true},
{Name: "steps", Readable: true},
{Name: "pauses", Readable: true},
// The condition keeper raises a first view of the indexer's manifests it could not get (ADR 0615 §6) from this.
{Name: "findings", Readable: true},
}
// keepStates announces Kept as this module's (stdio.Keeps): main calls it before it serves.
@@ -22,12 +22,14 @@ import (
"path/filepath"
"strings"
"sync"
"time"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/composer"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/views"
)
// ManifestsTool is the delivery indexer's read tool of its manifests by digest, which a compose ask's request names (the
@@ -71,12 +73,28 @@ func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a delive
return delivery.ComposeAnswer{Built: built, Key: key, Verdict: verdict}, nil
}
// askManifest asks the indexer's read tool for one manifest by its key: nil when it keeps none.
// askManifest asks the indexer's read tool for one manifest by its key: nil when it keeps none. A call the indexer does not
// answer is a finding of this module's own, which the condition keeper raises (ADR 0615 §6) and the next answer clears.
func askManifest(key string) (json.RawMessage, error) {
raw, err := stdio.Ask(ManifestsTool, map[string]any{"key": key})
return askManifestVia(stdio.Ask, views.OwnFindings{}, time.Now, key)
}
func askManifestVia(ask func(string, any) (json.RawMessage, error), findings interface {
Put(string, []byte) error
Delete(string) error
}, now func() time.Time, key string) (json.RawMessage, error) {
st := views.Status{Owner: delivery.IndexerModule, Tool: ManifestsTool, State: "manifests", Asked: now().UTC()}
raw, err := ask(ManifestsTool, map[string]any{"key": key})
if err != nil {
st.Error = err.Error()
if k, v, ferr := views.UnansweredFinding("mesh-build-go", st, now()); ferr == nil {
_ = findings.Put(k, v)
}
return nil, err
}
if k, _, ferr := views.UnansweredFinding("mesh-build-go", st, now()); ferr == nil {
_ = findings.Delete(k)
}
var a struct {
Found bool `json:"found"`
Value json.RawMessage `json:"value"`
@@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
"errors"
"os"
"path/filepath"
"slices"
@@ -130,6 +131,27 @@ func TestTheModuleReadsTheIndexersManifests(t *testing.T) {
}
}
// ADR 0615 §6: an indexer that does not answer is a finding of the module's own, and its next answer clears it.
func TestAnIndexerThatDoesNotAnswerIsAFinding(t *testing.T) {
held := map[string][]byte{}
f := mapFindings(held)
at := func() time.Time { return time.Date(2026, 11, 4, 12, 0, 0, 0, time.UTC) }
if _, err := askManifestVia(func(string, any) (json.RawMessage, error) { return nil, errors.New("no responders") }, f, at, "k"); err == nil || len(held) != 1 {
t.Fatalf("err %v, findings %v", err, held)
}
raw, err := askManifestVia(func(string, any) (json.RawMessage, error) {
return json.RawMessage(`{"found":true,"value":{"x":1}}`), nil
}, f, at, "k")
if err != nil || string(raw) != `{"x":1}` || len(held) != 0 {
t.Errorf("raw %s, err %v, findings %v", raw, err, held)
}
}
type mapFindings map[string][]byte
func (m mapFindings) Put(k string, v []byte) error { m[k] = v; return nil }
func (m mapFindings) Delete(k string) error { delete(m, k); return nil }
// ADR 0593 §7 (C9): a compose ask naming the node-engine's repository builds its composer command in the Go module at the
// repository's root, under a key of that repository, commit and package, and runs the program over the request with its
// manifests filled; the module's answer is the program's verdict whole.
@@ -106,7 +106,7 @@ func TestManifestKeepsItsStatesClaimsItsBuildSeatAndDeclaresItsHealthTool(t *tes
}
}
slices.Sort(states)
if want := []string{"keys", "pauses", "steps", "toolchains"}; !slices.Equal(states, want) {
if want := []string{"findings", "keys", "pauses", "steps", "toolchains"}; !slices.Equal(states, want) {
t.Errorf("state = %v, want %v", states, want)
}
if len(m.Claims) != 1 || m.Claims[0].Name != Seat {
+1 -1
View File
@@ -10,7 +10,7 @@
"state": [
"toolchains",
"keys",
{"name": "steps", "ttl-seconds": 172800}, "pauses"
{"name": "steps", "ttl-seconds": 172800}, "pauses", "findings"
],
"claims": [
{
@@ -40,7 +40,10 @@ const HistoryKeptFor = 90 * 24 * time.Hour
// table of 2026-10-29 for the provisioner's and the router's; ADR 0571 clause 2 for the seat artifact-store's holder,
// which observes S25, image-missing).
var Observers = []string{health.WatchmanModule, health.SelfCheckModule, health.HealersModule, delivery.AssignerModule,
"mesh-provisioner", "messenger", artifactStore, configModule}
"mesh-provisioner", "messenger", artifactStore, configModule,
// The readers of the indexer's and the assigner's state say a first view unanswered past its bound in their own findings
// (ADR 0615 §6).
"mesh-watcher", "minio", "nfs-server", "gitea", "mesh-build-go"}
// The other states it reads, as `<module>.<name>`.
const (
@@ -17,7 +17,8 @@ import (
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/views"
)
func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) }
@@ -147,7 +148,7 @@ const (
// NewViews is the keeper's pictures of the assigner's wants, placement and findings. A first view it cannot get past its
// bound is a finding of its own, taken in as any observer's: the keeper raises the condition itself.
func NewViews(k *Keeper) *views.Reader {
v := &views.Reader{Module: Module, Logf: logf, Findings: ownFindings{k}}
v := &views.Reader{Module: Module, Logf: logf, Findings: ownFindings{k}, Acts: handacts.Recorder{Ask: stdio.Ask}}
v.Follow(delivery.AssignerModule, "wants", WantsTool)
v.Follow(delivery.AssignerModule, "placement", PlacementTool)
v.Follow(delivery.AssignerModule, health.FindingsState, FindingsTool)
@@ -38,7 +38,7 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) {
reads = append(reads, o+"."+health.FindingsState)
}
}
if !slices.Equal(m.Invokes, []string{WantsTool, PlacementTool, FindingsTool}) ||
if !slices.Equal(m.Invokes, []string{WantsTool, PlacementTool, FindingsTool, "seat:mesh-hand-acts.hand-act"}) ||
!slices.Equal(m.Consumes, []string{"mesh-delivery-assigner.views.wants", "mesh-delivery-assigner.views.placement", "mesh-delivery-assigner.views.findings"}) {
t.Errorf("invokes %v, consumes %v", m.Invokes, m.Consumes)
}
+7 -1
View File
@@ -21,13 +21,19 @@
"mesh-provisioner.findings",
"artifact-store-tools.findings",
"mesh-config.findings",
"mesh-watcher.findings",
"minio.findings",
"nfs-server.findings",
"gitea.findings",
"mesh-build-go.findings",
"mesh-healers.attempts",
"node-engine.have"
],
"invokes": [
"mesh-delivery-assigner.assigner_read_wants",
"mesh-delivery-assigner.assigner_read_placement",
"mesh-delivery-assigner.assigner_read_findings"
"mesh-delivery-assigner.assigner_read_findings",
"seat:mesh-hand-acts.hand-act"
],
"consumes": [
"mesh-delivery-assigner.views.wants",
@@ -8,7 +8,6 @@ package main
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
@@ -19,9 +18,9 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/asks"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/views"
)
// Seat is the role this module holds, once for the mesh, and Verb its one verb.
@@ -182,20 +181,10 @@ const (
ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests"
)
// viewFindings writes the provisioner's finding of a first view unanswered into its own state findings, which the
// condition keeper raises the condition from.
type viewFindings struct{}
func (viewFindings) Put(key string, value []byte) error {
_, err := stdio.State(health.FindingsState).Put(key, json.RawMessage(value))
return err
}
func (viewFindings) Delete(key string) error { return stdio.State(health.FindingsState).Delete(key) }
// newViews is the provisioner's pictures of the assigner's placement and wants and the indexer's modules and manifests:
// each asked once of its owner's read tool, then followed by the owner's events (ADR 0615).
func newViews() *views.Reader {
v := &views.Reader{Module: Module, Logf: logf, Findings: viewFindings{}}
v := &views.Reader{Module: Module, Logf: logf, Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}}
v.Follow(delivery.AssignerModule, "placement", PlacementTool)
v.Follow(delivery.AssignerModule, "wants", WantsTool)
v.Follow(delivery.IndexerModule, "modules", ModulesTool)
@@ -9,8 +9,8 @@ import (
"sync"
"testing"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/views"
)
// memStore is the bus as mesh-provisioner reaches it, in memory: the states it keeps.
@@ -345,7 +345,7 @@ func TestTheManifestDeclaresWhatTheCodeKeeps(t *testing.T) {
t.Errorf("the manifest does not read %s, which the holder reads", r)
}
}
if !slices.Equal(m.Invokes, []string{PlacementTool, WantsTool, ModulesTool, ManifestsTool}) ||
if !slices.Equal(m.Invokes, []string{PlacementTool, WantsTool, ModulesTool, ManifestsTool, "seat:mesh-hand-acts.hand-act"}) ||
!slices.Equal(m.Consumes, []string{"mesh-delivery-assigner.views.placement", "mesh-delivery-assigner.views.wants",
"mesh-delivery-indexer.views.modules", "mesh-delivery-indexer.views.manifests"}) {
t.Errorf("invokes %v, consumes %v", m.Invokes, m.Consumes)
+2 -1
View File
@@ -30,7 +30,8 @@
"mesh-delivery-assigner.assigner_read_placement",
"mesh-delivery-assigner.assigner_read_wants",
"mesh-delivery-indexer.indexer_read_modules",
"mesh-delivery-indexer.indexer_read_manifests"
"mesh-delivery-indexer.indexer_read_manifests",
"seat:mesh-hand-acts.hand-act"
],
"consumes": [
"mesh-delivery-assigner.views.placement",
@@ -15,7 +15,8 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/views"
)
func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) }
@@ -73,7 +74,7 @@ func NewChecker() *Checker {
// its owner's read tool, then followed by the owner's events. A first view unanswered past its bound is a finding of the
// self-check's own (first-view-unanswered), written into its state findings.
func newViews() *views.Reader {
r := &views.Reader{Module: Module, Logf: logf, Findings: findings{}}
r := &views.Reader{Module: Module, Logf: logf, Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}}
r.Follow(delivery.AssignerModule, delivery.PlacementState, PlacementTool)
r.Follow(delivery.AssignerModule, delivery.SeatHoldersState, SeatHoldersTool)
r.Follow(delivery.IndexerModule, "modules", ModulesTool)
@@ -81,15 +82,6 @@ func newViews() *views.Reader {
return r
}
// findings writes the self-check's own state findings for the reader.
type findings struct{}
func (findings) Put(key string, value []byte) error {
_, err := stdio.State(FindingsState).Put(key, json.RawMessage(value))
return err
}
func (findings) Delete(key string) error { return stdio.State(FindingsState).Delete(key) }
func main() {
c := NewChecker()
go func() {
@@ -33,7 +33,7 @@ const (
// Invokes are the tools and seat verbs the probes ask, and Reads the states they read: the manifest's `invokes` and
// `reads`, which its test holds to these.
var (
Invokes = []string{StreamsTool, ClosedTool, SignalsVerb, BannedVerb, PlacementTool, SeatHoldersTool, ModulesTool, ManifestsTool}
Invokes = []string{StreamsTool, ClosedTool, SignalsVerb, BannedVerb, PlacementTool, SeatHoldersTool, ModulesTool, ManifestsTool, HandActVerb}
Reads = []string{PresenceRead, HealthRead, ReadingsRead, GoodRead}
// Consumes are the views families the probes follow (ADR 0615): the indexer's and the assigner's states are asked
// once, by their owners' read tools, and then followed by their events, never read.
@@ -41,6 +41,9 @@ var (
"mesh-delivery-indexer.views.modules", "mesh-delivery-indexer.views.manifests"}
)
// HandActVerb records a re-read of a first view by hand (ADR 0615 §6).
const HandActVerb = "seat:mesh-hand-acts.hand-act"
// The owners' read tools of the states the probes follow, which the manifest invokes.
const (
PlacementTool = "mesh-delivery-assigner.assigner_read_placement"
+2 -1
View File
@@ -20,7 +20,8 @@
"mesh-delivery-assigner.assigner_read_placement",
"mesh-delivery-assigner.assigner_read_seat_holders",
"mesh-delivery-indexer.indexer_read_modules",
"mesh-delivery-indexer.indexer_read_manifests"
"mesh-delivery-indexer.indexer_read_manifests",
"seat:mesh-hand-acts.hand-act"
],
"reads": [
"mesh-delivery-watchman.presence",
@@ -17,9 +17,10 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
)
func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) }
@@ -73,7 +74,7 @@ func main() {
node := os.Getenv("MESH_NODE")
w := NewWatcher(tg, time.Now, logf, node)
l := &listening{now: "not yet: starting"}
placement := &views.Reader{Module: "mesh-watcher", Logf: logf}
placement := &views.Reader{Module: "mesh-watcher", Logf: logf, Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}}
placement.Follow(delivery.AssignerModule, delivery.SeatHoldersState, SeatHoldersTool)
go run(w, l, node, placement)
if err := stdio.Serve("", append(tools(w, l), placement.Tools("watcher")...)); err != nil {
@@ -10,7 +10,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
)
// The manifest says what the code does: it consumes the heartbeat and nothing else, calls its own
@@ -41,7 +41,7 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) {
if !reflect.DeepEqual(m.Consumes, []string{"mesh-self-check.checked", "mesh-delivery-assigner.views.seat-holders"}) {
t.Fatalf("consumes %v", m.Consumes)
}
if !reflect.DeepEqual(m.Invokes, []string{SeatHoldersTool, m.Module + ".watcher_ping"}) || len(m.Reads) != 0 {
if !reflect.DeepEqual(m.Invokes, []string{SeatHoldersTool, m.Module + ".watcher_ping", "seat:mesh-hand-acts.hand-act"}) || len(m.Reads) != 0 {
t.Fatalf("invokes %v, reads %v", m.Invokes, m.Reads)
}
if len(m.Claims) != 0 {
+5 -1
View File
@@ -8,7 +8,11 @@
],
"invokes": [
"mesh-delivery-assigner.assigner_read_seat_holders",
"mesh-watcher.watcher_ping"
"mesh-watcher.watcher_ping",
"seat:mesh-hand-acts.hand-act"
],
"state": [
"findings"
],
"own-secrets": {
"telegram-token": "${dir:state}/telegram-token"
+3 -2
View File
@@ -17,7 +17,8 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/views"
)
// Words the manifest gives this bundle (modules/minio/module.json).
@@ -28,7 +29,7 @@ const (
)
func main() {
seats := &views.Reader{Module: "minio", Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[object-store] "+f+"\n", a...) }}
seats := &views.Reader{Module: "minio", Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}, Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[object-store] "+f+"\n", a...) }}
seats.Follow(delivery.AssignerModule, delivery.SeatHoldersState, SeatHoldersTool)
s, err := newServer(os.Getenv(ConfigWord), os.Getenv(LinksWord), os.Getenv(ReceivesWord),
func() (map[string][]byte, error) { return seats.Values(delivery.SeatHoldersRead) })
@@ -40,7 +40,7 @@ func TestManifestClaimsTheSeat(t *testing.T) {
}
invokes, _ := m["invokes"].([]any)
consumes, _ := m["consumes"].([]any)
if _, reads := m["reads"]; reads || len(invokes) != 1 || invokes[0] != SeatHoldersTool || len(consumes) != 1 || consumes[0] != "mesh-delivery-assigner.views.seat-holders" {
if _, reads := m["reads"]; reads || len(invokes) != 2 || invokes[0] != SeatHoldersTool || invokes[1] != "seat:mesh-hand-acts.hand-act" || len(consumes) != 1 || consumes[0] != "mesh-delivery-assigner.views.seat-holders" {
t.Fatalf("reads %v, invokes %v, consumes %v: it asks the assigner's seat-holders once and follows its events (ADR 0615)", m["reads"], invokes, consumes)
}
var goBundle map[string]any
+5 -1
View File
@@ -40,11 +40,15 @@
}
],
"invokes": [
"mesh-delivery-assigner.assigner_read_seat_holders"
"mesh-delivery-assigner.assigner_read_seat_holders",
"seat:mesh-hand-acts.hand-act"
],
"consumes": [
"mesh-delivery-assigner.views.seat-holders"
],
"state": [
"findings"
],
"contributes": {
"route": {
"api": {
+3 -2
View File
@@ -22,9 +22,10 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-delivery/sdk/views"
"git.novox.be/novox/mesh-sdk/go/views"
)
// ExportsState is the state the exports are kept in on the bus; MountsState the `mounts` modules' state,
@@ -126,7 +127,7 @@ const SeatHoldersTool = delivery.AssignerModule + ".assigner_read_seat_holders"
// seats is the picture of the placement seat's state of who holds which seat: asked of the assigner once and followed by
// its events, never read from its state (ADR 0615).
var seats = &views.Reader{Module: "nfs-server", Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "nfs-server: "+f+"\n", a...) }}
var seats = &views.Reader{Module: "nfs-server", Findings: views.OwnFindings{}, Acts: handacts.Recorder{Ask: stdio.Ask}, Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "nfs-server: "+f+"\n", a...) }}
// seatHolderKeys is the placement seat's state of who holds which seat, every key.
func seatHolderKeys() (map[string][]byte, error) { return seats.Values(delivery.SeatHoldersRead) }
@@ -144,7 +144,7 @@ func TestTheManifestCarriesGrantsTheRosterTheWantsAndTheRemovalOrder(t *testing.
if len(full.Reads) != 2 || full.Reads[0] != health.ReadingsRead || full.Reads[1] != MountsState {
t.Errorf("reads: %v", full.Reads)
}
if len(full.Invokes) != 1 || full.Invokes[0] != SeatHoldersTool || len(full.Consumes) != 1 || full.Consumes[0] != "mesh-delivery-assigner.views.seat-holders" {
if len(full.Invokes) != 2 || full.Invokes[0] != SeatHoldersTool || full.Invokes[1] != "seat:mesh-hand-acts.hand-act" || len(full.Consumes) != 1 || full.Consumes[0] != "mesh-delivery-assigner.views.seat-holders" {
t.Errorf("invokes %v, consumes %v", full.Invokes, full.Consumes)
}
roster := full.Facts["machines"]
+4 -2
View File
@@ -45,7 +45,8 @@
"name": "exports",
"ttl-seconds": 120,
"per-machine": true
}
},
"findings"
],
"reads": [
"disk-load.readings",
@@ -189,7 +190,8 @@
]
},
"invokes": [
"mesh-delivery-assigner.assigner_read_seat_holders"
"mesh-delivery-assigner.assigner_read_seat_holders",
"seat:mesh-hand-acts.hand-act"
],
"consumes": [
"mesh-delivery-assigner.views.seat-holders"