Files
mesh-sdk/go
jschoubben c2999a4e13
mesh/delivery merged: source.main moved to novox/mesh-sdk@394fec8a63c1
mesh/delivery-group group fix/1126-held-as-runs merged: every member is merged
mesh/check pass c2999a4e13cc on d4c61ee8ffd0 | unit 3054 run, 234 kept, 36 skipped | integration 3075 run, 266 kept, 29 skipped | over bound: unit (sl…
A held module is no dependence of its neighbours: its hold stops spreading (issue 1126)
novox's seed p-20261028t231141-ec84b4 refused 11 modules "what it composes of ..., held, is not what runs of them":
de-spiegel's hold spread through mailu to postgres, nftables and route-proxy, and from postgres to every consumer, and
gitea, held so, refused the node: "its credential of postgres-database is handed to the provisioner and the module is
not: nothing would fill it". Three rounds each moved the error. The kind: a held module still took part in the
composition as a dependence, so its hold spread.

- The quick fix: let heldAsToday also follow dependsOnHeld's words, and skip the handed refusal for gitea. It moves the
  error once more and leaves every node's applying path holding consumers.
- The thorough fix, chosen: a held module composes only as what runs of it. composeEach no longer compares the
  composition with each held module as its stub (dependsOnHeld removed): a consumer or collector composes against what
  runs of the held module like any other module, and a real difference is still a named difference in the answer, a
  module's own refusal still its refusal. A stub (compose.Stub, catalogue.Manifest.Stubbed) leaves the credentials and
  own secrets it would hand the provisioner out of its plan as they run, never refused for want of a plan. Only what a
  held module's new manifest says to others in their own files is still held behind it (dependents: the provider of
  what it contributes to, the filter where it listens), which heldAsToday already follows.

Tests: rows added to existing tests (a held provider with a binding consumer, which the old code held in the seed's
words; a held feeder of a collector; a held module with a handed credential and own secret). No new test function.
2026-10-29 00:49:00 +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.