Count a bus refusal by what the bus said, not by how often the controller looked (issue 402)
S9 reads the one remembered advisory again on every look for an hour, and each look was kept as an observation and a line of evidence, so a single refusal read as one repeated every 30 seconds. An observation may now say when what it reads happened and how often; the keeper counts that, and a look with nothing newer adds nothing. Sources that look at the present keep counting their looks.
This commit is contained in:
@@ -152,7 +152,9 @@ type Condition struct {
|
||||
// reopened after a send was there at the send unless the send fell in one of its gaps.
|
||||
First time.Time `json:"first,omitzero"`
|
||||
Gaps []Gap `json:"gaps,omitempty"`
|
||||
// Observations is how many times it was observed since raised.
|
||||
// Observations is how many times it was observed since raised: a look that sees it, for a source
|
||||
// that looks at the present; for one that reads a record of what happened (Observation.Happened),
|
||||
// how many times it happened, and LastObserved when it last did (novox/hq issue 402).
|
||||
Observations int `json:"observations"`
|
||||
// Count is how many times it has been raised, a reopening within ReopenWithin counted.
|
||||
Count int `json:"count"`
|
||||
@@ -208,6 +210,15 @@ type Observation struct {
|
||||
Said string
|
||||
Source string
|
||||
Resolver string
|
||||
// Happened is set by a source that reads a record of what happened rather than looking at the
|
||||
// present — a bus advisory, remembered for an hour and read again on every look — to when it last
|
||||
// happened; Times is how many times the record counts it. The condition then counts what happened,
|
||||
// not the looks (novox/hq issue 402): one refusal looked at every half minute read as "observed 15
|
||||
// time(s)", with a line of evidence every 30 seconds, and was taken for a refusal going on. A look
|
||||
// that brings nothing newer than the condition's last observation adds no observation and no
|
||||
// evidence. Zero for a source that looks at the present, whose every look is an observation.
|
||||
Happened time.Time
|
||||
Times int
|
||||
// Confirm says a single look can be wrong about this finding — a question over the network that
|
||||
// went unanswered, a time measured once on a loaded machine. The keeper does not read it: the
|
||||
// source that looks again does, and raises it only when the next look sees it too, or while it is
|
||||
|
||||
@@ -191,11 +191,16 @@ func (k *Keeper) Observe(ctx context.Context, o Observation) (Condition, error)
|
||||
if err != nil {
|
||||
return Condition{}, fmt.Errorf("reading the condition %s: %w", key, err)
|
||||
}
|
||||
// What was observed and when: the look, or what the record says happened (novox/hq issue 402).
|
||||
at, observations := now, 1
|
||||
if !o.Happened.IsZero() {
|
||||
at, observations = o.Happened.UTC(), max(1, o.Times)
|
||||
}
|
||||
if !found {
|
||||
c := Condition{Key: key, Kind: o.Kind, Subject: Subject{Scope: o.Scope, ID: o.ID, Machine: o.Machine, Also: o.Also},
|
||||
Severity: o.Severity, Summary: o.Summary, Headline: o.Headline, Explanation: o.Explanation,
|
||||
Resolved: o.Resolved, Needs: o.Needs, Actions: o.Actions, Evidence: []Evidence{{At: now, Said: said}},
|
||||
Source: o.Source, Raised: now, LastObserved: now, Observations: 1, Count: 1,
|
||||
Resolved: o.Resolved, Needs: o.Needs, Actions: o.Actions, Evidence: []Evidence{{At: at, Said: said}},
|
||||
Source: o.Source, Raised: now, LastObserved: at, Observations: observations, Count: 1,
|
||||
Resolver: orSelf(o.Resolver)}
|
||||
change := ChangeRaised
|
||||
k.mu.Lock()
|
||||
@@ -244,7 +249,10 @@ func (k *Keeper) Observe(ctx context.Context, o Observation) (Condition, error)
|
||||
}
|
||||
// The kind as the source says it now: a source that gave the same key a kind of its own since
|
||||
// (a probe's finding split out for a healer) is read by that kind from its next observation.
|
||||
c.Kind, c.Summary, c.Source, c.LastObserved = o.Kind, o.Summary, o.Source, now
|
||||
// A record read again with nothing newer in it is not observed again: its words are refreshed,
|
||||
// its count, evidence and last observation stay (novox/hq issue 402).
|
||||
fresh := o.Happened.IsZero() || at.After(c.LastObserved)
|
||||
c.Kind, c.Summary, c.Source = o.Kind, o.Summary, o.Source
|
||||
wasNeeds, wasActions := c.Needs, c.Actions
|
||||
c.Headline, c.Explanation, c.Resolved, c.Needs, c.Actions = o.Headline, o.Explanation, o.Resolved, o.Needs, o.Actions
|
||||
escalatedWords(&c)
|
||||
@@ -257,10 +265,15 @@ func (k *Keeper) Observe(ctx context.Context, o Observation) (Condition, error)
|
||||
if len(o.Also) > 0 {
|
||||
c.Subject.Also = o.Also
|
||||
}
|
||||
c.Observations++
|
||||
c.Evidence = append([]Evidence{{At: now, Said: said}}, c.Evidence...)
|
||||
if len(c.Evidence) > KeptEvidence {
|
||||
c.Evidence = c.Evidence[:KeptEvidence]
|
||||
if fresh {
|
||||
// A record counts what happened since it began; the condition never counts down, so a
|
||||
// record begun again (a controller restarted) still adds the one it shows.
|
||||
c.Observations = max(c.Observations+1, o.Times)
|
||||
c.LastObserved = at
|
||||
c.Evidence = append([]Evidence{{At: at, Said: said}}, c.Evidence...)
|
||||
if len(c.Evidence) > KeptEvidence {
|
||||
c.Evidence = c.Evidence[:KeptEvidence]
|
||||
}
|
||||
}
|
||||
if err := k.stamp(&c); err != nil {
|
||||
return Condition{}, err
|
||||
|
||||
Reference in New Issue
Block a user