mesh-build-go publishes the build runner as its own package, so the other build modules share it without mesh-sdk (ADR 0593 §1)

The runner, the toolchain guard, the fetch, the parsers, buildcpu, the conformance kit and mesh-pack move from mesh-sdk's
buildstep into modules/mesh-build-go/buildstep (own go.mod). mesh-build-go, mesh-build-node and mesh-build-image require it
by a same-repository replace; what the delivery parts read (the failure contract, the fetch request, the stale sweep, the
module tree shape, NewID, CapacitySetting) stays imported from mesh-sdk as sdkstep.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 18:22:41 +01:00
parent c52afdf88b
commit 9c57f7afb3
159 changed files with 9941 additions and 139 deletions
@@ -4,8 +4,9 @@ import (
"context"
"time"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
@@ -90,13 +91,13 @@ func (m *Module) SeatTools(p *buildstep.Puller) []stdio.Tool {
const StepEndTool = "build_node_step_end"
// endLeftRunning is the module's start sweep (issue 1890): it ends the steps of its node that a previous process left
// running (buildstep.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test
// running (sdkstep.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test
// runs it through the conformance kit's left-running case.
func (m *Module) endLeftRunning(ctx context.Context, scan buildstep.Scan, booted time.Time, logf func(string, ...any)) {
buildstep.EndStaleAtStart(ctx, scan, m.Node, booted, logf)
func (m *Module) endLeftRunning(ctx context.Context, scan sdkstep.Scan, booted time.Time, logf func(string, ...any)) {
sdkstep.EndStaleAtStart(ctx, scan, m.Node, booted, logf)
}
// stepScan is the module's steps state as buildstep reads it.
func (m *Module) stepScan() buildstep.Scan {
return buildstep.ScanOf(stdio.State(delivery.StepsState))
func (m *Module) stepScan() sdkstep.Scan {
return sdkstep.ScanOf(stdio.State(delivery.StepsState))
}
@@ -10,7 +10,8 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
@@ -31,7 +32,7 @@ func fakeSteps(calls *[]string) []StepTool {
}
func nodeAsk(kind string) delivery.StepAsk {
a := delivery.StepAsk{ID: buildstep.NewID(), Kind: kind, Language: delivery.AskNode, Asker: "mesh-delivery-checker", At: time.Now()}
a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: kind, Language: delivery.AskNode, Asker: "mesh-delivery-checker", At: time.Now()}
fetch := map[string]any{"repository": "novox/mesh-catalog", "commit": askCommit}
if kind == delivery.AskDelivery {
a.Asker = "mesh-delivery-builder"
@@ -115,7 +116,7 @@ func TestManifestTakesTheBuildCapacity(t *testing.T) {
t.Errorf("the build-hours description names a node pair")
}
var capacity float64
_ = json.Unmarshal(doc.Config[buildstep.CapacitySetting].Default, &capacity)
_ = json.Unmarshal(doc.Config[sdkstep.CapacitySetting].Default, &capacity)
if capacity != 0 {
t.Errorf("the capacity's default = %g, want 0", capacity)
}
@@ -17,7 +17,8 @@ import (
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
@@ -213,11 +214,11 @@ func (m *Module) bundle(ctx context.Context, root string, publish bool, dir stri
// writeLaunchers writes, beside every entrypoint, an executable that imports the entrypoint and serves what it
// registered over MCP on stdio (builder.go:1926-1956; novox/hq ADR 0193). Which entrypoint gets which launcher is
// mesh-sdk's one rule, buildstep.Launchers, which the controller reads a bundle by (R4e). Its answer is each
// mesh-sdk's one rule, sdkstep.Launchers, which the controller reads a bundle by (R4e). Its answer is each
// entrypoint's launcher, relative to the bundle's root.
func writeLaunchers(root string, a artifact) (map[string]string, error) {
out := map[string]string{}
for entry, launcher := range buildstep.Launchers(a.Language, a.Entrypoints) {
for entry, launcher := range sdkstep.Launchers(a.Language, a.Entrypoints) {
body := "#!/usr/bin/env node\n" +
"// Written by the mesh's builder (novox/hq ADR 0193): serve what " + entry + " registers,\n" +
"// over MCP on stdio, as the module the node's runtime names in MESH_SERVED_MODULE.\n" +
@@ -13,7 +13,7 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -255,7 +255,7 @@ func TestTheBuildRunsWithThePackagesTwoLevelsAboveTheModule(t *testing.T) {
}
}
// R4e: the launchers a build writes are mesh-sdk's one rule (buildstep.Launchers), the names the controller reads a bundle
// R4e: the launchers a build writes are mesh-sdk's one rule (sdkstep.Launchers), the names the controller reads a bundle
// by; an entrypoint that is not JavaScript gets none.
func TestTheLaunchersAreTheSDKsRule(t *testing.T) {
a := artifact{Language: "typescript", Entrypoints: []string{"tools/index.js", "web/server.js", "assets/x.css"}}
@@ -263,7 +263,7 @@ func TestTheLaunchersAreTheSDKsRule(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if want := buildstep.Launchers(a.Language, a.Entrypoints); !maps.Equal(got, want) || len(got) != 2 {
if want := sdkstep.Launchers(a.Language, a.Entrypoints); !maps.Equal(got, want) || len(got) != 2 {
t.Errorf("launchers %v, mesh-sdk's rule %v", got, want)
}
}
@@ -20,7 +20,8 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -55,15 +56,15 @@ type TestResult struct {
// the catalogue's TypeScript against the bounds is a later release's (R4f), not this one's gate.
OverBound bool `json:"over_bound"`
Failed []Failure `json:"failed,omitempty"`
// By is the build module and the SDK it was built with (buildstep.By): the checker names it when a failure hides
// By is the build module and the SDK it was built with (sdkstep.By): the checker names it when a failure hides
// its cause.
By string `json:"by,omitempty"`
}
// Failure is the SDK's failure contract (buildstep.Failure, issue 1901): a failing test of the test script, read from
// Failure is the SDK's failure contract (sdkstep.Failure, issue 1901): a failing test of the test script, read from
// node's TAP reporter, or a type-check or build that failed, each with its cause (never empty, never a passing line) and
// its own output up to 4096 bytes, cause first.
type Failure = buildstep.Failure
type Failure = sdkstep.Failure
func (m *Module) testTool() StepTool {
return StepTool{
@@ -106,7 +107,7 @@ func (m *Module) test(ctx context.Context, args map[string]any) (any, error) {
if err != nil {
return nil, err
}
res := &TestResult{Workspace: workspace, Module: module, Level: level, By: buildstep.By("mesh-build-node")}
res := &TestResult{Workspace: workspace, Module: module, Level: level, By: sdkstep.By("mesh-build-node")}
script := "test"
if level == "integration" {
script = "test:integration"
@@ -203,7 +204,7 @@ func testFailures(where, name, dir string, r forgekey.Ran, report string) []Fail
if name == "test" || name == "test:integration" {
return buildstep.ReadTAP(where, name, dir, report, r.Stdout+"\n"+r.Stderr)
}
return []Failure{buildstep.ConsoleFailure(where, name, r.Stdout+"\n"+r.Stderr)}
return []Failure{sdkstep.ConsoleFailure(where, name, r.Stdout+"\n"+r.Stderr)}
}
// failureWhy is the words of one failure: the test or check that failed, where, and its cause.
@@ -9,7 +9,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -1,8 +1,8 @@
package main
import (
"git.novox.be/novox/mesh-sdk/go/buildcpu"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu"
)
// The processors a step may take (novox/hq ADR 0553, issue 1806). The node-engine holds this module's runtime, with
@@ -23,7 +23,8 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -56,8 +57,8 @@ type FetchResult struct {
Conflicts []string `json:"conflicts,omitempty"`
Changed []string `json:"changed,omitempty"`
// Programs are the changed files that are compiled programs (issue 1577); a merge answers it, a pointer to an empty list when there are none, absent for a fetch that made no merge.
Programs *[]buildstep.Program `json:"programs,omitempty"`
Trees map[string]buildstep.ModuleTree `json:"trees,omitempty"`
Programs *[]buildstep.Program `json:"programs,omitempty"`
Trees map[string]sdkstep.ModuleTree `json:"trees,omitempty"`
// Group is the group's package the fetch packed and served to the TypeScript members (the call's `package`):
// "<name>@<version> <integrity>".
Group string `json:"group,omitempty"`
@@ -90,8 +91,8 @@ func (m *Module) fetchTool() StepTool {
"repository": map[string]any{"type": "string", "description": "<owner>/<repository> on the forge"},
"commit": map[string]any{"type": "string", "description": "the full commit, 40 hex digits"},
"ref": map[string]any{"type": "string", "description": "refs/pull/<n>/head when only a pull request's head carries the commit"},
"dir": buildstep.FetchRequestProperties()["dir"],
"paths": buildstep.FetchRequestProperties()["paths"],
"dir": sdkstep.FetchRequestProperties()["dir"],
"paths": sdkstep.FetchRequestProperties()["paths"],
"package": map[string]any{"type": "object", "description": "optional: the group's package member (ADR 0500 §5), packed here, publishing nothing, and served to each TypeScript member whose lock names its version, in place of the registry's",
"properties": map[string]any{"repository": map[string]any{"type": "string"}, "commit": map[string]any{"type": "string"}, "ref": map[string]any{"type": "string"}},
"required": []string{"repository", "commit"}},
@@ -109,7 +110,7 @@ func (m *Module) fetchTool() StepTool {
func (m *Module) fetch(ctx context.Context, args map[string]any) (res any, err error) {
// What the builder and the checker ask, in mesh-sdk's one form (ADR 0499 §4): with the module's directory and its
// named paths, the workspace is narrowed to them (buildstep.Narrow).
req, err := buildstep.ParseFetchRequest(args)
req, err := sdkstep.ParseFetchRequest(args)
if err != nil {
return nil, err
}
@@ -118,7 +119,7 @@ func (m *Module) fetch(ctx context.Context, args map[string]any) (res any, err e
return nil, err
}
m.CleanWorkspaces(m.now())
id := buildstep.NewID()
id := sdkstep.NewID()
done := m.spaces().Hold(id)
defer func() {
done()
@@ -131,7 +132,7 @@ func (m *Module) fetch(ctx context.Context, args map[string]any) (res any, err e
return m.fetchInto(ctx, req, group, id)
}
func (m *Module) fetchInto(ctx context.Context, req buildstep.FetchRequest, group *groupPackage, id string) (any, error) {
func (m *Module) fetchInto(ctx context.Context, req sdkstep.FetchRequest, group *groupPackage, id string) (any, error) {
repository, commit, ref, base := req.Repository, req.Commit, req.Ref, req.Base
var err error
root := filepath.Join(m.Work, id)
@@ -17,7 +17,7 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -9,7 +9,7 @@ import (
"sync"
"testing"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -5,18 +5,18 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/buildstep/conformance"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
// 1901/AC7: the module's own parse path (testFailures, as the test step calls it on a command that failed) keeps the
// failure contract on every captured node --test and tsc case of the SDK's conformance kit.
func TestTheTestStepKeepsTheFailureContract(t *testing.T) {
conformance.Run(t, conformance.NodeTest, func(o conformance.Output) []buildstep.Failure {
conformance.Run(t, conformance.NodeTest, func(o conformance.Output) []sdkstep.Failure {
return testFailures(".", "test", o.Dir, forgekey.Ran{Status: 1, Stdout: o.Stdout, Stderr: o.Stderr}, o.Report)
})
conformance.Run(t, conformance.TypeCheck, func(o conformance.Output) []buildstep.Failure {
conformance.Run(t, conformance.TypeCheck, func(o conformance.Output) []sdkstep.Failure {
return testFailures(".", "type-check", o.Dir, forgekey.Ran{Status: 2, Stdout: o.Stdout, Stderr: o.Stderr}, "")
})
}
@@ -25,7 +25,7 @@ func TestTheTestStepKeepsTheFailureContract(t *testing.T) {
// case: a step a previous process left running is ended at once and said, whatever its age, and a step of this process
// is kept.
func TestTheStartSweepEndsWhatAPreviousProcessLeft(t *testing.T) {
conformance.LeftRunning(t, func(ctx context.Context, scan buildstep.Scan, node string, before time.Time, logf func(string, ...any)) {
conformance.LeftRunning(t, func(ctx context.Context, scan sdkstep.Scan, node string, before time.Time, logf func(string, ...any)) {
(&Module{Node: node}).endLeftRunning(ctx, scan, before, logf)
})
}
@@ -8,7 +8,8 @@ import (
"sync"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
sdkstep "git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/forgekey"
"git.novox.be/novox/mesh-sdk/go/health"
@@ -68,7 +69,7 @@ type Module struct {
// sets floorOf(node), and a zero Floor checks nothing.
Floor buildstep.Floor
// Settings is the module's settings file, which holds the node's build capacity (buildstep.CapacitySetting); Capacity,
// Settings is the module's settings file, which holds the node's build capacity (sdkstep.CapacitySetting); Capacity,
// when set, answers it instead (a test).
Settings string
Capacity func() int
@@ -139,7 +140,7 @@ func (m *Module) Start(ctx context.Context) {
m.Say("the toolchain: %v", err)
}
m.CleanWorkspaces(m.now())
buildstep.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890)
sdkstep.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890)
select {
case <-ctx.Done():
return
@@ -29,7 +29,7 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -11,7 +11,7 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -6,7 +6,7 @@ package main
import (
"context"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -12,7 +12,7 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
@@ -12,7 +12,7 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
)
// registry is the artifact store's address, host:port, as the manifest bound it into RegistryFile.
@@ -5,8 +5,8 @@ package main
// it, and swept unheld past buildstep.UnheldBound.
import (
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
)
// ReleaseTool removes a workspace whose caller's steps have ended.
@@ -8,7 +8,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/forgekey"
"git.novox.be/novox/mesh-sdk/go/health"
@@ -2,7 +2,7 @@ package main
import (
"context"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
stdio "git.novox.be/novox/mesh-sdk/go"
)
+3
View File
@@ -3,6 +3,7 @@ module meshbuildnode
go 1.26.0
require (
git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep v0.0.0
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102112556-abf5eace7791
github.com/distribution/distribution/v3 v3.1.2
github.com/nats-io/nats.go v1.54.0
@@ -80,3 +81,5 @@ require (
google.golang.org/grpc v1.83.2 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
replace git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep => ../mesh-build-go/buildstep