Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2003ab616 | ||
|
|
1363a2fe27 |
@@ -91,7 +91,7 @@ func moduleCheck(paths []string, out io.Writer) error {
|
|||||||
if len(m.Invokes) > 0 {
|
if len(m.Invokes) > 0 {
|
||||||
fmt.Fprintf(out, ", invokes %s", joinInvokes(m.Invokes))
|
fmt.Fprintf(out, ", invokes %s", joinInvokes(m.Invokes))
|
||||||
}
|
}
|
||||||
// The state it keeps and reads (novox/hq ADR 0202), so a reviewer sees what lands on the bus.
|
// The state it keeps and reads (novox/hq ADR 0201), so a reviewer sees what lands on the bus.
|
||||||
if len(m.State) > 0 {
|
if len(m.State) > 0 {
|
||||||
kept := make([]string, 0, len(m.State))
|
kept := make([]string, 0, len(m.State))
|
||||||
for _, s := range m.State {
|
for _, s := range m.State {
|
||||||
|
|||||||
@@ -898,7 +898,7 @@ func raiseTheBus(ctx context.Context, inv *inventory.Inventory, address string)
|
|||||||
if err := broker.RaiseSeats(js, inventory.MeshSeats(), holders); err != nil {
|
if err := broker.RaiseSeats(js, inventory.MeshSeats(), holders); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Every module's state (novox/hq ADR 0202), from the catalogue: a bucket exists from
|
// Every module's state (novox/hq ADR 0201), from the catalogue: a bucket exists from
|
||||||
// registration, so a module reading one may watch it before its owner runs anywhere. One that
|
// registration, so a module reading one may watch it before its owner runs anywhere. One that
|
||||||
// nothing declares any more is said and kept — what it holds is data.
|
// nothing declares any more is said and kept — what it holds is data.
|
||||||
buckets, err := inv.DeclaredBuckets(ctx)
|
buckets, err := inv.DeclaredBuckets(ctx)
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ func retentionOf(r Retention) nats.RetentionPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnsureBucket creates a module's bucket if it is absent and brings its options to match if it is
|
// EnsureBucket creates a module's bucket if it is absent and brings its options to match if it is
|
||||||
// present (novox/hq ADR 0202).
|
// present (novox/hq ADR 0201).
|
||||||
//
|
//
|
||||||
// **An update, never a delete and recreate**, for the reason a stream is updated: recreating
|
// **An update, never a delete and recreate**, for the reason a stream is updated: recreating
|
||||||
// discards what the bucket holds, and what a module's state holds is data. The mesh's caps are
|
// discards what the bucket holds, and what a module's state holds is data. The mesh's caps are
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ type Membership struct {
|
|||||||
// it here rather than keeping a definition of its own.
|
// it here rather than keeping a definition of its own.
|
||||||
Mesh []string `json:"mesh,omitempty"`
|
Mesh []string `json:"mesh,omitempty"`
|
||||||
// State is every bucket this module's code may reach, by the name it uses for each, and whether
|
// State is every bucket this module's code may reach, by the name it uses for each, and whether
|
||||||
// it may write it (novox/hq ADR 0202): the runtime answers a bundle's state verbs from this list
|
// it may write it (novox/hq ADR 0201): the runtime answers a bundle's state verbs from this list
|
||||||
// and refuses, with the reason, what is not on it — the bus enforces only the union over every
|
// and refuses, with the reason, what is not on it — the bus enforces only the union over every
|
||||||
// module on the machine.
|
// module on the machine.
|
||||||
State []StateIssued `json:"state,omitempty"`
|
State []StateIssued `json:"state,omitempty"`
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ type Principal struct {
|
|||||||
Invokes []string
|
Invokes []string
|
||||||
|
|
||||||
// State is the local names of the state this principal's module keeps, and Reads the state of
|
// State is the local names of the state this principal's module keeps, and Reads the state of
|
||||||
// others it reads as `<module>.<name>` (novox/hq ADR 0202): a bucket each, kept by the owner's
|
// others it reads as `<module>.<name>` (novox/hq ADR 0201): a bucket each, kept by the owner's
|
||||||
// instances and read by whoever declares it.
|
// instances and read by whoever declares it.
|
||||||
State []string
|
State []string
|
||||||
Reads []string
|
Reads []string
|
||||||
@@ -427,7 +427,7 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Its state, and the state of others it reads (novox/hq ADR 0202): every one read and
|
// 5. Its state, and the state of others it reads (novox/hq ADR 0201): every one read and
|
||||||
// watched, its own written too.
|
// watched, its own written too.
|
||||||
pub = append(pub, stateGrants(p.Module, p.State, p.Reads)...)
|
pub = append(pub, stateGrants(p.Module, p.State, p.Reads)...)
|
||||||
|
|
||||||
@@ -497,7 +497,7 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
|||||||
"$JS.API.CONSUMER.MSG.NEXT."+stream+"."+durable,
|
"$JS.API.CONSUMER.MSG.NEXT."+stream+"."+durable,
|
||||||
"$JS.ACK."+stream+"."+durable+".>")
|
"$JS.ACK."+stream+"."+durable+".>")
|
||||||
}
|
}
|
||||||
// **And it keeps and reads state for the modules it carries** (novox/hq ADR 0202): the union
|
// **And it keeps and reads state for the modules it carries** (novox/hq ADR 0201): the union
|
||||||
// of what each may do with a bucket — an owner's write, a reader's read. That one module's code
|
// of what each may do with a bucket — an owner's write, a reader's read. That one module's code
|
||||||
// does not write another's bucket through it is the runtime's to keep, from the membership
|
// does not write another's bucket through it is the runtime's to keep, from the membership
|
||||||
// each assignment is issued, as it keeps each module's events under that module's own name.
|
// each assignment is issued, as it keeps each module's events under that module's own name.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A module's state on the bus (novox/hq ADR 0202, design 32 §4, design 25 §3).
|
// A module's state on the bus (novox/hq ADR 0201, design 32 §4, design 25 §3).
|
||||||
//
|
//
|
||||||
// A module names the state it keeps (`state`) and the state of others it reads (`reads`), and each
|
// A module names the state it keeps (`state`) and the state of others it reads (`reads`), and each
|
||||||
// is a key-value bucket: the server's own last-per-subject stream with direct reads, delete markers
|
// is a key-value bucket: the server's own last-per-subject stream with direct reads, delete markers
|
||||||
@@ -44,7 +44,7 @@ func (b Bucket) Bucket() string { return BucketName(b.Module, b.Name) }
|
|||||||
// Why is carried into the server's description of the bucket, so somebody reading the server's
|
// Why is carried into the server's description of the bucket, so somebody reading the server's
|
||||||
// own state finds whose it is and why it is kept.
|
// own state finds whose it is and why it is kept.
|
||||||
func (b Bucket) Why() string {
|
func (b Bucket) Why() string {
|
||||||
return fmt.Sprintf("%s's state %q (novox/hq ADR 0202): its current value per key, written by %s, "+
|
return fmt.Sprintf("%s's state %q (novox/hq ADR 0201): its current value per key, written by %s, "+
|
||||||
"read by whatever declares it reads it; kept when %s is unassigned, because it is data",
|
"read by whatever declares it reads it; kept when %s is unassigned, because it is data",
|
||||||
b.Module, b.Name, b.Module, b.Module)
|
b.Module, b.Name, b.Module, b.Module)
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ func stateGrants(module string, keeps []string, reads []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StateIssued is one bucket an assignment may reach, by the name its module uses for it: its own
|
// StateIssued is one bucket an assignment may reach, by the name its module uses for it: its own
|
||||||
// state by the local name, another's as `<module>.<name>` (novox/hq ADR 0202).
|
// state by the local name, another's as `<module>.<name>` (novox/hq ADR 0201).
|
||||||
type StateIssued struct {
|
type StateIssued struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Bucket string `json:"bucket"`
|
Bucket string `json:"bucket"`
|
||||||
@@ -142,7 +142,7 @@ type BucketAsserter interface {
|
|||||||
// RaiseBuckets asserts every declared bucket and answers the buckets on the server that nothing
|
// RaiseBuckets asserts every declared bucket and answers the buckets on the server that nothing
|
||||||
// declares any more.
|
// declares any more.
|
||||||
//
|
//
|
||||||
// **Those are reported, never removed** (novox/hq ADR 0202, ADR 0030): what a module stored is
|
// **Those are reported, never removed** (novox/hq ADR 0201, ADR 0030): what a module stored is
|
||||||
// data, and a manifest edited, a module renamed or a catalogue entry dropped is an ordinary day's
|
// data, and a manifest edited, a module renamed or a catalogue entry dropped is an ordinary day's
|
||||||
// work that must not take data with it. Removing one is a person's act.
|
// work that must not take data with it. Removing one is a person's act.
|
||||||
func RaiseBuckets(a BucketAsserter, buckets []Bucket) (undeclared []string, err error) {
|
func RaiseBuckets(a BucketAsserter, buckets []Bucket) (undeclared []string, err error) {
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ type Declared struct {
|
|||||||
Watches []Seat
|
Watches []Seat
|
||||||
// Invokes are the tools it calls, `<module>.<tool>` or `*` (novox/hq ADR 0152).
|
// Invokes are the tools it calls, `<module>.<tool>` or `*` (novox/hq ADR 0152).
|
||||||
Invokes []string
|
Invokes []string
|
||||||
// State is the state it keeps, each a bucket its instances write (novox/hq ADR 0202).
|
// State is the state it keeps, each a bucket its instances write (novox/hq ADR 0201).
|
||||||
State []Bucket
|
State []Bucket
|
||||||
// Reads are other modules' state it reads, each `<module>.<name>` (novox/hq ADR 0202).
|
// Reads are other modules' state it reads, each `<module>.<name>` (novox/hq ADR 0201).
|
||||||
Reads []string
|
Reads []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -907,6 +907,15 @@ func (r Resolution) compose(with Rendering, owner map[string]string,
|
|||||||
if renamed := reflectsRenamed(m.Module, resource["reload-on"]); renamed != nil {
|
if renamed := reflectsRenamed(m.Module, resource["reload-on"]); renamed != nil {
|
||||||
copied["reload-on"] = renamed
|
copied["reload-on"] = renamed
|
||||||
}
|
}
|
||||||
|
// And which of its module's containers a scheduled step holds still (novox/hq ADR 0189).
|
||||||
|
// **The loudest of the three when it is missed.** An unprefixed `restart-on` matches
|
||||||
|
// nothing and a service quietly never restarts; an unprefixed `while-stopped` names a
|
||||||
|
// container the declaration does not contain, and the host refuses the whole
|
||||||
|
// declaration — so the machine takes nothing at all, for every push, until this is
|
||||||
|
// right. That is what it did on the control node (2026-10-04).
|
||||||
|
if renamed := reflectsRenamed(m.Module, resource[WhileStopped]); renamed != nil {
|
||||||
|
copied[WhileStopped] = renamed
|
||||||
|
}
|
||||||
// And what a process replaces (novox/hq issue 213): a resource of this module's that it
|
// And what a process replaces (novox/hq issue 213): a resource of this module's that it
|
||||||
// no longer declares, named as the host recorded it, or the host hands nothing over and
|
// no longer declares, named as the host recorded it, or the host hands nothing over and
|
||||||
// removes it first.
|
// removes it first.
|
||||||
|
|||||||
@@ -327,11 +327,11 @@ type Manifest struct {
|
|||||||
|
|
||||||
// State is the current state this module keeps on the bus, by local name: each a key-value
|
// State is the current state this module keeps on the bus, by local name: each a key-value
|
||||||
// bucket the controller creates, which every instance of the module writes and reads
|
// bucket the controller creates, which every instance of the module writes and reads
|
||||||
// (novox/hq ADR 0202). Not history — that is an event — and never a secret, sealed or not.
|
// (novox/hq ADR 0201). Not history — that is an event — and never a secret, sealed or not.
|
||||||
State []StateDeclaration `json:"state,omitempty"`
|
State []StateDeclaration `json:"state,omitempty"`
|
||||||
|
|
||||||
// Reads are other modules' state this module reads and watches, each `<module>.<name>`
|
// Reads are other modules' state this module reads and watches, each `<module>.<name>`
|
||||||
// (novox/hq ADR 0202). Read-only: only the owner's instances write.
|
// (novox/hq ADR 0201). Read-only: only the owner's instances write.
|
||||||
Reads []string `json:"reads,omitempty"`
|
Reads []string `json:"reads,omitempty"`
|
||||||
|
|
||||||
// Capabilities the machine must have. A different field from Requires because the remedy
|
// Capabilities the machine must have. A different field from Requires because the remedy
|
||||||
@@ -1325,7 +1325,7 @@ func ParseManifest(raw []byte) (Manifest, error) {
|
|||||||
// module whose event names are wrong installs, starts, connects and reacts to nothing, with
|
// module whose event names are wrong installs, starts, connects and reacts to nothing, with
|
||||||
// every log line saying it is fine (novox/hq 04-ISSUES/127).
|
// every log line saying it is fine (novox/hq 04-ISSUES/127).
|
||||||
problems = append(problems, EventProblems(m)...)
|
problems = append(problems, EventProblems(m)...)
|
||||||
// And what it may call its state, and whose it may read (state.go, novox/hq ADR 0202).
|
// And what it may call its state, and whose it may read (state.go, novox/hq ADR 0201).
|
||||||
problems = append(problems, StateProblems(m)...)
|
problems = append(problems, StateProblems(m)...)
|
||||||
wellFormed := true
|
wellFormed := true
|
||||||
for _, c := range m.Claims {
|
for _, c := range m.Claims {
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ func CatalogueProblems(shelf Shelf) []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A read of a module's state that module does not keep (novox/hq ADR 0202) — said only where the
|
// A read of a module's state that module does not keep (novox/hq ADR 0201) — said only where the
|
||||||
// owner is on the shelf, as a consumer may be installed before its emitter.
|
// owner is on the shelf, as a consumer may be installed before its emitter.
|
||||||
var manifests []Manifest
|
var manifests []Manifest
|
||||||
for _, module := range shelfOrder(shelf) {
|
for _, module := range shelfOrder(shelf) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// What a module may call its state, and whose state it may ask to read (novox/hq ADR 0202).
|
// What a module may call its state, and whose state it may ask to read (novox/hq ADR 0201).
|
||||||
//
|
//
|
||||||
// A module names its state **locally** — `servers`, never a bucket or a subject — and another
|
// A module names its state **locally** — `servers`, never a bucket or a subject — and another
|
||||||
// module's as `<module>.<name>`, the way a consumed event names its emitter (design 32 §1). The
|
// module's as `<module>.<name>`, the way a consumed event names its emitter (design 32 §1). The
|
||||||
@@ -86,7 +86,7 @@ func StateProblems(m Manifest) []string {
|
|||||||
if len(m.State) > 0 && !stateName.MatchString(m.Module) {
|
if len(m.State) > 0 && !stateName.MatchString(m.Module) {
|
||||||
problems = append(problems, fmt.Sprintf(
|
problems = append(problems, fmt.Sprintf(
|
||||||
"%s keeps state, and a module's name is part of its buckets' names, which take one plain "+
|
"%s keeps state, and a module's name is part of its buckets' names, which take one plain "+
|
||||||
"name — no dot (novox/hq ADR 0202)", m.Module))
|
"name — no dot (novox/hq ADR 0201)", m.Module))
|
||||||
}
|
}
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, s := range m.State {
|
for _, s := range m.State {
|
||||||
@@ -94,7 +94,7 @@ func StateProblems(m Manifest) []string {
|
|||||||
case !stateName.MatchString(s.Name):
|
case !stateName.MatchString(s.Name):
|
||||||
problems = append(problems, fmt.Sprintf(
|
problems = append(problems, fmt.Sprintf(
|
||||||
"%s keeps state %q: a state is named locally — lower-case letters, digits and hyphens, "+
|
"%s keeps state %q: a state is named locally — lower-case letters, digits and hyphens, "+
|
||||||
"no dot and no underscore; the mesh derives the bucket (novox/hq ADR 0202)", m.Module, s.Name))
|
"no dot and no underscore; the mesh derives the bucket (novox/hq ADR 0201)", m.Module, s.Name))
|
||||||
case seen[s.Name]:
|
case seen[s.Name]:
|
||||||
problems = append(problems, fmt.Sprintf("%s keeps state %q twice", m.Module, s.Name))
|
problems = append(problems, fmt.Sprintf("%s keeps state %q twice", m.Module, s.Name))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A module declares the state it keeps and the state it reads (novox/hq ADR 0202), a bucket by its
|
// A module declares the state it keeps and the state it reads (novox/hq ADR 0201), a bucket by its
|
||||||
// bare name or with the owner's options.
|
// bare name or with the owner's options.
|
||||||
func TestAManifestMaySayWhatStateItKeepsAndReads(t *testing.T) {
|
func TestAManifestMaySayWhatStateItKeepsAndReads(t *testing.T) {
|
||||||
m, err := ParseManifest([]byte(`{"module":"claude-code","version":"1",` +
|
m, err := ParseManifest([]byte(`{"module":"claude-code","version":"1",` +
|
||||||
@@ -77,7 +77,7 @@ func TestEveryManifestsStateIsLocalAndEveryReadIsKept(t *testing.T) {
|
|||||||
}
|
}
|
||||||
problems = append(problems, StateReadsNothingDeclares(manifests)...)
|
problems = append(problems, StateReadsNothingDeclares(manifests)...)
|
||||||
if len(problems) > 0 {
|
if len(problems) > 0 {
|
||||||
t.Fatalf("the catalogue's state is not what ADR 0202 says:\n %s", strings.Join(problems, "\n "))
|
t.Fatalf("the catalogue's state is not what ADR 0201 says:\n %s", strings.Join(problems, "\n "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package catalogue
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -87,3 +88,58 @@ func TestAMaintenanceWindowIsRefusedWhereTheDefinitionShowsItCannotMean(t *testi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A composed declaration names the step's held containers the way the machine knows them.
|
||||||
|
//
|
||||||
|
// **The gap that let a bug through to the control node.** The manifest says `while-stopped:
|
||||||
|
// ["store"]`, because a module names its own resources locally; the declaration a machine
|
||||||
|
// receives calls that container `distribution.store`, because every resource is composed under
|
||||||
|
// its module. `restart-on` and `reload-on` are rewritten for exactly this reason, and
|
||||||
|
// `while-stopped` was not — so the host found no container by that id and refused the whole
|
||||||
|
// declaration, every push, until it was fixed.
|
||||||
|
//
|
||||||
|
// It passed every test on both sides: the controller's tests read manifests, the host's read
|
||||||
|
// hand-written declarations with bare ids. Only composing one and judging the result catches it.
|
||||||
|
func TestAComposedWindowNamesTheContainerAsTheMachineKnowsIt(t *testing.T) {
|
||||||
|
store := Manifest{
|
||||||
|
Module: "distribution", Version: "1",
|
||||||
|
Provides: FromAnywhere("artifact-store"),
|
||||||
|
Listens: []Listening{{Port: 5000, Protocol: "tcp", From: FromMesh}},
|
||||||
|
Serves: map[string]map[string]any{"artifact-store": {"port": 5000}},
|
||||||
|
Resources: []map[string]any{
|
||||||
|
{"id": "store", "type": "container", "name": "mesh-registry",
|
||||||
|
"image": "registry@sha256:" + strings.Repeat("a", 64), "ports": []any{"5000"}},
|
||||||
|
{"id": "collect", "type": "container", "name": "mesh-registry-collect",
|
||||||
|
"image": "registry@sha256:" + strings.Repeat("a", 64),
|
||||||
|
"schedule": "30 3 * * *", WhileStopped: []any{"store"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r, err := Resolve(shelf(store), []string{"distribution"}, reachable(), World{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
out, err := r.Declaration(Rendering{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
collect := fileNamed(out, "distribution.collect")
|
||||||
|
if collect == nil {
|
||||||
|
for _, res := range out {
|
||||||
|
if res["id"] == "distribution.collect" {
|
||||||
|
collect = res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if collect == nil {
|
||||||
|
t.Fatalf("the step was not composed at all: %v", out)
|
||||||
|
}
|
||||||
|
held, _ := collect[WhileStopped].([]any)
|
||||||
|
if len(held) != 1 {
|
||||||
|
t.Fatalf("the composed step holds %v still; want one container", collect[WhileStopped])
|
||||||
|
}
|
||||||
|
if got := fmt.Sprint(held[0]); got != "distribution.store" {
|
||||||
|
t.Fatalf("the composed step says it holds %q still, and the machine's container is "+
|
||||||
|
"called %q — the host refuses a declaration naming a container it does not have, "+
|
||||||
|
"whole, so the machine would take nothing at all", got, "distribution.store")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func declaredFor(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaratio
|
|||||||
Serves: m.Tools,
|
Serves: m.Tools,
|
||||||
// And what it calls (novox/hq ADR 0152) — the console's `*`, nothing else's.
|
// And what it calls (novox/hq ADR 0152) — the console's `*`, nothing else's.
|
||||||
Invokes: m.Invokes,
|
Invokes: m.Invokes,
|
||||||
// And the state it keeps and reads (novox/hq ADR 0202).
|
// And the state it keeps and reads (novox/hq ADR 0201).
|
||||||
State: bucketsOf(m),
|
State: bucketsOf(m),
|
||||||
Reads: m.Reads,
|
Reads: m.Reads,
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ func bucketsOf(m catalogue.Manifest) []broker.Bucket {
|
|||||||
|
|
||||||
// DeclaredBuckets is every bucket the catalogue declares, registered modules assigned or not: a
|
// DeclaredBuckets is every bucket the catalogue declares, registered modules assigned or not: a
|
||||||
// bucket exists from registration, like a seat's stream, so a module reading it may watch before its
|
// bucket exists from registration, like a seat's stream, so a module reading it may watch before its
|
||||||
// owner runs anywhere (novox/hq ADR 0202).
|
// owner runs anywhere (novox/hq ADR 0201).
|
||||||
func (i *Inventory) DeclaredBuckets(ctx context.Context) ([]broker.Bucket, error) {
|
func (i *Inventory) DeclaredBuckets(ctx context.Context) ([]broker.Bucket, error) {
|
||||||
declared, err := i.Catalogue(ctx)
|
declared, err := i.Catalogue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user