From 89a202f12e7d7b29bbc4299364c099431d6e4f67 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 3 Oct 2026 12:46:51 +0200 Subject: [PATCH] Issue 209: a bundle's own SDK copy registers into a registry the runtime never reads; design 38 WP4 note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found preparing WP4, before the first module's bundle was loaded beside the runtime's own: proven with a two-copies probe, located in mesh-tools (node-tools), fixed by mesh-tools #32. Design 38 WP4 records it and the two things the package left to the module — escalation through sudo, and the filter file read from the manifest's path rather than a container env. --- .../38-building-the-operators-machine.md | 12 +++++ .../00-report.md | 51 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 04-ISSUES/209-a-bundles-own-sdk-copy-registers-into-a-registry-the-runtime-never-reads/00-report.md diff --git a/03-DESIGN/01-to-be/38-building-the-operators-machine.md b/03-DESIGN/01-to-be/38-building-the-operators-machine.md index 435d554..e3b4134 100644 --- a/03-DESIGN/01-to-be/38-building-the-operators-machine.md +++ b/03-DESIGN/01-to-be/38-building-the-operators-machine.md @@ -191,6 +191,18 @@ tool where they need root, which they have, since the runtime runs as the node's four machines; `docker ps` shows no `mesh-nftables`; `status` is well. Then the fail2ban holder proposed in an open change follows the same way when it lands. +*Found 2026-10-03, before the step ran:* a bundle imported in-process brings its own copy of the SDK +(WP3's *carry its dependencies*), and the SDK's tool registry is the copy's own — the first module +loaded beside the runtime would have registered its tools where the runtime never looks, and served +nothing, silently. Issue +[209](../../04-ISSUES/209-a-bundles-own-sdk-copy-registers-into-a-registry-the-runtime-never-reads/00-report.md): +the runtime now resolves every bundle's import of the SDK to its own copy, one registry and one +broker per node. Two things the package did not say, settled in the module: the filter's commands +run through `sudo` without a prompt where the runtime is not root, since the operator's account may +escalate as the operator would; and a bundle has no environment of its own, so the tool reads the +filter from the path the manifest's `filtering` names rather than from a variable the container used +to carry. + ## WP5 — The shell, on a server first *mesh-catalog #224, already written. Half a day to assign and prove.* diff --git a/04-ISSUES/209-a-bundles-own-sdk-copy-registers-into-a-registry-the-runtime-never-reads/00-report.md b/04-ISSUES/209-a-bundles-own-sdk-copy-registers-into-a-registry-the-runtime-never-reads/00-report.md new file mode 100644 index 0000000..82eb261 --- /dev/null +++ b/04-ISSUES/209-a-bundles-own-sdk-copy-registers-into-a-registry-the-runtime-never-reads/00-report.md @@ -0,0 +1,51 @@ +--- +status: located +opened: 2026-10-03 +located-in: + - mesh-tools +fixed-by: +amended-design: +--- + +# 209 — A bundle's own copy of the SDK registers into a registry the runtime never reads + +## What was observed + +2026-10-03, preparing [design 38](../../03-DESIGN/01-to-be/38-building-the-operators-machine.md) +WP4 — the first module whose tools bundle the node's runtime would load beside its own. Before the +manifest changed, a probe on the laptop did what the runtime does: a process holding one copy of +`@novox/mesh-sdk` imported a bundle in another directory that carried its own copy, and the bundle +called `registerModuleTools` as every tools entrypoint does. + +``` +registrations seen by host after importing bundle: 0 +``` + +The import succeeds, the bundle registers, and the runtime's `collectTools` sees nothing. The +runtime would log the bundle as loaded and answer `tools` for the module with an empty list: silent, +and indistinguishable from a module that serves nothing by choice. + +## Why it matters beyond this instance + +WP3 found that *a TypeScript bundle must carry its dependencies*, and the toolchain copies them in +so a bundle starts anywhere. Among them is the SDK. The runtime imports a bundle in-process, and +the language resolves a bare import from the importing file's own tree — so every bundle brings a +second SDK into the process: its own registry of tools and its own broker handle. The SDK's registry +is a module-level list, and the runtime reads only the one it imported itself. + +Every module from WP4 on is loaded this way. The runtime's tests never met it because their fixture +bundles sit under the runtime's own tree and resolve the same copy. Nothing in design 38 WP1 or WP3 +says which SDK a loaded bundle speaks to, and the one-runtime record +([ADR 0175](../../02-DECISIONS/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md)) +assumes without saying that it is the runtime's. + +## Diagnosis + +Owner mesh-tools (`node-tools`): the runtime imports a bundle's entrypoint and counts the +registrations that appear after it, through the SDK it imported; the bundle's `import "@novox/mesh-sdk/tools"` +resolves to the copy under the bundle's own `node_modules`. **Fix direction:** the runtime resolves +every import of the SDK, from whichever bundle, as if the runtime had written it — one registry, +one broker — and leaves everything else a bundle carries to the bundle's own tree. A test loads a +bundle from a directory holding its own copy of the SDK and asserts its tools are served. The +toolchain keeps copying dependencies in: a bundle launched as a process ([ADR 0188](../../02-DECISIONS/0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md)) +needs them, and an imported one is simply not allowed to bring a second SDK.