Regenerate the domain contracts; hand-acts and conditions clients; operator-channel client moves; the seat-set package ends (ADR 0634, ADR 0635; issue 1966)

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-05 13:19:37 +01:00
parent 23a759c78b
commit 211bdcaa5e
62 changed files with 3808 additions and 8976 deletions
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go
go 1.26.0
+68
View File
@@ -3,6 +3,13 @@
// Package meshconfig is the contract of the seat "mesh-config", defined whole (seats/mesh-config/seat.json): The mesh's config values: read and set one, and the renames still open. mesh-config's own events stay under its own subjects (ADR 0620 §2).
package meshconfig
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "mesh-config"
@@ -38,6 +45,53 @@ func HolderSubjectRetiring(holder string) string { return "mesh.stream." + holde
// HolderSubjectRetired is where the holder publishes retired, kept in config.events.
func HolderSubjectRetired(holder string) string { return "mesh.stream." + holder + ".event.retired" }
const (
StateResolved = "resolved"
)
// ResolvedByNodeModuleKeyKey is the key of one value of the state resolved under the form "<node>.<module>.<key>".
func ResolvedByNodeModuleKeyKey(node, module, key string) string {
return node + "." + module + "." + key
}
// ParseResolvedByNodeModuleKeyKey reads the parts of a key of the form "<node>.<module>.<key>", in the order of the form; the last result is false for a key of another form.
func ParseResolvedByNodeModuleKeyKey(key string) (string, string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", "", false
}
rest = after0
v2, after2, found2 := strings.Cut(rest, ".")
if !found2 || v2 == "" {
return "", "", "", false
}
rest = after2
if rest == "" {
return "", "", "", false
}
v4 := rest
rest = ""
if rest != "" {
return "", "", "", false
}
return v0, v2, v4, true
}
// DecodeResolvedByNodeModuleKeyValue reads one value of the state resolved under the form "<node>.<module>.<key>", refusing a field ResolvedByNodeModuleKeyValue does not know and any text after the value.
func DecodeResolvedByNodeModuleKeyValue(raw []byte) (ResolvedByNodeModuleKeyValue, error) {
var v ResolvedByNodeModuleKeyValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ConfigInput is what config takes.
type ConfigInput struct {
// list (when not given), set, clear or history
@@ -129,3 +183,17 @@ type RetiredHolderEvent struct {
// the node
Node string `json:"node,omitempty"`
}
// ResolvedByNodeModuleKeyValue is one value of the state resolved under the key <node>.<module>.<key>.
type ResolvedByNodeModuleKeyValue struct {
Key string `json:"key"`
Module string `json:"module"`
Node string `json:"node"`
// the predefined key the value falls back to
Predefined string `json:"predefined,omitempty"`
// an unset value is the operator's own to set
Required bool `json:"required,omitempty"`
Source string `json:"source"`
Trusted bool `json:"trusted,omitempty"`
Value any `json:"value,omitempty"`
}
+324
View File
@@ -3,6 +3,13 @@
// Package nodeengine is the contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.<verb>.<node>, and each event is published on mesh.seat.node-engine.event.<event>.<node>, the node's name its last token.
package nodeengine
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "node-engine"
@@ -57,6 +64,222 @@ func SubjectManifestReadsChanged(caller string) string {
return "mesh.seat.node-engine.event.manifest-reads-changed." + caller
}
const (
StateHave = "have"
StateComposed = "composed"
StateData = "data"
StatePackages = "packages"
StateHealth = "health"
)
// HaveByNodeModuleKey is the key of one value of the state have under the form "<node>.<module>".
func HaveByNodeModuleKey(node, module string) string { return node + "." + module }
// ParseHaveByNodeModuleKey reads the parts of a key of the form "<node>.<module>", in the order of the form; the last result is false for a key of another form.
func ParseHaveByNodeModuleKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeHaveByNodeModuleValue reads one value of the state have under the form "<node>.<module>", refusing a field HaveByNodeModuleValue does not know and any text after the value.
func DecodeHaveByNodeModuleValue(raw []byte) (HaveByNodeModuleValue, error) {
var v HaveByNodeModuleValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// HaveByNodeNodeKey is the key of one value of the state have under the form "<node>.node".
func HaveByNodeNodeKey(node string) string { return node + ".node" }
// ParseHaveByNodeNodeKey reads the parts of a key of the form "<node>.node", in the order of the form; the last result is false for a key of another form.
func ParseHaveByNodeNodeKey(key string) (string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".node")
if !found0 || v0 == "" {
return "", false
}
rest = after0
if rest != "" {
return "", false
}
return v0, true
}
// DecodeHaveByNodeNodeValue reads one value of the state have under the form "<node>.node", refusing a field HaveByNodeNodeValue does not know and any text after the value.
func DecodeHaveByNodeNodeValue(raw []byte) (HaveByNodeNodeValue, error) {
var v HaveByNodeNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ComposedByNodeModuleFingerprintKey is the key of one value of the state composed under the form "<node>.<module>.<fingerprint>".
func ComposedByNodeModuleFingerprintKey(node, module, fingerprint string) string {
return node + "." + module + "." + fingerprint
}
// ParseComposedByNodeModuleFingerprintKey reads the parts of a key of the form "<node>.<module>.<fingerprint>", in the order of the form; the last result is false for a key of another form.
func ParseComposedByNodeModuleFingerprintKey(key string) (string, string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", "", false
}
rest = after0
v2, after2, found2 := strings.Cut(rest, ".")
if !found2 || v2 == "" {
return "", "", "", false
}
rest = after2
if rest == "" {
return "", "", "", false
}
v4 := rest
rest = ""
if rest != "" {
return "", "", "", false
}
return v0, v2, v4, true
}
// DecodeComposedByNodeModuleFingerprintValue reads one value of the state composed under the form "<node>.<module>.<fingerprint>", refusing a field ComposedByNodeModuleFingerprintValue does not know and any text after the value.
func DecodeComposedByNodeModuleFingerprintValue(raw []byte) (ComposedByNodeModuleFingerprintValue, error) {
var v ComposedByNodeModuleFingerprintValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// DataByNodeModuleKey is the key of one value of the state data under the form "<node>.<module>".
func DataByNodeModuleKey(node, module string) string { return node + "." + module }
// ParseDataByNodeModuleKey reads the parts of a key of the form "<node>.<module>", in the order of the form; the last result is false for a key of another form.
func ParseDataByNodeModuleKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeDataByNodeModuleValue reads one value of the state data under the form "<node>.<module>", refusing a field DataByNodeModuleValue does not know and any text after the value.
func DecodeDataByNodeModuleValue(raw []byte) (DataByNodeModuleValue, error) {
var v DataByNodeModuleValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PackagesByNodeKey is the key of one value of the state packages under the form "<node>".
func PackagesByNodeKey(node string) string { return node }
// ParsePackagesByNodeKey reads the parts of a key of the form "<node>", in the order of the form; the last result is false for a key of another form.
func ParsePackagesByNodeKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodePackagesByNodeValue reads one value of the state packages under the form "<node>", refusing a field PackagesByNodeValue does not know and any text after the value.
func DecodePackagesByNodeValue(raw []byte) (PackagesByNodeValue, error) {
var v PackagesByNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// HealthByNodeKey is the key of one value of the state health under the form "<node>".
func HealthByNodeKey(node string) string { return node }
// ParseHealthByNodeKey reads the parts of a key of the form "<node>", in the order of the form; the last result is false for a key of another form.
func ParseHealthByNodeKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeHealthByNodeValue reads one value of the state health under the form "<node>", refusing a field HealthByNodeValue does not know and any text after the value.
func DecodeHealthByNodeValue(raw []byte) (HealthByNodeValue, error) {
var v HealthByNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// Act is one act asked through the seat, as acts reads it (ADR 0563 §9).
type Act struct {
// the act: hand-over, access-act, judge-directories or setuid-search
@@ -561,3 +784,104 @@ type RefusedEvent = ActSaid
// ManifestReadsChangedEvent is the body of the event manifest-reads-changed.
type ManifestReadsChangedEvent = ManifestReadsChanged
// HaveByNodeModuleValue is one value of the state have under the key <node>.<module>.
type HaveByNodeModuleValue struct {
Build string `json:"build,omitempty"`
BuildAlone bool `json:"build-alone,omitempty"`
// the composition's digest
Composed string `json:"composed,omitempty"`
Detail string `json:"detail,omitempty"`
// the fingerprint held
Fp string `json:"fp,omitempty"`
// the accounts handed
Handed map[string]any `json:"handed,omitempty"`
// how it is
Health string `json:"health"`
Judgement string `json:"judgement,omitempty"`
Kept []string `json:"kept,omitempty"`
// how far it has come
Phase string `json:"phase"`
// a pull the engine waits for
PullWait map[string]any `json:"pull-wait,omitempty"`
Sealed []string `json:"sealed,omitempty"`
SealedAt map[string]any `json:"sealed-at,omitempty"`
// the user list written
UserList map[string]any `json:"user-list,omitempty"`
V int64 `json:"v"`
// what it waits for
Waits string `json:"waits,omitempty"`
}
// HaveByNodeNodeValue is one value of the state have under the key <node>.node.
type HaveByNodeNodeValue struct {
Busy map[string]any `json:"busy,omitempty"`
Candidates map[string]map[string]any `json:"candidates,omitempty"`
Composed string `json:"composed,omitempty"`
// own, or the controller's
Composes string `json:"composes,omitempty"`
ComposesWhy string `json:"composes-why,omitempty"`
Filters map[string]any `json:"filters,omitempty"`
Profile map[string]any `json:"profile,omitempty"`
// the node's record: its tunnel and certificate
Record map[string]any `json:"record,omitempty"`
Sealed []string `json:"sealed,omitempty"`
SealedAt map[string]any `json:"sealed-at,omitempty"`
Strays map[string]any `json:"strays,omitempty"`
V int64 `json:"v"`
Windows map[string]any `json:"windows,omitempty"`
}
// ComposedByNodeModuleFingerprintValue is one value of the state composed under the key <node>.<module>.<fingerprint>.
type ComposedByNodeModuleFingerprintValue struct {
Data bool `json:"Data,omitempty"`
FP string `json:"FP"`
Filled []string `json:"Filled,omitempty"`
Module string `json:"Module"`
Node string `json:"Node"`
// the node's own adoption, identities, groups, libraries and provisioner account
Own map[string]any `json:"Own,omitempty"`
// the module's plan
Plan map[string]any `json:"Plan,omitempty"`
// why the composition was refused
Refused string `json:"Refused,omitempty"`
Resources []map[string]any `json:"Resources,omitempty"`
V int64 `json:"V,omitempty"`
}
// DataByNodeModuleValue is one value of the state data under the key <node>.<module>.
type DataByNodeModuleValue struct {
Digest string `json:"digest"`
Items []map[string]any `json:"items"`
Module string `json:"module"`
Node string `json:"node"`
V int64 `json:"v,omitempty"`
}
// PackagesByNodeValuePackagesItem is a type of the contract.
type PackagesByNodeValuePackagesItem struct {
Absent bool `json:"absent,omitempty"`
Modules []string `json:"modules,omitempty"`
Package string `json:"package,omitempty"`
}
// PackagesByNodeValue is one value of the state packages under the key <node>.
type PackagesByNodeValue struct {
Node string `json:"node"`
Packages []PackagesByNodeValuePackagesItem `json:"packages"`
}
// HealthByNodeValue is one value of the state health under the key <node>.
type HealthByNodeValue struct {
At string `json:"at"`
Contract int64 `json:"contract,omitempty"`
Fallback map[string]any `json:"fallback,omitempty"`
Found []map[string]any `json:"found,omitempty"`
Network map[string]any `json:"network,omitempty"`
Node string `json:"node"`
Peers []map[string]any `json:"peers,omitempty"`
Relogin []map[string]any `json:"relogin,omitempty"`
Root []map[string]any `json:"root,omitempty"`
Units map[string]any `json:"units,omitempty"`
V int64 `json:"v"`
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/operatorchannel
go 1.26.0
-765
View File
File diff suppressed because one or more lines are too long
@@ -0,0 +1,172 @@
// Package meshconditionsclient is the logic every observer, healer and reader of conditions shares over the seat
// mesh-conditions (novox/hq ADR 0564, ADR 0634 §4): how a finding's key is made and checked, the scopes and the bounds,
// the order a person reads conditions in, and the answers a notification offers. The layouts are the seat's contract's.
package meshconditionsclient
import (
"fmt"
"regexp"
"sort"
"strings"
"time"
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
)
// The two severities, how soon the operator is needed.
const (
Urgent = "urgent"
Warning = "warning"
)
// The scopes a condition's key starts with: what kind of thing is wrong.
const (
ScopeMachine = "machine"
ScopePlan = "plan"
ScopeCall = "call"
ScopeBuild = "build"
ScopeMerge = "merge"
ScopeProvider = "provider"
ScopeSeat = "seat"
ScopeBus = "bus"
ScopeCore = "core"
ScopeProbe = "probe"
ScopeMesh = "mesh"
// ScopeDelivery is a delivery by its id (novox/hq ADR 0239); ScopeModule a module on a machine, `<module>.<machine>`.
ScopeDelivery = "delivery"
ScopeModule = "module"
)
// Scopes is every scope, in the order a person reads them.
var Scopes = []string{ScopeMachine, ScopePlan, ScopeCall, ScopeBuild, ScopeMerge, ScopeProvider,
ScopeSeat, ScopeBus, ScopeCore, ScopeProbe, ScopeMesh, ScopeDelivery, ScopeModule}
// Who resolves a condition.
const (
ResolverSelf = "self"
ResolverOperator = "operator"
ResolverAgent = "agent"
)
// ResolverHealer is the resolver of a condition a registered healer works on.
func ResolverHealer(name string) string { return "healer:" + name }
// The bounds a condition keeps.
const (
KeptEvidence = 10
KeptTried = 10
KeptGaps = 8
MaxSilence = 7 * 24 * time.Hour
ReopenWithin = 10 * time.Minute
)
// CauseOperatorAnswer is the cause of an act the operator chose.
const CauseOperatorAnswer = "operator-answer"
// The changes a condition event says.
const (
ChangeRaised = "raised"
ChangeReopened = "reopened"
ChangeSeverity = "severity"
ChangeResolver = "resolver"
ChangeSilenced = "silenced"
ChangeUnsilenced = "silence-ended"
ChangeCleared = "cleared"
ChangeWords = "words"
)
var unsafeKey = regexp.MustCompile(`[^A-Za-z0-9_=/-]`)
// Key is a condition's key: its scope, the parts of its id and a token, each made safe for a bus key.
func Key(scope, id, token string) string {
var parts []string
for _, p := range append(append([]string{scope}, strings.Split(id, ".")...), token) {
p = unsafeKey.ReplaceAllString(strings.TrimSpace(p), "_")
if p == "" {
p = "_"
}
parts = append(parts, p)
}
return strings.Join(parts, ".")
}
// EventFor is the seat's event that says a change.
func EventFor(change string) string {
switch change {
case ChangeRaised, ChangeReopened:
return seat.EventConditionRaised
case ChangeCleared:
return seat.EventConditionCleared
}
return seat.EventConditionChanged
}
// ShowKeeper is the call that shows one condition whole.
func ShowKeeper(key string) string { return seat.Seat + "." + seat.VerbConditions + " key=" + key }
// SilenceAction is the answer a notification offers to stop a condition's messages for a week.
func SilenceAction(key string) seat.Action {
return seat.Action{Label: "Silence for a week", Verb: seat.Seat + "." + seat.VerbSilence, Level: seat.ActionLevelAcknowledge,
Arguments: map[string]string{"key": key, "for": "7d", "why": "", "cause": CauseOperatorAnswer}}
}
// CheckFinding refuses a finding the keeper could not make a condition of, naming why.
func CheckFinding(f seat.FindingsByKeyValue) error {
known := false
for _, s := range Scopes {
known = known || s == f.Subject.Scope
}
token := f.Ref
if token == "" {
token = f.Kind
}
switch {
case !known:
return fmt.Errorf("health: a finding's scope is one of %s, not %q", strings.Join(Scopes, ", "), f.Subject.Scope)
case strings.TrimSpace(f.Subject.ID) == "":
return fmt.Errorf("health: a %s finding names what it is about", f.Subject.Scope)
case strings.TrimSpace(f.Kind) == "":
return fmt.Errorf("health: the finding %s has no kind", f.Key)
case f.Key != Key(f.Subject.Scope, f.Subject.ID, token):
return fmt.Errorf("health: the finding's key %q is not %q, its scope, id and kind", f.Key, Key(f.Subject.Scope, f.Subject.ID, token))
case f.Severity != Urgent && f.Severity != Warning:
return fmt.Errorf("health: the finding %s is urgent or a warning, not %q", f.Key, f.Severity)
case strings.TrimSpace(f.Summary) == "":
return fmt.Errorf("health: the finding %s says nothing", f.Key)
case strings.TrimSpace(f.Source) == "":
return fmt.Errorf("health: the finding %s does not say what saw it", f.Key)
case strings.TrimSpace(f.Observer) == "":
return fmt.Errorf("health: the finding %s does not name its observer", f.Key)
case len(f.Evidence) > KeptEvidence:
return fmt.Errorf("health: the finding %s keeps %d observations, at most %d", f.Key, len(f.Evidence), KeptEvidence)
}
return nil
}
// Order sorts conditions as a person reads them: urgent first, then oldest raised, then by key.
func Order(list []seat.ConditionsByKeyValue) {
raised := func(c seat.ConditionsByKeyValue) time.Time { t, _ := time.Parse(time.RFC3339Nano, c.Raised); return t }
sort.SliceStable(list, func(i, j int) bool {
if list[i].Severity != list[j].Severity {
return list[i].Severity == Urgent
}
if ri, rj := raised(list[i]), raised(list[j]); !ri.Equal(rj) {
return ri.Before(rj)
}
return list[i].Key < list[j].Key
})
}
// SilencedAt says whether the condition's messages are silenced at now.
func SilencedAt(c seat.ConditionsByKeyValue, now time.Time) bool {
if c.Silenced == nil {
return false
}
until, err := time.Parse(time.RFC3339Nano, c.Silenced.Until)
return err == nil && now.Before(until)
}
// Escalated says the condition waits on the operator after healers tried.
func Escalated(c seat.ConditionsByKeyValue) bool {
return c.Resolver == ResolverOperator && len(c.Tried) > 0
}
@@ -0,0 +1,62 @@
package meshconditionsclient
import (
"strings"
"testing"
"time"
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
)
// ADR 0564 clause 3: the key rule, the checks of a finding, the order and the silence a person reads conditions by.
func TestAFindingsKeyAndTheOrderOfConditions(t *testing.T) {
if k := Key("machine", "g14.local", "silent"); k != "machine.g14.local.silent" {
t.Errorf("key %s", k)
}
if k := Key("call", "a b", ""); k != "call.a_b._" {
t.Errorf("an unsafe part and an empty token: %s", k)
}
good := seat.FindingsByKeyValue{Key: "machine.g14.silent", Kind: "silent", Severity: Warning, Summary: "x", Source: "S1",
Observer: "mesh-delivery-watchman", Subject: seat.Subject{Scope: ScopeMachine, ID: "g14"}}
for _, c := range []struct {
name string
change func(*seat.FindingsByKeyValue)
refuse string
}{
{"a good finding", func(*seat.FindingsByKeyValue) {}, ""},
{"an unknown scope", func(f *seat.FindingsByKeyValue) { f.Subject.Scope = "moon" }, "scope is one of"},
{"a key that is not its subject's", func(f *seat.FindingsByKeyValue) { f.Key = "machine.g14.other" }, "is not"},
{"a reference as the key's last part", func(f *seat.FindingsByKeyValue) { f.Ref = "gone"; f.Key = "machine.g14.gone" }, ""},
{"no summary", func(f *seat.FindingsByKeyValue) { f.Summary = " " }, "says nothing"},
{"no observer", func(f *seat.FindingsByKeyValue) { f.Observer = "" }, "observer"},
{"a severity of neither kind", func(f *seat.FindingsByKeyValue) { f.Severity = "info" }, "urgent or a warning"},
{"too much evidence", func(f *seat.FindingsByKeyValue) { f.Evidence = make([]seat.Evidence, KeptEvidence+1) }, "keeps 11"},
} {
f := good
c.change(&f)
err := CheckFinding(f)
if (c.refuse == "") != (err == nil) || (err != nil && !strings.Contains(err.Error(), c.refuse)) {
t.Errorf("%s: %v", c.name, err)
}
}
list := []seat.ConditionsByKeyValue{
{Key: "b", Severity: Warning, Raised: "2026-11-01T10:00:00Z"},
{Key: "c", Severity: Urgent, Raised: "2026-11-02T10:00:00Z"},
{Key: "a", Severity: Urgent, Raised: "2026-11-01T10:00:00.5Z", Silenced: &seat.ConditionsByKeyValueSilenced{Until: "2026-11-03T00:00:00Z"}},
}
Order(list)
if got := list[0].Key + list[1].Key + list[2].Key; got != "acb" {
t.Errorf("order %s, want urgent oldest first", got)
}
now := time.Date(2026, 11, 2, 0, 0, 0, 0, time.UTC)
if !SilencedAt(list[0], now) || SilencedAt(list[0], now.Add(48*time.Hour)) || SilencedAt(list[1], now) {
t.Error("silence is until its end")
}
if EventFor(ChangeReopened) != seat.EventConditionRaised || EventFor(ChangeSilenced) != seat.EventConditionChanged ||
EventFor(ChangeCleared) != seat.EventConditionCleared {
t.Error("a change is said as its event")
}
if a := SilenceAction("k"); a.Verb != "mesh-conditions.silence" || ShowKeeper("k") != "mesh-conditions.conditions key=k" {
t.Errorf("the seat's addresses: %+v", a)
}
}
@@ -0,0 +1,5 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient
go 1.26.0
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0
@@ -0,0 +1,88 @@
// Package meshhandactsclient is the logic every module that records an act by hand shares over the seat mesh-hand-acts
// (novox/hq ADR 0565 clauses 10 and 11, ADR 0634 §4): the recorder, which asks the seat alone, and what makes an act a
// repair. The act's layout is the seat's contract's.
package meshhandactsclient
import (
"encoding/json"
"errors"
"fmt"
"strings"
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
)
// The verbs an act is recorded under in the log, and the causes and kinds that are no repair.
const (
VerbRecord = "hand-act record"
VerbDrill = "hand-act drill"
VerbWarrant = "warrant"
// CauseDrill is a drill's cause, never counted as a repair; CauseOperatorAnswer an act the operator chose.
CauseDrill = "drill"
CauseOperatorAnswer = "operator-answer"
// KindRecordedBuilds is a push that only moved recorded builds: no repair (ADR 0242).
KindRecordedBuilds = "recorded-builds"
)
// Repair says the act counts toward a cause repeated: not a drill, not an operator's answer, not recorded builds.
func Repair(a seat.Act) bool {
return a.Cause != CauseDrill && a.Verb != VerbDrill && a.Cause != CauseOperatorAnswer && a.Kind != KindRecordedBuilds
}
// Request is one act a recorder records: what, why, its cause, the condition it addresses, and its verb in the log (a
// repair when empty).
type Request struct {
What string `json:"what"`
Why string `json:"why"`
Cause string `json:"cause,omitempty"`
Condition string `json:"condition,omitempty"`
Verb string `json:"verb,omitempty"`
}
// Taken is which log took an act, and what its holder answered.
type Taken struct {
Log string `json:"log"`
Answer json.RawMessage `json:"answer,omitempty"`
}
// Recorder records acts for a module through the seat mesh-hand-acts alone. An act the seat does not take is an error
// that says nothing was recorded, never a quiet success.
type Recorder struct {
// Ask calls a seat verb by its address (`seat:<seat>.<verb>`): the runtime's ask.
Ask func(key string, body any) (json.RawMessage, error)
}
// NoResponder says err is the bus finding nobody to answer: the seat has no holder now.
func NoResponder(err error) bool {
return err != nil && strings.Contains(err.Error(), "no responders")
}
// Record records one act.
func (r Recorder) Record(q Request) (Taken, error) {
if strings.TrimSpace(q.What) == "" || strings.TrimSpace(q.Why) == "" {
return Taken{}, errors.New("a hand act says what was done and why: nothing was recorded")
}
body := map[string]any{"what": q.What, "why": q.Why}
for k, v := range map[string]string{"cause": q.Cause, "condition": q.Condition, "verb": q.Verb} {
if v != "" {
body[k] = v
}
}
return r.record(seat.VerbHandAct, body)
}
// RecordWarrant records what the asking module did on the operator's warrant for its ask.
func (r Recorder) RecordWarrant(asker, ask string) (Taken, error) {
return r.record(seat.VerbWarranted, map[string]any{"asker": asker, "ask": ask})
}
func (r Recorder) record(verb string, body any) (Taken, error) {
answer, err := r.Ask("seat:"+seat.Seat+"."+verb, body)
if err == nil {
return Taken{Log: seat.Seat, Answer: answer}, nil
}
if NoResponder(err) {
return Taken{}, fmt.Errorf("%s has no holder that answers: nothing was recorded (%w)", seat.Seat, err)
}
return Taken{}, fmt.Errorf("%s.%s refused, nothing was recorded: %w", seat.Seat, verb, err)
}
@@ -0,0 +1,73 @@
package meshhandactsclient
import (
"encoding/json"
"errors"
"reflect"
"strings"
"testing"
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
)
// ADR 0565 clauses 10 and 11 (issue 1953 L5-S2, S4, L5b): an act reads the controller's entries unchanged, and a
// recorder records through the seat alone, the controller's verbs being gone, and says loudly when nothing was recorded.
func TestAnActIsRecordedInTheLogThatAnswers(t *testing.T) {
// The shape of mesh-controller internal/link HandAct, as its bucket keeps an entry (handacts.go at 0fbb5ef3).
raw := `{"id":"act-1","at":"2026-10-28T09:00:00Z","by":"person.jochen","verb":"hand-act record","why":"a stuck consumer",` +
`"cause":"consumer-lost","condition":"bus.EVENTS.x.consumer-lost","via":"telegram","ask":"a-1","proofs":["P1"],` +
`"requested-by":"bus.EVENTS.x.consumer-lost","outcome":"done"}`
var a seat.Act
if err := json.Unmarshal([]byte(raw), &a); err != nil {
t.Fatal(err)
}
again, _ := json.Marshal(a)
var want, got map[string]any
_ = json.Unmarshal([]byte(raw), &want)
_ = json.Unmarshal(again, &got)
if !reflect.DeepEqual(want, got) || !Repair(a) || Repair(seat.Act{Cause: CauseDrill}) || Repair(seat.Act{Verb: VerbDrill}) {
t.Errorf("the controller's entry reads back as %s", again)
}
noResponders := errors.New("nats: no responders available for request")
for _, c := range []struct {
name string
seat error
ctrl error
log string
refused string
asked string
warrants bool
}{
{name: "the seat answers", log: seat.Seat, asked: "seat:mesh-hand-acts.hand-act"},
{name: "no holder: nothing recorded, the controller never asked", seat: noResponders, refused: "nothing was recorded",
asked: "seat:mesh-hand-acts.hand-act"},
{name: "the seat refuses", seat: errors.New("why is required"), refused: "refused, nothing was recorded",
asked: "seat:mesh-hand-acts.hand-act"},
{name: "a warrant without a holder", seat: noResponders, warrants: true, refused: "nothing was recorded",
asked: "seat:mesh-hand-acts.warranted"},
{name: "a warrant recorded", warrants: true, log: seat.Seat, asked: "seat:mesh-hand-acts.warranted"},
} {
var asked []string
r := Recorder{Ask: func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
if strings.HasPrefix(key, "seat:mesh-hand-acts.") {
return json.RawMessage(`{}`), c.seat
}
return json.RawMessage(`{}`), c.ctrl
}}
var taken Taken
var err error
if c.warrants {
taken, err = r.RecordWarrant("mesh-config", "ask-1")
} else {
taken, err = r.Record(Request{What: "silenced", Why: "known", Cause: "silent", Verb: "conditions silence"})
}
if (c.refused != "") != (err != nil) || (err != nil && !strings.Contains(err.Error(), c.refused)) || taken.Log != c.log ||
strings.Join(asked, ",") != c.asked {
t.Errorf("%s: took %q, %v, asked %v", c.name, taken.Log, err, asked)
}
}
if _, err := (Recorder{}).Record(Request{What: "x"}); err == nil {
t.Error("an act with no why was recorded")
}
}
@@ -0,0 +1,5 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient
go 1.26.0
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts v0.0.0
@@ -0,0 +1,384 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshconditions is the contract of the seat "mesh-conditions", defined whole (seats/mesh-conditions/seat.json): What is wrong with the mesh now (ADR 0564): the open conditions raised from the observers' findings and cleared when a finding goes.
package meshconditions
import (
"bytes"
"encoding/json"
"errors"
)
// Seat is the seat's name.
const Seat = "mesh-conditions"
const (
VerbConditions = "conditions"
VerbSilence = "silence"
VerbResync = "resync"
)
const (
EventConditionRaised = "condition-raised"
EventConditionChanged = "condition-changed"
EventConditionCleared = "condition-cleared"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbConditions, VerbSilence, VerbResync}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventConditionRaised, EventConditionChanged, EventConditionCleared}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "mesh-conditions.events"
FamilyMaxAgeDays = 7
)
// SubjectConditionRaised is where condition-raised is published.
const SubjectConditionRaised = "mesh.seat.mesh-conditions.event.condition-raised"
// SubjectConditionChanged is where condition-changed is published.
const SubjectConditionChanged = "mesh.seat.mesh-conditions.event.condition-changed"
// SubjectConditionCleared is where condition-cleared is published.
const SubjectConditionCleared = "mesh.seat.mesh-conditions.event.condition-cleared"
const (
StateConditions = "conditions"
StateFindings = "findings"
)
// ConditionsByKeyKey is the key of one value of the state conditions under the form "<key>".
func ConditionsByKeyKey(key string) string { return key }
// ParseConditionsByKeyKey reads the parts of a key of the form "<key>", in the order of the form; the last result is false for a key of another form.
func ParseConditionsByKeyKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeConditionsByKeyValue reads one value of the state conditions under the form "<key>", refusing a field ConditionsByKeyValue does not know and any text after the value.
func DecodeConditionsByKeyValue(raw []byte) (ConditionsByKeyValue, error) {
var v ConditionsByKeyValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// FindingsByKeyKey is the key of one value of the state findings under the form "<key>".
func FindingsByKeyKey(key string) string { return key }
// ParseFindingsByKeyKey reads the parts of a key of the form "<key>", in the order of the form; the last result is false for a key of another form.
func ParseFindingsByKeyKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeFindingsByKeyValue reads one value of the state findings under the form "<key>", refusing a field FindingsByKeyValue does not know and any text after the value.
func DecodeFindingsByKeyValue(raw []byte) (FindingsByKeyValue, error) {
var v FindingsByKeyValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// Action is one answer the operator may give from a notification.
type Action struct {
Arguments map[string]string `json:"arguments,omitempty"`
Label string `json:"label"`
Level string `json:"level,omitempty"`
Machine string `json:"machine,omitempty"`
// the seat verb the operator channel calls
Verb string `json:"verb"`
}
// The values of Action's level.
const (
ActionLevelAcknowledge = "acknowledge"
ActionLevelApprove = "approve"
)
// ConditionEventGapsItem is a type of the contract.
type ConditionEventGapsItem struct {
Cleared string `json:"cleared,omitempty"`
Reopened string `json:"reopened,omitempty"`
}
// ConditionEventSilenced is a type of the contract.
type ConditionEventSilenced struct {
By string `json:"by,omitempty"`
Since string `json:"since,omitempty"`
Until string `json:"until,omitempty"`
Why string `json:"why,omitempty"`
}
// ConditionEventTriedItem is a type of the contract.
type ConditionEventTriedItem struct {
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Outcome string `json:"outcome,omitempty"`
What string `json:"what,omitempty"`
}
// ConditionEvent is a condition and what changed.
type ConditionEvent struct {
Actions []Action `json:"actions,omitempty"`
At string `json:"at"`
Change string `json:"change"`
Cleared string `json:"cleared,omitempty"`
Count int64 `json:"count,omitempty"`
Epoch int64 `json:"epoch,omitempty"`
Event string `json:"event"`
// newest first, at most 10
Evidence []Evidence `json:"evidence,omitempty"`
Explanation string `json:"explanation,omitempty"`
First string `json:"first,omitempty"`
Gaps []ConditionEventGapsItem `json:"gaps,omitempty"`
Headline string `json:"headline,omitempty"`
// scope.id.token
Key string `json:"key"`
Kind string `json:"kind,omitempty"`
LastObserved string `json:"last-observed,omitempty"`
LooksUnread string `json:"looks-unread,omitempty"`
Needs string `json:"needs,omitempty"`
Observations int64 `json:"observations,omitempty"`
Raised string `json:"raised,omitempty"`
Resolved string `json:"resolved,omitempty"`
// self, operator, agent or healer:<name>
Resolver string `json:"resolver,omitempty"`
Severity string `json:"severity,omitempty"`
// the tool call that shows it
Show string `json:"show,omitempty"`
Silenced *ConditionEventSilenced `json:"silenced,omitempty"`
// the row, probe or event that saw it
Source string `json:"source,omitempty"`
Subject *Subject `json:"subject,omitempty"`
// one line
Summary string `json:"summary,omitempty"`
Tried []ConditionEventTriedItem `json:"tried,omitempty"`
Was string `json:"was,omitempty"`
Why string `json:"why,omitempty"`
}
// The values of ConditionEvent's change.
const (
ConditionEventChangeRaised = "raised"
ConditionEventChangeReopened = "reopened"
ConditionEventChangeSeverity = "severity"
ConditionEventChangeResolver = "resolver"
ConditionEventChangeSilenced = "silenced"
ConditionEventChangeSilenceEnded = "silence-ended"
ConditionEventChangeCleared = "cleared"
ConditionEventChangeWords = "words"
)
// The values of ConditionEvent's severity.
const (
ConditionEventSeverityUrgent = "urgent"
ConditionEventSeverityWarning = "warning"
)
// Evidence is one observation, as it was said.
type Evidence struct {
At string `json:"at"`
Said string `json:"said"`
}
// Subject is what the condition is about.
type Subject struct {
// the other machines it concerns
Also []string `json:"also,omitempty"`
// its id within the scope
ID string `json:"id"`
// the machine it concerns, when there is one
Machine string `json:"machine,omitempty"`
// machine, plan, call, build, merge, provider, seat, bus, core, probe, mesh, delivery or module
Scope string `json:"scope"`
}
// ConditionsInput is what conditions takes.
type ConditionsInput struct {
// with history: how many days back (default 7, at most 90)
Days string `json:"days,omitempty"`
// "true": every raising, change, silence and clearing lately, oldest first
History string `json:"history,omitempty"`
// a condition's key: that one whole; with history, only its transitions
Key string `json:"key,omitempty"`
// only those about this machine
Machine string `json:"machine,omitempty"`
// only this scope: machine, plan, call, build, merge, provider, seat, bus, core, probe, mesh, delivery or module
Scope string `json:"scope,omitempty"`
// only urgent, or only warning
Severity string `json:"severity,omitempty"`
}
// The values of ConditionsInput's history.
const (
ConditionsInputHistoryTrue = "true"
ConditionsInputHistoryFalse = "false"
)
// ConditionsAnswer is what conditions answers.
type ConditionsAnswer = map[string]any
// SilenceInput is what silence takes.
type SilenceInput struct {
// the cause in a word (the condition's kind when absent)
Cause string `json:"cause,omitempty"`
// how long: 30m, 4h, 2d; at most 7d
For string `json:"for"`
// the condition's key
Key string `json:"key"`
// why, required and recorded
Why string `json:"why"`
}
// SilenceAnswer is what silence answers.
type SilenceAnswer = map[string]any
// ResyncInput is what resync takes.
type ResyncInput struct {
}
// ResyncAnswer is what resync answers.
type ResyncAnswer = map[string]any
// ConditionRaisedEvent is the body of the event condition-raised.
type ConditionRaisedEvent = ConditionEvent
// ConditionChangedEvent is the body of the event condition-changed.
type ConditionChangedEvent = ConditionEvent
// ConditionClearedEvent is the body of the event condition-cleared.
type ConditionClearedEvent = ConditionEvent
// ConditionsByKeyValueGapsItem is a type of the contract.
type ConditionsByKeyValueGapsItem struct {
Cleared string `json:"cleared,omitempty"`
Reopened string `json:"reopened,omitempty"`
}
// ConditionsByKeyValueSilenced is a type of the contract.
type ConditionsByKeyValueSilenced struct {
By string `json:"by,omitempty"`
Since string `json:"since,omitempty"`
Until string `json:"until,omitempty"`
Why string `json:"why,omitempty"`
}
// ConditionsByKeyValueTriedItem is a type of the contract.
type ConditionsByKeyValueTriedItem struct {
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Outcome string `json:"outcome,omitempty"`
What string `json:"what,omitempty"`
}
// ConditionsByKeyValue is one value of the state conditions under the key <key>.
type ConditionsByKeyValue struct {
Actions []Action `json:"actions,omitempty"`
Count int64 `json:"count,omitempty"`
Epoch int64 `json:"epoch,omitempty"`
// newest first, at most 10
Evidence []Evidence `json:"evidence,omitempty"`
Explanation string `json:"explanation,omitempty"`
First string `json:"first,omitempty"`
Gaps []ConditionsByKeyValueGapsItem `json:"gaps,omitempty"`
Headline string `json:"headline,omitempty"`
// scope.id.token
Key string `json:"key"`
Kind string `json:"kind"`
LastObserved string `json:"last-observed"`
LooksUnread string `json:"looks-unread,omitempty"`
Needs string `json:"needs,omitempty"`
Observations int64 `json:"observations,omitempty"`
Raised string `json:"raised"`
Resolved string `json:"resolved,omitempty"`
// self, operator, agent or healer:<name>
Resolver string `json:"resolver,omitempty"`
Severity string `json:"severity"`
Silenced *ConditionsByKeyValueSilenced `json:"silenced,omitempty"`
// the row, probe or event that saw it
Source string `json:"source,omitempty"`
Subject Subject `json:"subject"`
// one line
Summary string `json:"summary,omitempty"`
Tried []ConditionsByKeyValueTriedItem `json:"tried,omitempty"`
}
// The values of ConditionsByKeyValue's severity.
const (
ConditionsByKeyValueSeverityUrgent = "urgent"
ConditionsByKeyValueSeverityWarning = "warning"
)
// FindingsByKeyValue is one value of the state findings under the key <key>.
type FindingsByKeyValue struct {
Actions []Action `json:"actions,omitempty"`
At string `json:"at"`
// newest first, at most 10
Evidence []Evidence `json:"evidence,omitempty"`
Explanation string `json:"explanation,omitempty"`
Headline string `json:"headline,omitempty"`
// scope.id.token
Key string `json:"key"`
Kind string `json:"kind"`
Needs string `json:"needs,omitempty"`
// the module that wrote it
Observer string `json:"observer"`
// the key's last part when it is not the kind
Ref string `json:"ref,omitempty"`
Resolved string `json:"resolved,omitempty"`
// self, operator, agent or healer:<name>
Resolver string `json:"resolver,omitempty"`
// what of its own saw it last
Run string `json:"run,omitempty"`
Severity string `json:"severity"`
// the row, probe or event that saw it
Source string `json:"source"`
Subject Subject `json:"subject"`
// one line
Summary string `json:"summary"`
// layout version, 1
V int64 `json:"v"`
}
// The values of FindingsByKeyValue's severity.
const (
FindingsByKeyValueSeverityUrgent = "urgent"
FindingsByKeyValueSeverityWarning = "warning"
)
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions
go 1.26.0
@@ -0,0 +1,222 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshhandacts is the contract of the seat "mesh-hand-acts", defined whole (seats/mesh-hand-acts/seat.json): Acts done by hand, recorded with who, why and cause (ADR 0565): the log every module records through.
package meshhandacts
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "mesh-hand-acts"
const (
VerbHandAct = "hand-act"
VerbHandActs = "hand-acts"
VerbWarranted = "warranted"
)
const (
EventActRecorded = "act-recorded"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbHandAct, VerbHandActs, VerbWarranted}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventActRecorded}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "mesh-hand-acts.events"
FamilyMaxAgeDays = 7
)
// SubjectActRecorded is where act-recorded is published.
const SubjectActRecorded = "mesh.seat.mesh-hand-acts.event.act-recorded"
const (
StateActs = "acts"
StateWarrants = "warrants"
)
// ActsByIDKey is the key of one value of the state acts under the form "<id>".
func ActsByIDKey(id string) string { return id }
// ParseActsByIDKey reads the parts of a key of the form "<id>", in the order of the form; the last result is false for a key of another form.
func ParseActsByIDKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeActsByIDValue reads one value of the state acts under the form "<id>", refusing a field ActsByIDValue does not know and any text after the value.
func DecodeActsByIDValue(raw []byte) (ActsByIDValue, error) {
var v ActsByIDValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// WarrantsByAskerAskKey is the key of one value of the state warrants under the form "<asker>.<ask>".
func WarrantsByAskerAskKey(asker, ask string) string { return asker + "." + ask }
// ParseWarrantsByAskerAskKey reads the parts of a key of the form "<asker>.<ask>", in the order of the form; the last result is false for a key of another form.
func ParseWarrantsByAskerAskKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeWarrantsByAskerAskValue reads one value of the state warrants under the form "<asker>.<ask>", refusing a field WarrantsByAskerAskValue does not know and any text after the value.
func DecodeWarrantsByAskerAskValue(raw []byte) (WarrantsByAskerAskValue, error) {
var v WarrantsByAskerAskValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// Act is one act done by hand.
type Act struct {
Arguments []string `json:"arguments,omitempty"`
Ask string `json:"ask,omitempty"`
At string `json:"at"`
// the caller the runtime proved
By string `json:"by"`
Carried []string `json:"carried,omitempty"`
Cause string `json:"cause"`
Condition string `json:"condition,omitempty"`
ID string `json:"id"`
// what the act was read to be from what it did
Kind string `json:"kind,omitempty"`
// which log holds it, set when it is read
Log string `json:"log,omitempty"`
Outcome string `json:"outcome,omitempty"`
Proofs []string `json:"proofs,omitempty"`
RequestedBy string `json:"requested-by,omitempty"`
Verb string `json:"verb"`
Via string `json:"via,omitempty"`
Why string `json:"why"`
}
// HandActInput is what hand-act takes.
type HandActInput struct {
// the cause in a word, or a condition's kind
Cause string `json:"cause,omitempty"`
// the key of the condition it addressed, if any (optional)
Condition string `json:"condition,omitempty"`
// the act's verb in the log: a repair when absent, `hand-act drill` for a drill, or a recorder's own
Verb string `json:"verb,omitempty"`
// what was done, in a line
What string `json:"what"`
// why it had to be done by hand
Why string `json:"why"`
}
// HandActAnswer is what hand-act answers.
type HandActAnswer = map[string]any
// HandActsInput is what hand-acts takes.
type HandActsInput struct {
// only this cause
Cause string `json:"cause,omitempty"`
// how many days back (default 14)
Days string `json:"days,omitempty"`
// "true": every warrant recorded
Warrants string `json:"warrants,omitempty"`
// only acts whose who contains this
Who string `json:"who,omitempty"`
}
// The values of HandActsInput's warrants.
const (
HandActsInputWarrantsTrue = "true"
HandActsInputWarrantsFalse = "false"
)
// HandActsAnswer is what hand-acts answers.
type HandActsAnswer = map[string]any
// WarrantedInput is what warranted takes.
type WarrantedInput struct {
// its ask's id
Ask string `json:"ask"`
// the module that asked
Asker string `json:"asker"`
}
// WarrantedAnswer is what warranted answers.
type WarrantedAnswer = map[string]any
// ActRecordedEvent is the body of the event act-recorded.
type ActRecordedEvent = Act
// ActsByIDValue is one value of the state acts under the key <id>.
type ActsByIDValue struct {
Arguments []string `json:"arguments,omitempty"`
Ask string `json:"ask,omitempty"`
At string `json:"at"`
// the caller the runtime proved
By string `json:"by"`
Carried []string `json:"carried,omitempty"`
Cause string `json:"cause"`
Condition string `json:"condition,omitempty"`
ID string `json:"id"`
// what the act was read to be from what it did
Kind string `json:"kind,omitempty"`
// which log holds it, set when it is read
Log string `json:"log,omitempty"`
Outcome string `json:"outcome,omitempty"`
Proofs []string `json:"proofs,omitempty"`
RequestedBy string `json:"requested-by,omitempty"`
Verb string `json:"verb"`
Via string `json:"via,omitempty"`
Why string `json:"why"`
}
// WarrantsByAskerAskValue is one value of the state warrants under the key <asker>.<ask>.
type WarrantsByAskerAskValue struct {
Ask string `json:"ask"`
Asker string `json:"asker"`
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Option string `json:"option,omitempty"`
}
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts
go 1.26.0
@@ -0,0 +1,197 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshhealers is the contract of the seat "mesh-healers", defined whole (seats/mesh-healers/seat.json): The healers (ADR 0564): each a registered response to one kind of condition, within a budget and the mesh-wide brake.
package meshhealers
import (
"bytes"
"encoding/json"
"errors"
)
// Seat is the seat's name.
const Seat = "mesh-healers"
const (
VerbHealers = "healers"
VerbHeal = "heal"
VerbDrill = "drill"
)
const (
EventHealerActed = "healer-acted"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbHealers, VerbHeal, VerbDrill}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventHealerActed}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "mesh-healers.events"
FamilyMaxAgeDays = 7
)
// SubjectHealerActed is where healer-acted is published.
const SubjectHealerActed = "mesh.seat.mesh-healers.event.healer-acted"
const (
StateAttempts = "attempts"
StateWould = "would"
)
// AttemptsByAttemptKey is the key of one value of the state attempts under the form "<attempt>".
func AttemptsByAttemptKey(attempt string) string { return attempt }
// ParseAttemptsByAttemptKey reads the parts of a key of the form "<attempt>", in the order of the form; the last result is false for a key of another form.
func ParseAttemptsByAttemptKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeAttemptsByAttemptValue reads one value of the state attempts under the form "<attempt>", refusing a field AttemptsByAttemptValue does not know and any text after the value.
func DecodeAttemptsByAttemptValue(raw []byte) (AttemptsByAttemptValue, error) {
var v AttemptsByAttemptValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// WouldByWouldKey is the key of one value of the state would under the form "<would>".
func WouldByWouldKey(would string) string { return would }
// ParseWouldByWouldKey reads the parts of a key of the form "<would>", in the order of the form; the last result is false for a key of another form.
func ParseWouldByWouldKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodeWouldByWouldValue reads one value of the state would under the form "<would>", refusing a field WouldByWouldValue does not know and any text after the value.
func DecodeWouldByWouldValue(raw []byte) (WouldByWouldValue, error) {
var v WouldByWouldValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// HealersInput is what healers takes.
type HealersInput struct {
// how many days of acts back (default 7)
Days string `json:"days,omitempty"`
}
// HealersAnswer is what healers answers.
type HealersAnswer = map[string]any
// HealInput is what heal takes.
type HealInput struct {
// the condition's key
Key string `json:"key"`
// why now, kept with the act
Why string `json:"why"`
}
// HealAnswer is what heal answers.
type HealAnswer = map[string]any
// DrillInput is what drill takes.
type DrillInput struct {
// the key of the condition the drill is meant to raise, if any (optional)
Condition string `json:"condition,omitempty"`
// what was done on purpose, in a line
What string `json:"what"`
// what the drill tests
Why string `json:"why"`
}
// DrillAnswer is what drill answers.
type DrillAnswer = map[string]any
// HealerActedEvent is the body of the event healer-acted.
type HealerActedEvent struct {
Act string `json:"act,omitempty"`
At string `json:"at"`
Budget string `json:"budget,omitempty"`
By string `json:"by,omitempty"`
Condition string `json:"condition"`
Event string `json:"event"`
Healer string `json:"healer"`
Kind string `json:"kind,omitempty"`
Outcome string `json:"outcome"`
Said string `json:"said,omitempty"`
Show string `json:"show,omitempty"`
}
// The values of HealerActedEvent's outcome.
const (
HealerActedEventOutcomeActing = "acting"
HealerActedEventOutcomeActed = "acted"
HealerActedEventOutcomeFailed = "failed"
HealerActedEventOutcomeEscalated = "escalated"
)
// AttemptsByAttemptValue is one value of the state attempts under the key <attempt>.
type AttemptsByAttemptValue struct {
Act string `json:"act"`
Begun string `json:"begun"`
// what the budget counts by: the condition's key unless the healer says another
BudgetKey string `json:"budget-key"`
Condition string `json:"condition"`
Finished string `json:"finished,omitempty"`
Healer string `json:"healer"`
Kind string `json:"kind"`
Outcome string `json:"outcome"`
Said string `json:"said,omitempty"`
}
// The values of AttemptsByAttemptValue's outcome.
const (
AttemptsByAttemptValueOutcomeActing = "acting"
AttemptsByAttemptValueOutcomeActed = "acted"
AttemptsByAttemptValueOutcomeFailed = "failed"
AttemptsByAttemptValueOutcomeEscalated = "escalated"
)
// WouldByWouldValue is one value of the state would under the key <would>.
type WouldByWouldValue struct {
Act string `json:"act"`
At string `json:"at"`
Condition string `json:"condition"`
Healer string `json:"healer"`
Kind string `json:"kind,omitempty"`
Why string `json:"why,omitempty"`
}
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers
go 1.26.0
@@ -0,0 +1,101 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshselfcheck is the contract of the seat "mesh-self-check", defined whole (seats/mesh-self-check/seat.json): The mesh checking itself (ADR 0564): probes run every five minutes, each failure a finding the seat's conditions raise.
package meshselfcheck
// Seat is the seat's name.
const Seat = "mesh-self-check"
const (
VerbDoctor = "doctor"
VerbProbes = "probes"
)
const (
EventChecked = "checked"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbDoctor, VerbProbes}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventChecked}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "mesh-self-check.events"
FamilyMaxAgeDays = 7
)
// SubjectChecked is where checked is published.
const SubjectChecked = "mesh.seat.mesh-self-check.event.checked"
// ProbeVerdict is one probe's verdict.
type ProbeVerdict struct {
Error string `json:"error,omitempty"`
Found []string `json:"found,omitempty"`
FoundCount int64 `json:"found-count,omitempty"`
ID string `json:"id"`
More string `json:"more,omitempty"`
Took string `json:"took,omitempty"`
Unconfirmed []string `json:"unconfirmed,omitempty"`
Verdict string `json:"verdict"`
}
// The values of ProbeVerdict's verdict.
const (
ProbeVerdictVerdictPassed = "passed"
ProbeVerdictVerdictFailed = "failed"
ProbeVerdictVerdictFailedToRun = "failed-to-run"
ProbeVerdictVerdictDeferred = "deferred"
)
// DoctorInput is what doctor takes.
type DoctorInput struct {
// one probe's id (D6): its verdict alone, with every finding
Probe string `json:"probe,omitempty"`
// "true": run every probe now and answer the verdict
Run string `json:"run,omitempty"`
}
// The values of DoctorInput's run.
const (
DoctorInputRunTrue = "true"
DoctorInputRunFalse = "false"
)
// DoctorAnswer is what doctor answers.
type DoctorAnswer = map[string]any
// ProbesInput is what probes takes.
type ProbesInput struct {
}
// ProbesAnswer is what probes answers.
type ProbesAnswer = map[string]any
// CheckedEventCounts is a type of the contract.
type CheckedEventCounts struct {
Deferred int64 `json:"deferred,omitempty"`
Failed int64 `json:"failed,omitempty"`
FailedToRun int64 `json:"failed-to-run,omitempty"`
Passed int64 `json:"passed,omitempty"`
}
// CheckedEvent is the body of the event checked.
type CheckedEvent struct {
At string `json:"at"`
Controller string `json:"controller,omitempty"`
Counts *CheckedEventCounts `json:"counts,omitempty"`
IntervalSeconds int64 `json:"interval-seconds,omitempty"`
Probes []ProbeVerdict `json:"probes"`
Run string `json:"run"`
Started string `json:"started,omitempty"`
Took string `json:"took,omitempty"`
Unsaid int64 `json:"unsaid,omitempty"`
Why string `json:"why,omitempty"`
}
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshselfcheck
go 1.26.0
@@ -0,0 +1,266 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshwatchdogs is the contract of the seat "mesh-watchdogs", defined whole (seats/mesh-watchdogs/seat.json): The watchman's seat (ADR 0564, ADR 0433): signals that expire unless renewed, what stopped moving, who is present, the dead letters.
package meshwatchdogs
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "mesh-watchdogs"
const (
VerbSignals = "signals"
VerbStuck = "stuck"
VerbPresence = "presence"
VerbDeadLetters = "dead-letters"
VerbResync = "resync"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbSignals, VerbStuck, VerbPresence, VerbDeadLetters, VerbResync}
}
const (
StatePresence = "presence"
StatePulse = "pulse"
StateStuck = "stuck"
)
// PresenceByNodeKey is the key of one value of the state presence under the form "<node>".
func PresenceByNodeKey(node string) string { return node }
// ParsePresenceByNodeKey reads the parts of a key of the form "<node>", in the order of the form; the last result is false for a key of another form.
func ParsePresenceByNodeKey(key string) (string, bool) {
rest := key
if rest == "" {
return "", false
}
v0 := rest
rest = ""
if rest != "" {
return "", false
}
return v0, true
}
// DecodePresenceByNodeValue reads one value of the state presence under the form "<node>", refusing a field PresenceByNodeValue does not know and any text after the value.
func DecodePresenceByNodeValue(raw []byte) (PresenceByNodeValue, error) {
var v PresenceByNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PresenceByPartPartInstanceKey is the key of one value of the state presence under the form "part.<part>.<instance>".
func PresenceByPartPartInstanceKey(part, instance string) string {
return "part." + part + "." + instance
}
// ParsePresenceByPartPartInstanceKey reads the parts of a key of the form "part.<part>.<instance>", in the order of the form; the last result is false for a key of another form.
func ParsePresenceByPartPartInstanceKey(key string) (string, string, bool) {
rest := key
if !strings.HasPrefix(rest, "part.") {
return "", "", false
}
rest = rest[5:]
v1, after1, found1 := strings.Cut(rest, ".")
if !found1 || v1 == "" {
return "", "", false
}
rest = after1
if rest == "" {
return "", "", false
}
v3 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v1, v3, true
}
// DecodePresenceByPartPartInstanceValue reads one value of the state presence under the form "part.<part>.<instance>", refusing a field PresenceByPartPartInstanceValue does not know and any text after the value.
func DecodePresenceByPartPartInstanceValue(raw []byte) (PresenceByPartPartInstanceValue, error) {
var v PresenceByPartPartInstanceValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PulseByBucketKeyKey is the key of one value of the state pulse under the form "<bucket>.<key>".
func PulseByBucketKeyKey(bucket, key string) string { return bucket + "." + key }
// ParsePulseByBucketKeyKey reads the parts of a key of the form "<bucket>.<key>", in the order of the form; the last result is false for a key of another form.
func ParsePulseByBucketKeyKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodePulseByBucketKeyValue reads one value of the state pulse under the form "<bucket>.<key>", refusing a field PulseByBucketKeyValue does not know and any text after the value.
func DecodePulseByBucketKeyValue(raw []byte) (PulseByBucketKeyValue, error) {
var v PulseByBucketKeyValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// StuckByBucketKeyKey is the key of one value of the state stuck under the form "<bucket>.<key>".
func StuckByBucketKeyKey(bucket, key string) string { return bucket + "." + key }
// ParseStuckByBucketKeyKey reads the parts of a key of the form "<bucket>.<key>", in the order of the form; the last result is false for a key of another form.
func ParseStuckByBucketKeyKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeStuckByBucketKeyValue reads one value of the state stuck under the form "<bucket>.<key>", refusing a field StuckByBucketKeyValue does not know and any text after the value.
func DecodeStuckByBucketKeyValue(raw []byte) (StuckByBucketKeyValue, error) {
var v StuckByBucketKeyValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// SignalsInput is what signals takes.
type SignalsInput struct {
// one row, e.g. S1
Row string `json:"row,omitempty"`
}
// SignalsAnswer is what signals answers.
type SignalsAnswer = map[string]any
// StuckInput is what stuck takes.
type StuckInput struct {
// only those on this machine
Machine string `json:"machine,omitempty"`
}
// StuckAnswer is what stuck answers.
type StuckAnswer = map[string]any
// PresenceInput is what presence takes.
type PresenceInput struct {
// one machine
Machine string `json:"machine,omitempty"`
}
// PresenceAnswer is what presence answers.
type PresenceAnswer = map[string]any
// DeadLettersInput is what dead-letters takes.
type DeadLettersInput struct {
// with deliver or drop: the cause in a word (dead-letter when absent)
Cause string `json:"cause,omitempty"`
// a consumer's name, or <stream>.<consumer>: only what that one gave up on
Consumer string `json:"consumer,omitempty"`
// a dead letter's id: deliver it again to the consumer that gave it up (needs why)
Deliver string `json:"deliver,omitempty"`
// a dead letter's id: drop it for good (needs why)
Drop string `json:"drop,omitempty"`
// a dead letter's id, as the list gives it: that one whole, with its message
ID string `json:"id,omitempty"`
// how many to list, newest first (default 50); only when listing
Limit string `json:"limit,omitempty"`
// with deliver or drop: why, required and recorded
Why string `json:"why,omitempty"`
}
// DeadLettersAnswer is what dead-letters answers.
type DeadLettersAnswer = map[string]any
// ResyncInput is what resync takes.
type ResyncInput struct {
}
// ResyncAnswer is what resync answers.
type ResyncAnswer = map[string]any
// PresenceByNodeValue is one value of the state presence under the key <node>.
type PresenceByNodeValue struct {
Online bool `json:"online"`
V int64 `json:"v,omitempty"`
}
// PresenceByPartPartInstanceValue is one value of the state presence under the key part.<part>.<instance>.
type PresenceByPartPartInstanceValue struct {
Online bool `json:"online"`
V int64 `json:"v,omitempty"`
}
// PulseByBucketKeyValue is one value of the state pulse under the key <bucket>.<key>.
type PulseByBucketKeyValue struct {
Bucket string `json:"bucket"`
Key string `json:"key"`
Owes string `json:"owes,omitempty"`
Revision int64 `json:"revision"`
V int64 `json:"v,omitempty"`
}
// StuckByBucketKeyValue is one value of the state stuck under the key <bucket>.<key>.
type StuckByBucketKeyValue struct {
Bucket string `json:"bucket"`
Key string `json:"key"`
// it has moved again
Moved bool `json:"moved,omitempty"`
Since string `json:"since"`
V int64 `json:"v,omitempty"`
// what it waited for, in words
Waited string `json:"waited,omitempty"`
}
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs
go 1.26.0
+10
View File
@@ -0,0 +1,10 @@
{
"format": 1,
"seats": [
"mesh-conditions",
"mesh-hand-acts",
"mesh-healers",
"mesh-self-check",
"mesh-watchdogs"
]
}
@@ -0,0 +1,19 @@
{
"description": "The contract of the seat mesh-conditions, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"name": "@novox/mesh-health-and-repair-contracts-mesh-conditions",
"scripts": {
"build": "tsc",
"prepare": "tsc"
},
"type": "module",
"version": "0.1.0"
}
@@ -0,0 +1,280 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-conditions", defined whole (seats/mesh-conditions/seat.json): What is wrong with the mesh now (ADR 0564): the open conditions raised from the observers' findings and cleared when a finding goes.
export const seat = "mesh-conditions";
export const verbs = {
conditions: "conditions",
silence: "silence",
resync: "resync",
} as const;
export const events = {
conditionRaised: "condition-raised",
conditionChanged: "condition-changed",
conditionCleared: "condition-cleared",
} as const;
export const family = { name: "mesh-conditions.events", maxAgeDays: 7 } as const;
export const conditionRaisedSubject = "mesh.seat.mesh-conditions.event.condition-raised";
export const conditionChangedSubject = "mesh.seat.mesh-conditions.event.condition-changed";
export const conditionClearedSubject = "mesh.seat.mesh-conditions.event.condition-cleared";
export const states = {
conditions: "conditions",
findings: "findings",
} as const;
/** The key of one value of the state conditions under the form "<key>". */
export function conditionsByKeyKey(key: string): string {
return key;
}
/** The parts of a key of the form "<key>", or undefined for a key of another form. */
export function parseConditionsByKeyKey(key: string): { key: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const key = rest;
rest = "";
if (rest !== "") return undefined;
return { key };
}
/** The key of one value of the state findings under the form "<key>". */
export function findingsByKeyKey(key: string): string {
return key;
}
/** The parts of a key of the form "<key>", or undefined for a key of another form. */
export function parseFindingsByKeyKey(key: string): { key: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const key = rest;
rest = "";
if (rest !== "") return undefined;
return { key };
}
/** one answer the operator may give from a notification */
export interface Action {
"arguments"?: Record<string, string>;
"label": string;
"level"?: "acknowledge" | "approve";
"machine"?: string;
/** the seat verb the operator channel calls */
"verb": string;
}
export interface ConditionEventGapsItem {
"cleared"?: string;
"reopened"?: string;
}
export interface ConditionEventSilenced {
"by"?: string;
"since"?: string;
"until"?: string;
"why"?: string;
}
export interface ConditionEventTriedItem {
"at"?: string;
"by"?: string;
"outcome"?: string;
"what"?: string;
}
/** a condition and what changed */
export interface ConditionEvent {
"actions"?: Action[];
"at": string;
"change": "raised" | "reopened" | "severity" | "resolver" | "silenced" | "silence-ended" | "cleared" | "words";
"cleared"?: string;
"count"?: number;
"epoch"?: number;
"event": string;
/** newest first, at most 10 */
"evidence"?: Evidence[];
"explanation"?: string;
"first"?: string;
"gaps"?: ConditionEventGapsItem[];
"headline"?: string;
/** scope.id.token */
"key": string;
"kind"?: string;
"last-observed"?: string;
"looks-unread"?: string;
"needs"?: string;
"observations"?: number;
"raised"?: string;
"resolved"?: string;
/** self, operator, agent or healer:<name> */
"resolver"?: string;
"severity"?: "urgent" | "warning";
/** the tool call that shows it */
"show"?: string;
"silenced"?: ConditionEventSilenced;
/** the row, probe or event that saw it */
"source"?: string;
"subject"?: Subject;
/** one line */
"summary"?: string;
"tried"?: ConditionEventTriedItem[];
"was"?: string;
"why"?: string;
}
/** one observation, as it was said */
export interface Evidence {
"at": string;
"said": string;
}
/** what the condition is about */
export interface Subject {
/** the other machines it concerns */
"also"?: string[];
/** its id within the scope */
"id": string;
/** the machine it concerns, when there is one */
"machine"?: string;
/** machine, plan, call, build, merge, provider, seat, bus, core, probe, mesh, delivery or module */
"scope": string;
}
/** is what conditions takes. */
export interface ConditionsInput {
/** with history: how many days back (default 7, at most 90) */
"days"?: string;
/** "true": every raising, change, silence and clearing lately, oldest first */
"history"?: "true" | "false";
/** a condition's key: that one whole; with history, only its transitions */
"key"?: string;
/** only those about this machine */
"machine"?: string;
/** only this scope: machine, plan, call, build, merge, provider, seat, bus, core, probe, mesh, delivery or module */
"scope"?: string;
/** only urgent, or only warning */
"severity"?: string;
}
/** is what conditions answers. */
export type ConditionsAnswer = Record<string, unknown>;
/** is what silence takes. */
export interface SilenceInput {
/** the cause in a word (the condition's kind when absent) */
"cause"?: string;
/** how long: 30m, 4h, 2d; at most 7d */
"for": string;
/** the condition's key */
"key": string;
/** why, required and recorded */
"why": string;
}
/** is what silence answers. */
export type SilenceAnswer = Record<string, unknown>;
/** is what resync takes. */
export interface ResyncInput {
}
/** is what resync answers. */
export type ResyncAnswer = Record<string, unknown>;
/** is the body of the event condition-raised. */
export type ConditionRaisedEvent = ConditionEvent;
/** is the body of the event condition-changed. */
export type ConditionChangedEvent = ConditionEvent;
/** is the body of the event condition-cleared. */
export type ConditionClearedEvent = ConditionEvent;
export interface ConditionsByKeyValueGapsItem {
"cleared"?: string;
"reopened"?: string;
}
export interface ConditionsByKeyValueSilenced {
"by"?: string;
"since"?: string;
"until"?: string;
"why"?: string;
}
export interface ConditionsByKeyValueTriedItem {
"at"?: string;
"by"?: string;
"outcome"?: string;
"what"?: string;
}
/** is one value of the state conditions under the key <key>. */
export interface ConditionsByKeyValue {
"actions"?: Action[];
"count"?: number;
"epoch"?: number;
/** newest first, at most 10 */
"evidence"?: Evidence[];
"explanation"?: string;
"first"?: string;
"gaps"?: ConditionsByKeyValueGapsItem[];
"headline"?: string;
/** scope.id.token */
"key": string;
"kind": string;
"last-observed": string;
"looks-unread"?: string;
"needs"?: string;
"observations"?: number;
"raised": string;
"resolved"?: string;
/** self, operator, agent or healer:<name> */
"resolver"?: string;
"severity": "urgent" | "warning";
"silenced"?: ConditionsByKeyValueSilenced;
/** the row, probe or event that saw it */
"source"?: string;
"subject": Subject;
/** one line */
"summary"?: string;
"tried"?: ConditionsByKeyValueTriedItem[];
}
/** is one value of the state findings under the key <key>. */
export interface FindingsByKeyValue {
"actions"?: Action[];
"at": string;
/** newest first, at most 10 */
"evidence"?: Evidence[];
"explanation"?: string;
"headline"?: string;
/** scope.id.token */
"key": string;
"kind": string;
"needs"?: string;
/** the module that wrote it */
"observer": string;
/** the key's last part when it is not the kind */
"ref"?: string;
"resolved"?: string;
/** self, operator, agent or healer:<name> */
"resolver"?: string;
/** what of its own saw it last */
"run"?: string;
"severity": "urgent" | "warning";
/** the row, probe or event that saw it */
"source": string;
"subject": Subject;
/** one line */
"summary": string;
/** layout version, 1 */
"v": number;
}
@@ -0,0 +1,19 @@
{
"description": "The contract of the seat mesh-hand-acts, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"name": "@novox/mesh-health-and-repair-contracts-mesh-hand-acts",
"scripts": {
"build": "tsc",
"prepare": "tsc"
},
"type": "module",
"version": "0.1.0"
}
@@ -0,0 +1,160 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-hand-acts", defined whole (seats/mesh-hand-acts/seat.json): Acts done by hand, recorded with who, why and cause (ADR 0565): the log every module records through.
export const seat = "mesh-hand-acts";
export const verbs = {
handAct: "hand-act",
handActs: "hand-acts",
warranted: "warranted",
} as const;
export const events = {
actRecorded: "act-recorded",
} as const;
export const family = { name: "mesh-hand-acts.events", maxAgeDays: 7 } as const;
export const actRecordedSubject = "mesh.seat.mesh-hand-acts.event.act-recorded";
export const states = {
acts: "acts",
warrants: "warrants",
} as const;
/** The key of one value of the state acts under the form "<id>". */
export function actsByIDKey(id: string): string {
return id;
}
/** The parts of a key of the form "<id>", or undefined for a key of another form. */
export function parseActsByIDKey(key: string): { id: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const id = rest;
rest = "";
if (rest !== "") return undefined;
return { id };
}
/** The key of one value of the state warrants under the form "<asker>.<ask>". */
export function warrantsByAskerAskKey(asker: string, ask: string): string {
return asker + "." + ask;
}
/** The parts of a key of the form "<asker>.<ask>", or undefined for a key of another form. */
export function parseWarrantsByAskerAskKey(key: string): { asker: string; ask: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const asker = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const ask = rest;
rest = "";
if (rest !== "") return undefined;
return { asker, ask };
}
/** one act done by hand */
export interface Act {
"arguments"?: string[];
"ask"?: string;
"at": string;
/** the caller the runtime proved */
"by": string;
"carried"?: string[];
"cause": string;
"condition"?: string;
"id": string;
/** what the act was read to be from what it did */
"kind"?: string;
/** which log holds it, set when it is read */
"log"?: string;
"outcome"?: string;
"proofs"?: string[];
"requested-by"?: string;
"verb": string;
"via"?: string;
"why": string;
}
/** is what hand-act takes. */
export interface HandActInput {
/** the cause in a word, or a condition's kind */
"cause"?: string;
/** the key of the condition it addressed, if any (optional) */
"condition"?: string;
/** the act's verb in the log: a repair when absent, `hand-act drill` for a drill, or a recorder's own */
"verb"?: string;
/** what was done, in a line */
"what": string;
/** why it had to be done by hand */
"why": string;
}
/** is what hand-act answers. */
export type HandActAnswer = Record<string, unknown>;
/** is what hand-acts takes. */
export interface HandActsInput {
/** only this cause */
"cause"?: string;
/** how many days back (default 14) */
"days"?: string;
/** "true": every warrant recorded */
"warrants"?: "true" | "false";
/** only acts whose who contains this */
"who"?: string;
}
/** is what hand-acts answers. */
export type HandActsAnswer = Record<string, unknown>;
/** is what warranted takes. */
export interface WarrantedInput {
/** its ask's id */
"ask": string;
/** the module that asked */
"asker": string;
}
/** is what warranted answers. */
export type WarrantedAnswer = Record<string, unknown>;
/** is the body of the event act-recorded. */
export type ActRecordedEvent = Act;
/** is one value of the state acts under the key <id>. */
export interface ActsByIDValue {
"arguments"?: string[];
"ask"?: string;
"at": string;
/** the caller the runtime proved */
"by": string;
"carried"?: string[];
"cause": string;
"condition"?: string;
"id": string;
/** what the act was read to be from what it did */
"kind"?: string;
/** which log holds it, set when it is read */
"log"?: string;
"outcome"?: string;
"proofs"?: string[];
"requested-by"?: string;
"verb": string;
"via"?: string;
"why": string;
}
/** is one value of the state warrants under the key <asker>.<ask>. */
export interface WarrantsByAskerAskValue {
"ask": string;
"asker": string;
"at"?: string;
"by"?: string;
"option"?: string;
}
@@ -1,5 +1,5 @@
{
"description": "The mesh's seat set, generated from every seat's definition.",
"description": "The contract of the seat mesh-healers, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
@@ -9,7 +9,7 @@
"files": [
"dist"
],
"name": "@novox/mesh-contracts",
"name": "@novox/mesh-health-and-repair-contracts-mesh-healers",
"scripts": {
"build": "tsc",
"prepare": "tsc"
@@ -0,0 +1,127 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-healers", defined whole (seats/mesh-healers/seat.json): The healers (ADR 0564): each a registered response to one kind of condition, within a budget and the mesh-wide brake.
export const seat = "mesh-healers";
export const verbs = {
healers: "healers",
heal: "heal",
drill: "drill",
} as const;
export const events = {
healerActed: "healer-acted",
} as const;
export const family = { name: "mesh-healers.events", maxAgeDays: 7 } as const;
export const healerActedSubject = "mesh.seat.mesh-healers.event.healer-acted";
export const states = {
attempts: "attempts",
would: "would",
} as const;
/** The key of one value of the state attempts under the form "<attempt>". */
export function attemptsByAttemptKey(attempt: string): string {
return attempt;
}
/** The parts of a key of the form "<attempt>", or undefined for a key of another form. */
export function parseAttemptsByAttemptKey(key: string): { attempt: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const attempt = rest;
rest = "";
if (rest !== "") return undefined;
return { attempt };
}
/** The key of one value of the state would under the form "<would>". */
export function wouldByWouldKey(would: string): string {
return would;
}
/** The parts of a key of the form "<would>", or undefined for a key of another form. */
export function parseWouldByWouldKey(key: string): { would: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const would = rest;
rest = "";
if (rest !== "") return undefined;
return { would };
}
/** is what healers takes. */
export interface HealersInput {
/** how many days of acts back (default 7) */
"days"?: string;
}
/** is what healers answers. */
export type HealersAnswer = Record<string, unknown>;
/** is what heal takes. */
export interface HealInput {
/** the condition's key */
"key": string;
/** why now, kept with the act */
"why": string;
}
/** is what heal answers. */
export type HealAnswer = Record<string, unknown>;
/** is what drill takes. */
export interface DrillInput {
/** the key of the condition the drill is meant to raise, if any (optional) */
"condition"?: string;
/** what was done on purpose, in a line */
"what": string;
/** what the drill tests */
"why": string;
}
/** is what drill answers. */
export type DrillAnswer = Record<string, unknown>;
/** is the body of the event healer-acted. */
export interface HealerActedEvent {
"act"?: string;
"at": string;
"budget"?: string;
"by"?: string;
"condition": string;
"event": string;
"healer": string;
"kind"?: string;
"outcome": "acting" | "acted" | "failed" | "escalated";
"said"?: string;
"show"?: string;
}
/** is one value of the state attempts under the key <attempt>. */
export interface AttemptsByAttemptValue {
"act": string;
"begun": string;
/** what the budget counts by: the condition's key unless the healer says another */
"budget-key": string;
"condition": string;
"finished"?: string;
"healer": string;
"kind": string;
"outcome": "acting" | "acted" | "failed" | "escalated";
"said"?: string;
}
/** is one value of the state would under the key <would>. */
export interface WouldByWouldValue {
"act": string;
"at": string;
"condition": string;
"healer": string;
"kind"?: string;
"why"?: string;
}
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
@@ -0,0 +1,19 @@
{
"description": "The contract of the seat mesh-self-check, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"name": "@novox/mesh-health-and-repair-contracts-mesh-self-check",
"scripts": {
"build": "tsc",
"prepare": "tsc"
},
"type": "module",
"version": "0.1.0"
}
@@ -0,0 +1,70 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-self-check", defined whole (seats/mesh-self-check/seat.json): The mesh checking itself (ADR 0564): probes run every five minutes, each failure a finding the seat's conditions raise.
export const seat = "mesh-self-check";
export const verbs = {
doctor: "doctor",
probes: "probes",
} as const;
export const events = {
checked: "checked",
} as const;
export const family = { name: "mesh-self-check.events", maxAgeDays: 7 } as const;
export const checkedSubject = "mesh.seat.mesh-self-check.event.checked";
/** one probe's verdict */
export interface ProbeVerdict {
"error"?: string;
"found"?: string[];
"found-count"?: number;
"id": string;
"more"?: string;
"took"?: string;
"unconfirmed"?: string[];
"verdict": "passed" | "failed" | "failed-to-run" | "deferred";
}
/** is what doctor takes. */
export interface DoctorInput {
/** one probe's id (D6): its verdict alone, with every finding */
"probe"?: string;
/** "true": run every probe now and answer the verdict */
"run"?: "true" | "false";
}
/** is what doctor answers. */
export type DoctorAnswer = Record<string, unknown>;
/** is what probes takes. */
export interface ProbesInput {
}
/** is what probes answers. */
export type ProbesAnswer = Record<string, unknown>;
export interface CheckedEventCounts {
"deferred"?: number;
"failed"?: number;
"failed-to-run"?: number;
"passed"?: number;
}
/** is the body of the event checked. */
export interface CheckedEvent {
"at": string;
"controller"?: string;
"counts"?: CheckedEventCounts;
"interval-seconds"?: number;
"probes": ProbeVerdict[];
"run": string;
"started"?: string;
"took"?: string;
"unsaid"?: number;
"why"?: string;
}
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
@@ -0,0 +1,19 @@
{
"description": "The contract of the seat mesh-watchdogs, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"name": "@novox/mesh-health-and-repair-contracts-mesh-watchdogs",
"scripts": {
"build": "tsc",
"prepare": "tsc"
},
"type": "module",
"version": "0.1.0"
}
@@ -0,0 +1,182 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-watchdogs", defined whole (seats/mesh-watchdogs/seat.json): The watchman's seat (ADR 0564, ADR 0433): signals that expire unless renewed, what stopped moving, who is present, the dead letters.
export const seat = "mesh-watchdogs";
export const verbs = {
signals: "signals",
stuck: "stuck",
presence: "presence",
deadLetters: "dead-letters",
resync: "resync",
} as const;
export const states = {
presence: "presence",
pulse: "pulse",
stuck: "stuck",
} as const;
/** The key of one value of the state presence under the form "<node>". */
export function presenceByNodeKey(node: string): string {
return node;
}
/** The parts of a key of the form "<node>", or undefined for a key of another form. */
export function parsePresenceByNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state presence under the form "part.<part>.<instance>". */
export function presenceByPartPartInstanceKey(part: string, instance: string): string {
return "part." + part + "." + instance;
}
/** The parts of a key of the form "part.<part>.<instance>", or undefined for a key of another form. */
export function parsePresenceByPartPartInstanceKey(key: string): { part: string; instance: string } | undefined {
let rest = key;
if (!rest.startsWith("part.")) return undefined;
rest = rest.slice(5);
const at1 = rest.indexOf(".");
if (at1 <= 0) return undefined;
const part = rest.slice(0, at1);
rest = rest.slice(at1 + 1);
if (rest === "") return undefined;
const instance = rest;
rest = "";
if (rest !== "") return undefined;
return { part, instance };
}
/** The key of one value of the state pulse under the form "<bucket>.<key>". */
export function pulseByBucketKeyKey(bucket: string, key: string): string {
return bucket + "." + key;
}
/** The parts of a key of the form "<bucket>.<key>", or undefined for a key of another form. */
export function parsePulseByBucketKeyKey(key: string): { bucket: string; key: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const bucket = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const key = rest;
rest = "";
if (rest !== "") return undefined;
return { bucket, key };
}
/** The key of one value of the state stuck under the form "<bucket>.<key>". */
export function stuckByBucketKeyKey(bucket: string, key: string): string {
return bucket + "." + key;
}
/** The parts of a key of the form "<bucket>.<key>", or undefined for a key of another form. */
export function parseStuckByBucketKeyKey(key: string): { bucket: string; key: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const bucket = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const key = rest;
rest = "";
if (rest !== "") return undefined;
return { bucket, key };
}
/** is what signals takes. */
export interface SignalsInput {
/** one row, e.g. S1 */
"row"?: string;
}
/** is what signals answers. */
export type SignalsAnswer = Record<string, unknown>;
/** is what stuck takes. */
export interface StuckInput {
/** only those on this machine */
"machine"?: string;
}
/** is what stuck answers. */
export type StuckAnswer = Record<string, unknown>;
/** is what presence takes. */
export interface PresenceInput {
/** one machine */
"machine"?: string;
}
/** is what presence answers. */
export type PresenceAnswer = Record<string, unknown>;
/** is what dead-letters takes. */
export interface DeadLettersInput {
/** with deliver or drop: the cause in a word (dead-letter when absent) */
"cause"?: string;
/** a consumer's name, or <stream>.<consumer>: only what that one gave up on */
"consumer"?: string;
/** a dead letter's id: deliver it again to the consumer that gave it up (needs why) */
"deliver"?: string;
/** a dead letter's id: drop it for good (needs why) */
"drop"?: string;
/** a dead letter's id, as the list gives it: that one whole, with its message */
"id"?: string;
/** how many to list, newest first (default 50); only when listing */
"limit"?: string;
/** with deliver or drop: why, required and recorded */
"why"?: string;
}
/** is what dead-letters answers. */
export type DeadLettersAnswer = Record<string, unknown>;
/** is what resync takes. */
export interface ResyncInput {
}
/** is what resync answers. */
export type ResyncAnswer = Record<string, unknown>;
/** is one value of the state presence under the key <node>. */
export interface PresenceByNodeValue {
"online": boolean;
"v"?: number;
}
/** is one value of the state presence under the key part.<part>.<instance>. */
export interface PresenceByPartPartInstanceValue {
"online": boolean;
"v"?: number;
}
/** is one value of the state pulse under the key <bucket>.<key>. */
export interface PulseByBucketKeyValue {
"bucket": string;
"key": string;
"owes"?: string;
"revision": number;
"v"?: number;
}
/** is one value of the state stuck under the key <bucket>.<key>. */
export interface StuckByBucketKeyValue {
"bucket": string;
"key": string;
/** it has moved again */
"moved"?: boolean;
"since": string;
"v"?: number;
/** what it waited for, in words */
"waited"?: string;
}
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
@@ -18,7 +18,7 @@ import (
"strings"
"time"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
)
// The levels an option is answered at: how much proof its answer needs (novox/hq ADR 0234 §8, the glossary's
@@ -9,7 +9,7 @@ import (
"testing"
"time"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
)
var now = time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC)
@@ -17,7 +17,7 @@ import (
"strings"
"time"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
stdio "git.novox.be/novox/mesh-sdk/go"
)
@@ -6,7 +6,7 @@ import (
"testing"
"time"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/process"
)
@@ -7,7 +7,7 @@ import (
"reflect"
"strings"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
)
// ConditionSubject is where a module says a condition to the operator: the seat's by-caller condition accept
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
seat "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
seat "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
)
func TestConditionSubject(t *testing.T) { // 1202/AC1
@@ -1,14 +1,13 @@
module git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient
module git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/seats/operatorchannel v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef
)
require (
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a // indirect
github.com/klauspost/compress v1.20.1 // indirect
github.com/nats-io/nats.go v1.54.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
@@ -3,6 +3,13 @@
// Package operatorchannel is the contract of the seat "operator-channel", defined whole (seats/operator-channel/seat.json): Asking a person and answering on a channel (ADR 0259): held by the router, the messenger module, whose manifest declares the seat; written from that seat entry (design 26).
package operatorchannel
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "operator-channel"
@@ -75,9 +82,45 @@ func HolderSubjectOffered(holder string) string { return "mesh.stream." + holder
func HolderSubjectClosed(holder string) string { return "mesh.stream." + holder + ".event.closed" }
const (
RecordAsks = "asks"
StateAsks = "asks"
)
// AsksByAskerIDKey is the key of one value of the state asks under the form "<asker>.<id>".
func AsksByAskerIDKey(asker, id string) string { return asker + "." + id }
// ParseAsksByAskerIDKey reads the parts of a key of the form "<asker>.<id>", in the order of the form; the last result is false for a key of another form.
func ParseAsksByAskerIDKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeAsksByAskerIDValue reads one value of the state asks under the form "<asker>.<id>", refusing a field AsksByAskerIDValue does not know and any text after the value.
func DecodeAsksByAskerIDValue(raw []byte) (AsksByAskerIDValue, error) {
var v AsksByAskerIDValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// Ask is a type of the contract.
type Ask struct {
// what it is about: a newer ask about it replaces the older
@@ -328,5 +371,5 @@ const (
ClosedHolderEventHowUnlinked = "unlinked"
)
// AsksRecord is one value of the record asks.
type AsksRecord = map[string]any
// AsksByAskerIDValue is one value of the state asks under the key <asker>.<id>.
type AsksByAskerIDValue = map[string]any
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel
go 1.26.0
@@ -0,0 +1,6 @@
{
"format": 1,
"seats": [
"operator-channel"
]
}
@@ -9,7 +9,7 @@
"files": [
"dist"
],
"name": "@novox/mesh-contracts-operator-channel",
"name": "@novox/mesh-operator-and-conversation-contracts-operator-channel",
"scripts": {
"build": "tsc",
"prepare": "tsc"
@@ -58,6 +58,29 @@ export function closedHolderSubject(holder: string): string {
return "mesh.stream." + holder + ".event.closed";
}
export const states = {
asks: "asks",
} as const;
/** The key of one value of the state asks under the form "<asker>.<id>". */
export function asksByAskerIDKey(asker: string, id: string): string {
return asker + "." + id;
}
/** The parts of a key of the form "<asker>.<id>", or undefined for a key of another form. */
export function parseAsksByAskerIDKey(key: string): { asker: string; id: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const asker = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const id = rest;
rest = "";
if (rest !== "") return undefined;
return { asker, id };
}
export interface Ask {
/** what it is about: a newer ask about it replaces the older */
"about"?: string;
@@ -277,6 +300,6 @@ export interface ClosedHolderEvent {
"id": string;
}
/** is one value of the record asks. */
export type AsksRecord = Record<string, unknown>;
/** is one value of the state asks under the key <asker>.<id>. */
export type AsksByAskerIDValue = Record<string, unknown>;
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
@@ -0,0 +1,285 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshprovisioner is the contract of the seat "mesh-provisioner", defined whole (seats/mesh-provisioner/seat.json): The provisioner (ADR 0349): which domain answers which kind of placeholder, what each module needs, what is applied where.
package meshprovisioner
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "mesh-provisioner"
const (
VerbProvisioning = "provisioning"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbProvisioning}
}
const (
StatePlans = "plans"
StateProvisions = "provisions"
)
// PlansByNodeModuleKey is the key of one value of the state plans under the form "<node>.<module>".
func PlansByNodeModuleKey(node, module string) string { return node + "." + module }
// ParsePlansByNodeModuleKey reads the parts of a key of the form "<node>.<module>", in the order of the form; the last result is false for a key of another form.
func ParsePlansByNodeModuleKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodePlansByNodeModuleValue reads one value of the state plans under the form "<node>.<module>", refusing a field PlansByNodeModuleValue does not know and any text after the value.
func DecodePlansByNodeModuleValue(raw []byte) (PlansByNodeModuleValue, error) {
var v PlansByNodeModuleValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ProvisionsByNodeConsumerProvisionKey is the key of one value of the state provisions under the form "<node>.<consumer>.<provision>".
func ProvisionsByNodeConsumerProvisionKey(node, consumer, provision string) string {
return node + "." + consumer + "." + provision
}
// ParseProvisionsByNodeConsumerProvisionKey reads the parts of a key of the form "<node>.<consumer>.<provision>", in the order of the form; the last result is false for a key of another form.
func ParseProvisionsByNodeConsumerProvisionKey(key string) (string, string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", "", false
}
rest = after0
v2, after2, found2 := strings.Cut(rest, ".")
if !found2 || v2 == "" {
return "", "", "", false
}
rest = after2
if rest == "" {
return "", "", "", false
}
v4 := rest
rest = ""
if rest != "" {
return "", "", "", false
}
return v0, v2, v4, true
}
// DecodeProvisionsByNodeConsumerProvisionValue reads one value of the state provisions under the form "<node>.<consumer>.<provision>", refusing a field ProvisionsByNodeConsumerProvisionValue does not know and any text after the value.
func DecodeProvisionsByNodeConsumerProvisionValue(raw []byte) (ProvisionsByNodeConsumerProvisionValue, error) {
var v ProvisionsByNodeConsumerProvisionValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ProvisionsByNodeConsumerProvisionLocalKey is the key of one value of the state provisions under the form "<node>.<consumer>.<provision>.<local>".
func ProvisionsByNodeConsumerProvisionLocalKey(node, consumer, provision, local string) string {
return node + "." + consumer + "." + provision + "." + local
}
// ParseProvisionsByNodeConsumerProvisionLocalKey reads the parts of a key of the form "<node>.<consumer>.<provision>.<local>", in the order of the form; the last result is false for a key of another form.
func ParseProvisionsByNodeConsumerProvisionLocalKey(key string) (string, string, string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", "", "", false
}
rest = after0
v2, after2, found2 := strings.Cut(rest, ".")
if !found2 || v2 == "" {
return "", "", "", "", false
}
rest = after2
v4, after4, found4 := strings.Cut(rest, ".")
if !found4 || v4 == "" {
return "", "", "", "", false
}
rest = after4
if rest == "" {
return "", "", "", "", false
}
v6 := rest
rest = ""
if rest != "" {
return "", "", "", "", false
}
return v0, v2, v4, v6, true
}
// DecodeProvisionsByNodeConsumerProvisionLocalValue reads one value of the state provisions under the form "<node>.<consumer>.<provision>.<local>", refusing a field ProvisionsByNodeConsumerProvisionLocalValue does not know and any text after the value.
func DecodeProvisionsByNodeConsumerProvisionLocalValue(raw []byte) (ProvisionsByNodeConsumerProvisionLocalValue, error) {
var v ProvisionsByNodeConsumerProvisionLocalValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ProvisioningInput is what provisioning takes.
type ProvisioningInput struct {
// for collect: a collection
Collection string `json:"collection,omitempty"`
// a module: for collect, a contributor
Module string `json:"module,omitempty"`
// a node
Node string `json:"node,omitempty"`
// registry (when not given), needs, applied or collect
What string `json:"what,omitempty"`
}
// ProvisioningAnswer is what provisioning answers.
type ProvisioningAnswer = map[string]any
// PlansByNodeModuleValue is one value of the state plans under the key <node>.<module>.
type PlansByNodeModuleValue struct {
Module string `json:"module"`
Node string `json:"node"`
// the module's plan
Plan map[string]any `json:"plan"`
V int64 `json:"v,omitempty"`
}
// ProvisionsByNodeConsumerProvisionValueConsumer is a type of the contract.
type ProvisionsByNodeConsumerProvisionValueConsumer struct {
Module string `json:"module,omitempty"`
Node string `json:"node,omitempty"`
}
// ProvisionsByNodeConsumerProvisionValueProvider is a type of the contract.
type ProvisionsByNodeConsumerProvisionValueProvider struct {
Module string `json:"module,omitempty"`
Node string `json:"node,omitempty"`
}
// ProvisionsByNodeConsumerProvisionValueReference is a type of the contract.
type ProvisionsByNodeConsumerProvisionValueReference struct {
Generation int64 `json:"generation,omitempty"`
ID string `json:"id,omitempty"`
}
// ProvisionsByNodeConsumerProvisionValueWarrant is a type of the contract.
type ProvisionsByNodeConsumerProvisionValueWarrant struct {
Ask string `json:"ask,omitempty"`
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Option string `json:"option,omitempty"`
}
// ProvisionsByNodeConsumerProvisionValue is one value of the state provisions under the key <node>.<consumer>.<provision>.
type ProvisionsByNodeConsumerProvisionValue struct {
Ask string `json:"ask,omitempty"`
At string `json:"at"`
Consumer ProvisionsByNodeConsumerProvisionValueConsumer `json:"consumer"`
DependsOn []string `json:"depends-on,omitempty"`
Local string `json:"local,omitempty"`
// the plan's provision
Plan map[string]any `json:"plan,omitempty"`
Provider ProvisionsByNodeConsumerProvisionValueProvider `json:"provider"`
Provision string `json:"provision"`
Reference *ProvisionsByNodeConsumerProvisionValueReference `json:"reference,omitempty"`
State string `json:"state"`
V int64 `json:"v,omitempty"`
Warrant *ProvisionsByNodeConsumerProvisionValueWarrant `json:"warrant,omitempty"`
Why string `json:"why,omitempty"`
}
// The values of ProvisionsByNodeConsumerProvisionValue's state.
const (
ProvisionsByNodeConsumerProvisionValueStateAsked = "asked"
ProvisionsByNodeConsumerProvisionValueStateProvided = "provided"
ProvisionsByNodeConsumerProvisionValueStateWaits = "waits"
ProvisionsByNodeConsumerProvisionValueStateFailed = "failed"
ProvisionsByNodeConsumerProvisionValueStateRetiring = "retiring"
)
// ProvisionsByNodeConsumerProvisionLocalValueConsumer is a type of the contract.
type ProvisionsByNodeConsumerProvisionLocalValueConsumer struct {
Module string `json:"module,omitempty"`
Node string `json:"node,omitempty"`
}
// ProvisionsByNodeConsumerProvisionLocalValueProvider is a type of the contract.
type ProvisionsByNodeConsumerProvisionLocalValueProvider struct {
Module string `json:"module,omitempty"`
Node string `json:"node,omitempty"`
}
// ProvisionsByNodeConsumerProvisionLocalValueReference is a type of the contract.
type ProvisionsByNodeConsumerProvisionLocalValueReference struct {
Generation int64 `json:"generation,omitempty"`
ID string `json:"id,omitempty"`
}
// ProvisionsByNodeConsumerProvisionLocalValueWarrant is a type of the contract.
type ProvisionsByNodeConsumerProvisionLocalValueWarrant struct {
Ask string `json:"ask,omitempty"`
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Option string `json:"option,omitempty"`
}
// ProvisionsByNodeConsumerProvisionLocalValue is one value of the state provisions under the key <node>.<consumer>.<provision>.<local>.
type ProvisionsByNodeConsumerProvisionLocalValue struct {
Ask string `json:"ask,omitempty"`
At string `json:"at"`
Consumer ProvisionsByNodeConsumerProvisionLocalValueConsumer `json:"consumer"`
DependsOn []string `json:"depends-on,omitempty"`
Local string `json:"local,omitempty"`
// the plan's provision
Plan map[string]any `json:"plan,omitempty"`
Provider ProvisionsByNodeConsumerProvisionLocalValueProvider `json:"provider"`
Provision string `json:"provision"`
Reference *ProvisionsByNodeConsumerProvisionLocalValueReference `json:"reference,omitempty"`
State string `json:"state"`
V int64 `json:"v,omitempty"`
Warrant *ProvisionsByNodeConsumerProvisionLocalValueWarrant `json:"warrant,omitempty"`
Why string `json:"why,omitempty"`
}
// The values of ProvisionsByNodeConsumerProvisionLocalValue's state.
const (
ProvisionsByNodeConsumerProvisionLocalValueStateAsked = "asked"
ProvisionsByNodeConsumerProvisionLocalValueStateProvided = "provided"
ProvisionsByNodeConsumerProvisionLocalValueStateWaits = "waits"
ProvisionsByNodeConsumerProvisionLocalValueStateFailed = "failed"
ProvisionsByNodeConsumerProvisionLocalValueStateRetiring = "retiring"
)
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-contracts/provisioning/go/seats/meshprovisioner
go 1.26.0
+9
View File
@@ -0,0 +1,9 @@
{
"format": 1,
"seats": [
"mesh-provisioner",
"node-mounts",
"node-nfs-server",
"node-provisioner"
]
}
@@ -0,0 +1,19 @@
{
"description": "The contract of the seat mesh-provisioner, generated from its definition.",
"devDependencies": {
"typescript": "^5.6.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"name": "@novox/mesh-provisioning-contracts-mesh-provisioner",
"scripts": {
"build": "tsc",
"prepare": "tsc"
},
"type": "module",
"version": "0.1.0"
}
@@ -0,0 +1,188 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-provisioner", defined whole (seats/mesh-provisioner/seat.json): The provisioner (ADR 0349): which domain answers which kind of placeholder, what each module needs, what is applied where.
export const seat = "mesh-provisioner";
export const verbs = {
provisioning: "provisioning",
} as const;
export const states = {
plans: "plans",
provisions: "provisions",
} as const;
/** The key of one value of the state plans under the form "<node>.<module>". */
export function plansByNodeModuleKey(node: string, module: string): string {
return node + "." + module;
}
/** The parts of a key of the form "<node>.<module>", or undefined for a key of another form. */
export function parsePlansByNodeModuleKey(key: string): { node: string; module: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const module = rest;
rest = "";
if (rest !== "") return undefined;
return { node, module };
}
/** The key of one value of the state provisions under the form "<node>.<consumer>.<provision>". */
export function provisionsByNodeConsumerProvisionKey(node: string, consumer: string, provision: string): string {
return node + "." + consumer + "." + provision;
}
/** The parts of a key of the form "<node>.<consumer>.<provision>", or undefined for a key of another form. */
export function parseProvisionsByNodeConsumerProvisionKey(key: string): { node: string; consumer: string; provision: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
const at2 = rest.indexOf(".");
if (at2 <= 0) return undefined;
const consumer = rest.slice(0, at2);
rest = rest.slice(at2 + 1);
if (rest === "") return undefined;
const provision = rest;
rest = "";
if (rest !== "") return undefined;
return { node, consumer, provision };
}
/** The key of one value of the state provisions under the form "<node>.<consumer>.<provision>.<local>". */
export function provisionsByNodeConsumerProvisionLocalKey(node: string, consumer: string, provision: string, local: string): string {
return node + "." + consumer + "." + provision + "." + local;
}
/** The parts of a key of the form "<node>.<consumer>.<provision>.<local>", or undefined for a key of another form. */
export function parseProvisionsByNodeConsumerProvisionLocalKey(key: string): { node: string; consumer: string; provision: string; local: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
const at2 = rest.indexOf(".");
if (at2 <= 0) return undefined;
const consumer = rest.slice(0, at2);
rest = rest.slice(at2 + 1);
const at4 = rest.indexOf(".");
if (at4 <= 0) return undefined;
const provision = rest.slice(0, at4);
rest = rest.slice(at4 + 1);
if (rest === "") return undefined;
const local = rest;
rest = "";
if (rest !== "") return undefined;
return { node, consumer, provision, local };
}
/** is what provisioning takes. */
export interface ProvisioningInput {
/** for collect: a collection */
"collection"?: string;
/** a module: for collect, a contributor */
"module"?: string;
/** a node */
"node"?: string;
/** registry (when not given), needs, applied or collect */
"what"?: string;
}
/** is what provisioning answers. */
export type ProvisioningAnswer = Record<string, unknown>;
/** is one value of the state plans under the key <node>.<module>. */
export interface PlansByNodeModuleValue {
"module": string;
"node": string;
/** the module's plan */
"plan": Record<string, unknown>;
"v"?: number;
}
export interface ProvisionsByNodeConsumerProvisionValueConsumer {
"module"?: string;
"node"?: string;
}
export interface ProvisionsByNodeConsumerProvisionValueProvider {
"module"?: string;
"node"?: string;
}
export interface ProvisionsByNodeConsumerProvisionValueReference {
"generation"?: number;
"id"?: string;
}
export interface ProvisionsByNodeConsumerProvisionValueWarrant {
"ask"?: string;
"at"?: string;
"by"?: string;
"option"?: string;
}
/** is one value of the state provisions under the key <node>.<consumer>.<provision>. */
export interface ProvisionsByNodeConsumerProvisionValue {
"ask"?: string;
"at": string;
"consumer": ProvisionsByNodeConsumerProvisionValueConsumer;
"depends-on"?: string[];
"local"?: string;
/** the plan's provision */
"plan"?: Record<string, unknown>;
"provider": ProvisionsByNodeConsumerProvisionValueProvider;
"provision": string;
"reference"?: ProvisionsByNodeConsumerProvisionValueReference;
"state": "asked" | "provided" | "waits" | "failed" | "retiring";
"v"?: number;
"warrant"?: ProvisionsByNodeConsumerProvisionValueWarrant;
"why"?: string;
}
export interface ProvisionsByNodeConsumerProvisionLocalValueConsumer {
"module"?: string;
"node"?: string;
}
export interface ProvisionsByNodeConsumerProvisionLocalValueProvider {
"module"?: string;
"node"?: string;
}
export interface ProvisionsByNodeConsumerProvisionLocalValueReference {
"generation"?: number;
"id"?: string;
}
export interface ProvisionsByNodeConsumerProvisionLocalValueWarrant {
"ask"?: string;
"at"?: string;
"by"?: string;
"option"?: string;
}
/** is one value of the state provisions under the key <node>.<consumer>.<provision>.<local>. */
export interface ProvisionsByNodeConsumerProvisionLocalValue {
"ask"?: string;
"at": string;
"consumer": ProvisionsByNodeConsumerProvisionLocalValueConsumer;
"depends-on"?: string[];
"local"?: string;
/** the plan's provision */
"plan"?: Record<string, unknown>;
"provider": ProvisionsByNodeConsumerProvisionLocalValueProvider;
"provision": string;
"reference"?: ProvisionsByNodeConsumerProvisionLocalValueReference;
"state": "asked" | "provided" | "waits" | "failed" | "retiring";
"v"?: number;
"warrant"?: ProvisionsByNodeConsumerProvisionLocalValueWarrant;
"why"?: string;
}
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
+41
View File
@@ -32,6 +32,33 @@ export function retiredHolderSubject(holder: string): string {
return "mesh.stream." + holder + ".event.retired";
}
export const states = {
resolved: "resolved",
} as const;
/** The key of one value of the state resolved under the form "<node>.<module>.<key>". */
export function resolvedByNodeModuleKeyKey(node: string, module: string, key: string): string {
return node + "." + module + "." + key;
}
/** The parts of a key of the form "<node>.<module>.<key>", or undefined for a key of another form. */
export function parseResolvedByNodeModuleKeyKey(key: string): { node: string; module: string; key: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
const at2 = rest.indexOf(".");
if (at2 <= 0) return undefined;
const module = rest.slice(0, at2);
rest = rest.slice(at2 + 1);
if (rest === "") return undefined;
const key = rest;
rest = "";
if (rest !== "") return undefined;
return { node, module, key };
}
/** is what config takes. */
export interface ConfigInput {
/** list (when not given), set, clear or history */
@@ -117,3 +144,17 @@ export interface RetiredHolderEvent {
"node"?: string;
}
/** is one value of the state resolved under the key <node>.<module>.<key>. */
export interface ResolvedByNodeModuleKeyValue {
"key": string;
"module": string;
"node": string;
/** the predefined key the value falls back to */
"predefined"?: string;
/** an unset value is the operator's own to set */
"required"?: boolean;
"source": string;
"trusted"?: boolean;
"value"?: unknown;
}
+215
View File
@@ -43,6 +43,121 @@ export function manifestReadsChangedSubject(caller: string): string {
return "mesh.seat.node-engine.event.manifest-reads-changed." + caller;
}
export const states = {
have: "have",
composed: "composed",
data: "data",
packages: "packages",
health: "health",
} as const;
/** The key of one value of the state have under the form "<node>.<module>". */
export function haveByNodeModuleKey(node: string, module: string): string {
return node + "." + module;
}
/** The parts of a key of the form "<node>.<module>", or undefined for a key of another form. */
export function parseHaveByNodeModuleKey(key: string): { node: string; module: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const module = rest;
rest = "";
if (rest !== "") return undefined;
return { node, module };
}
/** The key of one value of the state have under the form "<node>.node". */
export function haveByNodeNodeKey(node: string): string {
return node + ".node";
}
/** The parts of a key of the form "<node>.node", or undefined for a key of another form. */
export function parseHaveByNodeNodeKey(key: string): { node: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".node");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 5);
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state composed under the form "<node>.<module>.<fingerprint>". */
export function composedByNodeModuleFingerprintKey(node: string, module: string, fingerprint: string): string {
return node + "." + module + "." + fingerprint;
}
/** The parts of a key of the form "<node>.<module>.<fingerprint>", or undefined for a key of another form. */
export function parseComposedByNodeModuleFingerprintKey(key: string): { node: string; module: string; fingerprint: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
const at2 = rest.indexOf(".");
if (at2 <= 0) return undefined;
const module = rest.slice(0, at2);
rest = rest.slice(at2 + 1);
if (rest === "") return undefined;
const fingerprint = rest;
rest = "";
if (rest !== "") return undefined;
return { node, module, fingerprint };
}
/** The key of one value of the state data under the form "<node>.<module>". */
export function dataByNodeModuleKey(node: string, module: string): string {
return node + "." + module;
}
/** The parts of a key of the form "<node>.<module>", or undefined for a key of another form. */
export function parseDataByNodeModuleKey(key: string): { node: string; module: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const module = rest;
rest = "";
if (rest !== "") return undefined;
return { node, module };
}
/** The key of one value of the state packages under the form "<node>". */
export function packagesByNodeKey(node: string): string {
return node;
}
/** The parts of a key of the form "<node>", or undefined for a key of another form. */
export function parsePackagesByNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state health under the form "<node>". */
export function healthByNodeKey(node: string): string {
return node;
}
/** The parts of a key of the form "<node>", or undefined for a key of another form. */
export function parseHealthByNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** one act asked through the seat, as acts reads it (ADR 0563 §9) */
export interface Act {
/** the act: hand-over, access-act, judge-directories or setuid-search */
@@ -505,3 +620,103 @@ export type RefusedEvent = ActSaid;
/** is the body of the event manifest-reads-changed. */
export type ManifestReadsChangedEvent = ManifestReadsChanged;
/** is one value of the state have under the key <node>.<module>. */
export interface HaveByNodeModuleValue {
"build"?: string;
"build-alone"?: boolean;
/** the composition's digest */
"composed"?: string;
"detail"?: string;
/** the fingerprint held */
"fp"?: string;
/** the accounts handed */
"handed"?: Record<string, unknown>;
/** how it is */
"health": string;
"judgement"?: string;
"kept"?: string[];
/** how far it has come */
"phase": string;
/** a pull the engine waits for */
"pull-wait"?: Record<string, unknown>;
"sealed"?: string[];
"sealed-at"?: Record<string, unknown>;
/** the user list written */
"user-list"?: Record<string, unknown>;
"v": number;
/** what it waits for */
"waits"?: string;
}
/** is one value of the state have under the key <node>.node. */
export interface HaveByNodeNodeValue {
"busy"?: Record<string, unknown>;
"candidates"?: Record<string, Record<string, unknown>>;
"composed"?: string;
/** own, or the controller's */
"composes"?: string;
"composes-why"?: string;
"filters"?: Record<string, unknown>;
"profile"?: Record<string, unknown>;
/** the node's record: its tunnel and certificate */
"record"?: Record<string, unknown>;
"sealed"?: string[];
"sealed-at"?: Record<string, unknown>;
"strays"?: Record<string, unknown>;
"v": number;
"windows"?: Record<string, unknown>;
}
/** is one value of the state composed under the key <node>.<module>.<fingerprint>. */
export interface ComposedByNodeModuleFingerprintValue {
"Data"?: boolean;
"FP": string;
"Filled"?: string[];
"Module": string;
"Node": string;
/** the node's own adoption, identities, groups, libraries and provisioner account */
"Own"?: Record<string, unknown>;
/** the module's plan */
"Plan"?: Record<string, unknown>;
/** why the composition was refused */
"Refused"?: string;
"Resources"?: Record<string, unknown>[];
"V"?: number;
}
/** is one value of the state data under the key <node>.<module>. */
export interface DataByNodeModuleValue {
"digest": string;
"items": Record<string, unknown>[];
"module": string;
"node": string;
"v"?: number;
}
export interface PackagesByNodeValuePackagesItem {
"absent"?: boolean;
"modules"?: string[];
"package"?: string;
}
/** is one value of the state packages under the key <node>. */
export interface PackagesByNodeValue {
"node": string;
"packages": PackagesByNodeValuePackagesItem[];
}
/** is one value of the state health under the key <node>. */
export interface HealthByNodeValue {
"at": string;
"contract"?: number;
"fallback"?: Record<string, unknown>;
"found"?: Record<string, unknown>[];
"network"?: Record<string, unknown>;
"node": string;
"peers"?: Record<string, unknown>[];
"relogin"?: Record<string, unknown>[];
"root"?: Record<string, unknown>[];
"units"?: Record<string, unknown>;
"v": number;
}
-3
View File
@@ -1,3 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
export * as seats from "./seats.js";
-8185
View File
File diff suppressed because it is too large Load Diff