DLV-G2: the bus module's process gets its own account: it defines every module's bus state by its names and an orphan's it created, serves mesh-broker's eight verbs, and no other account holds the acting four (ADR 0595 §4, §5)
The grants are composed for the process of the module holding mesh-broker, from every manifest's bus-state entries and the streams of the bindings kept; the writers table names it beside the grants part as a definer of streams; the acting verbs are denied to every principal whose grant reaches them, and neither the holder's own account nor the tool runner serves the seat's verbs. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -50,6 +50,7 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
|
||||
t.Run("a declared stream is created as the controller asserted it", declaredStreamsAreCreatedAsTheControllerAssertsThem)
|
||||
t.Run("every node's compositions are read by their named readers alone and written by their node", everyNodesCompositions)
|
||||
t.Run("a module's ledger is written by its ledger account alone", aLedgerIsWrittenByItsLedgerAccountAlone)
|
||||
t.Run("the bus module's process alone keeps every module's bus state and serves the broker's verbs", theBusModulesProcessKeepsBusState)
|
||||
// ADR 0567 §3, §9: a node reads every key of the seat's placement and its candidates (it composes with the whole
|
||||
// proposal laid over), and none of its open proposals; it writes neither.
|
||||
reads := strings.Join(NodeComposeReads("laptop"), " ")
|
||||
@@ -1060,3 +1061,72 @@ func aLedgerIsWrittenByItsLedgerAccountAlone(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DLV-G2, 1966/AC35 (novox/hq ADR 0595 §4, §5; design 25 § 12.2, § 12.3): the process of the module holding mesh-broker
|
||||
// may create, update and delete every module's bus state by its names (a bucket's KV_, an object store's OBJ_, a ledger's
|
||||
// four parts) and an orphan's the bus module said it created, never a stream of the foundation; it serves the seat's eight
|
||||
// verbs; and no other principal, the tool runner and the bus module's own account included, holds the acting four.
|
||||
func theBusModulesProcessKeepsBusState(t *testing.T) {
|
||||
r := Records{Nodes: []string{"a"}, Assigned: map[string][]Declared{"a": {
|
||||
{Module: "node-tools", ToolRunner: true},
|
||||
{Module: "nats", SnapshotsTheBus: true, Holds: []Seat{{Name: catalogue.BrokerSeat, Serves: BrokerVerbs()}},
|
||||
Processes: []ProcessPrincipal{{Process: "keeper", Emits: []string{"created"}}, {Process: "nats-tools", Tools: true,
|
||||
Removes: []string{catalogue.RemovesEngineActs}}}},
|
||||
{Module: "mod-x"},
|
||||
{Module: "admin-ish", Invokes: []string{"*"}},
|
||||
}},
|
||||
BusState: map[string][]catalogue.BusStateEntry{"mod-x": {
|
||||
{Name: "records", Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState},
|
||||
{Name: "audit", Storage: catalogue.StorageLedger, Template: catalogue.TemplateLedger,
|
||||
Types: []catalogue.LedgerType{{Name: "decision", Indexes: []catalogue.LedgerIndex{{Name: "by-status", On: []string{"status"}}}}}},
|
||||
{Name: "parts", Storage: catalogue.StorageObjectStore, Template: catalogue.TemplateObjects}}},
|
||||
Bound: map[string][]string{"gone": {"KV_gone_kept"}}}
|
||||
users, err := Users(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
perms := map[string]Permissions{}
|
||||
for _, u := range users {
|
||||
p, err := PermissionsFor(u)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", u.Username(), err)
|
||||
}
|
||||
perms[u.Username()] = p
|
||||
}
|
||||
keeper := perms["a.nats.keeper"]
|
||||
for _, s := range []string{"KV_mod-x_records", "mod-x_audit", "mod-x_audit_snapshot", "KV_mod-x_audit_state",
|
||||
"KV_mod-x_audit_index-by-status", "OBJ_mod-x_parts", "KV_gone_kept"} {
|
||||
for _, op := range []string{"CREATE", "UPDATE", "DELETE"} {
|
||||
if !MayPublish(keeper, "$JS.API.STREAM."+op+"."+s) {
|
||||
t.Errorf("the bus module's process may not %s %s", op, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range []string{"EVENTS", "KV_mesh-grants_memberships", "KV_mod-x_other"} {
|
||||
if MayPublish(keeper, "$JS.API.STREAM.CREATE."+s) || MayPublish(keeper, "$JS.API.STREAM.DELETE."+s) {
|
||||
t.Errorf("the bus module's process may define %s", s)
|
||||
}
|
||||
}
|
||||
for _, v := range BrokerVerbs() {
|
||||
if !MaySubscribe(keeper, "mesh.seat.mesh-broker.tool."+v) {
|
||||
t.Errorf("the bus module's process does not serve %s", v)
|
||||
}
|
||||
}
|
||||
if !keeper.AllowResponses {
|
||||
t.Error("the bus module's process cannot answer what it serves")
|
||||
}
|
||||
for user, p := range perms {
|
||||
if user == "a.nats.keeper" {
|
||||
continue
|
||||
}
|
||||
for _, v := range BrokerActingVerbs {
|
||||
subject := "mesh.seat.mesh-broker.tool." + v
|
||||
if MayPublish(p, subject) || MaySubscribe(p, subject) {
|
||||
t.Errorf("%s holds %s", user, subject)
|
||||
}
|
||||
}
|
||||
if MayPublish(p, "$JS.API.STREAM.CREATE.KV_mod-x_records") && user != "a.mesh-grants" {
|
||||
t.Errorf("%s may create mod-x's bus state", user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package buscompose
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
// **The bus module's process has a bus account of its own** (novox/hq ADR 0595 §4, §5; design 25 § 12.2, § 12.3;
|
||||
// DLV-G2): composed for the process of the module holding the seat mesh-broker (a seat, never a module's name), it
|
||||
// creates, updates, reads, snapshots and deletes every module's bus state under that module's names only, each stream
|
||||
// by its name (a key-value bucket's and an object store's by the stream the bus keeps it in), and serves the seat's
|
||||
// eight verbs. No other account holds the four acting verbs' subjects, the tool runner's included: each is denied to
|
||||
// every principal whose publish would reach it, and only the bus module's process subscribes to them.
|
||||
//
|
||||
// The names are one rule (BusStateStreams), read by the bus module where it creates them: until mesh-sdk carries it
|
||||
// as one function (asked of the mesh-sdk member of the milestone), this is the grants part's side of it.
|
||||
|
||||
// The verbs of the seat mesh-broker (design 25 § 12.3), until its definition is generated in mesh-contracts: the four
|
||||
// reading verbs any caller its role grants may ask, and the four acting verbs the bus module's process alone serves.
|
||||
var (
|
||||
BrokerReadingVerbs = []string{"list", "show", "check", "orphans"}
|
||||
BrokerActingVerbs = []string{"create", "apply", "recreate", "drop"}
|
||||
)
|
||||
|
||||
// BrokerVerbs are the eight.
|
||||
func BrokerVerbs() []string {
|
||||
return append(append([]string(nil), BrokerReadingVerbs...), BrokerActingVerbs...)
|
||||
}
|
||||
|
||||
// brokerSeat is the seat mesh-broker as its verbs' subjects name it: held once, for the mesh.
|
||||
var brokerSeat = Seat{Name: catalogue.BrokerSeat}
|
||||
|
||||
// BrokerVerbSubjects are where the seat's verbs are asked: each verb's tool subject, and its caller-named form (issue
|
||||
// 365).
|
||||
func BrokerVerbSubjects(verbs []string) []string {
|
||||
var out []string
|
||||
for _, v := range verbs {
|
||||
out = append(out, seatToolSubject(brokerSeat, v, ""), seatSubject(brokerSeat, CallKind, v)+".>")
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// BrokerActingOnly are the subjects of the seat's acting verbs, which no principal publishes on, however wide its
|
||||
// grant: the bus module's process serves them, and a person's ask reaches it on its own tool subject instead
|
||||
// (design 25 § 12.3).
|
||||
func BrokerActingOnly() []string { return BrokerVerbSubjects(BrokerActingVerbs) }
|
||||
|
||||
// BusStateStreams are the streams one bus-state entry of module is kept in on the bus, by the mesh's names
|
||||
// `<module>_<local>` (design 25 § 12.1): a stream's own; a key-value bucket's KV_ stream; an object store's OBJ_
|
||||
// stream; a ledger's history stream, its snapshot stream, and its state and index buckets' KV_ streams. A name that is
|
||||
// not one plain subject token names nothing.
|
||||
func BusStateStreams(module string, e catalogue.BusStateEntry) []string {
|
||||
base := module + "_" + e.Name
|
||||
if !safeSubject.MatchString(base) || strings.Contains(e.Name, "_") || strings.Contains(module, "_") {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
switch e.Storage {
|
||||
case catalogue.StorageKeyValue:
|
||||
out = []string{"KV_" + base}
|
||||
case catalogue.StorageObjectStore:
|
||||
out = []string{"OBJ_" + base}
|
||||
case catalogue.StorageLedger:
|
||||
out = []string{base, base + "_snapshot", "KV_" + base + "_state"}
|
||||
for _, t := range e.Types {
|
||||
for _, ix := range t.Indexes {
|
||||
if safeSubject.MatchString(ix.Name) {
|
||||
out = append(out, "KV_"+base+"_index-"+ix.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
out = []string{base}
|
||||
}
|
||||
sort.Strings(out)
|
||||
return slices.Compact(out)
|
||||
}
|
||||
|
||||
// BusStateNames are every stream the bus module's process may define: those of every entry a manifest asks for now
|
||||
// (asked), and those the bus module said it created and has not dropped (bound, by module: names of streams), so an
|
||||
// orphan whose manifest left the trunk can still be dropped. Sorted, once each.
|
||||
func BusStateNames(asked map[string][]catalogue.BusStateEntry, bound map[string][]string) []string {
|
||||
var out []string
|
||||
for module, entries := range asked {
|
||||
for _, e := range entries {
|
||||
out = append(out, BusStateStreams(module, e)...)
|
||||
}
|
||||
}
|
||||
for _, names := range bound {
|
||||
for _, n := range names {
|
||||
if safeSubject.MatchString(n) {
|
||||
out = append(out, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(out)
|
||||
return slices.Compact(out)
|
||||
}
|
||||
|
||||
// busStateKeeperGrants are what the bus module's process publishes to keep the bus state named: each stream's create,
|
||||
// update, information, deletion and snapshot, and the stream list it finds orphans in.
|
||||
func busStateKeeperGrants(names []string) []string {
|
||||
out := []string{"$JS.API.STREAM.NAMES", "$JS.API.STREAM.LIST"}
|
||||
for _, n := range names {
|
||||
for _, op := range []string{"CREATE", "UPDATE", "INFO", "DELETE", "SNAPSHOT"} {
|
||||
out = append(out, "$JS.API.STREAM."+op+"."+n)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// keepsBusState is the bus module's process defining one of the bus-state streams it keeps: the writers table's
|
||||
// exemption from stream definitions being the grants part's (ADR 0595 §4).
|
||||
func keepsBusState(p Principal, pattern string) bool {
|
||||
if p.Kind != KindProcess || len(p.KeepsBusState) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, op := range []string{"CREATE", "UPDATE", "DELETE"} {
|
||||
if name, ok := strings.CutPrefix(pattern, "$JS.API.STREAM."+op+"."); ok {
|
||||
return slices.Contains(p.KeepsBusState, name)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -110,6 +110,11 @@ type Principal struct {
|
||||
// Ledgers are the local names of the ledgers its module asks for in `requires`, for a KindLedger principal alone
|
||||
// (issue 1966 D5): its whole authority is publishing on those ledgers' histories and snapshots (LedgerPublishGrants).
|
||||
Ledgers []string
|
||||
// ServesBroker says this is the process of the module holding mesh-broker, the bus module's own (busstate.go, ADR
|
||||
// 0595 §4, §5): it serves the seat's eight verbs, and KeepsBusState are the streams it defines, every module's bus
|
||||
// state by its name.
|
||||
ServesBroker bool
|
||||
KeepsBusState []string
|
||||
// Process is the process resource's id, for a KindProcess principal alone (novox/hq ADR 0436 §2):
|
||||
// Username and inbox are <node>.<module>.<process id>.
|
||||
Process string
|
||||
@@ -894,8 +899,11 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
"$JS.API.CONSUMER.INFO."+consumerStream(p)+"."+consumerDurable(p),
|
||||
"$JS.API.CONSUMER.MSG.NEXT."+consumerStream(p)+"."+consumerDurable(p))
|
||||
|
||||
// 3. Seats it holds: full participation.
|
||||
// 3. Seats it holds: full participation. But mesh-broker's verbs, which its module's process serves (busstate.go).
|
||||
for _, s := range p.Holds {
|
||||
if s.Name == catalogue.BrokerSeat {
|
||||
s.Serves = nil
|
||||
}
|
||||
if s.isNewTraffic() {
|
||||
// Composed by SeatTrafficOf below, worker and all; only its tools are served here.
|
||||
for _, t := range s.Serves {
|
||||
@@ -991,6 +999,10 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
// And its own streams' events (novox/hq ADR 0363 §2).
|
||||
pub = append(pub, ownStreamGrants(d.Module, d.Streams)...)
|
||||
for _, s := range d.Holds {
|
||||
// mesh-broker's verbs are its holder's process's, never the runtime's (busstate.go).
|
||||
if s.Name == catalogue.BrokerSeat {
|
||||
continue
|
||||
}
|
||||
for _, t := range s.Serves {
|
||||
sub = append(sub, seatToolSubject(s, t, p.Node))
|
||||
}
|
||||
@@ -1157,6 +1169,13 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// And the seat mesh-broker's acting verbs to every principal whose grant reaches them (ADR 0595 §5): served by the bus
|
||||
// module's process alone, asked by nobody on the bus.
|
||||
for _, only := range BrokerActingOnly() {
|
||||
if slices.ContainsFunc(pub, func(a string) bool { return SubjectsOverlap(a, only) }) {
|
||||
deny = append(deny, only)
|
||||
}
|
||||
}
|
||||
// And the vault's enrolment verbs to every principal but mesh-enrolment's (novox/hq ADR 0587 §1).
|
||||
if p.VaultEnrols && !((p.Kind == KindModule || p.Kind == KindProcess) && p.Module == delivery.EnrolmentModule) {
|
||||
for _, only := range EnrolmentOnly() {
|
||||
@@ -1177,7 +1196,7 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
// provisioner client is asked by its own machine's tool runner alone, on its own machine's subject (novox/hq
|
||||
// ADR 0370 §3), and answers that. A person is never asked anything, and is granted nothing here.
|
||||
AllowResponses: p.Kind == KindModule || p.Kind == KindNodeTools || p.Kind == KindNode ||
|
||||
p.Kind == KindProvisioner,
|
||||
p.Kind == KindProvisioner || (p.Kind == KindProcess && p.ServesBroker),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -52,5 +52,12 @@ func processGrants(p Principal) (pub, sub []string, err error) {
|
||||
}
|
||||
pub = append(pub, invoked...)
|
||||
|
||||
// 6. The bus module's process (busstate.go, ADR 0595 §4, §5): every module's bus state it keeps, by name, and the
|
||||
// seat mesh-broker's eight verbs it serves.
|
||||
if p.ServesBroker {
|
||||
pub = append(pub, busStateKeeperGrants(p.KeepsBusState)...)
|
||||
sub = append(sub, BrokerVerbSubjects(BrokerVerbs())...)
|
||||
}
|
||||
|
||||
return pub, sub, nil
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -131,6 +131,8 @@ type ProcessPrincipal struct {
|
||||
// Invokes are the tools and seat verbs this process calls, each <module>.<tool> or a role's
|
||||
// seat:<seat>.<verb>, or * for every tool on the mesh.
|
||||
Invokes []string
|
||||
// Tools says it is a tools bundle's account, run by the node's tool runtime, not a process the node runs.
|
||||
Tools bool
|
||||
}
|
||||
|
||||
// Records is what composing a user list needs to know about the mesh, and nothing more.
|
||||
@@ -164,6 +166,11 @@ type Records struct {
|
||||
// Announced is each module's last announcement of the states it keeps (novox/hq ADR 0495, issue 1790), as the
|
||||
// controller keeps it; a module absent has announced nothing yet. Nil where none was read.
|
||||
Announced map[string]announce.States
|
||||
// BusState is every bus-state entry each manifest asks for in `requires`, by module, and Bound the streams of each
|
||||
// entry the bus module said it created and has not dropped, by module: what the bus module's process may define
|
||||
// (busstate.go, ADR 0595 §4).
|
||||
BusState map[string][]catalogue.BusStateEntry
|
||||
Bound map[string][]string
|
||||
}
|
||||
|
||||
// Users is every user the composed file should contain, in the order it will be written.
|
||||
@@ -232,6 +239,11 @@ func Users(r Records) ([]Principal, error) {
|
||||
Emits: pr.Emits, Queues: pr.Queues, State: pr.State, Uses: d.Uses, Asks: pr.Asks,
|
||||
Invokes: pr.Invokes, Removes: pr.Removes,
|
||||
})
|
||||
// The process of the module holding mesh-broker keeps every module's bus state (busstate.go, ADR 0595 §4).
|
||||
if d.SnapshotsTheBus && !pr.Tools && len(pr.Removes) == 0 {
|
||||
out[len(out)-1].ServesBroker = true
|
||||
out[len(out)-1].KeepsBusState = BusStateNames(r.BusState, r.Bound)
|
||||
}
|
||||
// The ended controller's leftovers include each node's declaration files' bucket (ADR 0590 clause 6).
|
||||
if slices.Contains(pr.Removes, catalogue.RemovesControllerLeftovers) {
|
||||
out[len(out)-1].FilesFor = sortedCopy(r.Nodes)
|
||||
|
||||
@@ -40,7 +40,7 @@ type WriterRow struct {
|
||||
// update or a delete (novox/hq ADR 0547 §5; the operator, 2026-10-26 08:54); or the bus module's tools deleting one of
|
||||
// the ended controller's leftover streams (ADR 0590 clause 6).
|
||||
func createsDeclared(p Principal, pattern string) bool {
|
||||
if removesLeftover(p, pattern) {
|
||||
if removesLeftover(p, pattern) || keepsBusState(p, pattern) {
|
||||
return true
|
||||
}
|
||||
name, ok := strings.CutPrefix(pattern, "$JS.API.STREAM.CREATE.")
|
||||
@@ -151,7 +151,7 @@ var WritersTable = []WriterRow{
|
||||
Subjects: []string{"$JS.API.STREAM.CREATE.>", "$JS.API.STREAM.UPDATE.>", "$JS.API.STREAM.DELETE.>",
|
||||
"$JS.API.CONSUMER.DURABLE.CREATE.>"},
|
||||
Writes: createsDeclared,
|
||||
Shared: "the grants part creates a stream a manifest declares, by its name, and never updates or deletes one (novox/hq ADR 0547 §5; the operator, 2026-10-26 08:54); the bus module's tools account deletes the ended controller's leftover streams, each by its name, and no other (novox/hq ADR 0590 clause 6)"},
|
||||
Shared: "the grants part creates a stream a manifest declares, by its name, and never updates or deletes one (novox/hq ADR 0547 §5; the operator, 2026-10-26 08:54); the bus module's tools account deletes the ended controller's leftover streams, each by its name, and no other (novox/hq ADR 0590 clause 6); the bus module's process creates, updates and deletes every module's bus state, each stream by its name (novox/hq ADR 0595 §4)"},
|
||||
{State: "builds and their outcomes", Writer: "the build seat's holder", KeptIn: "its own state",
|
||||
Others: "the builder asks",
|
||||
Subjects: []string{"mesh.seat.mesh-build-machine.event.built"},
|
||||
|
||||
@@ -196,3 +196,52 @@ func OwnHears(s Store, node string) ([]membership.HeardIssued, error) {
|
||||
}
|
||||
return m.Hears, nil
|
||||
}
|
||||
|
||||
// boundStreams are, by module, the streams on the bus of every binding kept (BoundKey): what the bus module's process
|
||||
// may still define, an orphan's among them (buscompose.BusStateNames).
|
||||
func (p *Part) boundStreams() (map[string][]string, error) {
|
||||
keys, err := p.Store.Keys(StateMemberships)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("its own %s cannot be listed: %w", StateMemberships, err)
|
||||
}
|
||||
out := map[string][]string{}
|
||||
for _, key := range keys {
|
||||
module, ok := strings.CutPrefix(key, BoundPrefix)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
b, err := p.bound(module)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, bind := range b.Bindings {
|
||||
out[module] = append(out[module], bindingStreams(bind)...)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// bindingStreams are the streams on the bus a binding names: a stream's, a bucket's KV_, an object store's OBJ_, a ledger's
|
||||
// history, its snapshot stream and its state and index buckets.
|
||||
func bindingStreams(b membership.BusBinding) []string {
|
||||
var out []string
|
||||
if b.Stream != "" {
|
||||
out = append(out, b.Stream)
|
||||
}
|
||||
if b.Bucket != "" {
|
||||
out = append(out, "KV_"+b.Bucket)
|
||||
}
|
||||
if b.ObjectStore != "" {
|
||||
out = append(out, "OBJ_"+b.ObjectStore)
|
||||
}
|
||||
if b.History != "" {
|
||||
out = append(out, b.History, b.History+"_snapshot")
|
||||
}
|
||||
if b.State != "" {
|
||||
out = append(out, "KV_"+b.State)
|
||||
}
|
||||
for _, ix := range b.Indexes {
|
||||
out = append(out, "KV_"+ix)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -107,6 +107,9 @@ type Inputs struct {
|
||||
Placed map[string]delivery.Placement
|
||||
// Manifests is each module's manifest at the indexer's trunk, by module.
|
||||
Manifests map[string]catalogue.Manifest
|
||||
// Bound is, by module, the streams of each bus-state entry the bus module said it created and has not dropped, from
|
||||
// the part's own state memberships (bindings.go): set by the pass, never read from another part.
|
||||
Bound map[string][]string
|
||||
// Digests is each module's manifest digest, by module.
|
||||
Digests map[string]string
|
||||
// Fingerprints is the fingerprint of the new form the indexer's trunk value names for each module, by module: what a
|
||||
|
||||
@@ -268,6 +268,11 @@ func (p *Part) Compose() Result {
|
||||
}()
|
||||
in := ReadInputs(p.Read, &p.cache)
|
||||
p.keepBrokers(in)
|
||||
if bound, err := p.boundStreams(); err != nil {
|
||||
res.Errors = append(res.Errors, err.Error())
|
||||
} else {
|
||||
in.Bound = bound
|
||||
}
|
||||
for _, g := range in.Refused {
|
||||
res.Refused = append(res.Refused, g.Input+": "+g.Why)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,14 @@ func records(in Inputs, union bool) (buscompose.Records, []Gap) {
|
||||
out := buscompose.Records{Assigned: map[string][]buscompose.Declared{}, People: map[string][]string{},
|
||||
Interchangeable: map[string]bool{}, Enrolling: slices.Clone(in.Enrolling),
|
||||
// And each node's logins (ADR 0583 §1): both while it rotates.
|
||||
NodeLogins: in.NodeLogins}
|
||||
NodeLogins: in.NodeLogins,
|
||||
// What the bus module's process may define: every manifest's bus state, and what it said it created (DLV-G2).
|
||||
BusState: map[string][]catalogue.BusStateEntry{}, Bound: in.Bound}
|
||||
for module, m := range in.Manifests {
|
||||
if len(m.BusState) > 0 {
|
||||
out.BusState[module] = m.BusState
|
||||
}
|
||||
}
|
||||
values := func(provider, setting string) []any {
|
||||
var vs []any
|
||||
for _, node := range in.Nodes {
|
||||
@@ -370,7 +377,7 @@ func processesOf(m catalogue.Manifest) []buscompose.ProcessPrincipal {
|
||||
// what it may remove from the bus (ADR 0564 Limits 4, issue 1952 S5).
|
||||
for _, a := range accounts {
|
||||
pr := buscompose.ProcessPrincipal{Process: a.ID, Emits: a.Bus.Emits, State: a.Bus.State, Asks: a.Bus.Asks,
|
||||
Invokes: a.Bus.Invokes, Removes: a.Bus.Removes}
|
||||
Invokes: a.Bus.Invokes, Removes: a.Bus.Removes, Tools: a.Tools}
|
||||
for _, q := range queues {
|
||||
if q.Process == a.ID {
|
||||
pr.Queues = append(pr.Queues, q)
|
||||
|
||||
Reference in New Issue
Block a user