Merge branch 'b5/registry' into feat/registry-milestone

This commit is contained in:
2026-11-05 16:52:51 +01:00
14 changed files with 49 additions and 38 deletions
@@ -19,7 +19,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
"gitea/internal/forgehttp"
"gitea/internal/packageseats"
)
@@ -133,7 +133,7 @@ func TestThePackageSeatsStoreIntoTheForge(t *testing.T) {
// and the next write the forge takes clears it (no timer looks at the token).
var refused []bool
forge.Refused = func(raised bool) { refused = append(refused, raised) }
if k := health.FindingKey(health.ScopeSeat, packageseats.Self, PackagesTokenRefused+".write"); k != PackagesTokenRefusedKey {
if k := meshconditionsclient.Key(meshconditionsclient.ScopeSeat, packageseats.Self, PackagesTokenRefused+".write"); k != PackagesTokenRefusedKey {
t.Errorf("the refusal's key is %s, the watcher watches %s", k, PackagesTokenRefusedKey)
}
_ = os.WriteFile(writer.TokenFile, []byte("stale\n"), 0o600)
@@ -164,7 +164,11 @@ func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ext := pkgs["git.novox.be/novox/mesh-sdk/go/buildstep"]
// The capture holds the one package go list was asked about, whichever package that was.
var ext *goPackage
for _, p := range pkgs {
ext = p
}
if ext == nil || ext.Module == nil || ext.Module.Sum == "" || ext.Module.Version == "" || ext.Module.Main {
t.Fatalf("the capture holds no external package with a version and a checksum: %+v", ext)
}
@@ -24,35 +24,36 @@ import (
"sync/atomic"
"time"
handactsclient "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
handacts "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
"git.novox.be/novox/mesh-sdk/go/handacts"
)
// The seat, the log, the states and the event, as mesh-sdk's handacts names them.
// The seat, the log, the states and the event, as the seat mesh-hand-acts's contract names them.
const (
Module = handacts.Module
Module = "mesh-hand-acts"
Seat = handacts.Seat
ActsLog = handacts.ActsLog
WarrantsState = handacts.WarrantsState
ActsLog = handacts.StateActs
WarrantsState = handacts.StateWarrants
// RouterRecords is the router's record of every ask, `<asker>.<ask>` (ADR 0259): the warrant is read there.
RouterRecords = "messenger.asks"
RecordedEvent = handacts.EventRecorded
RecordedEvent = handacts.EventActRecorded
// RecordedSubject is where the seat says it: a seat's events are on mesh.seat.<seat>.event.<name>, which its
// consumers hear (catalogue.SeatSays).
RecordedSubject = "mesh.seat." + Seat + ".event." + RecordedEvent
VerbRecord = handacts.VerbRecord
VerbDrill = handacts.VerbDrill
VerbWarrant = handacts.VerbWarrant
CauseDrill = handacts.CauseDrill
CauseOperatorAnswer = handacts.CauseOperatorAnswer
VerbRecord = handactsclient.VerbRecord
VerbDrill = handactsclient.VerbDrill
VerbWarrant = handactsclient.VerbWarrant
CauseDrill = handactsclient.CauseDrill
CauseOperatorAnswer = handactsclient.CauseOperatorAnswer
)
// RepeatedWithin is how far back a cause counts as repeated (S15).
const RepeatedWithin = 14 * 24 * time.Hour
// Act is one entry of the log: mesh-sdk's handacts.Act, the controller's HandAct unchanged.
// Act is one entry of the log: the seat's Act.
type Act = handacts.Act
// Store is the bus's buckets and this module's log as it reaches them, through its runtime. Create writes a key only
@@ -130,7 +131,7 @@ func (l *Log) HandAct(by, verb, what, why, cause, condition string) (Recorded, e
", which no healer is wanted for. Nothing was recorded")
}
at := l.Now().UTC()
act := Act{ID: actKey(at), At: at, By: by, Verb: verb, Args: []string{what}, Why: why, Cause: cause,
act := Act{ID: actKey(at), At: at, By: by, Verb: verb, Arguments: []string{what}, Why: why, Cause: cause,
Condition: strings.TrimSpace(condition)}
if err := l.record(act); err != nil {
return Recorded{}, err
@@ -219,10 +220,10 @@ func (l *Log) Warranted(caller, asker, ask string) (Recorded, error) {
}
at := l.Now().UTC()
act := Act{ID: "warrant-" + asker + "-" + ask, At: warranted.UTC(), Verb: VerbWarrant,
Args: []string{fmt.Sprintf("the operator chose %s on %s's ask %s", w.Label, asker, ask)},
Why: fmt.Sprintf("%s (ask %s of %s)", occ.Says(*w), ask, asker),
By: fmt.Sprintf("the %s, as %s identity %s", w.By.Who, w.By.Kind, w.By.Identity),
Cause: CauseOperatorAnswer, Via: via(*w), Ask: ask, Proofs: w.Proofs,
Arguments: []string{fmt.Sprintf("the operator chose %s on %s's ask %s", w.Label, asker, ask)},
Why: fmt.Sprintf("%s (ask %s of %s)", occ.Says(*w), ask, asker),
By: fmt.Sprintf("the %s, as %s identity %s", w.By.Who, w.By.Kind, w.By.Identity),
Cause: CauseOperatorAnswer, Via: via(*w), Ask: ask, Proofs: w.Proofs,
RequestedBy: asker + ", recorded at the word of " + caller,
Outcome: "chosen; what " + asker + " did with it is in its own record"}
if claimed == nil {
@@ -297,7 +298,7 @@ func (l *Log) HandActs(days int, cause, who string) Listing {
out.Kept[ActsLog] = kept
}
for _, a := range all {
if now.Sub(a.At) <= RepeatedWithin && a.Repair() {
if now.Sub(a.At) <= RepeatedWithin && handactsclient.Repair(a) {
out.Repeated[a.Cause]++
}
if a.At.Before(since) || (cause != "" && a.Cause != cause) || (who != "" && !strings.Contains(a.By, who)) {
@@ -329,7 +330,7 @@ func (l *Log) read(since time.Time) ([]Act, int, error) {
if json.Unmarshal(raw, &a) != nil || a.At.Before(since) {
continue
}
a.Log = handacts.LogSeat
a.Log = handacts.Seat
out = append(out, a)
}
return out, len(entries), nil
@@ -171,7 +171,7 @@ func TestHandActRecordsWhatTheProvenCallerDid(t *testing.T) {
raw, _, _ := store.Last(ActsLog, keys[0])
_ = json.Unmarshal(raw, &kept)
if kept.By != tc.by || kept.Verb != tc.wantVerb || kept.Cause != tc.wantCause || kept.Condition != "bus.x.missing" ||
kept.Args[0] != tc.what || kept.Log != "" {
kept.Arguments[0] != tc.what || kept.Log != "" {
t.Errorf("%s: kept %+v", tc.name, kept)
}
}
+2
View File
@@ -3,6 +3,8 @@ module mesh-hand-acts
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174359-05b3e2e1b94f
@@ -26,9 +26,9 @@ import (
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
handacts "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
meshhealers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/handacts"
)
// Module and Seat are this module and the seat it holds once for the mesh.
@@ -47,7 +47,7 @@ const (
// ActedSubject is where the seat says it, which its consumers hear (catalogue.SeatSays).
ActedSubject = "mesh.seat." + Seat + ".event." + ActedEvent
// RecordedEvent is the hand-act log's seat event, each act recorded there (ADR 0565 §11).
RecordedEvent = handacts.Seat + "." + handacts.EventRecorded
RecordedEvent = handacts.Seat + "." + handacts.EventActRecorded
// The events it hears: the keeper's, on the seat mesh-conditions.
RaisedEvent = "mesh-conditions.condition-raised"
ChangedEvent = "mesh-conditions.condition-changed"
@@ -12,7 +12,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/handacts"
handacts "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
)
type memStore struct {
@@ -426,7 +426,7 @@ func TestTheVerbsAndReads(t *testing.T) {
args map[string]any
log, err string
}{
{"into the seat", false, map[string]any{"what": "stopped records", "why": "does it raise"}, handacts.LogSeat, ""},
{"into the seat", false, map[string]any{"what": "stopped records", "why": "does it raise"}, handacts.Seat, ""},
{"no holder: refused, the controller's not asked", true, map[string]any{"what": "stopped records", "why": "x"}, "", "nothing was recorded"},
{"says nothing", false, map[string]any{}, "", "says what"},
}
@@ -455,7 +455,7 @@ func TestTheVerbsAndReads(t *testing.T) {
}
case err != nil || got.(map[string]any)["log"] != d.log:
t.Errorf("drill %s: %v, %v", d.name, got, err)
case d.log == handacts.LogSeat && !strings.Contains(asked[0], `"verb":"hand-act drill"`):
case d.log == handacts.Seat && !strings.Contains(asked[0], `"verb":"hand-act drill"`):
t.Errorf("drill %s asked %v", d.name, asked)
}
for _, k := range asked {
@@ -12,8 +12,9 @@ import (
"strings"
"time"
handactsclient "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
handacts "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/handacts"
)
// Verbs are the seat's verbs, as the manifest claims them.
@@ -92,7 +93,7 @@ func (h *Healers) Drill(what, why, condition string) (any, error) {
if h.Ask == nil {
return nil, errors.New("the hand-act log cannot be reached from here: nothing was recorded")
}
body := map[string]any{"what": what, "why": why, "verb": handacts.VerbDrill}
body := map[string]any{"what": what, "why": why, "verb": handactsclient.VerbDrill}
if condition != "" {
body["condition"] = condition
}
@@ -100,7 +101,7 @@ func (h *Healers) Drill(what, why, condition string) (any, error) {
if err != nil {
return nil, fmt.Errorf("%s.hand-act refused the drill, so nothing was recorded: %w", handacts.Seat, err)
}
return map[string]any{"log": handacts.LogSeat, "answer": answer}, nil
return map[string]any{"log": handacts.Seat, "answer": answer}, nil
}
// Heal is the verb heal: one condition judged now by its healer.
@@ -16,13 +16,13 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/handacts"
handacts "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts"
)
// Within is how far back a repeated cause counts.
const Within = 14 * 24 * time.Hour
// HandAct is what S15 reads of one act of the hand-act log (mesh-sdk handacts.Act).
// HandAct is what S15 reads of one act of the hand-act log (the seat mesh-hand-acts's Act).
type HandAct struct {
ID string `json:"id"`
At time.Time `json:"at"`
@@ -85,7 +85,7 @@ func (h *Healers) ActRecorded(body []byte) {
if h.acts == nil {
h.acts = map[string]HandAct{}
}
h.acts[handacts.LogSeat+":"+a.ID] = a
h.acts[handacts.Seat+":"+a.ID] = a
h.mu.Unlock()
h.Wanted()
}
+2
View File
@@ -3,6 +3,7 @@ module mesh-healers
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174359-05b3e2e1b94f
github.com/nats-io/nats.go v1.54.0
)
@@ -24,3 +25,4 @@ require (
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers v0.0.0-00010101000000-000000000000
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000
@@ -9,7 +9,7 @@ import (
"sync"
"testing"
"git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
"git.novox.be/novox/mesh-sdk/go/views"
)
@@ -313,7 +313,7 @@ func TestTheManifestDeclaresWhatTheCodeKeeps(t *testing.T) {
t.Errorf("the claim: %+v", m.Claims)
}
// needs stays declared this release so its first start can empty it (ADR 0570 clause 1).
if want := []string{Registry, Needs, Applied, Collect, ProvisionsState, PlansState, RefusedState, health.FindingsState}; !slices.Equal(m.State, want) {
if want := []string{Registry, Needs, Applied, Collect, ProvisionsState, PlansState, RefusedState, meshconditionsclient.FindingsState}; !slices.Equal(m.State, want) {
t.Errorf("the state is %v, want %v", m.State, want)
}
// Every state and act has its tool (ADR 0570 Consequences): the verb reads the clients' states, the holder's tools
+1 -1
View File
@@ -23,8 +23,8 @@ import (
"time"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/overlay"
)
// The vault's own signing secrets: each an ed25519 seed in base64 (never PEM, which the vault takes as a private key
@@ -14,7 +14,7 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/overlay"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
"git.novox.be/novox/mesh-sdk/go/seal"
)
+1
View File
@@ -29,3 +29,4 @@ require (
golang.org/x/sys v0.48.0 // indirect
golang.org/x/time v0.16.0 // indirect
)
require git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go v0.0.0-20261105000000-000000000000