From c41a84ee95104fbd7b290e6467e6086ba8f82f47 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 23:23:44 +0100 Subject: [PATCH] A-C5: mesh-build-node builds against the latest published SDK, the toolchain pins none MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recovered from cfee5f2d (feat/47-G-buildmods). Builds: design 47 G §571 (the build writes a mesh package's lock entry from the latest published version), A-56 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- modules/mesh-build-node/README.md | 5 +- .../cmd/mesh-build-node/fetch.go | 15 ++- .../cmd/mesh-build-node/fetch_test.go | 5 +- .../cmd/mesh-build-node/manifest_test.go | 6 +- .../cmd/mesh-build-node/package.go | 117 ++++++++++++++---- .../cmd/mesh-build-node/package_test.go | 68 ++++++---- .../cmd/mesh-build-node/recipe.go | 2 +- .../cmd/mesh-build-node/workspace.go | 2 +- .../toolchain/package-lock.json | 6 - .../mesh-build-node/toolchain/package.json | 1 - 10 files changed, 158 insertions(+), 69 deletions(-) diff --git a/modules/mesh-build-node/README.md b/modules/mesh-build-node/README.md index c0307486e..14029f891 100644 --- a/modules/mesh-build-node/README.md +++ b/modules/mesh-build-node/README.md @@ -18,11 +18,12 @@ one changed byte of the lock or another recipe moves it, and typescript and esbu ## The toolchain directory `toolchain/package.json` and its committed `package-lock.json` name typescript 5.9.3, esbuild 0.25.12, @types/node 22.20.1 (the types tsc checks node imports against), -@novox/mesh-sdk 0.1.14 and nats 2.29.3. The mesh unpacks both, as the archive artifact `toolchain`, into `/toolchain/` (resource `toolchain-dir`; a +and nats 2.29.3; it names no @novox/mesh-sdk: each TypeScript module is built against the latest release of the SDK the registry +holds, placed in its own `node_modules` by the fetch whatever its lock names, or the group's tagged version (ADR 0573 §2, ADR 0607 §3). The mesh unpacks both, as the archive artifact `toolchain`, into `/toolchain/` (resource `toolchain-dir`; a manifest names no host, and the lock does, so it is not a template); the program reads the lock from there. When `/toolchain/` is missing the module runs `npm ci --ignore-scripts` there once (a directory without its `.installed` mark counts as missing). -**How the registry is reached** (the choice of issue 1488): the lock holds @novox/mesh-sdk at the forge's public +**How the registry is reached** (the choice of issue 1488): a lock names an @novox package at the forge's public address, and npm 12 installs a locked tarball only from the registry it is configured with. The module therefore requires `npm-package-registry` (provided by gitea, form none: reads are anonymous) and, like the lab module, takes its binding as a file in its home. The install gets a private npm config file with the `@novox` scope at the binding's diff --git a/modules/mesh-build-node/cmd/mesh-build-node/fetch.go b/modules/mesh-build-node/cmd/mesh-build-node/fetch.go index 8d96b6641..10643180d 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/fetch.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/fetch.go @@ -5,7 +5,8 @@ package main // TypeScript module in it the packages its package.json names beyond the SDK, installed from its committed lock. // // **Only what the module itself depends on is installed.** The SDK and nats come with the toolchain, so a bundle that -// names only @novox/mesh-sdk (and build-time types and typescript) resolves nothing. One that names more must carry a +// names only @novox/mesh-sdk (and build-time types and typescript) resolves nothing beyond the SDK, which is placed at +// its latest published version (ADR 0573 §2). One that names more must carry a // package-lock.json, or the step fails naming its directory. The install is the build agent's (mesh-controller // internal/builder/dependencies.go:49-95): in a scratch copy of package.json and the lock with the SDK, devDependencies // and scripts taken out, `npm ci --omit=dev --omit=peer --ignore-scripts`, the install's copies of the SDK removed, and @@ -64,6 +65,9 @@ type FetchResult struct { // Group is the group's package the fetch packed and served to the TypeScript members (the call's `package`): // "@ ". Group string `json:"group,omitempty"` + // SDK is the version of @novox/mesh-sdk placed in each TypeScript module, by directory: the latest release, the + // group's tagged version or the group's package (placeSDK; ADR 0573 §2). + SDK map[string]string `json:"sdk,omitempty"` } // narrowedMark is the file beside a workspace's tree saying the fetch narrowed it to a module's named paths. @@ -197,10 +201,14 @@ func (m *Module) fetchInto(ctx context.Context, req sdkstep.FetchRequest, group return nil, err } if refused == "" { - // The SDK the module's own lock names, from the group or the registry (the lead's decision L10). + // The latest published SDK, or the group's (ADR 0573 §2, ADR 0607 §3). if err := m.placeSDK(ctx, dir, d, served, group); err != nil { return nil, err } + if res.SDK == nil { + res.SDK = map[string]string{} + } + res.SDK[d] = placedSDK(dir) } if refused != "" { res.Refused = append(res.Refused, Refusal{Module: d, Reason: refused}) @@ -368,7 +376,8 @@ func (m *Module) installOwn(ctx context.Context, root, dir, rel string) (install return true, "", os.RemoveAll(scratch) } -// removeSDKCopies removes every copy of the SDK the install pulled in: the toolchain's is the pin. +// removeSDKCopies removes every copy of the SDK the install pulled in: the one placeSDK places, the latest published +// or the group's, is the one the module is built against. func removeSDKCopies(nm string) error { var found []string err := filepath.WalkDir(nm, func(p string, d fs.DirEntry, err error) error { diff --git a/modules/mesh-build-node/cmd/mesh-build-node/fetch_test.go b/modules/mesh-build-node/cmd/mesh-build-node/fetch_test.go index 76bda1a28..bdff248eb 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/fetch_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/fetch_test.go @@ -97,7 +97,7 @@ func TestAModuleNamingOnlyTheSdkAndTypesInstallsNothing(t *testing.T) { } // 1489/AC2: a module naming lodash with a lock gets npm ci --omit=dev --ignore-scripts (fake runner), its install put -// at its node_modules without the SDK and without any copy of it; without a lock the step fails naming the directory. +// at its node_modules without the install's SDK or any copy of it; without a lock the step fails naming the directory. func TestAModuleNamingLodashWithALockIsInstalledWithoutTheSdkAndWithoutALockFails(t *testing.T) { files := typeScriptModule(`{"dependencies":{"@novox/mesh-sdk":"^0.1.6","lodash":"^4"},"devDependencies":{"x":"1"},"scripts":{"test":"y"}}`) files["modules/m/package-lock.json"] = `{"lockfileVersion":3}` @@ -119,7 +119,8 @@ func TestAModuleNamingLodashWithALockIsInstalledWithoutTheSdkAndWithoutALockFail if _, err := os.Stat(filepath.Join(nm, "lodash", "index.js")); err != nil { t.Errorf("lodash is not at the module's node_modules: %v", err) } - for _, gone := range []string{"@novox/mesh-sdk", "a/node_modules/@novox/mesh-sdk"} { + // The install's copies are gone; the one at the top is the latest release placed after it (placeSDK). + for _, gone := range []string{"@novox/mesh-sdk/index.js", "a/node_modules/@novox/mesh-sdk"} { if _, err := os.Stat(filepath.Join(nm, gone)); err == nil { t.Errorf("a copy of the SDK is left at %s", gone) } 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 288922bf5..3d28b5550 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 @@ -161,8 +161,8 @@ func TestTheModuleCarriesItsToolchainLockAndTheManifestPlacesIt(t *testing.T) { } } -// 1488/AC1: the lock names the versions of the recipe: typescript 5.9.3, esbuild 0.25.12, @novox/mesh-sdk 0.1.14 -// and nats, all by the lock's own hash (read from the file the module carries). +// 1488/AC1: the lock names the versions of the recipe: typescript 5.9.3, esbuild 0.25.12 and nats, all by the lock's +// own hash (read from the file the module carries), and no @novox/mesh-sdk: the SDK is unpinned (ADR 0573 §2). func TestTheLockNamesTheToolchainVersions(t *testing.T) { raw, err := os.ReadFile(filepath.Join(moduleDir, "toolchain", "package-lock.json")) if err != nil { @@ -176,7 +176,7 @@ func TestTheLockNamesTheToolchainVersions(t *testing.T) { if err := json.Unmarshal(raw, &lock); err != nil { t.Fatal(err) } - for pkg, want := range map[string]string{"typescript": "5.9.3", "esbuild": "0.25.12", "@novox/mesh-sdk": "0.1.14", "nats": "2.29.3", "@types/node": "22.20.1"} { + for pkg, want := range map[string]string{"typescript": "5.9.3", "esbuild": "0.25.12", "@novox/mesh-sdk": "", "nats": "2.29.3", "@types/node": "22.20.1"} { if got := lock.Packages["node_modules/"+pkg].Version; got != want { t.Errorf("%s = %q in the lock, want %s", pkg, got, want) } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/package.go b/modules/mesh-build-node/cmd/mesh-build-node/package.go index 4a994da7e..5da68ec97 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/package.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/package.go @@ -27,6 +27,7 @@ import ( "path/filepath" "regexp" "sort" + "strconv" "strings" "time" @@ -292,7 +293,7 @@ func (m *Module) packGroup(ctx context.Context, root string, run forgekey.Runner } // sdkLocked is what a module's lock names of the SDK: its version, its integrity and where it was resolved from; ok is -// false when the lock names none (the toolchain's SDK is then the module's, as before). +// false when the lock names none (the latest release is then placed, placeSDK). func sdkLocked(dir string) (version, integrity string, ok bool, err error) { raw, err := os.ReadFile(filepath.Join(dir, "package-lock.json")) if os.IsNotExist(err) { @@ -317,21 +318,25 @@ func sdkLocked(dir string) (version, integrity string, ok bool, err error) { return p.Version, p.Integrity, true, nil } -// placeSDK places in the module's node_modules the SDK version its lock names (the lead's decision L10): the group's -// packed package when it is that version (its integrity must be the lock's), else the registry's; a version neither -// holds is a wait (`waits for:`) when no group package was given, and a failure naming both when one was. Given the -// group's tagged version (tagged, ADR 0607 §3), that version is placed from the registry whatever the lock names, its -// integrity the lock's when the lock names it, else the registry's own; one the registry lacks fails naming it. +// placeSDK places in the module's node_modules the SDK it is built against: the latest release the registry holds, +// whatever its lock names (novox/hq ADR 0573 §2: a module builds against the latest published version of each mesh +// package; the lead's decision L10's version from the lock is gone), or the group's packed package when the lock names +// its version. Every TypeScript module gets it, named in its package.json or not, since its launcher imports the SDK +// (writeLaunchers) and the toolchain holds none. The lock's integrity is checked when the lock names the version placed; +// a registry holding no release is a wait (`waits for:`) when no group package was given, and a failure naming the group +// when one was. Given the group's tagged version (tagged, ADR 0607 §3), that version is placed from the registry +// whatever the lock names, its integrity the lock's when the lock names it, else the registry's; one the registry lacks +// fails naming it. func (m *Module) placeSDK(ctx context.Context, dir, rel string, group *packed, tagged *groupPackage) error { - version, integrity, ok, err := sdkLocked(dir) - if err != nil || !ok { + version, integrity, _, err := sdkLocked(dir) + if err != nil { return err } var tgz []byte switch { case tagged.tagged(): if version != tagged.Version { - if m.Say != nil { + if m.Say != nil && version != "" { m.Say("%s: its lock names %s@%s; the group's tagged version %s is placed (ADR 0607 §3)", rel, sdkPackage, version, tagged.Version) } version, integrity = tagged.Version, "" @@ -351,23 +356,39 @@ func (m *Module) placeSDK(ctx context.Context, dir, rel string, group *packed, t return fmt.Errorf("the registry's %s is %s, and %s names %s", want, integrityOf(got), rel, integrity) } tgz = got - case group != nil && group.Name == sdkPackage && group.Version == version: + case group != nil && group.Name == sdkPackage && version != "" && group.Version == version: if integrity != "" && integrity != group.Integrity { return fmt.Errorf("the lock of %s names %s with the integrity %s, and the group's package packs to %s", rel, sdkPackage+"@"+version, integrity, group.Integrity) } tgz = group.tgz default: + latest, err := m.registryLatest(ctx, sdkPackage) + if err != nil { + return err + } + if latest == "" { + if group != nil { + return fmt.Errorf("the registry holds no release of %s and the group's package is %s@%s, which the lock of %s does not name", sdkPackage, group.Name, group.Version, rel) + } + return fmt.Errorf("%s%s", builds.WaitsFor, sdkPackage) + } + if version != latest { + if m.Say != nil && version != "" { + m.Say("%s: its lock names %s@%s; the latest published %s is placed (ADR 0573 §2)", rel, sdkPackage, version, latest) + } + version, integrity = latest, "" + } want := sdkPackage + "@" + version - got, held, err := m.registryPackage(ctx, sdkPackage, version) + got, registered, held, err := m.registryPackageChecked(ctx, sdkPackage, version) if err != nil { return err } if !held { - if group != nil { - return fmt.Errorf("the lock of %s names %s, which neither the registry nor the group (%s@%s) holds", rel, want, group.Name, group.Version) - } return fmt.Errorf("%s%s", builds.WaitsFor, want) } + if integrity == "" { + integrity = registered + } if integrity != "" && integrityOf(got) != integrity { return fmt.Errorf("the registry's %s is %s, and the lock of %s names %s", want, integrityOf(got), rel, integrity) } @@ -380,6 +401,47 @@ func (m *Module) placeSDK(ctx context.Context, dir, rel string, group *packed, t return unpackPackage(tgz, into) } +// placedSDK is the version of the SDK placed in the module's node_modules ("" when none is). +func placedSDK(dir string) string { + p, err := readPackageJSON(filepath.Join(dir, "node_modules", filepath.FromSlash(sdkPackage))) + if err != nil { + return "" + } + return p.Version +} + +// registryLatest is the latest release of name the registry holds: the highest version with no pre-release, so a +// group's tagged version is never taken for it; "" when the registry holds none. +func (m *Module) registryLatest(ctx context.Context, name string) (string, error) { + p, held, err := m.packumentOf(ctx, name) + if err != nil || !held { + return "", err + } + latest := "" + for v := range p.Versions { + if !npmVersionOK.MatchString(v) || strings.Contains(v, "-") { + continue + } + if latest == "" || releaseLess(latest, v) { + latest = v + } + } + return latest, nil +} + +// releaseLess orders two releases (major.minor.patch, no pre-release) by their numbers. +func releaseLess(a, b string) bool { + pa, pb := strings.Split(a, "."), strings.Split(b, ".") + for i := 0; i < 3; i++ { + x, _ := strconv.Atoi(pa[i]) + y, _ := strconv.Atoi(pb[i]) + if x != y { + return x < y + } + } + return false +} + // registryPackageChecked is registryPackage with the integrity the registry's document names of name@version. func (m *Module) registryPackageChecked(ctx context.Context, name, version string) (tgz []byte, integrity string, held bool, err error) { _, integrity, held, err = m.registryVersion(ctx, name, version) @@ -408,32 +470,41 @@ type packument struct { } `json:"versions"` } -// registryVersion reads what the registry holds of name@version: its packed file's address and integrity, and whether -// it holds it at all. -func (m *Module) registryVersion(ctx context.Context, name, version string) (tarball, integrity string, held bool, err error) { +// packumentOf reads the registry's document of name; held is false when the registry has none. +func (m *Module) packumentOf(ctx context.Context, name string) (packument, bool, error) { reg, err := m.Toolchain.Registry() if err != nil { - return "", "", false, err + return packument{}, false, err } req, err := http.NewRequestWithContext(ctx, http.MethodGet, reg.URL+url.PathEscape(name), nil) if err != nil { - return "", "", false, err + return packument{}, false, err } resp, err := m.httpClient().Do(req) if err != nil { - return "", "", false, fmt.Errorf("asking the registry for %s: %w", name, err) + return packument{}, false, fmt.Errorf("asking the registry for %s: %w", name, err) } defer resp.Body.Close() if resp.StatusCode == http.StatusNotFound { - return "", "", false, nil + return packument{}, false, nil } if resp.StatusCode != http.StatusOK { said, _ := io.ReadAll(io.LimitReader(resp.Body, 512)) - return "", "", false, fmt.Errorf("the registry answered %s for %s: %s", resp.Status, name, strings.TrimSpace(string(said))) + return packument{}, false, fmt.Errorf("the registry answered %s for %s: %s", resp.Status, name, strings.TrimSpace(string(said))) } var p packument if err := json.NewDecoder(io.LimitReader(resp.Body, 64<<20)).Decode(&p); err != nil { - return "", "", false, fmt.Errorf("the registry's document of %s: %w", name, err) + return packument{}, false, fmt.Errorf("the registry's document of %s: %w", name, err) + } + return p, true, nil +} + +// registryVersion reads what the registry holds of name@version: its packed file's address and integrity, and whether +// it holds it at all. +func (m *Module) registryVersion(ctx context.Context, name, version string) (tarball, integrity string, held bool, err error) { + p, held, err := m.packumentOf(ctx, name) + if err != nil || !held { + return "", "", false, err } v, ok := p.Versions[version] if !ok { diff --git a/modules/mesh-build-node/cmd/mesh-build-node/package_test.go b/modules/mesh-build-node/cmd/mesh-build-node/package_test.go index 7340d7f85..56087e935 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/package_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/package_test.go @@ -91,29 +91,42 @@ func placedVersion(dir string) string { return p.Version } -// The lead's decision L10 (ADR 0500 §6): a member is built against the SDK version its own lock names, downloaded from -// the registry and checked against the lock's integrity; a version the registry does not hold is a wait, `waits for:`. -func TestAMemberGetsTheSDKVersionItsLockNamesOrWaitsForIt(t *testing.T) { +// ADR 0573 §2 (unpinned, the lead's decision L10's lock version gone): a member is built against the latest release the +// registry holds, whatever its lock names or when it names none, checked against the lock's integrity only when the lock +// names that version; a pre-release is never the latest; a registry holding no release is a wait, `waits for:`. +func TestAMemberGetsTheLatestPublishedSDKWhateverItsLockNames(t *testing.T) { m, _, _ := newMachine(t) - held := tgzOf(t, sdkPackage, "0.1.15") + held, older, pre := tgzOf(t, sdkPackage, "0.1.15"), tgzOf(t, sdkPackage, "0.1.9"), tgzOf(t, sdkPackage, "0.1.16-feat-x.1") + fakeRegistry(t, m, map[string][]byte{"0.1.15": held, "0.1.9": older, "0.1.16-feat-x.1": pre}) + for _, c := range []struct { + name, locks, integrity, fails string + }{ + {name: "a lock naming the latest", locks: "0.1.15", integrity: integrityOf(held)}, + {name: "a lock naming an older version (the pin)", locks: "0.1.9", integrity: integrityOf(older)}, + {name: "a lock naming a version the registry lacks", locks: "0.1.16", integrity: "sha512-x"}, + {name: "a lock naming none", locks: ""}, + {name: "a lock naming the latest with another integrity", locks: "0.1.15", integrity: "sha512-another", fails: "sha512-another"}, + } { + dir := memberLocking(t, c.locks, c.integrity) + err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil) + switch { + case c.fails == "" && (err != nil || placedVersion(dir) != "0.1.15"): + t.Errorf("%s: %v, placed %q, want the latest release 0.1.15", c.name, err, placedVersion(dir)) + case c.fails != "" && (err == nil || !strings.Contains(err.Error(), c.fails)): + t.Errorf("%s: %v, want it to fail naming %s", c.name, err, c.fails) + } + } + fakeRegistry(t, m, map[string][]byte{"0.1.16-feat-x.1": pre}) + if err := m.placeSDK(context.Background(), memberLocking(t, "0.1.15", ""), "modules/m", nil, nil); err == nil || err.Error() != builds.WaitsFor+"@novox/mesh-sdk" { + t.Errorf("a registry with no release answered %v, want %s@novox/mesh-sdk", err, builds.WaitsFor) + } + held = tgzOf(t, sdkPackage, "0.1.15") fakeRegistry(t, m, map[string][]byte{"0.1.15": held}) - dir := memberLocking(t, "0.1.15", integrityOf(held)) - if err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil); err != nil || placedVersion(dir) != "0.1.15" { - t.Errorf("the registry's 0.1.15: %v, placed %q", err, placedVersion(dir)) - } - dir = memberLocking(t, "0.1.16", "sha512-x") - err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil) - if err == nil || err.Error() != builds.WaitsFor+"@novox/mesh-sdk@0.1.16" { - t.Errorf("a version the registry lacks answered %v, want %s@novox/mesh-sdk@0.1.16", err, builds.WaitsFor) - } - dir = memberLocking(t, "0.1.15", "sha512-another") - if err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil); err == nil || !strings.Contains(err.Error(), "sha512-another") { - t.Errorf("a registry file of another integrity than the lock's answered %v", err) - } + var dir string // ADR 0607 §3, §5 (design 51 *Tagged versions*): given the group's tagged version, the fetch places it from the // registry whatever the lock names, against the lock's integrity when the lock names it, else the registry's; one the // registry lacks fails naming it, no wait (the check waited for its published). - tagged := tgzOf(t, sdkPackage, "0.1.16-feat-x.1") + tagged := pre fakeRegistry(t, m, map[string][]byte{"0.1.15": held, "0.1.16-feat-x.1": tagged}) group := &groupPackage{Name: sdkPackage, Version: "0.1.16-feat-x.1"} for _, c := range []struct { @@ -140,8 +153,8 @@ func TestAMemberGetsTheSDKVersionItsLockNamesOrWaitsForIt(t *testing.T) { } // ADR 0500 §5 (S3, S4): the group's packed package is served in place of the registry's when the member's lock names its -// version with its integrity; another integrity, or a version neither the group nor the registry holds, fails naming both. -// A member whose lock names no SDK keeps the toolchain's and asks the registry nothing. +// version with its integrity; another integrity fails naming both. A member locking another version, or none, gets the +// registry's latest release (ADR 0573 §2); with no release in the registry it fails naming the group's, no wait. func TestTheGroupsPackageIsServedToAMemberLockingItsVersion(t *testing.T) { m, _, _ := newMachine(t) asked := fakeRegistry(t, m, map[string][]byte{"0.1.14": tgzOf(t, sdkPackage, "0.1.14")}) @@ -159,14 +172,15 @@ func TestTheGroupsPackageIsServedToAMemberLockingItsVersion(t *testing.T) { if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err != nil || placedVersion(dir) != "0.1.14" { t.Errorf("a member locking the registry's 0.1.14 in a group: %v, placed %q", err, placedVersion(dir)) } - dir = memberLocking(t, "0.1.13", "sha512-x") - if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err == nil || !strings.Contains(err.Error(), "0.1.13") || !strings.Contains(err.Error(), "0.1.15") || strings.HasPrefix(err.Error(), builds.WaitsFor) { - t.Errorf("a version neither holds answered %v, want both named and no wait", err) + for _, locks := range []string{"0.1.13", ""} { + dir = memberLocking(t, locks, "sha512-x") + if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err != nil || placedVersion(dir) != "0.1.14" { + t.Errorf("a member in a group locking %q: %v, placed %q, want the registry's latest 0.1.14", locks, err, placedVersion(dir)) + } } - before := asked.Load() - dir = memberLocking(t, "", "") - if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err != nil || placedVersion(dir) != "" || asked.Load() != before { - t.Errorf("a lock naming no SDK: %v, placed %q, the registry asked", err, placedVersion(dir)) + fakeRegistry(t, m, nil) + if err := m.placeSDK(context.Background(), memberLocking(t, "0.1.13", "sha512-x"), "modules/m", group, nil); err == nil || !strings.Contains(err.Error(), "0.1.15") || strings.HasPrefix(err.Error(), builds.WaitsFor) { + t.Errorf("no release and a group answered %v, want the group's named and no wait", err) } } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/recipe.go b/modules/mesh-build-node/cmd/mesh-build-node/recipe.go index ea3a8eb75..b06fbcc4a 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/recipe.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/recipe.go @@ -14,7 +14,7 @@ import ( // RecipeSteps is the recipe's own version: changed whenever the steps of fetch, test or build change in a way that // can change what they produce (ADR 0405 §7). It is one of the two values the recipe version hashes. -const RecipeSteps = "2" // 2: a member is built against the SDK its own lock names (R4e, the lead's decision L10) +const RecipeSteps = "3" // 3: a member is built against the latest published SDK, the toolchain holds none (ADR 0573 §2) // Recipe is every value that makes up the recipe version. type Recipe struct { diff --git a/modules/mesh-build-node/cmd/mesh-build-node/workspace.go b/modules/mesh-build-node/cmd/mesh-build-node/workspace.go index 845bf4ce8..11f1936ce 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/workspace.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/workspace.go @@ -3,7 +3,7 @@ package main // A workspace and the packages a step runs against (novox/hq ADR 0469 §2 and §5; issues 1490, 1491). A workspace is // //tree, made by the fetch step. The toolchain's packages are copied to // // node_modules, which lies above the tree: node, tsc and esbuild resolve an import by walking up from the importing -// file, so @novox/mesh-sdk and the types are found there while the tree itself, which a bundle is packed from, stays +// file, so the types are found there while the tree itself, which a bundle is packed from, stays // what the commit holds. A copy and not a link, because the mesh makes no symlink. import ( diff --git a/modules/mesh-build-node/toolchain/package-lock.json b/modules/mesh-build-node/toolchain/package-lock.json index e4867d9cf..caf8a8c99 100644 --- a/modules/mesh-build-node/toolchain/package-lock.json +++ b/modules/mesh-build-node/toolchain/package-lock.json @@ -8,7 +8,6 @@ "name": "mesh-build-node-toolchain", "version": "1.0.0", "dependencies": { - "@novox/mesh-sdk": "0.1.14", "nats": "2.29.3" }, "devDependencies": { @@ -459,11 +458,6 @@ "node": ">=18" } }, - "node_modules/@novox/mesh-sdk": { - "version": "0.1.14", - "resolved": "https://git.novox.be/api/packages/novox/npm/%40novox%2Fmesh-sdk/-/0.1.14/mesh-sdk-0.1.14.tgz", - "integrity": "sha512-ICdIfVicQQXSw6fkLiwzoRx3weiWh0jsIEYG/m98CKgFIlziZzb7V+ZmT/TvPO9bTDFDtfqDLoFu+OXY5+ryQw==" - }, "node_modules/@types/node": { "version": "22.20.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", diff --git a/modules/mesh-build-node/toolchain/package.json b/modules/mesh-build-node/toolchain/package.json index 42c5f21c0..7ef253a1d 100644 --- a/modules/mesh-build-node/toolchain/package.json +++ b/modules/mesh-build-node/toolchain/package.json @@ -4,7 +4,6 @@ "private": true, "description": "The Node build module's toolchain: what npm ci installs into /toolchain/ (issue 1488).", "dependencies": { - "@novox/mesh-sdk": "0.1.14", "nats": "2.29.3" }, "devDependencies": {