view status: the conditions and the healers' attempts are read as the seats' types (mesh-conditions, mesh-healers) and ordered by meshconditionsclient (ADR 0634 §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 16:48:32 +01:00
parent a6c8db74f4
commit 436ab59214
3 changed files with 23 additions and 16 deletions
+3
View File
@@ -51,3 +51,6 @@ require (
replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk
replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein => ../mesh-delivery-indexer/takein
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers v0.0.0-00010101000000-000000000000
@@ -8,9 +8,11 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/motion"
)
@@ -28,8 +30,8 @@ const StatusTool = "view_status"
// The states status reads, as the view's manifest names them.
const (
StatusConditionsState = health.KeeperModule + "." + health.ConditionsState
StatusAttemptsState = health.HealersModule + "." + health.AttemptsState
StatusConditionsState = mcseat.Seat + "." + mcseat.StateConditions
StatusAttemptsState = healers.Seat + "." + healers.StateAttempts
StatusPresenceState = WatchmanModule + ".presence"
StatusStuckState = WatchmanModule + ".stuck"
)
@@ -115,17 +117,17 @@ func DeriveStatus(r StatusRead, now time.Time) Status {
if raw, err := values(r.Conditions); err != nil {
st.ConditionsUnread = "the condition keeper's conditions cannot be read: " + err.Error()
} else {
var open []health.Condition
var open []mcseat.ConditionsByKeyValue
for _, v := range raw {
var c health.Condition
var c mcseat.ConditionsByKeyValue
if json.Unmarshal(v, &c) == nil && c.Key != "" {
open = append(open, c)
}
}
health.Order(open)
mcc.Order(open)
for _, c := range open {
st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: string(c.Severity), Machine: c.Subject.Machine,
Summary: c.Summary, Raised: c.Raised, Silenced: c.SilencedAt(now)})
st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: c.Severity, Machine: c.Subject.Machine,
Summary: c.Summary, Raised: c.Raised, Silenced: mcc.SilencedAt(c, now)})
}
}
@@ -203,13 +205,13 @@ func DeriveStatus(r StatusRead, now time.Time) Status {
st.HealsUnread = "mesh-healers' attempts cannot be read: " + err.Error()
} else {
for _, v := range raw {
var a health.Attempt
var a healers.AttemptsByAttemptValue
if json.Unmarshal(v, &a) != nil || now.Sub(a.Begun) > HealsWithin {
continue
}
outcome := a.Outcome
if outcome == "" {
outcome = health.OutcomeActing
outcome = healers.AttemptsByAttemptValueOutcomeActing
}
st.Heals[outcome]++
}
@@ -10,12 +10,14 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/keys"
"git.novox.be/novox/mesh-sdk/go/motion"
)
@@ -301,8 +303,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
fin := t0.Add(time.Minute)
r := StatusRead{
Conditions: states(map[string]string{
"machine.b.silent": enc(health.Condition{Key: "machine.b.silent", Severity: health.Warning, Summary: "b silent", Raised: t0}),
"core.doctor.self-check": enc(health.Condition{Key: "core.doctor.self-check", Severity: health.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}),
"machine.b.silent": enc(mcseat.ConditionsByKeyValue{Key: "machine.b.silent", Severity: mcc.Warning, Summary: "b silent", Raised: t0}),
"core.doctor.self-check": enc(mcseat.ConditionsByKeyValue{Key: "core.doctor.self-check", Severity: mcc.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}),
}),
Presence: states(map[string]string{"a": presence(true), "b": presence(false)}),
Stuck: states(map[string]string{stuckWant: stuckOf(AssignerWantsBucket, "want.b.web", "b to run web", false),
@@ -310,8 +312,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
Wants: states(map[string]string{"want.a.web": want(fp2), "want.a.mail": want(fp1), "want.b.web": want(fp2), "want.a.db": want(fp3)}),
Haves: states(map[string]string{"a.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.mail": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""),
"b.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.db": have(fp3, nodeengineclient.PhaseRunning, nodeengineclient.HealthFailed, "the unit failed")}),
Attempts: states(map[string]string{"1": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: t0, Finished: &fin}),
"2": enc(health.Attempt{Outcome: health.OutcomeEscalated, Begun: t0}), "old": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}),
Attempts: states(map[string]string{"1": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: t0, Finished: &fin}),
"2": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeEscalated, Begun: t0}), "old": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}),
}
st := DeriveStatus(r, now)
if len(st.Conditions) != 2 || st.Conditions[0].Key != "core.doctor.self-check" || st.Conditions[1].Key != "machine.b.silent" {
@@ -328,7 +330,7 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
if !reflect.DeepEqual(st.Moving, wantMoving) {
t.Errorf("moving = %+v\nwant %+v", st.Moving, wantMoving)
}
if !reflect.DeepEqual(st.Heals, map[string]int{health.OutcomeActed: 1, health.OutcomeEscalated: 1}) || st.Well {
if !reflect.DeepEqual(st.Heals, map[string]int{healers.AttemptsByAttemptValueOutcomeActed: 1, healers.AttemptsByAttemptValueOutcomeEscalated: 1}) || st.Well {
t.Errorf("heals = %v, well %v", st.Heals, st.Well)
}
// A part it cannot read is said, and the mesh is not well; with nothing wrong and every part read it is.