From c112df0c1ca67bc01566894302d2b08510013a66 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 22 Oct 2026 18:03:06 +0200 Subject: [PATCH] =?UTF-8?q?Announce=20the=20states=20the=20forge=20module?= =?UTF-8?q?=20keeps=20(issue=201790,=20ADR=200495=20=C2=A72=20=C2=A75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/gitea/index.ts | 5 +++++ modules/gitea/kept.ts | 8 ++++++++ modules/gitea/package.json | 2 +- modules/gitea/test/kept.test.ts | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 modules/gitea/kept.ts create mode 100644 modules/gitea/test/kept.test.ts diff --git a/modules/gitea/index.ts b/modules/gitea/index.ts index 601290e6..cca6f610 100644 --- a/modules/gitea/index.ts +++ b/modules/gitea/index.ts @@ -38,6 +38,8 @@ import { emit, on } from "@novox/mesh-sdk/events"; import { registerModuleTools } from "@novox/mesh-sdk/tools"; +import { keeps } from "@novox/mesh-sdk/state"; +import { KEPT } from "./kept.js"; import { commitStatusTool } from "./delivery.js"; import { announce, keepWatermark, readWatermark } from "./announce.js"; import { mergeTool } from "./merge.js"; @@ -473,6 +475,9 @@ const gates = new GateWriter({ const pace = new Pace(); if (!gitea) pace.unheard("the forge is not watched: no way to a token", false); +// The states this module keeps and which others may read, said on the bus before it serves (novox/hq ADR 0495 clause 2). +await keeps(KEPT); + // gitea_events is served whether or not the forge is watched: it says so (novox/hq issue 729). registerModuleTools("gitea", () => [eventsTool(pace), ...(gitea ? [commitStatusTool({ setCommitStatus: (owner, repo, sha, status) => (gitea as GiteaClient).setCommitStatus(owner, repo, sha, status), diff --git a/modules/gitea/kept.ts b/modules/gitea/kept.ts new file mode 100644 index 00000000..baa70f84 --- /dev/null +++ b/modules/gitea/kept.ts @@ -0,0 +1,8 @@ +// The states this module keeps on the bus and whether other modules may read them (novox/hq ADR 0495 clause 2; issue +// 1790): the module says it itself, from its code, as it starts (index.ts calls keeps with this list), and a reader is +// granted what it said (clause 3). A state is readable when another module's manifest reads it; none reads gitea's. +// test/kept.test.ts holds the list to the manifest's `state`. +export const KEPT: readonly { readonly name: string; readonly readable?: boolean }[] = [ + { name: "announced" }, + { name: "bound" }, +]; diff --git a/modules/gitea/package.json b/modules/gitea/package.json index 21a6feb5..2a21d1f5 100644 --- a/modules/gitea/package.json +++ b/modules/gitea/package.json @@ -9,7 +9,7 @@ "test": "npm run build && node --test --experimental-strip-types 'test/*.test.ts'" }, "dependencies": { - "@novox/mesh-sdk": "^0.1.1" + "@novox/mesh-sdk": "^0.1.15" }, "devDependencies": { "@types/node": "^22.0.0", diff --git a/modules/gitea/test/kept.test.ts b/modules/gitea/test/kept.test.ts new file mode 100644 index 00000000..2f942fd5 --- /dev/null +++ b/modules/gitea/test/kept.test.ts @@ -0,0 +1,20 @@ +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { readFileSync } from "node:fs"; + +// 1790: the states the module announces are the states its manifest declares, no more, no fewer; none is readable +// because no other module's manifest reads one of them. +test("the states the module announces are the states its manifest declares", async () => { + const { KEPT } = await import("../kept.ts"); + const manifest = JSON.parse(readFileSync(new URL("../module.json", import.meta.url), "utf8")); + const declared = (manifest.state as (string | { name: string })[]).map((s) => (typeof s === "string" ? s : s.name)).sort(); + assert.deepEqual(KEPT.map((k) => k.name).sort(), declared); + assert.ok(KEPT.every((k) => !k.readable), "no other module's manifest reads a state of gitea"); +}); + +test("index.ts announces the list through the SDK before it serves", () => { + const source = readFileSync(new URL("../index.ts", import.meta.url), "utf8"); + assert.match(source, /import \{ keeps \} from "@novox\/mesh-sdk\/state"/); + assert.match(source, /await keeps\(KEPT\)/); + assert.ok(source.indexOf("await keeps(KEPT)") < source.indexOf("registerModuleTools(\"gitea\""), "keeps comes before the tools are served"); +});