diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go index 3deac5e8..af40c021 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go @@ -453,6 +453,14 @@ func ofHolder(holder func(seat string) (string, bool), read func(name string) vi } } +// seatStateRead reads a seat's state in the state of the seat's holder (ofHolder), the holder found each time the state is read so +// a moved holder is read as it moves and a start never waits for one (design 47 G A-210, A-128). +func seatStateRead(holder func(seat string) (string, bool), read func(name string) view.StateRead, seat, state string) view.StateRead { + at := func() view.StateRead { return ofHolder(holder, read, state)(seat) } + return view.StateRead{Keys: func() ([]string, error) { return at().Keys() }, + Get: func(key string) (json.RawMessage, error) { return at().Get(key) }} +} + func main() { logf := func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] "+f+"\n", a...) } // The catalog half per watched branch, followed by the bundle itself through meshcatalogclient's branch follower on @@ -469,7 +477,7 @@ func main() { r.Builds, r.HavesState = read(stdio.State("mesh-delivery-builder.builds")), read(stdio.State("node-engine.have")) r.ReachState = read(stdio.State("reach")) r.WaitsState = read(stdio.State(viewstate.WaitsState)) - r.SignersState = read(stdio.State("mesh-vault.signers")) + r.SignersState = seatStateRead(holderOf(stdio.Ask), func(name string) view.StateRead { return read(stdio.State(name)) }, view.VaultSeat, view.SignersState) r.ConditionsState, r.AttemptsState = read(stdio.State(view.StatusConditionsState)), read(stdio.State(view.StatusAttemptsState)) r.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState)) r.Sources = view.SourcesOf(stdio.Ask, branches.Followed) diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main_test.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main_test.go index 939dbd62..f9839784 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main_test.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main_test.go @@ -658,7 +658,7 @@ func TestBuildSeatStatesAreReadInTheHoldersState(t *testing.T) { var named []string read := func(name string) view.StateRead { named = append(named, name) - return view.StateRead{Keys: func() ([]string, error) { return nil, nil }} + return view.StateRead{Keys: func() ([]string, error) { return nil, nil }, Get: func(string) (json.RawMessage, error) { return nil, nil }} } holder := func(seat string) (string, bool) { return "acme-" + seat, seat != "node-build-node" } ofHolder(holder, read, view.StepsState)("node-build-go") @@ -669,4 +669,10 @@ func TestBuildSeatStatesAreReadInTheHoldersState(t *testing.T) { if _, err := ofHolder(holder, read, view.StepsState)("node-build-node").Keys(); err == nil { t.Error("a seat with no holder reads without an error") } + // The vault's signers are read the same way, the holder found at each read. + named = nil + signers := seatStateRead(holder, read, view.VaultSeat, view.SignersState) + if _, err := signers.Get(view.SignersKeyKey); err != nil || !slices.Equal(named, []string{"acme-mesh-vault.signers"}) { + t.Errorf("the signers read %v, %v; want acme-mesh-vault.signers", named, err) + } } diff --git a/modules/mesh-delivery-view/internal/view/names.go b/modules/mesh-delivery-view/internal/view/names.go index d9f15729..76a4a5b3 100644 --- a/modules/mesh-delivery-view/internal/view/names.go +++ b/modules/mesh-delivery-view/internal/view/names.go @@ -20,7 +20,6 @@ const ( WatchmanModule = "mesh-delivery-watchman" GateModule = "mesh-delivery-gate" TellerModule = "mesh-delivery-teller" - VaultModule = "mesh-vault" EngineModule = "node-engine" // The indexer's states the view reads. @@ -61,8 +60,11 @@ const ( AnswersHistory = 5 AssignerAsksHistory = 5 - // SignersRead is the vault's state of signing keys as a manifest's `reads` names it, SignersKeyKey its one key. - SignersRead = VaultModule + ".signers" + // SignersRead is the seat mesh-vault's state of signing keys as a manifest's `reads` names it (the seat form, resolved at the seat's + // holder, A-210), SignersKeyKey its one key. + VaultSeat = "mesh-vault" + SignersState = "signers" + SignersRead = "seat:" + VaultSeat + "." + SignersState SignersKeyKey = "key" ) diff --git a/modules/mesh-delivery-view/manifest_test.go b/modules/mesh-delivery-view/manifest_test.go index 54573bb6..62adbc25 100644 --- a/modules/mesh-delivery-view/manifest_test.go +++ b/modules/mesh-delivery-view/manifest_test.go @@ -153,7 +153,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7 if m.Module != "mesh-delivery-view" { t.Errorf("module = %q", m.Module) } - want := []string{"mesh-conditions.conditions", "mesh-config.resolved", "mesh-delivery-builder.build-log", "mesh-delivery-builder.builds", "mesh-delivery-checker.tries", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-provisioner.provisions", "mesh-vault.signers", "node-engine.have", "seat:node-build-go.pauses", "seat:node-build-go.steps", "seat:node-build-image.pauses", "seat:node-build-image.steps", "seat:node-build-node.pauses", "seat:node-build-node.steps"} // the build seats' states by seat, never a build module (design 47 G A-82); no read of the gate's source: each watched branch's is its verb source's (§512, A-173); // 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-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-provisioner.provisions", "node-engine.have", "seat:mesh-vault.signers", "seat:node-build-go.pauses", "seat:node-build-go.steps", "seat:node-build-image.pauses", "seat:node-build-image.steps", "seat:node-build-node.pauses", "seat:node-build-node.steps"} // the build seats' states by seat, never a build module (design 47 G A-82); no read of the gate's source: each watched branch's is its verb source's (§512, A-173); // 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) { diff --git a/modules/mesh-delivery-view/module.json b/modules/mesh-delivery-view/module.json index e900155f..88b8cd0f 100644 --- a/modules/mesh-delivery-view/module.json +++ b/modules/mesh-delivery-view/module.json @@ -136,7 +136,7 @@ "mesh-provisioner.provisions", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", - "mesh-vault.signers", + "seat:mesh-vault.signers", "node-engine.have" ], "own-secrets": {