The input a node answers a check with says what holds each held module and carries its build (issue 1921, milestone 47/G H3)
A module the running indexer refused stood in the input as its stub with no build, so a check's composer that judges the change's manifest itself had nothing to compose it at. Each held module now says whether its verdict or the decoder holds it; for a check's answer the node also takes in the build it would compose it at, when the builder holds it done, beside the stub and never into what the node composes. Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -218,6 +218,26 @@ func answerNamesEveryRefusalAndLeavesAnOldBuildToTheNode(t *testing.T) {
|
||||
t.Errorf("spiegel in InOwn wanted at %s: %v, held %v, read as %s; want its build's image", sp.Fp2, err,
|
||||
read.ComposedHow, raw)
|
||||
}
|
||||
// Issue 1921: held by its manifest's verdict, spiegel is still held in what the node composes, and the input a check
|
||||
// is answered with says what holds it and carries the build the node would compose it at, taken in while done; a
|
||||
// node's own read takes in no build of it.
|
||||
sp.Verdict, sp.Problems = meshcatalogclient.VerdictRefused, []string{"p"}
|
||||
bb.modules["spiegel"] = sp
|
||||
for _, done := range []bool{true, false} {
|
||||
if !done {
|
||||
bb.builds["spiegel "+sp.Fp2].State = builds.BuildBuilding
|
||||
}
|
||||
read, err = ComposingInput(ctx, bb, Mesh{}, Scope{Node: "n1"}, map[string]string{"lemurs": fp("e"), "spiegel": sp.Fp2})
|
||||
hold := read.Holds["spiegel"]
|
||||
raw, _ = json.Marshal(hold.Built)
|
||||
if err != nil || !read.Catalogue["spiegel"].Stubbed || hold.By != compose.HeldByVerdict || hold.Build != sp.Fp2 ||
|
||||
strings.Contains(string(raw), strings.Repeat("7", 64)) != done || (hold.Built == nil) == done {
|
||||
t.Errorf("spiegel refused, its build done %v: %v, hold %+v (built %s)", done, err, hold, raw)
|
||||
}
|
||||
}
|
||||
if own, err := Input(ctx, bb, Mesh{}, Scope{Node: "n1"}); err != nil || own.Holds["spiegel"] != (compose.Hold{By: compose.HeldByVerdict}) {
|
||||
t.Errorf("a node's own read of spiegel refused: %v, hold %+v", err, own.Holds["spiegel"])
|
||||
}
|
||||
}
|
||||
|
||||
// (C) Issue 1126, C5: what the others read of a module carried as it runs is what runs, never its stub's: the filter
|
||||
|
||||
@@ -167,6 +167,10 @@ type Scope struct {
|
||||
// Kept is told, in words, each module composed as what runs shows because its manifest does not yet say it (the tool
|
||||
// runner, the core's credentials; ADR 0601 §4), so the node says it. Nil: said nowhere.
|
||||
Kept func(module, words string)
|
||||
// takeInHeld, set for the input a node answers a check with (ComposingInput), takes in the build of each module placed
|
||||
// on the node that its manifest's verdict or its decoder holds, into compose.Input.Holds, never into what the node composes: the
|
||||
// check's composer, judging the change's manifest itself, composes it at that build (issue 1921).
|
||||
takeInHeld bool
|
||||
}
|
||||
|
||||
// InOwn is, of the modules p places on its node, those whose resources the node's own composition it runs
|
||||
@@ -214,21 +218,23 @@ func Input(ctx context.Context, r Reader, mesh Mesh, s Scope) (compose.Input, er
|
||||
// taken is a module's manifest as a reader takes it (novox/hq ADR 0578 §3): decoded leniently, with the indexer's verdict
|
||||
// from its modules value. A refused one, or bytes that do not decode, stands as its stub (unusable) and why says so; a
|
||||
// manifest not read past a field it set aside holds its name alone and is held the same.
|
||||
func taken(name string, raw []byte, m meshcatalog.ModulesByModuleValue) (man catalogue.Manifest, why string) {
|
||||
//
|
||||
// by is what holds it (compose.HeldByVerdict or compose.HeldByDecoder), empty when nothing does.
|
||||
func taken(name string, raw []byte, m meshcatalog.ModulesByModuleValue) (man catalogue.Manifest, why, by string) {
|
||||
if v := meshcatalogclient.ModuleVerdict(name, m); v != nil {
|
||||
if refused, _ := meshcatalogclient.TakeVerdict(v); refused {
|
||||
return unusable(name, raw), meshcatalogclient.VerdictWhy(*v)
|
||||
return unusable(name, raw), meshcatalogclient.VerdictWhy(*v), compose.HeldByVerdict
|
||||
}
|
||||
}
|
||||
man, err := catalogue.Decode(raw)
|
||||
switch {
|
||||
case err != nil:
|
||||
return unusable(name, raw), fmt.Sprintf("the manifest of %s does not decode: %v", name, err)
|
||||
return unusable(name, raw), fmt.Sprintf("the manifest of %s does not decode: %v", name, err), compose.HeldByDecoder
|
||||
case man.ReadNoFurther():
|
||||
return unusable(name, raw), fmt.Sprintf("the manifest of %s could not be read past a field this reader does not "+
|
||||
"know: %s", name, man.SetAside())
|
||||
"know: %s", name, man.SetAside()), compose.HeldByDecoder
|
||||
}
|
||||
return man, ""
|
||||
return man, "", ""
|
||||
}
|
||||
|
||||
// input is Input; with refuse set, a module placed on the composing node whose build cannot be read or taken in, or whose
|
||||
@@ -374,9 +380,13 @@ func readBase(ctx context.Context, r Reader, mesh Mesh, s Scope) (base, error) {
|
||||
// follows (issue 774: power's bar item refused every node's composition, 2026-10-30; ADR 0578 §3: one refused
|
||||
// manifest silenced disk-load for 45 hours). It stands in as its stub, so what it provides and requires still
|
||||
// shapes the rest; it is held on the composing node where it is placed there, and elsewhere only its offer is read.
|
||||
man, why := taken(name, raw, m)
|
||||
man, why, by := taken(name, raw, m)
|
||||
if why != "" {
|
||||
named(&in.Refused, name, why)
|
||||
if in.Holds == nil {
|
||||
in.Holds = map[string]compose.Hold{}
|
||||
}
|
||||
in.Holds[name] = compose.Hold{By: by}
|
||||
if ownPlaced[name] {
|
||||
b.ownRefused = append(b.ownRefused, [2]string{name, why})
|
||||
}
|
||||
@@ -600,6 +610,7 @@ func Compose(ctx context.Context, r Reader, mesh Mesh, s Scope, fps map[string]s
|
||||
// credential: the sandbox composes no pair value.
|
||||
func ComposingInput(ctx context.Context, r Reader, mesh Mesh, s Scope, fps map[string]string) (compose.Input, error) {
|
||||
held := map[string]string{}
|
||||
s.takeInHeld = true
|
||||
in, err := input(ctx, r, mesh, s, func(module string, err error) { held[module] = err.Error() }, fps)
|
||||
if err != nil {
|
||||
return compose.Input{}, err
|
||||
@@ -909,7 +920,23 @@ func fromBuilds(ctx context.Context, r Reader, build func(ctx context.Context, m
|
||||
continue
|
||||
}
|
||||
if _, refused := in.Refused[pm.Module]; refused {
|
||||
continue // held as its stub: no build of a refused manifest is taken in (ADR 0578 §3)
|
||||
// Held as its stub: no build of a refused manifest is composed (ADR 0578 §3). For a check, the build the node
|
||||
// would compose it at is said beside it, and taken in when done, for the check's composer alone.
|
||||
if hold, said := in.Holds[pm.Module]; s.takeInHeld && said {
|
||||
hold.Build = m.Fp2
|
||||
if w := wanted[pm.Module]; w != "" {
|
||||
hold.Build = w
|
||||
}
|
||||
// Its stub names no build, so the builder is asked: a build not done, or not taken in, is awaited.
|
||||
if b, err := build(ctx, pm.Module, hold.Build); err == nil && b != nil && b.State == builds.BuildDone {
|
||||
if resolved, err := built(pm.Module, hold.Build, b); err == nil {
|
||||
hold.Built = &resolved
|
||||
}
|
||||
}
|
||||
in.Holds = maps.Clone(in.Holds)
|
||||
in.Holds[pm.Module] = hold
|
||||
}
|
||||
continue
|
||||
}
|
||||
if man, ok := in.Catalogue[pm.Module]; !ok || (man.Build == nil && !man.Templated()) {
|
||||
continue // nothing is built of it: its manifest is what it composes from
|
||||
|
||||
@@ -114,11 +114,36 @@ type Input struct {
|
||||
// (compose.Stub), so it is held: nothing of its own is composed, while what it provides and requires still shapes the
|
||||
// rest. A module not named is accepted, a missing verdict included.
|
||||
Refused map[string]string `json:",omitempty"`
|
||||
// Holds is, by module Refused names, what holds it and the build its node would compose it at (issue 1921): a check's
|
||||
// composer that judges the change's manifest itself (novox/hq ADR 0578 §2) composes a module refused by the running
|
||||
// indexer alone from that build, and names one whose build it is not given. Nil from a node-engine before it.
|
||||
Holds map[string]Hold `json:",omitempty"`
|
||||
// SetAside is each module whose manifest has a field the reader's decoder does not know, by module, with what was set
|
||||
// aside (catalogue.Manifest.SetAside): the rest of it is composed, and the reader names it (ADR 0578 §6).
|
||||
SetAside map[string]string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// What holds a module Refused names (Hold.By).
|
||||
const (
|
||||
// HeldByVerdict is a module the indexer's judge refused the manifest of (its verdict).
|
||||
HeldByVerdict = "verdict"
|
||||
// HeldByDecoder is a module whose bytes this reader's decoder does not decode, or cannot read past a field it does not
|
||||
// know: no judge of the manifest overrules it.
|
||||
HeldByDecoder = "decoder"
|
||||
)
|
||||
|
||||
// Hold is what holds one module Refused names, and the build its node would compose it at (Input.Holds).
|
||||
type Hold struct {
|
||||
// By is HeldByVerdict or HeldByDecoder.
|
||||
By string
|
||||
// Build is the fingerprint the node would compose it at, its want's or else the indexer's newest; empty where it is not
|
||||
// placed on the composing node or names no build.
|
||||
Build string `json:",omitempty"`
|
||||
// Built is its manifest as the node takes it in from that build, when the builder holds it done; nil while that build
|
||||
// is awaited (or not asked: only a node's answer to a check asks it).
|
||||
Built *catalogue.Manifest `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Issued is one pair credential made for a consumer of a provider (inv.Secret): ForProvider is its copy sealed to the
|
||||
// provider, optional.
|
||||
type Issued struct {
|
||||
|
||||
Reference in New Issue
Block a user