delivery, catalogue: the node-engine's compose-candidate verb, compositions carrying their plan or refusal, the kept import form and a build's imports on its key, so the engine alone composes and the indexer switches form without a rebuild (ADR 0593 §4, §6, §7)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/declaration"
|
||||
)
|
||||
|
||||
@@ -46,6 +47,15 @@ type Composed struct {
|
||||
Resources []json.RawMessage
|
||||
Filled []string
|
||||
Own NodeOwn
|
||||
// Plan is the module's whole provisioning plan as the node-engine hands it to the provisioner (templates, files,
|
||||
// own secrets by name, items, collections, provisions; never a value), composed node-wide (novox/hq ADR 0593 §6,
|
||||
// §8): the provisioner makes every plan from it. Nil when the module hands the provisioner nothing; only on a
|
||||
// module's key. It is part of the encoding, so the digest moves when the plan does.
|
||||
Plan *catalogue.Plan
|
||||
// Refused is why the module cannot be composed at this fingerprint on this node, the rest of the node composed
|
||||
// (ADR 0593 §6): a refused composition holds no resource, filled file, data or plan, and has no digest
|
||||
// (ComposedDigestOf refuses it); only on a module's key. The node keeps running what it ran of the module.
|
||||
Refused string
|
||||
// Signature is the controller's or, made by hand, the operator's (ADR 0539 clause 3, SignComposed); it signs the
|
||||
// digest and is never part of it.
|
||||
Signature *Signature
|
||||
@@ -61,6 +71,8 @@ type composedWire struct {
|
||||
Resources []json.RawMessage `json:"resources"`
|
||||
Filled []string `json:"filled_files,omitempty"`
|
||||
Own *NodeOwn `json:"own,omitempty"`
|
||||
Plan *catalogue.Plan `json:"plan,omitempty"`
|
||||
Refused string `json:"refused,omitempty"`
|
||||
Signature *Signature `json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
@@ -99,6 +111,12 @@ func (c Composed) check() error {
|
||||
return fmt.Errorf("delivery: the composition of %s carries the node's own parts, which only <node>.node carries", c.Module)
|
||||
}
|
||||
}
|
||||
if c.Module == "" && (c.Plan != nil || c.Refused != "") {
|
||||
return fmt.Errorf("delivery: the node's own composition carries no plan and no refusal: only a module's does")
|
||||
}
|
||||
if c.Refused != "" && (len(c.Resources) > 0 || len(c.Filled) > 0 || c.Data || c.Plan != nil) {
|
||||
return fmt.Errorf("delivery: the composition of %s on %s is refused and holds resources, filled files, data or a plan", c.Module, c.Node)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
files := map[string][]*declaration.File{}
|
||||
for _, raw := range c.Resources {
|
||||
@@ -166,7 +184,7 @@ func (c Composed) wire() (composedWire, error) {
|
||||
return composedWire{}, err
|
||||
}
|
||||
w := composedWire{V: Version, Node: c.Node, Module: c.Module, FP: c.FP, Data: c.Data, Filled: c.Filled,
|
||||
Signature: c.Signature, Resources: make([]json.RawMessage, len(c.Resources))}
|
||||
Plan: c.Plan, Refused: c.Refused, Signature: c.Signature, Resources: make([]json.RawMessage, len(c.Resources))}
|
||||
for i, r := range c.Resources {
|
||||
canon, err := canonicalJSON(r)
|
||||
if err != nil {
|
||||
@@ -205,7 +223,7 @@ func DecodeComposed(data []byte) (Composed, error) {
|
||||
return Composed{}, fmt.Errorf("delivery: a composition does not fit its shape: %w", err)
|
||||
}
|
||||
c := Composed{V: w.V, Node: w.Node, Module: w.Module, FP: w.FP, Data: w.Data, Resources: w.Resources,
|
||||
Filled: w.Filled, Signature: w.Signature}
|
||||
Filled: w.Filled, Plan: w.Plan, Refused: w.Refused, Signature: w.Signature}
|
||||
if w.Own != nil {
|
||||
c.Own = *w.Own
|
||||
}
|
||||
@@ -217,7 +235,12 @@ func DecodeComposed(data []byte) (Composed, error) {
|
||||
|
||||
// ComposedDigestOf is a composition's digest, "sha256:<hex>", of its encoding without its signature. A want names it
|
||||
// (ADR 0539 clause 1), the controller writes it beside the composition, and the signature signs it.
|
||||
//
|
||||
// A refused composition has no digest: it is refused, naming the module (ADR 0593 §6).
|
||||
func ComposedDigestOf(c Composed) (string, error) {
|
||||
if c.Refused != "" {
|
||||
return "", fmt.Errorf("delivery: the composition of %s on %s is refused (%s) and has no digest", c.Module, c.Node, c.Refused)
|
||||
}
|
||||
c.Signature = nil
|
||||
raw, err := EncodeComposed(c)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user