From 5440a144a09a2aedafe955753fccee8695aacb65 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 03:44:34 +0200 Subject: [PATCH] ADR 0201 (module state) renumbered 0202: 0201 landed first on main for a provider's derivations --- .../00-overview.md | 2 +- ...s-it-declares-and-reaches-through-the-runtime.md} | 2 +- 02-DECISIONS/README.md | 2 +- 03-DESIGN/01-to-be/25-the-bus-on-nats.md | 12 ++++++------ 03-DESIGN/01-to-be/32-what-a-module-declares.md | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) rename 02-DECISIONS/{0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md => 0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md} (99%) diff --git a/01-RESEARCH/024-state-a-module-keeps-on-the-bus/00-overview.md b/01-RESEARCH/024-state-a-module-keeps-on-the-bus/00-overview.md index 91bc89e..803385d 100644 --- a/01-RESEARCH/024-state-a-module-keeps-on-the-bus/00-overview.md +++ b/01-RESEARCH/024-state-a-module-keeps-on-the-bus/00-overview.md @@ -2,7 +2,7 @@ status: graduated initiated: 2026-10-04 touches: [the bus, what a module declares, the tool runtime, the SDK, the bus grants, 03-DESIGN/01-to-be/25-the-bus-on-nats.md, 03-DESIGN/01-to-be/32-what-a-module-declares.md] -became: [02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md, 03-DESIGN/01-to-be/32-what-a-module-declares.md, 03-DESIGN/01-to-be/25-the-bus-on-nats.md] +became: [02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md, 03-DESIGN/01-to-be/32-what-a-module-declares.md, 03-DESIGN/01-to-be/25-the-bus-on-nats.md] --- # 024 — State a module keeps on the bus diff --git a/02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md b/02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md similarity index 99% rename from 02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md rename to 02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md index 67f831a..f80be39 100644 --- a/02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md +++ b/02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md @@ -7,7 +7,7 @@ reconstructed: false extends: 02-DECISIONS/0198-a-modules-long-running-code-is-launched-by-the-node-runtime-and-reaches-the-bus-through-it.md --- -# 201. A module keeps its current state in key-value buckets it declares, and reaches them through the runtime +# 202. A module keeps its current state in key-value buckets it declares, and reaches them through the runtime ## Context diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 1d582bd..9926c45 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -300,7 +300,7 @@ python3 00-META/checks/index.py fail if stale - **0195** — [The mesh's tools are found by address, not announced whole](0195-the-meshs-tools-are-found-by-address-not-announced-whole.md) - **0197** — [Every tool announces itself on the bus, in the NATS services protocol](0197-every-tool-announces-itself-on-the-bus-in-the-nats-services-protocol.md) - **0198** — [A module's long-running code is launched by the node's runtime, and reaches the bus through it](0198-a-modules-long-running-code-is-launched-by-the-node-runtime-and-reaches-the-bus-through-it.md) -- **0201** — [A module keeps its current state in key-value buckets it declares, and reaches them through the runtime](0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md) +- **0202** — [A module keeps its current state in key-value buckets it declares, and reaches them through the runtime](0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md) ### How it is built diff --git a/03-DESIGN/01-to-be/25-the-bus-on-nats.md b/03-DESIGN/01-to-be/25-the-bus-on-nats.md index ad0f387..d3fde0b 100644 --- a/03-DESIGN/01-to-be/25-the-bus-on-nats.md +++ b/03-DESIGN/01-to-be/25-the-bus-on-nats.md @@ -7,10 +7,10 @@ code: - mesh-tools src/broker-amqp.ts (to be replaced) - mesh-catalog modules/nats (to be written) - mesh-sdk src (the protocol's NATS binding, step 3) - - mesh-tools node-tools/internal/bus (a module's state, ADR 0201) + - mesh-tools node-tools/internal/bus (a module's state, ADR 0202) updated: 2026-10-04 decisions: - - 02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md + - 02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md - 02-DECISIONS/0167-a-membership-carries-what-its-module-receives-and-who-the-mesh-is.md - 02-DECISIONS/0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md - 02-DECISIONS/0157-a-build-says-what-it-does-on-the-bus-as-it-happens.md @@ -60,7 +60,7 @@ property of the mesh's architecture that happens to be expressed in subjects. And more of the mesh lands here as it is built: conditions and observed state in key-value buckets that anything may watch — the first of them a module's own declared state, *2026-10-04* -([ADR 0201](../../02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)) — the server's own advisories becoming observations like any other +([ADR 0202](../../02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)) — the server's own advisories becoming observations like any other ([research 017](../../01-RESEARCH/017-a-mesh-that-heals-itself/00-overview.md)), and a person's client speaking the bus directly rather than through a surface built over it (§7). None of that is a message being moved; all of it is the bus being the mesh's centre. @@ -91,7 +91,7 @@ mesh.assignment.. an assignment's membership (JetStream: ASSIG $KV._. a module's state (JetStream: a key-value bucket per declared name) ``` -**Added 2026-10-04** ([ADR 0201](../../02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)): +**Added 2026-10-04** ([ADR 0202](../../02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)): the last row is outside `mesh.` on purpose. A key-value bucket is NATS's own construct and lives under NATS's own prefix, which is what lets the server's key-value layer — direct reads, rollups, delete markers, watches — do the work instead of the mesh writing it again. The bucket is named for @@ -167,7 +167,7 @@ Core NATS is at-most-once. Everything the mesh must not lose lives in a JetStrea | CONTROL | `mesh.control.>` except `alive` (a build's outcome moved to its seat, ADR 0121) | work queue, one consumer (the controller), explicit ack | the store-window guarantee ([ADR 0083](../../02-DECISIONS/0083-one-push-leaves-the-mesh-consistent.md)): the controller `nak`s with a delay while its store is away and the message is redelivered; nothing is dropped | | NODES | `mesh.node.>` | last per subject | one declaration per node, always the newest | | EVENTS | `mesh.mod.*.event.>` and `mesh.seat.*.event.>` | limits (age, size), durable consumer per subscribing module | a subscriber that was down catches up; after `max-deliver` attempts the advisory feeds `mesh.events.dead` (its own small stream). *2026-10-01:* a build's whole log is here too, as the build-machine seat's `log.` events ([ADR 0157](../../02-DECISIONS/0157-a-build-says-what-it-does-on-the-bus-as-it-happens.md)) — one subject per build, a week of retention, read back by `builds --log ` with a consumer that is gone when the reading is done | -| `KV__` | `$KV._.>` | the newest value per key — as many past values as the owner declared — no age unless the owner declared one; a value at most 256 KiB, a bucket at most 64 MiB | a module's state (ADR 0201): one per name in a manifest's `state`, created from the catalogue on every raise, so it exists before its owner runs anywhere; kept when the module is unassigned, because what it holds is data | +| `KV__` | `$KV._.>` | the newest value per key — as many past values as the owner declared — no age unless the owner declared one; a value at most 256 KiB, a bucket at most 64 MiB | a module's state (ADR 0202): one per name in a manifest's `state`, created from the catalogue on every raise, so it exists before its owner runs anywhere; kept when the module is unassigned, because what it holds is data | Tool calls and heartbeats stay on core NATS: a lost heartbeat is the next heartbeat; a lost tool call is a timeout the caller already handles. @@ -247,7 +247,7 @@ expresses this exactly, per subject, and better than a vhost could: permissions for each consumed event's subject, its tool subjects, and that same inbox prefix. Nothing else. A module that tries to publish outside its emits is refused by the server, not by convention. -- **A module's state** (ADR 0201), for whichever principal carries the module — today the machine's +- **A module's state** (ADR 0202), for whichever principal carries the module — today the machine's runtime, whose grant is the union of its modules': binding to the bucket, reading a key directly, and an ordered consumer for listing and watching, created and deleted on the bucket's own stream and nothing else's; and, for the owner's instances only, publishing under the bucket's own diff --git a/03-DESIGN/01-to-be/32-what-a-module-declares.md b/03-DESIGN/01-to-be/32-what-a-module-declares.md index d8c1850..1982194 100644 --- a/03-DESIGN/01-to-be/32-what-a-module-declares.md +++ b/03-DESIGN/01-to-be/32-what-a-module-declares.md @@ -11,10 +11,10 @@ code: - mesh-host internal/apply/apply.go - mesh-tools src/main.ts - mesh-catalog modules/mesh-catalog - - mesh-tools node-tools/internal/runtime (a module's state, ADR 0201) + - mesh-tools node-tools/internal/runtime (a module's state, ADR 0202) updated: 2026-10-04 decisions: - - 02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md + - 02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md - 02-DECISIONS/0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md - 02-DECISIONS/0126-a-module-declares-its-own-seats.md - 02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md @@ -241,7 +241,7 @@ That is the wire-level answer to [issue 107](../../04-ISSUES/107-a-declaration-carries-no-order/00-report.md). **A module declares state too.** *Added 2026-10-04, -[ADR 0201](../../02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md).* +[ADR 0202](../../02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md).* State was the mesh's alone, and modules had the same need with nowhere to put it: an MCP server registered for every machine, sent as an event, never reached a machine assigned afterwards — its consumer did not exist yet when the event passed — and a licence binding sent as events replays a @@ -484,7 +484,7 @@ sealing key leaks, that stream is an archive rather than a moment. So: it is worst. **A key-value bucket is a stream, so the same holds for it.** *Added 2026-10-04, -[ADR 0201](../../02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md).* +[ADR 0202](../../02-DECISIONS/0202-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md).* No secret is put in a module's state, sealed or not: state is exactly what a machine joining a year later reads in full. A value that needs a secret names it, and the secret travels on request/reply. Sealed values are plain text to anything inspecting them, so this is checked only partly — the