Follow L2 under L3: the vault and mesh-config read the seat mesh-placement's placement, and the check that only listed modules read the controller's assignments moves into noplacement, as L2 deleted the placement check (issue 774, ADR 0567, ADR 0549 §3, §6)

This commit is contained in:
2026-10-28 21:54:36 +01:00
parent 24fad2b92a
commit 5be6576117
17 changed files with 139 additions and 31 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ account alone writes its buckets.
## How a value resolves
For every module the catalogue's placement puts on a node (`mesh-delivery-indexer.placement`, ADR 0549 §3), from the
For every module the seat mesh-placement's placement puts on a node (`mesh-delivery-assigner.placement`, ADR 0567), from the
controller's mirror of each module's declarations (`mesh-controller.declared-config`): the manifest's default; mesh config for the predefined key the value falls back
to; node config for that key on the node; the module's own value on that node, the most specific winning. A value
naming no predefined key resolves from its default and the module's own value only (ADR 0348 §2). It resolves at
@@ -121,13 +121,13 @@ func (m *memStore) mirror(t *testing.T, read, key, raw string) {
m.states[read][key] = []byte(raw)
}
// assign puts module on node in the catalogue's placement (ADR 0549 §3), beside what is placed there already.
// assign puts module on node in the seat's placement (ADR 0549 §3), beside what is placed there already.
func (m *memStore) assign(t *testing.T, node, module string) {
t.Helper()
m.place(t, node, func(modules []string) []string { return append(modules, module) })
}
// unassign takes module off node in the catalogue's placement.
// unassign takes module off node in the seat's placement.
func (m *memStore) unassign(t *testing.T, node, module string) {
t.Helper()
m.place(t, node, func(modules []string) []string {
@@ -592,7 +592,7 @@ func TestTheVerbsArgumentsAreReadStrictly(t *testing.T) {
}
}
// Issue 774 (ADR 0549 §3, §5): the catalogue's placement alone says where modules stand. Before any node's placement
// Issue 774 (ADR 0549 §3, §5): the seat's placement alone says where modules stand. Before any node's placement
// is read nothing is resolved anew and what is resolved stays; a placement that does not read resolves nothing on its
// node, said.
func TestThePlacementAloneSaysWhereValuesResolve(t *testing.T) {
@@ -121,7 +121,7 @@ type Published struct {
Commit string `json:"commit"`
}
// Assignment is a module the catalogue's placement puts on a node (ADR 0549 §3): what a resolution resolves values for.
// Assignment is a module the seat's placement puts on a node (ADR 0549 §3): what a resolution resolves values for.
type Assignment struct {
Node string
Module string
@@ -2,7 +2,7 @@ package main
import "testing"
// 1126 (ADR 0549 §3), issue 774: a module the catalogue's placement names on a node resolves there; it goes when the
// 1126 (ADR 0549 §3), issue 774: a module the seat's placement names on a node resolves there; it goes when the
// placement no longer names it. A module another pulls in is placed in its own right (the seed placed what runs).
func TestAModulePlacedHasItsValuesResolvedOnItsNode(t *testing.T) {
c, m := aMesh(t)
@@ -122,10 +122,10 @@ type Resolved struct {
// ResolvedKey is a resolved value's key in mesh-config_resolved.
func ResolvedKey(node, module, key string) string { return node + "." + module + "." + key }
// Sources is everything a resolution reads: where modules stand (the catalogue's placement), every module's
// Sources is everything a resolution reads: where modules stand (the seat's placement), every module's
// declarations, the published list of predefined keys, and every value set.
type Sources struct {
// Assignments is every module the catalogue's placement puts on a node (ADR 0549 §3), and Placed whether any node's
// Assignments is every module the seat's placement puts on a node (ADR 0549 §3), and Placed whether any node's
// placement was read: without one nothing is resolved anew.
Assignments []Assignment
Placed bool
+1 -1
View File
@@ -140,7 +140,7 @@ func watchWants(env *Env) bool {
return true
}
// placement reads the indexer's placement through the runtime under the vault's own account (its manifest reads it).
// placement reads the seat mesh-placement's placement through the runtime under the vault's own account (its manifest reads it).
var placement = PlacementReader{
Keys: func() ([]string, error) { return stdio.State(PlacementRead).Keys() },
Read: func(key string) ([]byte, error) {
@@ -317,7 +317,7 @@ func TestTheVaultWholeMintsOnTheBusOnlyFromTheLeaseWrite(t *testing.T) {
t.Fatal(err)
}
for _, b := range []string{"mesh-vault_bus-accounts", "mesh-grants_accounts", "mesh-controller_lease",
"mesh-controller_assignments", "node-engine_have", "mesh-delivery-indexer_placement"} {
"mesh-controller_assignments", "node-engine_have", "mesh-delivery-assigner_placement"} {
if _, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: b, History: 2}); err != nil {
t.Fatal(err)
}
+6 -6
View File
@@ -1,8 +1,8 @@
package main
// Where modules stand, from the catalogue's placement (novox/hq ADR 0549 §3, §5; ADR 0561; issue 774). The controller's
// assignments mirror goes with its lease, so the vault reads which module stands on which node from the indexer's
// placement first, and the assignments beside it while both stand: a module either names stands. The provisioner's plan,
// Where modules stand, from the placement (novox/hq ADR 0549 §3, §5; ADR 0561; issue 774), the seat mesh-placement's
// state held by the assigner (ADR 0567). The controller's assignments mirror goes with its lease, so the vault reads which
// module stands on which node from the seat's placement first, and the assignments beside it while both stand: a module either names stands. The provisioner's plan,
// which only an assignment's value carries, is read from the assignments still: its home after the lease is a subtask of
// its own (issue 774).
@@ -16,10 +16,10 @@ import (
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// PlacementRead is the indexer's placement, as the vault's manifest reads it.
const PlacementRead = delivery.IndexerModule + "." + delivery.PlacementState
// PlacementRead is the seat mesh-placement's placement, as the vault's manifest reads it (mesh-sdk's contract).
const PlacementRead = delivery.PlacementRead
// PlacementReader reads the indexer's placement: every key, and one key's value (nil when there is none).
// PlacementReader reads the seat's placement: every key, and one key's value (nil when there is none).
type PlacementReader struct {
Keys func() ([]string, error)
Read func(key string) ([]byte, error)
@@ -7,7 +7,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// placementsOf is the indexer's placement of each node, as the vault reads it.
// placementsOf is the seat mesh-placement's placement of each node, as the vault reads it.
func placementsOf(t *testing.T, nodes map[string][]string) PlacementReader {
t.Helper()
values := map[string][]byte{}
@@ -35,7 +35,7 @@ func placementsOf(t *testing.T, nodes map[string][]string) PlacementReader {
}
}
// 774/AC11 (novox/hq ADR 0561, ADR 0549 §3, §5): with no assignments to read, the vault tells from the catalogue's
// 774/AC11 (novox/hq ADR 0561, ADR 0549 §3, §5): with no assignments to read, the vault tells from the seat's
// placement which node holds the bus and whether a consumer's module stands on its node; while both stand, a module
// either names stands.
func TestTheVaultReadsWhereModulesStandFromPlacement(t *testing.T) {
@@ -47,15 +47,15 @@ func TestTheVaultReadsWhereModulesStandFromPlacement(t *testing.T) {
asked := func(node, module string) CredentialAsked {
return CredentialAsked{Role: "consumer", Provision: "postgres", Consumer: node, ConsumerModule: module, Provider: "novox"}
}
if why := v.credentialRefusal("ace", asked("ace", "shop")); why != "" {
if why := v.credentialRefusal("ace", asked("ace", "shop"), v.plansOf("ace")); why != "" {
t.Errorf("shop stands on ace by placement, refused: %s", why)
}
if why := v.credentialRefusal("ace", asked("ace", "web")); !strings.Contains(why, "is not on ace") {
if why := v.credentialRefusal("ace", asked("ace", "web"), v.plansOf("ace")); !strings.Contains(why, "is not on ace") {
t.Errorf("web is not placed on ace, and is answered %q", why)
}
// While both stand, an assignment still names a module placement does not yet.
v.Askers = Declared{Read: assignments{"ace.web": `{"node":"ace","module":"web"}`}.read, Store: v.Store}
if why := v.credentialRefusal("ace", asked("ace", "web")); why != "" {
if why := v.credentialRefusal("ace", asked("ace", "web"), v.plansOf("ace")); why != "" {
t.Errorf("web assigned on ace, refused: %s", why)
}
// Two nodes placed with the bus: the vault adopts from neither.
+1 -1
View File
@@ -312,7 +312,7 @@ func (v *Vault) internalName(node string) (string, error) {
return "", fmt.Errorf(notYetPrefix+"the placement of %s could not be read: %w", node, err)
}
if raw == nil {
return "", fmt.Errorf("%s has no placement in the catalogue, so it has no name inside the mesh", node)
return "", fmt.Errorf("%s has no placement of the seat mesh-placement, so it has no name inside the mesh", node)
}
p, err := delivery.DecodePlacement(raw)
if err != nil {
+1 -1
View File
@@ -64,7 +64,7 @@ type Vault struct {
adoption adoptionKept
// WantRead reads one wanted account afresh (issue-account): nil reads the wants as the watch handed them.
WantRead func(user string) ([]byte, bool, error)
// Placement reads the catalogue's placement (placed.go): where modules stand once the assignments are gone.
// Placement reads the seat's placement (placed.go): where modules stand once the assignments are gone.
Placement PlacementReader
// LeaseRead reads the controller's lease afresh before a mint (lease.go): nil reads it only as the watch hands it.
LeaseRead func() ([]byte, bool, error)
@@ -134,7 +134,7 @@ func filesUnder(t *testing.T, dir string) map[string]string {
// (ADR 0547 clause 9), opened in accounts.go alone. It reads five buckets of others', and only reads them: the
// controller's assignments, for what each node's plan names (askers.go, design 57 V4), the node-engines' haves, where
// the bus node hands the loaded list's hashes sealed to the vault (adopt.go, ADR 0547 clause 9), the grants part's wanted
// accounts and the controller's lease (mint.go, lease.go, ADR 0561 §2, §3), and the catalogue's placement (placed.go), in
// accounts and the controller's lease (mint.go, lease.go, ADR 0561 §2, §3), and the seat's placement (placed.go), in
// main.go alone.
func TestNoBucketHoldsASecret(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
@@ -149,7 +149,7 @@ func TestNoBucketHoldsASecret(t *testing.T) {
t.Errorf("the manifest declares buckets %s: a secret is in no bucket, sealed or not (ADR 0201 §13), and the "+
"buckets are the accounts' hashes (ADR 0547 clause 9) and the signing keys' public halves (ADR 0550 §2)", s)
}
if r, _ := json.Marshal(manifest["reads"]); string(r) != `["mesh-controller.assignments","node-engine.have","mesh-grants.accounts","mesh-controller.lease","mesh-delivery-indexer.placement"]` {
if r, _ := json.Marshal(manifest["reads"]); string(r) != `["mesh-controller.assignments","node-engine.have","mesh-grants.accounts","mesh-controller.lease","mesh-delivery-assigner.placement"]` {
t.Errorf("the manifest reads %s: the vault reads the controller's assignments, the haves and the grants part's "+
"wanted accounts alone", r)
}
@@ -189,7 +189,7 @@ func TestNoBucketHoldsASecret(t *testing.T) {
// And the controller's lease, one read and one watch (ADR 0561 §3).
code = []byte(strings.Replace(string(code), "stdio.State(LeaseRead).Get(", "", 1))
code = []byte(strings.Replace(string(code), "stdio.State(LeaseRead).Watch(", "", 1))
// And the catalogue's placement, where modules stand (placed.go): its keys and one key, read.
// And the seat's placement, where modules stand (placed.go): its keys and one key, read.
code = []byte(strings.Replace(string(code), "stdio.State(PlacementRead).Keys(", "", 1))
code = []byte(strings.Replace(string(code), "stdio.State(PlacementRead).Get(", "", 1))
}
+1 -1
View File
@@ -25,7 +25,7 @@
"node-engine.have",
"mesh-grants.accounts",
"mesh-controller.lease",
"mesh-delivery-indexer.placement"
"mesh-delivery-assigner.placement"
],
"state": [
{