COND5: the keeper hears a machine away and back from the watchman
An observer on a machine away is not named in findings-unstated; a machine back has its observers asked again (mesh-watchdogs machine-away and machine-back in consumes). Builds: design 47 G §389 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
cc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
watchdogs "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
)
|
||||
|
||||
@@ -40,6 +41,12 @@ func (k *Keeper) FindingEvent(e stdio.Envelope) error {
|
||||
if observer, ok := emitterOf(e.Key, EventFindingCleared); ok {
|
||||
return k.FindingCleared(observer, e.Node, e.Body)
|
||||
}
|
||||
if _, ok := emitterOf(e.Key, watchdogs.EventMachineAway); ok && strings.HasPrefix(e.Key, watchdogs.Seat+".") {
|
||||
return k.MachinePresence(e.Body, true)
|
||||
}
|
||||
if _, ok := emitterOf(e.Key, watchdogs.EventMachineBack); ok && strings.HasPrefix(e.Key, watchdogs.Seat+".") {
|
||||
return k.MachinePresence(e.Body, false)
|
||||
}
|
||||
if observer, ok := emitterOf(e.Key, EventFindingsStated); ok {
|
||||
return k.FindingsStated(observer, e.Node, e.Body)
|
||||
}
|
||||
@@ -148,10 +155,52 @@ func storedFinding(f seat.Finding) seat.FindingsByKeyValue {
|
||||
Ref: f.Ref, Run: f.Run, WaitingOn: f.WaitingOn, At: f.At}
|
||||
}
|
||||
|
||||
// MachinePresence takes the watchman's word that a machine is away or back (design 47 G §389): an observer on a machine
|
||||
// away is not named in findings-unstated, and an ask is said again to the modules of a machine back.
|
||||
func (k *Keeper) MachinePresence(body []byte, away bool) error {
|
||||
var m struct {
|
||||
Machine string `json:"machine"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &m); err != nil || m.Machine == "" {
|
||||
k.Logf("the watchman's word on a machine's presence is not readable: %v", err)
|
||||
return nil
|
||||
}
|
||||
k.mu.Lock()
|
||||
k.init()
|
||||
if k.away == nil {
|
||||
k.away = map[string]bool{}
|
||||
}
|
||||
if away {
|
||||
k.away[m.Machine] = true
|
||||
k.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
delete(k.away, m.Machine)
|
||||
var modules []string
|
||||
for _, v := range k.views {
|
||||
if v.node == m.Machine && v.observer != "" && !slices.Contains(modules, v.observer) {
|
||||
modules = append(modules, v.observer)
|
||||
}
|
||||
}
|
||||
k.mu.Unlock()
|
||||
sort.Strings(modules)
|
||||
var problems []string
|
||||
for _, module := range modules {
|
||||
if _, err := k.Ask(Module, module); err != nil {
|
||||
problems = append(problems, err.Error())
|
||||
}
|
||||
}
|
||||
if len(problems) > 0 {
|
||||
return errors.New(strings.Join(problems, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hear subscribes to the observers' events once the runtime serves, asked again until it takes each.
|
||||
func hear(k *Keeper) {
|
||||
for _, event := range []string{EventFindingWritten, EventFindingCleared, EventFindingsStated} {
|
||||
pattern := "*." + event
|
||||
patterns := []string{"*." + EventFindingWritten, "*." + EventFindingCleared, "*." + EventFindingsStated,
|
||||
watchdogs.Seat + "." + watchdogs.EventMachineAway, watchdogs.Seat + "." + watchdogs.EventMachineBack}
|
||||
for _, pattern := range patterns {
|
||||
go func() {
|
||||
<-stdio.Served()
|
||||
for wait := 2 * time.Second; ; wait = min(wait*2, time.Minute) {
|
||||
|
||||
@@ -539,12 +539,26 @@ func TestTheKeeperSetsItsViewFromWhatAnObserverStates(t *testing.T) {
|
||||
{"its next findings-stated clears it", func() error {
|
||||
return stated(watchman, "ace", ask, t0.Add(10*time.Minute), nil, f(watchman, "d"))
|
||||
}, []string{"machine.d.silent", "machine.g.silent"}, "its finding went"},
|
||||
{"a machine away is not named", func() error {
|
||||
{"a machine away is not named, and a machine back is asked again", func() error {
|
||||
if _, err := r.k.Ask("jochen", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
r.k.away = map[string]bool{"g14": true}
|
||||
return r.k.AskPassed(askedKey(selfCheck, "g14", asked[len(asked)-1]["ask"].(string)))
|
||||
last := asked[len(asked)-1]["ask"].(string)
|
||||
away := mustJSON(t, map[string]any{"machine": "g14", "at": r.now})
|
||||
if err := r.k.FindingEvent(stdio.Envelope{Key: "mesh-watchdogs.machine-away", Node: "ace", Body: away}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.k.AskPassed(askedKey(selfCheck, "g14", last)); err != nil {
|
||||
return err
|
||||
}
|
||||
before := len(asked)
|
||||
if err := r.k.FindingEvent(stdio.Envelope{Key: "mesh-watchdogs.machine-back", Node: "ace", Body: away}); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(asked) != before+2 || asked[before]["module"] != watchman || asked[before+1]["module"] != selfCheck {
|
||||
t.Errorf("a machine back was asked %v", asked[before:])
|
||||
}
|
||||
return nil
|
||||
}, []string{"machine.d.silent", "machine.g.silent"}, ""},
|
||||
{"resync names one module: its hand act and its ask", func() error {
|
||||
if _, err := r.k.ResyncVerb("person.jochen", selfCheck); err != nil {
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) {
|
||||
reads := []string{HavesRead, AttemptsRead}
|
||||
if !slices.Equal(m.Invokes, []string{WantsTool, AssignmentsTool, "seat:mesh-hand-acts.hand-act"}) ||
|
||||
!slices.Equal(m.Consumes, []string{"mesh-delivery-assigner.views.wants", "mesh-delivery-assigner.views.assignments",
|
||||
"*.finding-written", "*.finding-cleared", "*.findings-stated"}) {
|
||||
"*.finding-written", "*.finding-cleared", "*.findings-stated", "mesh-watchdogs.machine-away", "mesh-watchdogs.machine-back"}) {
|
||||
t.Errorf("invokes %v, consumes %v", m.Invokes, m.Consumes)
|
||||
}
|
||||
for _, r := range m.Reads {
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
"mesh-delivery-assigner.views.assignments",
|
||||
"*.finding-written",
|
||||
"*.finding-cleared",
|
||||
"*.findings-stated"
|
||||
"*.findings-stated",
|
||||
"mesh-watchdogs.machine-away",
|
||||
"mesh-watchdogs.machine-back"
|
||||
],
|
||||
"state": [
|
||||
"conditions",
|
||||
|
||||
Reference in New Issue
Block a user