Fix 9.4e: the four readers use the branch follower's Entry, Ready, entries rows, entry-not-found finding and entry_again tool; their copies are deleted

Builds: design 47 G A-103, A-15, §614

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 01:12:43 +01:00
parent 5d1456257c
commit c6de76740f
32 changed files with 109 additions and 211 deletions
@@ -6,10 +6,6 @@ package main
// `manifests`.
import (
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
@@ -20,41 +16,3 @@ type CatalogHalf interface {
// Ready is nil once every watched branch has its first view (none-yet counting as one), else says what it waits for.
Ready() error
}
// branchesHalf is the CatalogHalf over the follower of the watched branches.
type branchesHalf struct{ b *meshcatalogclient.Branches }
func (h branchesHalf) Ready() error {
followed := h.b.Followed()
if len(followed) == 0 {
return fmt.Errorf("the catalog half names no watched branch yet (the seat mesh-catalog's registrations are asked until they answer)")
}
var waiting []string
for _, branch := range followed {
if c, ok := h.b.Catalog(branch); ok {
select {
case <-c.Ready():
default:
waiting = append(waiting, branch)
}
}
}
if len(waiting) > 0 {
return fmt.Errorf("the catalog half has no first view of %s yet", strings.Join(waiting, ", "))
}
return nil
}
func (h branchesHalf) Entry(module string) (catalog.CatalogEntry, bool, error) {
if err := h.Ready(); err != nil {
return catalog.CatalogEntry{}, false, err
}
for _, branch := range h.b.Followed() { // the branch followed first names a module more than one hold
if c, ok := h.b.Catalog(branch); ok {
if e, ok := c.Entry(module); ok {
return e, true, nil
}
}
}
return catalog.CatalogEntry{}, false, nil
}
@@ -58,7 +58,7 @@ func TestCatalogHalfIsTheWatchedBranchesNewestRevision(t *testing.T) {
if err != nil {
t.Fatal(err)
}
h := branchesHalf{b}
h := b
if _, _, err := h.Entry("pg"); err == nil || !strings.Contains(err.Error(), "no watched branch") {
t.Fatalf("before the registrations: %v, want an error naming the missing branch", err)
}
@@ -4,9 +4,6 @@ import (
"context"
"encoding/json"
"errors"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"os"
"reflect"
"slices"
@@ -14,6 +11,10 @@ import (
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"git.novox.be/novox/mesh-sdk/go/seatdef"
"git.novox.be/novox/mesh-sdk/go/seatlist"
"git.novox.be/novox/mesh-sdk/go/views"
+1 -1
View File
@@ -488,7 +488,7 @@ func main() {
default:
}
}
meshCatalog = branchesHalf{branches}
meshCatalog = branches
if launched {
fsys = FilesFor(p)
}
+3 -2
View File
@@ -16,8 +16,6 @@ import (
"encoding/json"
"errors"
"fmt"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"net"
"os"
"path/filepath"
@@ -26,6 +24,9 @@ import (
"sync"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/seatdef"
"git.novox.be/novox/mesh-sdk/go/seatlist"
@@ -2,11 +2,12 @@ package main
import (
"encoding/json"
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"
"strings"
"testing"
"time"
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"
)
// A section registered for the mesh before the controller's terminal took that over, or set at the terminal, is
@@ -7,8 +7,6 @@ package main
import (
"context"
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
@@ -20,49 +18,7 @@ type CatalogHalf interface {
Entry(module string) (catalog.CatalogEntry, bool, error)
// Ready is nil once every watched branch has its first view (none-yet counting as one), else says what it waits for.
Ready() error
// ByFingerprint reads an entry by the fingerprint of a build: from a branch's half when one lists it, else asked of the
// Resolve reads an entry by the fingerprint of a build: from a branch's half when one lists it, else asked of the
// seat's verb `entry` once and kept (asked, answered or not found).
ByFingerprint(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState)
}
// branchesHalf is the CatalogHalf over the follower of the watched branches.
type branchesHalf struct{ b *meshcatalogclient.Branches }
func (h branchesHalf) Ready() error {
followed := h.b.Followed()
if len(followed) == 0 {
return fmt.Errorf("the catalog half names no watched branch yet (the seat mesh-catalog's registrations are asked until they answer)")
}
var waiting []string
for _, branch := range followed {
if c, ok := h.b.Catalog(branch); ok {
select {
case <-c.Ready():
default:
waiting = append(waiting, branch)
}
}
}
if len(waiting) > 0 {
return fmt.Errorf("the catalog half has no first view of %s yet", strings.Join(waiting, ", "))
}
return nil
}
func (h branchesHalf) Entry(module string) (catalog.CatalogEntry, bool, error) {
if err := h.Ready(); err != nil {
return catalog.CatalogEntry{}, false, err
}
for _, branch := range h.b.Followed() { // the branch followed first names a module more than one hold
if c, ok := h.b.Catalog(branch); ok {
if e, ok := c.Entry(module); ok {
return e, true, nil
}
}
}
return catalog.CatalogEntry{}, false, nil
}
func (h branchesHalf) ByFingerprint(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState) {
return h.b.Resolve(ctx, fingerprint)
Resolve(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState)
}
@@ -58,7 +58,7 @@ func TestCatalogHalfIsTheWatchedBranchesNewestRevision(t *testing.T) {
if err != nil {
t.Fatal(err)
}
h := branchesHalf{b}
h := b
if _, _, err := h.Entry("pg"); err == nil || !strings.Contains(err.Error(), "no watched branch") {
t.Fatalf("before the registrations: %v, want an error naming the missing branch", err)
}
@@ -5,15 +5,16 @@ import (
"encoding/json"
"errors"
"fmt"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"sort"
"strings"
"sync"
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// memStore is the bus as mesh-config reaches it, in memory: its states and the mirrors it reads, its history log,
@@ -43,7 +44,7 @@ func (m *memStore) Entry(module string) (catalog.CatalogEntry, bool, error) {
func (m *memStore) Ready() error { return m.notYet }
func (m *memStore) ByFingerprint(_ context.Context, fp string) (catalog.CatalogEntry, catalogclient.EntryState) {
func (m *memStore) Resolve(_ context.Context, fp string) (catalog.CatalogEntry, catalogclient.EntryState) {
m.mu.Lock()
defer m.mu.Unlock()
if e, ok := m.byFp[fp]; ok {
@@ -6,9 +6,10 @@ package main
import (
"encoding/json"
"fmt"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"strings"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
)
+6 -4
View File
@@ -152,13 +152,15 @@ func main() {
default:
}
}
branches.Entries.Changed = func(catalogclient.EntryRow) {
// An entry the catalog holds none of is a finding `entry-not-found`, and a new pass starts at each answer (design 47 G A-103).
branches.WriteEntryFindings(w, func(catalogclient.EntryRow) {
select {
case moved <- struct{}{}:
default:
}
}
c.Catalog = branchesHalf{branches}
})
theViews.entries = func() any { return branches.EntryStatuses() }
c.Catalog = branches
theViews.catalog = func() []*views.Follower {
out := []*views.Follower{branches.Registrations.Follower}
for _, b := range branches.Followed() {
@@ -180,7 +182,7 @@ func main() {
go resolving(c, moved)
go hearing(c)
go hearingDelivery(c)
if err := stdio.Serve("", Tools(c)); err != nil {
if err := stdio.Serve("", append(Tools(c), branches.EntryAgainTool("config", c.Store.HandAct))); err != nil {
logf("%v", err)
os.Exit(1)
}
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"os"
"path/filepath"
"slices"
@@ -62,6 +63,8 @@ func TestEveryStateAndActHasItsTool(t *testing.T) {
for _, tool := range Tools(&Config{}) {
served[tool.Name] = true
}
// the catalog half's follower serves the part's `entry_again` (design 47 G A-103), beside the module's own tools
served[(&catalogclient.Branches{}).EntryAgainTool("config", nil).Name] = true
if len(m.Claims) != 1 || m.Claims[0].Name != Seat || strings.Join(m.Claims[0].Serves, ",") != strings.Join(SeatVerbs, ",") {
t.Errorf("claims %+v, want %s serving %v", m.Claims, Seat, SeatVerbs)
}
@@ -16,10 +16,11 @@ import (
"encoding/json"
"errors"
"fmt"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"sort"
"strings"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/views"
)
@@ -53,6 +54,8 @@ type ownerViews struct {
// catalog is the followers of the catalog half (the registrations and each watched branch's revision view), which the
// first-view tools list and ask again beside the owners' (design 47 G §614); nil before they are followed.
catalog func() []*views.Follower
// entries lists the entries by fingerprint the catalog half's follower keeps (design 47 G A-103).
entries func() any
}
// newOwnerViews makes a follower for each state; changed is told when any picture changes. findings is the module's writer,
@@ -194,7 +197,11 @@ func viewTools(c *Config, o func() *ownerViews) []stdio.Tool {
if ov == nil {
return nil, errors.New("mesh-config reads its owners through views only when it runs as the module")
}
return map[string]any{"first-views": ov.statuses()}, nil
out := map[string]any{"first-views": ov.statuses()}
if ov.entries != nil {
out["entries"] = ov.entries()
}
return out, nil
}},
{Name: FirstViewAgainTool,
Description: "Ask a first view once more by hand, `<owner>.<state>` (all when not given), recorded as a hand act with " +
+2 -1
View File
@@ -6,11 +6,12 @@ import (
"encoding/json"
"errors"
"fmt"
"git.novox.be/novox/mesh-contracts/go/clients/meshconfigclient"
"regexp"
"strconv"
"strings"
"time"
"git.novox.be/novox/mesh-contracts/go/clients/meshconfigclient"
)
// A config value held for the open pull request that introduces its key (novox/hq ADR 0502, issue 1826).
@@ -3,11 +3,12 @@ package main
import (
"encoding/json"
"errors"
"git.novox.be/novox/mesh-contracts/go/clients/meshconfigclient"
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-contracts/go/clients/meshconfigclient"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
)
@@ -3,10 +3,11 @@ package main
import (
"encoding/json"
"fmt"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"sort"
"strings"
"time"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
)
// The four sources (novox/hq ADR 0348 §2, §3, §9): a module's value on a node resolves, the most specific winning,
@@ -5,11 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"sort"
"strings"
)
// Reading the sources, writing the resolved values, and publishing the list of predefined keys.
@@ -212,7 +213,7 @@ func (c *Config) trunkEntry(module string) (catalog.CatalogEntry, error) {
// builtDeclarations is a module's declarations at a build: the manifest of the catalog entry of its fingerprint (design 47
// G §594, §614); an entry still asked, or the seat's word that it holds none, is an error naming it.
func (c *Config) builtDeclarations(module, fp string) (ModuleDeclarations, error) {
e, state := c.Catalog.ByFingerprint(context.Background(), fp)
e, state := c.Catalog.Resolve(context.Background(), fp)
switch state {
case catalogclient.EntryAnswered:
if e.Module != module {
@@ -13,8 +13,9 @@ import (
"encoding/json"
"errors"
"fmt"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"time"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// The states and reads.
@@ -2,9 +2,10 @@ package main
import (
"encoding/json"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"strings"
"testing"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// The trunk's manifests aMesh declares.
@@ -18,13 +18,6 @@ import (
"encoding/json"
"errors"
"fmt"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
delivery "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery"
"io"
"maps"
"os"
@@ -36,6 +29,14 @@ import (
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
delivery "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
+2 -1
View File
@@ -59,7 +59,8 @@
"config_rename_close",
"config_retiring",
"config_first_views",
"config_first_view_again"
"config_first_view_again",
"config_entry_again"
],
"state": [
"values",
@@ -69,7 +69,7 @@ func (f *fakeCatalog) Ready() error {
return f.notYet
}
func (f *fakeCatalog) ByFingerprint(_ context.Context, fp string) (catalog.CatalogEntry, catalogclient.EntryState) {
func (f *fakeCatalog) Resolve(_ context.Context, fp string) (catalog.CatalogEntry, catalogclient.EntryState) {
f.mu.Lock()
defer f.mu.Unlock()
if e, ok := f.byFp[fp]; ok {
@@ -7,8 +7,6 @@ package main
import (
"context"
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
@@ -20,49 +18,7 @@ type CatalogHalf interface {
Entry(module string) (catalog.CatalogEntry, bool, error)
// Ready is nil once every watched branch has its first view (none-yet counting as one), else says what it waits for.
Ready() error
// ByFingerprint reads an entry by the fingerprint of a build: from a branch's half when one lists it, else asked of the
// Resolve reads an entry by the fingerprint of a build: from a branch's half when one lists it, else asked of the
// seat's verb `entry` once and kept (asked, answered or not found).
ByFingerprint(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState)
}
// branchesHalf is the CatalogHalf over the follower of the watched branches.
type branchesHalf struct{ b *meshcatalogclient.Branches }
func (h branchesHalf) Ready() error {
followed := h.b.Followed()
if len(followed) == 0 {
return fmt.Errorf("the catalog half names no watched branch yet (the seat mesh-catalog's registrations are asked until they answer)")
}
var waiting []string
for _, branch := range followed {
if c, ok := h.b.Catalog(branch); ok {
select {
case <-c.Ready():
default:
waiting = append(waiting, branch)
}
}
}
if len(waiting) > 0 {
return fmt.Errorf("the catalog half has no first view of %s yet", strings.Join(waiting, ", "))
}
return nil
}
func (h branchesHalf) Entry(module string) (catalog.CatalogEntry, bool, error) {
if err := h.Ready(); err != nil {
return catalog.CatalogEntry{}, false, err
}
for _, branch := range h.b.Followed() { // the branch followed first names a module more than one hold
if c, ok := h.b.Catalog(branch); ok {
if e, ok := c.Entry(module); ok {
return e, true, nil
}
}
}
return catalog.CatalogEntry{}, false, nil
}
func (h branchesHalf) ByFingerprint(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState) {
return h.b.Resolve(ctx, fingerprint)
Resolve(ctx context.Context, fingerprint string) (catalog.CatalogEntry, meshcatalogclient.EntryState)
}
@@ -58,7 +58,7 @@ func TestCatalogHalfIsTheWatchedBranchesNewestRevision(t *testing.T) {
if err != nil {
t.Fatal(err)
}
h := branchesHalf{b}
h := b
if _, _, err := h.Entry("pg"); err == nil || !strings.Contains(err.Error(), "no watched branch") {
t.Fatalf("before the registrations: %v, want an error naming the missing branch", err)
}
@@ -12,16 +12,17 @@ package main
import (
"context"
"encoding/json"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogkey"
"os"
"slices"
"strings"
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogkey"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
@@ -31,17 +31,18 @@ import (
"encoding/json"
"errors"
"fmt"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogkey"
"slices"
"sort"
"strings"
"sync"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogkey"
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-contracts/provisioning/go/clients/meshprovisionerclient"
@@ -903,7 +904,7 @@ func (h *Holder) haveOutcome(p *meshprovisionerclient.Provision) {
// read from the catalog entry of that fingerprint (design 47 G §594, §614); known is false while the entry is asked or when
// the seat holds none (the caller then does not refuse).
func (h *Holder) buildOffers(module, fingerprint, provision string) (offers, known bool) {
entry, state := h.Catalog.ByFingerprint(context.Background(), fingerprint)
entry, state := h.Catalog.Resolve(context.Background(), fingerprint)
if state != catalogclient.EntryAnswered || entry.Module != module {
return false, false
}
@@ -14,12 +14,13 @@ import (
"context"
"encoding/json"
"errors"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"strings"
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
@@ -4,8 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"go/ast"
"go/parser"
"go/token"
@@ -15,6 +13,9 @@ import (
"testing"
"time"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
meshseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
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-contracts/provisioning/go/clients/meshprovisionerclient"
@@ -10,13 +10,14 @@ import (
"context"
"encoding/json"
"fmt"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"os"
"strings"
"sync"
"sync/atomic"
"time"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
seat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
stdio "git.novox.be/novox/mesh-sdk/go"
@@ -249,7 +250,7 @@ func main() {
os.Exit(1)
}
branches.Logf = logf
cat := branchesHalf{branches}
cat := branches
findings, err := newFindingsWriter()
if err != nil {
logf("%v", err)
@@ -295,11 +296,12 @@ func main() {
w.add(h.NodesOfModule(module)...)
w.add(loads.heldBack(h)...)
}
branches.Entries.Changed = func(row catalogclient.EntryRow) {
// An entry the catalog holds none of is a finding `entry-not-found` (design 47 G A-103).
branches.WriteEntryFindings(findings, func(row catalogclient.EntryRow) {
if row.Entry != nil {
w.add(h.NodesOfModule(row.Entry.Module)...)
}
}
})
v.Start(context.Background())
go w.run(h)
go starting(h)
@@ -350,7 +352,8 @@ func main() {
time.Sleep(wait)
}
}()
if err := stdio.Serve("", append(append(Tools(s), holderTools(h)...), v.Tools("provisioner")...)); err != nil {
if err := stdio.Serve("", append(append(append(Tools(s), holderTools(h)...), v.Tools("provisioner")...),
branches.EntryAgainTool("provisioner", handAct))); err != nil {
logf("%v", err)
os.Exit(1)
}
@@ -405,3 +408,9 @@ func Tools(s Store) []stdio.Tool {
},
}}
}
// handAct records a hand act in the log of the seat mesh-hand-acts.
func handAct(what, why, cause string) error {
_, err := meshhandactsclient.Recorder{Ask: stdio.Ask}.Record(meshhandactsclient.Request{What: what, Why: why, Cause: cause})
return err
}
@@ -3,6 +3,7 @@ package main
import (
"encoding/json"
"fmt"
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"os"
"regexp"
"slices"
@@ -348,6 +349,8 @@ func TestTheManifestDeclaresWhatTheCodeKeeps(t *testing.T) {
for _, tool := range append(append(Tools(newStore()), holderTools(&Holder{})...), (&views.Reader{}).Tools("provisioner")...) {
served[tool.Name] = true
}
// the catalog half's follower serves the part's `entry_again` (design 47 G A-103), beside the module's own tools
served[(&catalogclient.Branches{}).EntryAgainTool("provisioner", nil).Name] = true
for what, tool := range map[string]string{Registry: Seat + "." + Verb, Needs: Seat + "." + Verb,
Applied: Seat + "." + Verb, Collect: Seat + "." + Verb, ProvisionsState: ProvisionsTool, PlansState: PlansTool,
"a composition on a change": ComposeTool, "a decision on an answer": DecideTool} {
+2 -1
View File
@@ -49,7 +49,8 @@
"provisioner_decide",
"provisioner_health",
"provisioner_first_views",
"provisioner_first_view_again"
"provisioner_first_view_again",
"provisioner_entry_again"
],
"state": [
"registry",
@@ -5,9 +5,6 @@ package main
// catalog graph entry carries whole (§443), never the indexer's state `modules` or `manifests`.
import (
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
@@ -22,23 +19,15 @@ type CatalogHalf interface {
type branchesHalf struct{ b *meshcatalogclient.Branches }
func (h branchesHalf) Modules() (map[string]catalog.CatalogEntry, error) {
followed := h.b.Followed()
if len(followed) == 0 {
return nil, fmt.Errorf("the catalog half names no watched branch yet (the seat mesh-catalog's registrations are asked until they answer)")
if err := h.b.Ready(); err != nil {
return nil, err
}
out := map[string]catalog.CatalogEntry{}
var waiting []string
for _, branch := range followed {
for _, branch := range h.b.Followed() {
c, ok := h.b.Catalog(branch)
if !ok {
continue
}
select {
case <-c.Ready():
default:
waiting = append(waiting, branch)
continue
}
half, _ := c.View() // a branch at none-yet is ready and empty (§614)
for m, e := range half.Entries {
if _, ok := out[m]; !ok { // the branch followed first names a module both hold
@@ -46,8 +35,5 @@ func (h branchesHalf) Modules() (map[string]catalog.CatalogEntry, error) {
}
}
}
if len(waiting) > 0 {
return nil, fmt.Errorf("the catalog half has no first view of %s yet", strings.Join(waiting, ", "))
}
return out, nil
}