Let a module's code announce the states it keeps, in Go and TypeScript (issue 1790, S10, ADR 0495 §2 §5)

process.Conn.Keeps, stdio.Keeps and the TypeScript keeps publish the announcement on
the module's own subject; afterwards a state the code did not announce is refused at
the call, so announcement and code cannot drift. The package goes to 0.1.15 for keeps.
This commit is contained in:
2026-10-22 17:42:24 +02:00
parent bb8b3bb43b
commit 57d2f31f05
15 changed files with 410 additions and 4 deletions
+11
View File
@@ -0,0 +1,11 @@
// A launched bundle that says what it keeps (novox/hq ADR 0495 clause 2; issue 1790): it announces its states as it is
// imported, and a state of its own it did not announce is refused at the call.
import { keeps, state } from "../../dist/state/index.js";
import { registerModuleTools } from "../../dist/tools/index.js";
import { serveRegisteredOverStdio } from "../../dist/stdio/index.js";
await keeps([{ name: "servers", readable: true }, { name: "own" }]);
registerModuleTools("keeper", () => [
{ name: "unannounced", description: "reads a state it did not announce", input: {}, run: async () => state("drafts").get("k") },
]);
await serveRegisteredOverStdio();
+37
View File
@@ -273,3 +273,40 @@ test("topics match as the runtime's do: * one segment, # and ** any number", asy
assert.ok(topicMatches("alpha.**", "alpha.a.b"));
assert.ok(!topicMatches("beta.*", "alpha.happened"));
});
test("a launched bundle announces what it keeps as it is imported, and binds no state it did not announce (ADR 0495, issue 1790)", async () => {
const child = spawn(process.execPath, [fileURLToPath(new URL("./fixtures/stdio-keeps.mjs", import.meta.url))],
{ stdio: ["pipe", "pipe", "inherit"], env: { ...process.env, MESH_SERVED_MODULE: "keeper", MESH_MODULE: "keeper", MESH_NODE: "anchor" } });
const seen: any[] = [];
let buffered = "";
child.stdout.on("data", (d) => {
buffered += d.toString();
let at: number;
while ((at = buffered.indexOf("\n")) >= 0) {
seen.push(JSON.parse(buffered.slice(0, at)));
buffered = buffered.slice(at + 1);
}
});
const until = async (match: (m: any) => boolean) => {
for (let i = 0; i < 150 && !seen.some(match); i++) await new Promise((r) => setTimeout(r, 20));
return seen.find(match);
};
const send = (m: unknown) => child.stdin.write(JSON.stringify(m) + "\n");
try {
const asked = await until((m) => m.method === "mesh/publish");
assert.ok(asked, "the bundle announced nothing as it was imported");
assert.equal(asked.params.key, "states");
assert.deepEqual(asked.params.body, {
v: 1, module: "keeper", node: "anchor", states: [{ name: "own" }, { name: "servers", readable: true }],
});
send({ jsonrpc: "2.0", id: asked.id, result: {} });
send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-03-26", capabilities: {} } });
await until((m) => m.id === 1);
send({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "unannounced", arguments: {} } });
const answered = await until((m) => m.id === 2);
assert.match(JSON.stringify(answered), /drafts/, "a state the bundle did not announce was bound");
assert.equal(seen.find((m) => m.method === "mesh/state.get"), undefined, "the runtime was asked for an unannounced state");
} finally {
child.kill();
}
});