ADR 0201 (module state) renumbered 0202: 0201 landed first on main for a provider's derivations
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
status: graduated
|
status: graduated
|
||||||
initiated: 2026-10-04
|
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]
|
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
|
# 024 — State a module keeps on the bus
|
||||||
|
|||||||
+1
-1
@@ -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
|
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
|
## Context
|
||||||
|
|
||||||
@@ -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)
|
- **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)
|
- **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)
|
- **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
|
### How it is built
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ code:
|
|||||||
- mesh-tools src/broker-amqp.ts (to be replaced)
|
- mesh-tools src/broker-amqp.ts (to be replaced)
|
||||||
- mesh-catalog modules/nats (to be written)
|
- mesh-catalog modules/nats (to be written)
|
||||||
- mesh-sdk src (the protocol's NATS binding, step 3)
|
- 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
|
updated: 2026-10-04
|
||||||
decisions:
|
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/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/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
|
- 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
|
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*
|
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
|
([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
|
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.
|
is a message being moved; all of it is the bus being the mesh's centre.
|
||||||
@@ -91,7 +91,7 @@ mesh.assignment.<node>.<module> an assignment's membership (JetStream: ASSIG
|
|||||||
$KV.<module>_<name>.<key> a module's state (JetStream: a key-value bucket per declared name)
|
$KV.<module>_<name>.<key> 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
|
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,
|
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
|
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 |
|
| 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 |
|
| 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.<build id>` 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 <id>` with a consumer that is gone when the reading is done |
|
| 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.<build id>` 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 <id>` with a consumer that is gone when the reading is done |
|
||||||
| `KV_<module>_<name>` | `$KV.<module>_<name>.>` | 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_<module>_<name>` | `$KV.<module>_<name>.>` | 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
|
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.
|
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.
|
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
|
Nothing else. A module that tries to publish outside its emits is refused by the server, not by
|
||||||
convention.
|
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,
|
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 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
|
and nothing else's; and, for the owner's instances only, publishing under the bucket's own
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ code:
|
|||||||
- mesh-host internal/apply/apply.go
|
- mesh-host internal/apply/apply.go
|
||||||
- mesh-tools src/main.ts
|
- mesh-tools src/main.ts
|
||||||
- mesh-catalog modules/mesh-catalog
|
- 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
|
updated: 2026-10-04
|
||||||
decisions:
|
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/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/0126-a-module-declares-its-own-seats.md
|
||||||
- 02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.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).
|
[issue 107](../../04-ISSUES/107-a-declaration-carries-no-order/00-report.md).
|
||||||
|
|
||||||
**A module declares state too.** *Added 2026-10-04,
|
**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
|
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
|
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
|
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.
|
it is worst.
|
||||||
|
|
||||||
**A key-value bucket is a stream, so the same holds for it.** *Added 2026-10-04,
|
**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
|
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.
|
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
|
Sealed values are plain text to anything inspecting them, so this is checked only partly — the
|
||||||
|
|||||||
Reference in New Issue
Block a user