From 75d98dd9083a8c606426e852bcb43495427d0235 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 22:29:28 +0100 Subject: [PATCH] C4: the build modules ask the steps state with its objects store in requires; outputs goes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds: design 47 G A-254, A-313, A-314, §58, §547 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- .../cmd/mesh-build-go/forge_test.go | 6 +++--- .../cmd/mesh-build-go/manifest_test.go | 6 +++--- modules/mesh-build-go/module.json | 21 ++++++++----------- .../cmd/mesh-build-image/forge_test.go | 4 ++-- .../cmd/mesh-build-image/manifest_test.go | 14 ++++++------- modules/mesh-build-image/module.json | 4 ++-- .../cmd/mesh-build-node/manifest_test.go | 14 ++++++------- modules/mesh-build-node/module.json | 4 ++-- modules/nats/internal/keeper/keeper_test.go | 2 ++ 9 files changed, 37 insertions(+), 38 deletions(-) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go b/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go index 51248bd7c..a54618ce4 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go @@ -151,14 +151,14 @@ func TestManifestRequiresForgeAccountKeepsKeysAndTakesFilesFromTemplates(t *test // detected-steps: the state of the verb steps (design 47 G §326, §414), asked by the template state. // kept-builds: the builds kept for the artifact store's holder (keptbuilds.go), by the template objects (W12.5). kept := map[string]any{"name": "kept-builds", "storage": "object-store", "template": "objects", "options": map[string]any{"max-mib": float64(1024)}} - // outputs: a run's answer over what step-ended carries inline, by the template objects (design 47 G A-254). - outputs := map[string]any{"name": "outputs", "storage": "object-store", "template": "objects", "options": map[string]any{"max-mib": float64(256)}} + // outputs: a run's answer over what step-ended carries inline, in the steps state's objects store (design 47 G A-254, A-313). + outputs := map[string]any{"name": "steps", "storage": "key-value", "template": "state", "options": map[string]any{"ttl-seconds": float64(172800), "objects-max-mib": float64(256)}} detected := map[string]any{"name": "detected-steps", "storage": "key-value", "template": "state", "options": map[string]any{"history": float64(1)}} // The findings are asked in requires as a part that is no foundation part asks them (design 47 G §529, A-30). findings := map[string]any{"name": "findings", "storage": "key-value", "template": "state"} findingEvents := map[string]any{"name": "finding-events", "storage": "stream", "template": "events", "options": map[string]any{ "events": []any{"finding-written.*", "finding-cleared.*", "findings-stated.*"}, "max-age-days": float64(7), "max-mib": float64(16)}} - if want := []any{detected, kept, outputs, "artifact-store", "forge-account", "go-toolchain", "go-package-registry", "node-tools", findings, findingEvents}; !reflect.DeepEqual(m.Requires, want) { + if want := []any{outputs, detected, kept, "artifact-store", "forge-account", "go-toolchain", "go-package-registry", "node-tools", findings, findingEvents}; !reflect.DeepEqual(m.Requires, want) { t.Errorf("requires = %v, want %v", m.Requires, want) } keeps := false diff --git a/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go index 5da7eca27..dd8db4984 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go @@ -113,12 +113,12 @@ func TestManifestKeepsItsStatesClaimsItsBuildSeatAndDeclaresItsHealthTool(t *tes for _, s := range m.State { states = append(states, s.Name) // A step's key is per step and dropped after its age, so the bucket cannot fill; a pause has no age. - if (s.Name == "steps") != (s.TTLSeconds > 0) { - t.Errorf("state %s has ttl-seconds %d: only steps has an age", s.Name, s.TTLSeconds) + if s.TTLSeconds > 0 { + t.Errorf("state %s has ttl-seconds %d: steps, the one with an age, is asked in requires (A-314)", s.Name, s.TTLSeconds) } } slices.Sort(states) - if want := []string{"keys", "pauses", "steps", "toolchains"}; !slices.Equal(states, want) { + if want := []string{"keys", "pauses", "toolchains"}; !slices.Equal(states, want) { t.Errorf("state = %v, want %v", states, want) } if len(m.Claims) != 1 || m.Claims[0].Name != Seat { diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index df53dbd90..acc49284d 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -15,10 +15,6 @@ "state": [ "toolchains", "keys", - { - "name": "steps", - "ttl-seconds": 172800 - }, "pauses" ], "claims": [ @@ -89,6 +85,15 @@ "build_go_health" ], "requires": [ + { + "name": "steps", + "storage": "key-value", + "template": "state", + "options": { + "ttl-seconds": 172800, + "objects-max-mib": 256 + } + }, { "name": "detected-steps", "storage": "key-value", @@ -105,14 +110,6 @@ "max-mib": 1024 } }, - { - "name": "outputs", - "storage": "object-store", - "template": "objects", - "options": { - "max-mib": 256 - } - }, "artifact-store", "forge-account", "go-toolchain", diff --git a/modules/mesh-build-image/cmd/mesh-build-image/forge_test.go b/modules/mesh-build-image/cmd/mesh-build-image/forge_test.go index dd0e4be71..7e37eedc5 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/forge_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/forge_test.go @@ -145,8 +145,8 @@ func TestForgeFilesRenderFromTheBoundValuesInTheModulesOwnHome(t *testing.T) { // template in the files/ archive (novox/hq ADR 0349 §2). func TestManifestRequiresForgeAccountKeepsKeysAndTakesFilesFromTemplates(t *testing.T) { m := readForgeManifest(t) - // outputs: a run's answer over what step-ended carries inline, by the template objects (design 47 G A-254). - outputs := map[string]any{"name": "outputs", "storage": "object-store", "template": "objects", "options": map[string]any{"max-mib": float64(256)}} + // outputs: a run's answer over what step-ended carries inline, in the steps state's objects store (design 47 G A-254, A-313). + outputs := map[string]any{"name": "steps", "storage": "key-value", "template": "state", "options": map[string]any{"ttl-seconds": float64(172800), "objects-max-mib": float64(256)}} if want := []any{outputs, "forge-account", "rootless-image-build", "node-tools"}; !reflect.DeepEqual(m.Requires, want) { t.Errorf("requires = %v, want %v", m.Requires, want) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go index 91fed199f..5a8fd6111 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go @@ -118,12 +118,12 @@ func TestManifestKeepsItsStatesClaimsItsBuildSeatAndDeclaresItsHealthTool(t *tes states = append(states, s.Name) // A step's key is per step and dropped after its age, so the bucket cannot fill, and so is a copy's wait, which a // stopped process leaves; a pause has no age. - if (s.Name == "steps" || s.Name == MirrorWaitsState) != (s.TTLSeconds > 0) { - t.Errorf("state %s has ttl-seconds %d: only steps and %s have an age", s.Name, s.TTLSeconds, MirrorWaitsState) + if (s.Name == MirrorWaitsState) != (s.TTLSeconds > 0) { + t.Errorf("state %s has ttl-seconds %d: only %s has an age here, steps being asked in requires (A-314)", s.Name, s.TTLSeconds, MirrorWaitsState) } } slices.Sort(states) - if want := []string{"keys", MirrorWaitsState, "pauses", "steps"}; !slices.Equal(states, want) { + if want := []string{"keys", MirrorWaitsState, "pauses"}; !slices.Equal(states, want) { t.Errorf("state = %v, want %v", states, want) } if len(m.Claims) != 1 || m.Claims[0].Name != Seat || !slices.Equal(m.Claims[0].Serves, []string{"current", "drop", "pause", "resume", "steps", "kept-artifact", "output"}) { @@ -213,9 +213,9 @@ func TestTheModuleRequiresNodeToolsItPullsThrough(t *testing.T) { } } -// Design 47 G A-254: the module keeps a run's answer over what step-ended carries inline in an object store of its own, asked for -// in `requires` by the template objects, and serves it through the verb output. -func TestManifestRequiresTheOutputsStore(t *testing.T) { +// Design 47 G A-254, A-313, A-314: the module keeps a run's answer over what step-ended carries inline in the steps state's own +// objects store, sized in `requires` by the state option objects-max-mib, and serves it through the verb output. +func TestManifestRequiresTheStepsStateWithItsObjectsStore(t *testing.T) { raw, err := os.ReadFile(moduleDir + "/module.json") if err != nil { t.Fatal(err) @@ -226,7 +226,7 @@ func TestManifestRequiresTheOutputsStore(t *testing.T) { if err := json.Unmarshal(raw, &doc); err != nil { t.Fatal(err) } - want := map[string]any{"name": "outputs", "storage": "object-store", "template": "objects", "options": map[string]any{"max-mib": float64(256)}} + want := map[string]any{"name": "steps", "storage": "key-value", "template": "state", "options": map[string]any{"ttl-seconds": float64(172800), "objects-max-mib": float64(256)}} for _, r := range doc.Requires { if reflect.DeepEqual(r, want) { return diff --git a/modules/mesh-build-image/module.json b/modules/mesh-build-image/module.json index 5eb0ee006..3da2c35c5 100644 --- a/modules/mesh-build-image/module.json +++ b/modules/mesh-build-image/module.json @@ -14,7 +14,7 @@ ], "state": [ "keys", - {"name": "steps", "ttl-seconds": 172800}, "pauses", + "pauses", {"name": "mirror-waits", "ttl-seconds": 172800} ], "claims": [ @@ -57,7 +57,7 @@ "build_image_health" ], "requires": [ - {"name": "outputs", "storage": "object-store", "template": "objects", "options": {"max-mib": 256}}, + {"name": "steps", "storage": "key-value", "template": "state", "options": {"ttl-seconds": 172800, "objects-max-mib": 256}}, "forge-account", "rootless-image-build", "node-tools" diff --git a/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go b/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go index 11ea32d03..03d182e38 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go @@ -110,12 +110,12 @@ func TestManifestKeepsItsStatesClaimsItsBuildSeatAndDeclaresItsHealthTool(t *tes for _, s := range m.State { states = append(states, s.Name) // A step's key is per step and dropped after its age, so the bucket cannot fill; a pause has no age. - if (s.Name == "steps") != (s.TTLSeconds > 0) { - t.Errorf("state %s has ttl-seconds %d: only steps has an age", s.Name, s.TTLSeconds) + if s.TTLSeconds > 0 { + t.Errorf("state %s has ttl-seconds %d: steps, the one with an age, is asked in requires (A-314)", s.Name, s.TTLSeconds) } } slices.Sort(states) - if want := []string{"keys", "pauses", "steps", "toolchains"}; !slices.Equal(states, want) { + if want := []string{"keys", "pauses", "toolchains"}; !slices.Equal(states, want) { t.Errorf("state = %v, want %v", states, want) } if len(m.Claims) != 1 || m.Claims[0].Name != Seat || !slices.Equal(m.Claims[0].Serves, []string{"current", "drop", "pause", "resume", "steps", "kept-artifact", "output"}) { @@ -279,9 +279,9 @@ func TestTheModuleRequiresNodeToolsItPullsThrough(t *testing.T) { } } -// Design 47 G A-254: the module keeps a run's answer over what step-ended carries inline in an object store of its own, asked for -// in `requires` by the template objects, and serves it through the verb output. -func TestManifestRequiresTheOutputsStore(t *testing.T) { +// Design 47 G A-254, A-313, A-314: the module keeps a run's answer over what step-ended carries inline in the steps state's own +// objects store, sized in `requires` by the state option objects-max-mib, and serves it through the verb output. +func TestManifestRequiresTheStepsStateWithItsObjectsStore(t *testing.T) { raw, err := os.ReadFile(moduleDir + "/module.json") if err != nil { t.Fatal(err) @@ -292,7 +292,7 @@ func TestManifestRequiresTheOutputsStore(t *testing.T) { if err := json.Unmarshal(raw, &doc); err != nil { t.Fatal(err) } - want := map[string]any{"name": "outputs", "storage": "object-store", "template": "objects", "options": map[string]any{"max-mib": float64(256)}} + want := map[string]any{"name": "steps", "storage": "key-value", "template": "state", "options": map[string]any{"ttl-seconds": float64(172800), "objects-max-mib": float64(256)}} for _, r := range doc.Requires { if reflect.DeepEqual(r, want) { return diff --git a/modules/mesh-build-node/module.json b/modules/mesh-build-node/module.json index da27f0712..1f141d375 100644 --- a/modules/mesh-build-node/module.json +++ b/modules/mesh-build-node/module.json @@ -15,7 +15,7 @@ "state": [ "toolchains", "keys", - {"name": "steps", "ttl-seconds": 172800}, "pauses" + "pauses" ], "claims": [ { @@ -57,8 +57,8 @@ "build_node_health" ], "requires": [ + {"name": "steps", "storage": "key-value", "template": "state", "options": {"ttl-seconds": 172800, "objects-max-mib": 256}}, {"name": "detected-steps", "storage": "key-value", "template": "state", "options": {"history": 1}}, - {"name": "outputs", "storage": "object-store", "template": "objects", "options": {"max-mib": 256}}, "artifact-store", "forge-account", "npm-package-registry", diff --git a/modules/nats/internal/keeper/keeper_test.go b/modules/nats/internal/keeper/keeper_test.go index 381b2cbc5..b7c2aa305 100644 --- a/modules/nats/internal/keeper/keeper_test.go +++ b/modules/nats/internal/keeper/keeper_test.go @@ -341,6 +341,8 @@ func TestEachTemplateIsPlannedUnderTheModulesNames(t *testing.T) { {name: "state", entry: entry("drafts", catalogue.StorageKeyValue, catalogue.TemplateState, map[string]string{"history": "5"}), objects: "key-value mesh-knowledge_drafts {64 MiB, age 0, history 5, new, size 262144}; object-store mesh-knowledge_drafts-objects {16 MiB, age 0, history 0, new, size 0}", binding: "bucket mesh-knowledge_drafts"}, + {name: "state naming objects-max-mib and a time to live (A-314): the same bucket as the old section's, its objects store sized", entry: entry("steps", catalogue.StorageKeyValue, catalogue.TemplateState, map[string]string{"ttl-seconds": "172800", "objects-max-mib": "256"}), + objects: "key-value mesh-knowledge_steps {64 MiB, age 172800, history 1, new, size 262144}; object-store mesh-knowledge_steps-objects {256 MiB, age 0, history 0, new, size 0}", binding: "bucket mesh-knowledge_steps"}, {name: "state naming max-mib (A-283)", entry: entry("drafts", catalogue.StorageKeyValue, catalogue.TemplateState, map[string]string{"max-mib": "8"}), objects: "key-value mesh-knowledge_drafts {8 MiB, age 0, history 1, new, size 262144}; object-store mesh-knowledge_drafts-objects {16 MiB, age 0, history 0, new, size 0}", binding: "bucket mesh-knowledge_drafts"},