Send files over 64 KiB by digest through the bus's object bucket to nodes that read them, grant it, and warn at 75 percent (issues 1696, 1697, 1698; ADR 0486 step 3)

A node that reports file-references gets the digest and size of each file over 64 KiB that may travel so, and the content is put in
the bucket declaration-files before the declaration is sent; others get every content inline. The controller alone writes the
bucket and node-engines read an object by name (the four grants the node-engine's own fetch makes, no list, no write). An object
goes a day after no node's latest declaration names it. The near-limit condition warns at 75 percent, and a test holds the control
node's declaration, in the reference form, under half the bus's largest message.
This commit is contained in:
2026-10-21 15:16:11 +02:00
parent fa5b5e1c11
commit ceaa616d01
18 changed files with 1486 additions and 18 deletions
+27 -3
View File
@@ -39,6 +39,10 @@ type sendable struct {
// ReadsModules says the machine's node-engine reads a module per resource and a build per module (novox/hq issue
// 1145): only then are they sent, because an older node-engine refuses a key it does not know, whole.
ReadsModules bool
// fileReferences says the machine's node-engine reports the capability of reading a file given as a digest and a size
// (declaration.FileReferencesCapability, novox/hq ADR 0486 §5): then every file over 64 KiB that may travel so does (Body,
// objects). Not on the wire as a field; the bodies differ.
fileReferences bool
// moduleOf is the composer's owner of each resource id, and buildIDs the build each module carries (its id):
// kept beside the resources, and on the wire only to a machine that reads them.
moduleOf map[string]string
@@ -115,12 +119,16 @@ type adoptionEnvelope struct {
// Body is the declaration's bytes, as sent and as digested.
func (s sendable) Body() ([]byte, error) {
envelope := map[string]any{"declaration": 1, "resources": s.Resources}
resources, _, err := s.byReference()
if err != nil {
return nil, err
}
envelope := map[string]any{"declaration": 1, "resources": resources}
if s.ReadsModules {
// The module of each resource the composer owns (what the mesh adds of its own has none), and the build of each
// module (novox/hq issue 1145): to a machine that said it reads them, and no other.
named := make([]map[string]any, len(s.Resources))
for n, r := range s.Resources {
named := make([]map[string]any, len(resources))
for n, r := range resources {
module, owned := s.moduleOf[fmt.Sprint(r["id"])]
if !owned {
named[n] = r
@@ -165,3 +173,19 @@ func (s sendable) Body() ([]byte, error) {
}
return json.Marshal(envelope)
}
// byReference is the resources as the machine is sent them: with the contents of its large files replaced by their digests when
// it reports it reads them (issue 1696), and the contents it replaced, by the name of the object that holds each.
func (s sendable) byReference() ([]map[string]any, map[string][]byte, error) {
if !s.fileReferences {
return s.Resources, nil, nil
}
return referencing(s.Resources)
}
// objects are the contents the body names by digest, by the name of each one's object: what is put in the bucket before the
// body is sent. Empty for a machine that is sent every content inline.
func (s sendable) objects() (map[string][]byte, error) {
_, objects, err := s.byReference()
return objects, err
}