Module state is hq ADR 0202: 0201 landed first for a provider's derivations

This commit is contained in:
jochen
2026-10-04 03:44:56 +02:00
parent 0677cebb9b
commit d937c7bc2f
8 changed files with 11 additions and 11 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ react to mesh events, and the envelope/routing-key conventions. Transport primit
`state(name)` reaches a state the module declared it keeps (`state` in its manifest) or reads `state(name)` reaches a state the module declared it keeps (`state` in its manifest) or reads
(`reads`, as `<module>.<name>`): `get`, `put`, `delete`, `keys`, and `watch`, which hands the current (`reads`, as `<module>.<name>`): `get`, `put`, `delete`, `keys`, and `watch`, which hands the current
values and then every change. Through the runtime that launched the bundle, which refuses what the values and then every change. Through the runtime that launched the bundle, which refuses what the
module did not declare. Current values, never history and never a secret (novox/hq ADR 0201). module did not declare. Current values, never history and never a secret (novox/hq ADR 0202).
### `primitives` — sealing, semver, resolved-env ### `primitives` — sealing, semver, resolved-env
Seal/unseal for secrets, semantic version comparison, and the accessor a module uses to read its Seal/unseal for secrets, semantic version comparison, and the accessor a module uses to read its
+1 -1
View File
@@ -6,7 +6,7 @@ import (
) )
// State — the current value of something a module keeps on the bus, which every machine sees, // State — the current value of something a module keeps on the bus, which every machine sees,
// including one that joins later (novox/hq ADR 0201). Not history: that is an event. Never a secret, // including one that joins later (novox/hq ADR 0202). Not history: that is an event. Never a secret,
// sealed or not. A module declares what it keeps (`state`) and what it reads (`reads`, as // sealed or not. A module declares what it keeps (`state`) and what it reads (`reads`, as
// `<module>.<name>`) and names each here as it named it there; the runtime refuses, with the reason, // `<module>.<name>`) and names each here as it named it there; the runtime refuses, with the reason,
// what it did not declare. // what it did not declare.
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"time" "time"
) )
// A Go bundle keeps and watches its state through the runtime (novox/hq ADR 0201): the watch's // A Go bundle keeps and watches its state through the runtime (novox/hq ADR 0202): the watch's
// current values are handled before it returns, its changes are named by the watch's id, a change for // current values are handled before it returns, its changes are named by the watch's id, a change for
// no watch of this bundle is refused, and put, get and keys are asked of the runtime as the module. // no watch of this bundle is refused, and put, get and keys are asked of the runtime as the module.
func TestABundleKeepsAndWatchesStateThroughTheRuntime(t *testing.T) { func TestABundleKeepsAndWatchesStateThroughTheRuntime(t *testing.T) {
+2 -2
View File
@@ -60,7 +60,7 @@ type channel struct {
next int next int
waiting map[string]chan message waiting map[string]chan message
listeners []listener listeners []listener
// watches are this bundle's state watches by the id each was asked with (ADR 0201). // watches are this bundle's state watches by the id each was asked with (ADR 0202).
watches map[string]func(StateChange) error watches map[string]func(StateChange) error
} }
@@ -247,7 +247,7 @@ func ServeOn(name string, tools []Tool, in io.Reader, out io.Writer) error {
c.say(map[string]any{"id": id, "result": map[string]any{}}) c.say(map[string]any{"id": id, "result": map[string]any{}})
}(id, *p.Envelope, matching) }(id, *p.Envelope, matching)
case "mesh/state": case "mesh/state":
// One change to a state this bundle watches (ADR 0201), named by the watch's id, answered // One change to a state this bundle watches (ADR 0202), named by the watch's id, answered
// once its handler has taken it. Beside the loop, like a tool call. // once its handler has taken it. Beside the loop, like a tool call.
var p struct { var p struct {
Watch string `json:"watch"` Watch string `json:"watch"`
+2 -2
View File
@@ -1,5 +1,5 @@
// State — the current value of something a module keeps on the bus, which every machine sees, // State — the current value of something a module keeps on the bus, which every machine sees,
// including one that joins later (novox/hq ADR 0201). Not history: that is an event. Never a secret, // including one that joins later (novox/hq ADR 0202). Not history: that is an event. Never a secret,
// sealed or not: a bucket is kept, and a machine joining a year later reads it whole. // sealed or not: a bucket is kept, and a machine joining a year later reads it whole.
// //
// A module declares the state it keeps (`state` in its manifest) and the state of others it reads // A module declares the state it keeps (`state` in its manifest) and the state of others it reads
@@ -65,7 +65,7 @@ function bound(): StateChannel {
if (!channel) { if (!channel) {
throw new Error( throw new Error(
"no runtime to keep state through — a module's state is reached through the runtime that launched " + "no runtime to keep state through — a module's state is reached through the runtime that launched " +
"its bundle (novox/hq ADR 0201)", "its bundle (novox/hq ADR 0202)",
); );
} }
return channel; return channel;
+2 -2
View File
@@ -71,7 +71,7 @@ function startSession(): Session {
}); });
const ask = (method: string, params: unknown): Promise<unknown> => askAs(`bundle-${nextOut++}`, method, params); const ask = (method: string, params: unknown): Promise<unknown> => askAs(`bundle-${nextOut++}`, method, params);
// The module's state (ADR 0201): each watch's changes arrive as `mesh/state` requests naming the // The module's state (ADR 0202): each watch's changes arrive as `mesh/state` requests naming the
// watch by the id it was asked with, so its handler is registered under that id before it is asked // watch by the id it was asked with, so its handler is registered under that id before it is asked
// — the current values arrive before the watch itself is answered. // — the current values arrive before the watch itself is answered.
const watches = new Map<string, (change: StateChange<unknown>) => Promise<void>>(); const watches = new Map<string, (change: StateChange<unknown>) => Promise<void>>();
@@ -176,7 +176,7 @@ function startSession(): Session {
return; return;
} }
case "mesh/state": { case "mesh/state": {
// One change to a state this bundle watches (ADR 0201), answered once its handler has taken // One change to a state this bundle watches (ADR 0202), answered once its handler has taken
// it. The runtime delivers a watch's changes one at a time, in order. // it. The runtime delivers a watch's changes one at a time, in order.
const p = request.params as { watch?: string; change?: StateChange<unknown> } | undefined; const p = request.params as { watch?: string; change?: StateChange<unknown> } | undefined;
const deliver = p?.watch !== undefined ? watches.get(String(p.watch)) : undefined; const deliver = p?.watch !== undefined ? watches.get(String(p.watch)) : undefined;
+1 -1
View File
@@ -1,4 +1,4 @@
// A launched bundle that keeps state through its runtime (novox/hq ADR 0201): it watches its servers as // A launched bundle that keeps state through its runtime (novox/hq ADR 0202): it watches its servers as
// it is imported, before it says what it serves, and its tools write, read and list them. // it is imported, before it says what it serves, and its tools write, read and list them.
import { state } from "../../dist/state/index.js"; import { state } from "../../dist/state/index.js";
import { registerModuleTools } from "../../dist/tools/index.js"; import { registerModuleTools } from "../../dist/tools/index.js";
+1 -1
View File
@@ -160,7 +160,7 @@ test("a launched bundle subscribes as it is imported, handles events the runtime
} }
}); });
test("a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0201)", async () => { test("a launched bundle watches its state as it is imported, has the current values before it goes on, and keeps state through the runtime (ADR 0202)", async () => {
const child = spawn(process.execPath, [fileURLToPath(new URL("./fixtures/stdio-state.mjs", import.meta.url))], const child = spawn(process.execPath, [fileURLToPath(new URL("./fixtures/stdio-state.mjs", import.meta.url))],
{ stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, MESH_SERVED_MODULE: "keeper" } }); { stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, MESH_SERVED_MODULE: "keeper" } });
const seen: any[] = []; const seen: any[] = [];