Design 25: answer the third review (views families on the old streams sections under a record extending ADR 0595 §10, the tool runner's first-view tools on the mesh MCP server, the running judge takes the process-subject form in)

The assigner must start on a fresh mesh before the bus module can answer, so its new stream
stays on its old section; a new indexer can never judge its own manifest, so the running judge
must accept the form first. The glossary stops counting the mesh MCP server's tools.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 00:46:25 +01:00
parent a9745b63cb
commit 546a18a20e
2 changed files with 43 additions and 21 deletions
+1 -1
View File
@@ -858,7 +858,7 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03
**Uses:** operator, person, node, module, seat, tool (Module), proof and identity (Identity and access), release (Delivery).
- **mesh MCP server** — the endpoint on a node's loopback through which every agent and person on that
node reaches the mesh: the MCP server named `mesh`, with its five tools `mesh_overview`,
node reaches the mesh: the MCP server named `mesh`, with its tools, among them `mesh_overview`,
`mesh_machine`, `mesh_search`, `mesh_describe` and `mesh_call`. It is the tool runner's loopback mode,
not a module of its own. "Console" suggested a terminal or a shell, and the module `mesh-console` it
once named no longer exists; "the tool bridge" and "the brain" named the predecessor's program.
+42 -20
View File
@@ -757,12 +757,12 @@ vault as an own secret: JetStream create and update under modules' names only (s
no manifest form today (the assigner serves its seat verbs as tools); the form is new in mesh-sdk's manifest types
and rides the milestone's one rebuild. Which part issues these subjects' grants first is not yet decided: the
grants part composes every grant from the manifests, and is itself one of these readers, so its own first view
cannot wait on a grant it has not composed (an open point, tracked on issue 1966). Under the same point: which
judge takes in the indexer's and the assigner's own new manifests, which use that form. Every manifest of the
merge is judged by the indexer that runs, the old build, and mesh-sdk's strict decoding refuses a field it does
not know (research 082, its Findings for question 5), so the running judge would refuse the new form; whether the
form rides an earlier release the running judge already decodes, or the new indexer judges its own manifest, is
not decided by a record. The owner answers at once from what it holds, as soon as its process is
cannot wait on a grant it has not composed (an open point, tracked on issue 1966). **The judge that runs takes the
form in.** Every manifest of the merge is judged by the indexer that runs, the old build, before any new build
runs, so a new indexer can never judge its own manifest; and mesh-sdk's strict decoding refuses a field it does not
know (research 082, its Findings for question 5). So the running judge accepts the process-subject form before the
indexer and the assigner use it, decided in a record of this milestone extending ADR 0615 §3 (to be proposed), and
design 51's *When the group is pushed* holds the push until the judge that runs accepts it. The owner answers at once from what it holds, as soon as its process is
connected and before it has its own first view of any other part, with the revision of its state it answered at,
so the indexer and the assigner, each asking the other at start, never wait on each other (§4). The reader then
follows the owner's declared events, each carrying the revision of the state it follows, and never asks the verb
@@ -770,19 +770,32 @@ vault as an own secret: JetStream create and update under modules' names only (s
families of their own, apart from the indexer's `manifest-refused` and `manifest-accepted` and the assigner's
`put`: the indexer's `indexer.views` and the assigner's `assigner.views`, one event per changed key with its
bucket, key and revision and the key's value whole, or a delete mark for a key removed, so a reader keeps its
picture from the events alone and asks the verb only on a gap (ADR 0615 §5). Each family is kept seven days and
capped at 256 MiB, dropping its oldest when full (the template events); a reader that misses a dropped event sees
the gap in revisions and asks once more. The indexer declares `indexer.views` in its old `streams` section, its
own kept data staying there (ADR 0595 §10 names the indexer among the foundation). The assigner is not named
there and is touched in this milestone, so it asks for `assigner.views` in the new form, as bus state of the
template events in its `requires` (ADR 0595 §1, §11). A waiter on an existing event, `manifest-accepted` or the
picture from the events alone and asks the verb only on a gap (ADR 0615 §5). **Both families are declared in
their owners' old `streams` sections**, each an entry with `max-age-days` 7 and `max-mib` 256: the old section keeps
a stream by limits, which drops its oldest when full (only a work queue refuses the new instead), so a reader that
misses a dropped event sees the gap in revisions and asks once more. The indexer's own kept data stays on the old
sections (ADR 0595 §10 names it among the foundation); the assigner's goes beside its existing `streams` entry
`placement`, under a record of this milestone extending ADR 0595 §10's foundation (to be proposed) to the parts
the bus module's own composition, placement, build or delivery needs before it can answer: the assigner, the tool
runner, the builder, the checker, mesh-config and the vault. **The size, an estimate**: read on the bus on
2026-11-04, the buckets the readers read hold about 3 MiB of current values at the indexer (its manifests about
5 KiB a value) and about 1.5 MiB at the assigner (its wants about 0.25 KiB a value). The milestone's one mesh-sdk
rebuild rewrites every module's keys, up to three times in its window (design 51 *How many builds*), so a week of
it is some 20 MiB on `indexer.views` and some 10 MiB on `assigner.views` with ordinary merges added, each well
under its 256 MiB. Each event carries one value whole, the largest today a manifest of tens of KiB, under the bus's
largest message, 1 MiB (the bus server's `max_payload`); an owner whose value with its event would pass it emits
the key's revision alone, as a gap, so the reader asks the first view once, and the owner writes its finding
naming the key.
A waiter on an existing event, `manifest-accepted` or the
assigner's `put`, never wakes on them. **When an owner's revisions go back**: should an owner's state be rebuilt
by the bus module's `recreate`, its revisions start again; a reader that hears a revision lower than the one it
holds takes it as a gap and asks the first view again, and keeps what that answer says, whatever revision it held
before. A `recreate` that could not keep the data answers empty at revision 0, so the grants part keeps its list
in force (below): a login revoked meanwhile stays until the owner's first change, and the grants part's
first-view condition stays raised meanwhile, naming the owner and the empty answer, cleared by an answer above
revision 0. A reader that starts while its owner is down raises a
first-view condition stays raised meanwhile, naming the owner, the empty answer and the operator's step: let the
owner write its state again from its sources (the indexer by taking each module in again, `indexer_take_in`; the
assigner by its next composition of the wants), then ask the grants part's first view again,
`grants_first_view_again`. It is cleared by an answer above revision 0. A reader that starts while its owner is down raises a
condition naming the owner and the verb past its bound and keeps asking until it answers, never reading the
owner's state instead; once it had its first view, it keeps working on what it heard (§6). The bound is longer
than an owner's start (two minutes), so a normal start, readers and owners coming up together, notifies nobody;
@@ -791,9 +804,13 @@ vault as an own secret: JetStream create and update under modules' names only (s
force until an answer at a revision above 0. Each reader's tools say the owner, verb and revision its first view
holds, when it asked and when it was answered (a read tool), and ask the first view again by hand (a re-read tool,
recorded as a hand act): the grants part's `grants_first_views` and `grants_first_view_again`, the tool runner's
`runtime_first_views` and `runtime_first_view_again`, the indexer's `indexer_first_views` and
`indexer_first_view_again`, and the assigner's `assigner_first_views` and `assigner_first_view_again`. The
order of owner before reader is kept by the module graph's served-verb edge for the 19 readers (ADR 0614 §2), and,
`mesh_first_views` and `mesh_first_view_again`, the indexer's `indexer_first_views` and
`indexer_first_view_again`, and the assigner's `assigner_first_views` and `assigner_first_view_again`. The tool
runner's two are tools of the mesh MCP server, beside `mesh_runtimes`, since the tool runner serves its own state
there: the mesh MCP server gains them, and the operator sees them among its tools. **On a fresh mesh** the
assigner starts before any new-form bus state exists and needs no binding of the bus module first: its own state
and `assigner.views` are on its old sections, which the grants part creates, so it answers the indexer, the grants
part and the tool runner their first views while the bus module still waits on it. The order of owner before reader is kept by the module graph's served-verb edge for the 19 readers (ADR 0614 §2), and,
for the four, whose verb edges lie on cycles the graph leaves out (ADR 0614 §3), by the owner's answer at once and
the reader's wait (ADR 0615 §2).
- **Only the owner reaches it** (ADR 0596 §2). The membership grants the owner's account its own entries and no
@@ -944,7 +961,10 @@ and the new form are never both used for one local name. During the move the gra
sections' entries, so each entry has one creator. The indexer counts the modules on each old section, a tool reads
the count, and the judge refuses a section once its count is 0. The foundation's own kept data (the bus module's,
the grants part's and the indexer's) stays on the old sections for good and is not counted: those modules cannot
wait for a process that needs them first.
wait for a process that needs them first. A record of this milestone extending ADR 0595 §10's foundation (to be
proposed) adds the parts the bus module's own composition, placement, build or delivery needs before it can answer:
the assigner, the tool runner, the builder, the checker, mesh-config and the vault; their new state and streams of
this milestone go on their old sections too (§ 12.2; design 51 *The move*; design 32).
**Readers move after their owners** (ADR 0596 §3). Today 195 `reads` entries in 37 modules read another module's
bus state (counted 2026-11-03 02:00). **A correction of fact**: the indexer's and the assigner's state, counted again
@@ -965,8 +985,10 @@ issue 1966.
| The bus module creates, and the binding follows | live, by tool call: a module asking for a state, a log, objects and a ledger in `requires` receives each binding in its membership, written after `created`, never before; `show` gives each entry's template, settings and fill; a module calling `create` is refused |
| The bus module runs whole | one integration test in the nats module's repository that starts the bus module whole against the real bus server: a verdict, then `created`, then the binding in the membership; a restart that catches up a verdict given while it was down; a bucket whose settings differ raises `drifted`, the seat's `apply` of a larger cap clears it with `drift-cleared`; a refused create raises its condition and hands no binding; `recreate` and `drop` without the operator's warrant are refused, and with it act after a stream snapshot; an orphan is listed, raises `orphaned`, and goes only by `drop`; each template at a small cap refuses, events drop the oldest, and `full` is raised at the raise mark and cleared only below the clear mark; `recreated` rewrites the binding and `dropped` removes it; at start the first view from `indexer_bus_state` creates what a verdict given while it was down asked; the older remove tools refuse a new-form entry, naming `drop`'s tool |
| A module asking bus state waits for the bus module | the module graph's table test: a manifest with a ledger entry has a requirement edge to the module providing `bus-state`, one without has none (ADR 0614 §5) |
| A foundation part's first view | unit tests of each owner and reader (ADR 0615's How it is checked), as table cases, and these cases of the whole-module integration tests that exist today (mesh-delivery is over its integration budget, so no new test function): the indexer's (`cmd/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`cmd/mesh-delivery-assigner`) and the grants part's (`cmd/mesh-grants`), and the tool runner's in mesh-tools: the owner answers its verb at once from what it holds, with its revision, before its own first view; the reader asks once at start, then only on a gap in revisions; a reader whose owner is down raises its condition only past the bound and never reads the owner's state, and the owner's answer clears it; an empty answer at revision 0 drops no login; an owner's event carries the changed value whole, and a reader applies a put and a delete from the events alone and never asks the verb; a revision lower than the one held makes the reader ask its first view again; an existing waiter on `manifest-accepted` or on the assigner's `put` does not wake on the new families; the read tool shows the revision each reader holds, and the re-read tool asks once and records the hand act. Live, after the delivery: the indexer's count of `reads` entries on the indexer's and the assigner's state reads 0 |
| A foundation part's first view comes within its bound | live, after the delivery: each reader's read tool (`grants_first_views`, `runtime_first_views`, `indexer_first_views`, `assigner_first_views`) shows, for the indexer's and the assigner's verbs, the time from its ask to the owner's answer under the two-minute bound, and no first-view condition raised by the delivery |
| A foundation part's first view | unit tests of each owner and reader (ADR 0615's How it is checked), as table cases, and these cases of the whole-module integration tests that exist today (mesh-delivery is over its integration budget, so no new test function): the indexer's (`cmd/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`cmd/mesh-delivery-assigner`) and the grants part's (`cmd/mesh-grants`), and the tool runner's in mesh-tools: the owner answers its verb at once from what it holds, with its revision, before its own first view; the reader asks once at start, then only on a gap in revisions; a reader whose owner is down raises its condition only past the bound and never reads the owner's state, and the owner's answer clears it; an empty answer at revision 0 drops no login; an owner's event carries the changed value whole, and a reader applies a put and a delete from the events alone and never asks the verb; a revision lower than the one held makes the reader ask its first view again; an existing waiter on `manifest-accepted` or on the assigner's `put` does not wake on the new families; the read tool shows the revision each reader holds, and the re-read tool asks once and records the hand act; in the
assigner's whole-module test, the assigner starts before any new-form bus state exists, with no binding of the bus
module, and the indexer, the grants part and the tool runner each get their first view of it. Live, after the delivery: the indexer's count of `reads` entries on the indexer's and the assigner's state reads 0 |
| A foundation part's first view comes within its bound | live, after the delivery: each reader's read tool (`grants_first_views`, the mesh MCP server's `mesh_first_views`, `indexer_first_views`, `assigner_first_views`) shows, for the indexer's and the assigner's verbs, the time from its ask to the owner's answer under the two-minute bound, and no first-view condition raised by the delivery |
| The bus module's first view | cases in the nats module's one integration test: a replayed verdict older than the first view is not applied; an `indexer_bus_state` that does not answer turns the health unhealthy naming it and is asked again on the backoff; a set-aside manifest missing from the first view keeps its `asked` key, an empty `manifest-accepted` removes it; a deleted module's entry, after its empty `manifest-accepted`, is listed by `orphans` and raises `orphaned`, and a set-aside module's entry is neither; `nats_first_view_again` asks at once and records the hand act |
| `manifest-accepted` is never lost silently | unit tests of the indexer: a failed publish is published again, and one still failing writes the finding; `indexer_say_accepted` says it again for one module from the verdict held, and refuses a module with no accepted verdict |
| Until the identity seat, the caller is the one the tool runner proved | a unit test of the bus module's process: a request on its tool subject naming another caller in its body acts for the proved caller; `drop` without the warrant is refused |