Files
mesh-sdk/go
jschoubben dbcaa29a1a
mesh/delivery merged: source.main moved to novox/mesh-sdk@307b6234e6bb
mesh/delivery-group group fix/1960-no-hold-spread merged: every member is merged
mesh/check pass dbcaa29a1a38 on 394fec8a63c1 | unit 3318 run, 1951 kept, 38 skipped | integration 3994 run, 2125 kept, 38 skipped | over bound: unit, …
Never hold a module because a module it reads from is held: it composes with what the held one last offered (issue 1960)
On novox on 2026-10-29 de-spiegel, held for an unset config value, held mailu, route-proxy and nftables ("it reads
what de-spiegel contributes or listens on"), and mailu held postgres. mesh-sdk #128 (issue 1126) stopped the hold
spreading to consumers and collectors but kept dependents(): the provider of what a held module contributes to, and
the filter where it listens, were held behind it, transitively.

- Quick fix: drop dependents() alone. The filter and the proxy would then read a held module's new manifest, which
  may not be what runs (review of the apply, round 2).
- Thorough fix, chosen: no module is held behind another, in the apply and in the answer (dependents, heldBehind and
  the held-behind path of heldAsToday removed). A held module offers what it last offered: its contributions and
  listens from its manifest at the build its own composition runs at (ranOf), else the manifest it is composed from.
  Only the part of its offer that does not compose is left out, by provision (culprit): de-spiegel's routes leave
  route-proxy without them, while mailu keeps its smtp account; the hold names it.

Tests: rows changed in the existing answer test (de-spiegel held, mailu and proxy composed; site held, the filter
composed with what runs; leave-out by provision). No new test function.
2026-10-29 15:54:21 +01:00
..

mesh-sdk for Go

stdio.Serve("", tools) speaks MCP over stdio to the node's tool runtime, as the module the runtime names (novox/hq ADR 0188, ADR 0193). A Tool is a name, a description, an argument schema and a function; calls run concurrently. stdio.CallerOf(args) inside a tool is who called it: the bus user the runtime took from the subject the call arrived on, named in the call's _meta, never read from the arguments — or stdio.Unproven when the runtime named none (novox/hq issue 365). A tool named <seat>.<verb> is the seat's implementation. stdio.Emit(type, body) publishes an event as the module, stdio.Subscribe(pattern, handler) receives the module's events (taken when the handler returns nil, offered again when it returns an error — the one rule is in the repository README, "Taking an event") and stdio.Ask(key, body) calls a tool, and stdio.State(name) gets, puts, deletes, lists, watches and reads the kept history of the module's declared state, and stdio.Log(name) appends to, reads, and measures a log of operations the module declared — all through the runtime (novox/hq ADR 0193, 0198, 0201, 0297, 0307). stdio.Config(key) and stdio.Bound(provision, key) read, and stdio.WatchConfig and stdio.WatchBound watch, the module's own config values and the non-secret values of what it is bound to, for what its manifest declares: the runtime asks its machine's provisioner client as the module it launched, never a module the code names. stdio.Secret(name) is refused while the module's code runs in the tool runner; its secrets reach it through its files (novox/hq ADR 0349 §14, ADR 0370). provider is a providing module's half of a binding (novox/hq ADR 0349 §12, issue 678): it sees each consumer that binds the provider in the plans of the assignments mirror, writes one entry per consumer to <module>_bound (<node>.<module>.<provision>[.<local>]: served values composed with the consumer's identity, the login, and the name of the vault's credential, never a secret), hands the provider's adapter the vault's value (provision/<provider>/<provision> shared, pair/<provider>/<provision>/<node>/<module>[/<local>] per consumer), refuses a derived value to a consumer bound under a local name, naming both ends, and removes the entry of one that unbinds; the bus and the vault are interfaces the provider wires, the vault as provider.ConsumersFile, the file its machine's provisioner client fills from ${consumers:<provision>} with each bound consumer's credential (novox/hq ADR 0373), since a provider in the tool runner never asks the vault itself. Standard library only.

Installing

GOPRIVATE=git.novox.be go get git.novox.be/novox/mesh-sdk/go@latest

Releases are tagged go/vX.Y.Z in this repository, the subdirectory form Go's module system expects, at the same version as the TypeScript package.

What it holds, under ADR 0039's test: the stdio loop and the tool type, and cli, the local protocol mesh-cli speaks to the node-engine on its machine (novox/hq ADR 0272): the socket's path and one request and one answer; and seal, the mesh's sealed box (novox/hq ADR 0206: X25519, HKDF-SHA256, AES-256-GCM, {v, eph, iv, tag, ct}), byte for byte the box the licence manager made before it lived here and the TypeScript @novox/mesh-sdk/seal makes. Nothing else — no bus, no client, nothing of any module's. go build ./example and pipe a tools/list request into it.

From release 4a of design 47 (novox/hq ADR 0453 clause 3, ADR 0446 clause 4) it also holds the composition of a machine's declaration, over a plain input and with nothing behind it: declaration and validate, the node-engine's parser and its validator, copied from mesh-host; catalogue, the manifests, their resolution and rendering, and overlay, the private network's generator, copied from mesh-controller; compose, the controller's planFor, renderingFor and declarationWith as functions of an Input (the composition never allocates, makes, keeps or writes: what a send would do it names as foreseen or returns); sdkversion, which mesh-sdk version a program was built with; and, in delivery, the layouts of the keys the builder, the checker and the indexer write (the source fingerprint's new form, the builds, the verdicts and kept verdicts, the manifests by digest). None of them holds a bus, a store or a vault client, which go list -deps of compose shows.