From 49c825f5ba7ce6c52d5c9c6247381fd1d79364c7 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 16 Sep 2026 00:06:37 +0200 Subject: [PATCH 1/3] Remove the dead contract types that contradicted the live wire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grant, Credential and an Interface type lived in contracts, exported and imported by nothing, describing a grant with fields — resource, consumer — the live wire does not use. The wire is the contributions file, whose shape (as, secret, node, at, values) agrees between Go and TypeScript. These dead types are how ADR 0074 came to claim a drift that inspection does not find: they read as the contract and were not. A type is only as good as its being the wire, and one that has drifted from it while still being exported is worse than no type. Removed. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx --- src/contracts/index.ts | 44 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/src/contracts/index.ts b/src/contracts/index.ts index 2c2a21e..d57ae11 100644 --- a/src/contracts/index.ts +++ b/src/contracts/index.ts @@ -1,39 +1,13 @@ // The runtime shapes a module's own code touches — NOT the manifest schema, which the control -// plane owns and parses (in Go). These are what a running module receives and returns: a grant -// and its credentials, the mesh interface a provider and consumer both conform to, and the tool -// and event types. They change rarely and deliberately (novox/hq ADR 0039). - -/** A request for one instance of a provided resource, addressed to a provider. */ -export interface Grant { - /** The mesh interface being provisioned, e.g. "analytics", "postgres-database". */ - readonly resource: string; - /** Who asked — the consumer module, on which node. */ - readonly consumer: string; - readonly node: string; - /** What the consumer contributed (per the interface's spec keys), e.g. `{ name: "umami" }`. */ - readonly values: Readonly>; -} - -/** What a provider hands back for a grant. Sealed by the harness before it leaves the machine. */ -export interface Credential { - /** The fields the interface promises a consumer, e.g. `{ host, port, as, password }`. */ - readonly fields: Readonly>; -} - -/** - * A mesh interface: the provider-neutral contract for a capability (novox/hq ADR 0040). Both a - * provider (which adapts its software to it) and a consumer (which depends on it, never on a - * provider) conform. `spec` names what a consumer may contribute; `credential` names what it - * receives. The interface is drawn at the consumer's real coupling: neutral where thin - * (`analytics`), the protocol where the consumer speaks one (`postgres-database`). - */ -export interface Interface { - readonly name: string; - /** Keys a consumer may contribute when requesting it. */ - readonly spec: readonly string[]; - /** Fields a consumer receives in its credential. */ - readonly credential: readonly string[]; -} +// plane owns and parses (in Go). What is here is what actually crosses the wire: the tool +// definition and the event envelope. They change rarely and deliberately (novox/hq ADR 0039). +// +// **The provisioning shapes are NOT here, and used to be — wrongly.** Grant, Credential and an +// Interface type lived here, exported and imported by nothing, and they described a grant with +// fields (`resource`, `consumer`) the live wire does not use: the wire is the contributions file, +// whose shape is in `provisioner/index.ts` and agrees with the Go side. Dead types that +// contradict the live wire are worse than none — they read as the contract and are not, which is +// exactly how ADR 0074 came to claim a drift that was not there. Removed. /** A tool a module exposes through the mesh's command surface. */ export interface ToolDefinition { From 286cf0bba2884daeff0eee5e82f1d0c85db1bfe5 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 16 Sep 2026 10:27:26 +0200 Subject: [PATCH 2/3] The SDK is a module the mesh builds and publishes A package artifact, built on a public base and published to the mesh's package registry by version, so every module resolves it the ordinary way (hq ADR 0076). Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx --- module.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 module.json diff --git a/module.json b/module.json new file mode 100644 index 0000000..bf74eb7 --- /dev/null +++ b/module.json @@ -0,0 +1,11 @@ +{ + "module": "mesh-sdk", + "version": "1", + "slug": "sdk", + "build": { + "artifacts": [ + { "name": "lib", "kind": "package", "language": "typescript" } + ] + }, + "resources": [] +} From f062235c5ebcb73861b071c86c79f16c474c471c Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 16 Sep 2026 18:40:40 +0200 Subject: [PATCH 3/3] Rename mesh-control -> mesh-controller, substrate -> foundation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One name per thing, per the HQ glossary: the module/container/image/binary/repo becomes mesh-controller, the seat the-controller, and the store+broker pair the foundation (embedded base bundles, default template and example lock renamed with their go:embed directives). No behaviour change — a pure vocabulary rename. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx --- README.md | 2 +- src/messaging/index.ts | 2 +- test/sdk.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d390ef0..90e5101 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ own resolved environment. - **A module's API client and its tool implementations** → in the module. (The Plex client, the Umami client, `tools/plex.ts` — all module-local. ADR 0039.) - **Delivery machinery** — build executor, bundler, dependency resolver, artifact manager, feature - handlers → **mesh-control**. It co-evolves with the pipeline. + handlers → **mesh-controller**. It co-evolves with the pipeline. - **Host synchronisers** — config-sync, ufw config, vhost generation, systemd, health checks → **mesh-host**'s apply engine. The host applies these; they are not module code. - **Domain logic** — tasks, workflows, agents, provider integrations → **tier-2 contexts**. diff --git a/src/messaging/index.ts b/src/messaging/index.ts index 31a7257..ce71883 100644 --- a/src/messaging/index.ts +++ b/src/messaging/index.ts @@ -9,7 +9,7 @@ export type { Envelope, EventHeaders }; /** A request/reply call and a publish/subscribe surface over the mesh broker. */ export interface Broker { - /** Ask one question and await one answer — the client side; the shape mesh-control's command + /** Ask one question and await one answer — the client side; the shape mesh-controller's command * API is reached by. */ request(key: string, body: Req): Promise; /** Answer a question — the server side of request/reply. A tool runtime serves invocations this diff --git a/test/sdk.test.ts b/test/sdk.test.ts index 1caa16d..02dac73 100644 --- a/test/sdk.test.ts +++ b/test/sdk.test.ts @@ -106,7 +106,7 @@ test("modules can SERVE: a real async tool, loaded and invoked over the broker", const broker = memBroker(); const stop = await serveTools(broker, {}); - // Invoke it the way a caller (mesh-control's command API) would — over the broker, by module and + // Invoke it the way a caller (mesh-controller's command API) would — over the broker, by module and // tool, each served on its own key `demo.create_site` (novox/hq ADR 0047). const result = (await invokeTool(broker, "demo", "create_site", { domain: "my-app" })) as { snippet: string }; assert.match(result.snippet, /data-website-id="site-123"/);