Files
hq/04-ISSUES/053-the-sdk-is-pinned-twice-and-the-two-disagree/00-report.md
T
jschoubben a5e351f4cb Nine resolved issues name where their fix landed
The cycle check now asks a resolved issue for its owner, and these had none.
2026-09-21 17:39:34 +02:00

77 lines
3.9 KiB
Markdown

---
status: resolved
opened: 2026-09-15
located-in: [mesh-tools, mesh-host, mesh-sdk]
fixed-by: mesh-tools b618057 (the SDK resolved by version from the registry, one pin); mesh-host 7986306; mesh-controller 4b9bc50. Caveat: the base image still builds with npm install and no lock, so the build is not reproducible
amended-design:
---
# 053 — The SDK is pinned twice, and the two disagree
## Symptom
The module that carries the tool runtime names the SDK two ways, and they are not the same thing:
```
package.json @novox/mesh-sdk -> git+https://<the forge>/mesh-sdk.git#<a commit>
package-lock.json @novox/mesh-sdk -> ../mesh-sdk
```
The manifest names a commit in a repository any machine can reach. The lock names a **sibling
directory**, which exists on the workstation the lock was generated on and nowhere else.
It builds anyway, because the recipe runs `npm install` — which tolerates a lock that disagrees
with its manifest and re-resolves from the manifest. It is the one command that hides this.
## Why this matters
**A lock file exists to make a build reproducible, and this one describes one machine.** `npm ci` —
the command for exactly the case a lock is for — fails here, or worse, succeeds against whatever
happens to be at that path.
**It is the first thing a fresh mesh builds.** The toolchain image carries the SDK, and everything
with code of its own is compiled inside it. A dependency resolved differently on the build machine
than on a workstation is a difference in every module the mesh will ever build, arriving as a
compile error or a runtime mismatch far from here.
**And it is about to be copied.** Each language's toolchain will carry that language's SDK the same
way ([ADR 0074](../../02-DECISIONS/0074-the-wire-is-specified-not-the-types.md)). Whatever this
repository does, the Rust and Python ones will do, so the shape is worth getting right before there
are four of them.
## It is a violation, not an open question
[ADR 0014](../../02-DECISIONS/0014-no-npm-workspace.md) already decided this, and was accepted:
> Each module is an independent package that declares its dependencies and **consumes them from
> the private registry, including the mesh's own shared library.** A cross-package change is
> therefore two steps: publish the producer, then consume it.
So a git dependency at a pinned commit is not an alternative mechanism under consideration. It is
the mesh's own shared library being consumed by a means the record rules out, and the lock naming
a sibling directory is what that looks like when nobody publishes.
**Which makes the fix a direction rather than a discussion**: publish the SDK to the private
registry, consume it by version, and the lock stops being able to name a path that exists on one
machine.
## Open questions
- **Which private registry, and does the bootstrap have one?** The catalogue holds `verdaccio`;
a git host typically serves package registries too. ADR 0014 says *the* private registry as
though there is one, and today a fresh mesh has neither until something installs it — so the
first SDK build happens before the registry the record assumes.
- **Or should the SDK be a published package?** The catalogue holds a private registry module, and a
published package is how the rest of the world does this — at the cost of a mesh needing that
registry up before it can build anything, which is a bootstrap problem where there is currently
none.
- **What generates the lock, and on what?** A lock produced on a workstation with sibling checkouts
will keep saying this. A lock produced the way the image builds would not.
## How this would be checked
| Rule | Checked by |
|---|---|
| A build does not depend on the machine it runs on | The toolchain image builds with `npm ci` rather than `npm install`, which refuses a lock that disagrees with its manifest. |
| The SDK a module compiles against is the one named | The commit baked into the toolchain image is compared with the one the manifest pins. |