Files
mesh-delivery/sdk/views/findings.go
T
jschoubben 5d7fff91ce DLV-O1, DLV-O3, DLV-O4: the indexer answers its first views and says its views family
The indexer's tools bundle runs in a runtime of its own on its own account
(runs-as) and serves the first-view tools manifests, modules and verdicts,
each answering only the callers its manifest writes (ADR 0621 §1-§2, ADR
0622 §1), and the nine read tools of design 25 § 12.2. The process says each
change of its ten read states on the family indexer-views in its old streams
section (7 days, 256 MiB), with a mark per state the first view answers its
revision from, so a reader that takes the answer misses no event after it
(ADR 0615 §4-§5). The shared shape lives in sdk/views: event, answer, mark,
the emitter, the tools and the reader's follower.

Issue 1966.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 12:22:26 +01:00

48 lines
2.6 KiB
Go

package views
import (
"fmt"
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/health"
)
// The findings a views part writes in its own state `findings`, which the condition keeper raises and clears
// (novox/hq ADR 0564 §2): an owner's value too large for an event (TooLargeKind), and a reader's first view unanswered
// past its bound (UnansweredKind).
const (
TooLargeKind = "view-too-large"
UnansweredKind = "first-view-unanswered"
)
// TooLargeFinding is the owner's finding of state's key too large to say whole on its views family.
func TooLargeFinding(owner, state, key string, size int, at time.Time) (string, []byte, error) {
id := owner + "." + state + "." + key
summary := fmt.Sprintf("%s's %s.%s holds %d bytes, more than one views event carries (%d): every reader asks its first view again at each change of it", owner, state, key, size, MaxValueBytes)
return finding(owner, TooLargeKind, id, summary,
fmt.Sprintf("A value of %s is too large for its views event", owner),
"Each change of this key is said as a gap, so every reader of the state asks the owner's first view once more. "+
"It works, but costs a first view per change; the value should be made smaller or split.", at)
}
// UnansweredFinding is a reader's finding of its first view of s unanswered past its bound (ADR 0615 §6): it names the
// owner and the tool. A first view answered at revision 0 with nothing in it is said too, with the operator's step.
func UnansweredFinding(reader string, s Status, at time.Time) (string, []byte, error) {
id := reader + "." + s.Owner + "." + s.State
summary := fmt.Sprintf("%s has no first view of %s's %s: %s has not answered since %s (%s)", reader, s.Owner, s.State, s.Tool,
s.Asked.Format(time.RFC3339), strings.TrimSpace(s.Error))
return finding(reader, UnansweredKind, id, summary,
fmt.Sprintf("%s waits for %s", reader, s.Owner),
fmt.Sprintf("%s reads %s's %s only through %s, and keeps asking it; it never reads the state itself. The answer clears this. "+
"Look at %s's runtime of its own: is it running and connected?", reader, s.Owner, s.State, s.Tool, s.Owner), at)
}
func finding(observer, kind, id, summary, headline, explanation string, at time.Time) (string, []byte, error) {
key := health.FindingKey(health.ScopeModule, id, kind)
value, err := health.EncodeFinding(health.Finding{Key: key, Kind: kind, Subject: health.Subject{Scope: health.ScopeModule, ID: id},
Severity: health.Warning, Summary: summary, Headline: headline, Explanation: explanation,
Evidence: []health.Evidence{{At: at.UTC(), Said: summary}}, Source: observer + "." + kind, Observer: observer, At: at.UTC()})
return key, value, err
}