CAT-RD3: mesh-build-go asks the indexer's read tool for the manifest a compose ask names, no reads of the indexer

This commit is contained in:
2026-11-04 12:12:01 +01:00
parent f49b6de79b
commit dd120b1c90
4 changed files with 52 additions and 14 deletions
@@ -24,14 +24,16 @@ import (
"sync"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/composer"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// ManifestsState is the delivery indexer's manifests by digest, which a compose ask's request names (the module reads
// it, module.json reads).
const ManifestsState = delivery.IndexerModule + ".manifests"
// ManifestsTool is the delivery indexer's read tool of its manifests by digest, which a compose ask's request names (the
// module invokes it, module.json invokes). A manifest by its digest never changes and a compose ask is rare, so the
// module asks for the one key it needs when it needs it, and keeps no picture of the indexer's whole state (ADR 0615).
const ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests"
// composerLocks hold one mutex per composer key, so a composer two asks need at once is built once.
var composerLocks sync.Map
@@ -69,6 +71,25 @@ func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a delive
return delivery.ComposeAnswer{Built: built, Key: key, Verdict: verdict}, nil
}
// askManifest asks the indexer's read tool for one manifest by its key: nil when it keeps none.
func askManifest(key string) (json.RawMessage, error) {
raw, err := stdio.Ask(ManifestsTool, map[string]any{"key": key})
if err != nil {
return nil, err
}
var a struct {
Found bool `json:"found"`
Value json.RawMessage `json:"value"`
}
if err := json.Unmarshal(raw, &a); err != nil {
return nil, fmt.Errorf("%s answered something that is not a key's value: %w", ManifestsTool, err)
}
if !a.Found {
return nil, nil
}
return a.Value, nil
}
// manifestOf is the manifest the indexer keeps under digest, as its repository holds it.
func (m *Module) manifestOf(digest string) ([]byte, error) {
if m.ReadManifest == nil {
@@ -122,10 +122,11 @@ func TestAComposeAskFailsLoudly(t *testing.T) {
}
}
// 1622: the module reads the delivery indexer's manifests, which a compose ask names by digest.
// 1622, ADR 0615: the module asks the delivery indexer's read tool for the manifests a compose ask names by digest, and
// reads none of the indexer's state.
func TestTheModuleReadsTheIndexersManifests(t *testing.T) {
if m := readManifest(t); !slices.Contains(m.Reads, ManifestsState) {
t.Errorf("reads = %v, lacks %s", m.Reads, ManifestsState)
if m := readManifest(t); !slices.Contains(m.Invokes, ManifestsTool) || slices.Contains(m.Reads, delivery.IndexerModule+".manifests") {
t.Errorf("invokes = %v, reads = %v: it asks %s", m.Invokes, m.Reads, ManifestsTool)
}
}
@@ -57,7 +57,7 @@ func main() {
m.RegistryFile = m.Home + "/registry"
m.Settings = m.Home + "/settings.json"
m.ReadKept = readOf(stdio.State(KeptState)).Get
m.ReadManifest = readOf(stdio.State(ManifestsState)).Get
m.ReadManifest = askManifest
m.Probe = ProbeGo(m.Home, m.Cache)
m.Bubblewrap = ProbeBubblewrap
// Outside a launch by the runtime — a build, a check — there is no node and no state to write.
+23 -7
View File
@@ -10,23 +10,33 @@
"state": [
"toolchains",
"keys",
{"name": "steps", "ttl-seconds": 172800}, "pauses"
{
"name": "steps",
"ttl-seconds": 172800
},
"pauses"
],
"claims": [
{
"name": "node-build-go",
"scope": "node",
"serves": ["current", "pause", "resume"]
"serves": [
"current",
"pause",
"resume"
]
}
],
"reads": [
"mesh-delivery-checker.kept",
"mesh-delivery-indexer.manifests"
"mesh-delivery-checker.kept"
],
"invokes": [
"mesh-delivery-indexer.indexer_read_manifests"
],
"config": {
"capacity": {
"type": "number",
"description": "How many asks of the Go build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.",
"description": "How many asks of the Go build seat this module runs at once on this node (novox/hq ADR 0525 \u00a75); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.",
"minimum": 0,
"default": 0
},
@@ -60,7 +70,9 @@
"streams": [
{
"name": "toolchains-go",
"events": ["toolchain.**"]
"events": [
"toolchain.**"
]
}
],
"requires": [
@@ -120,7 +132,11 @@
"path": "${dir:state}/settings.json",
"mode": "0600",
"owner": "mesh-build-go",
"takes-config": ["capacity", "cores-per-step", "build-hours"],
"takes-config": [
"capacity",
"cores-per-step",
"build-hours"
],
"merge": "json",
"template": "files/settings.json"
},