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 3d5f10db..07399487 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 @@ -14,6 +14,9 @@ updated: 2026-11-04 decisions: - "ADR 0595" - "ADR 0626" + - "ADR 0631" + - "ADR 0620" + - "ADR 0259" - "ADR 0627" - "ADR 0436" - "ADR 0619" @@ -769,17 +772,23 @@ raises that module's condition and leaves the bus module healthy. **Its process foundation parts that read each other (the grants part, the tool runner, the indexer and the assigner) stop reading the indexer's and the assigner's bus state in the milestone of ADR 0612, with the other 19 readers of that state (ADR 0615 §1). **Each owner serves them as tools of its own module**, the indexer `manifests`, - `modules` and `verdicts` (ADR 0622 §1), the assigner `placement`, `seat-holders` and `wants`, and declares `runs-as`, so its tools bundle runs in + `modules`, `verdicts` (ADR 0622 §1) and `graph` (ADR 0631 §1), the assigner `placement`, `seat-holders` and `wants`, and declares `runs-as`, so its tools bundle runs in a runtime of its own on the module's own bus account, never in the node's tool runner, and the tool runner never asks through itself (ADR 0621 §1). No new manifest form is added: a process still answers no tool call or seat verb (ADR 0436 §3). **Each verb is granted to exactly its readers** (ADR 0621 §2, as ADR 0615 §3 lists them): `placement` to the grants part, the tool runner and the indexer; `seat-holders` to the tool runner; `wants` to the grants part; `manifests` and `modules` to the grants part, the tool runner and the assigner; `verdicts` to the grants part - alone, its `callers` list holding the grants part only (ADR 0622 §1). These six are the first-view tools. + alone, its `callers` list holding the grants part only (ADR 0622 §1); `graph` to the assigner alone, its `callers` + list holding the assigner only, the indexer itself refused, and the assigner's `reads` entry of the indexer's + `graph` goes (ADR 0631 §1). These seven are the first-view tools, four of the indexer and three of the assigner. `verdicts` follows the first-view rules whole (ADR 0622 §2, under ADR 0615 §4 to §6): its answer carries the revision, the grants part then follows `manifest-accepted` and `manifest-refused` and asks once more on a gap in their revisions, it raises the condition naming the indexer and `verdicts` past the bound and never reads the - indexer's state, and `grants_first_views` and `grants_first_view_again` cover it. A reader declares each in `invokes` + indexer's state, and `grants_first_views` and `grants_first_view_again` cover it. `graph` follows them whole too + (ADR 0631 §2, under ADR 0615 §4 to §6): its answer carries the revision, the assigner then follows the indexer's + `indexer.views` events for the bucket `graph`, which carry the revision, and asks once more on a gap, said in its + log; started while the indexer is down, it raises the condition naming the indexer and `graph` past the bound and + never reads the indexer's state; and `assigner_first_views` and `assigner_first_view_again` cover it. A reader declares each in `invokes` as `.` only where it is granted, which is the grant the grants part composes as for any tool, and each tool checks the proved caller against a `callers` list holding exactly its readers and refuses any other, the owner itself included. **The judge of the milestone is its own group's** (ADR 0621 §4): since no field is added, @@ -836,7 +845,7 @@ raises that module's condition and leaves the bus module healthy. **Its process 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). -- **The other 19 readers ask the owners' read tools, one per bucket they read** (ADR 0615 §1, §2). Beside the six +- **The other 19 readers ask the owners' read tools, one per bucket they read** (ADR 0615 §1, §2). Beside the seven first-view tools above, each owner serves a read tool for every bucket of its state one of the 19 reads today, named `indexer_read_` or `assigner_read_` and marked as a read: fifteen. The indexer's nine: `indexer_read_manifests`, `indexer_read_modules`, `indexer_read_predefined`, `indexer_read_config_candidates`, @@ -846,8 +855,8 @@ raises that module's condition and leaves the bus module healthy. **Its process the nine buckets of the indexer and the six of the assigner the 19 read (§ 12.6), `modules`, `wants` and `placement` among them for the status view; the indexer's tenth, `verdicts`, is read by the grants part alone, through its first-view tool. **They are ordinary module tools**: granted, as any tool is, to every - reader that declares it in `invokes`, and callable by a session; the `callers` list of ADR 0621 §2 and ADR 0622 §1 covers only the six - first-view tools. **The status view keeps all its tools**, their names, arguments and answers + reader that declares it in `invokes`, and callable by a session; the `callers` list of ADR 0621 §2, ADR 0622 §1 and ADR 0631 §1 covers + only the seven first-view tools. **The status view keeps all its tools**, their names, arguments and answers unchanged, its `indexer_*` and `assigner_*` tools included: as a reader it answers them by asking the owners' read tools instead of reading their buckets. Checked live after the delivery: a session's call of each status view tool answers, and `mesh_search` finds each owner's read tool by its bucket's words. @@ -917,13 +926,20 @@ person. **A person's request reaches the process through the process's own state account answers no tool call (ADR 0436 §3). Such a tool, in the bus module's bundle, holds no grant of the bus's create, update or delete subjects, and neither does the tool runner's account: it writes the request into the bus module's state `requests` (an old `state` section, as `asked` is, ADR 0595 §10), stamped with the caller the tool -runner proved and recorded (ADR 0386 §8), and reads the process's answer back from the same key. The stamp names +runner proved and recorded (ADR 0386 §8), and watches that key for the process's answer, never asking again on a +timer. The process watches its own state `requests` (ADR 0596 §4) and takes a request up when it is written. The stamp names who asked, for the record; it is no boundary, because every session on a machine reaches the bus as the tool runner's account (ADR 0436 §9). **So the process verifies the operator's warrant itself**: for `recreate` and `drop` it trusts nothing in the request, reads the operator channel's record of the ask under its own account and checks that the warrant binds exactly this act on this entry (ADR 0259 §6), as the mail sender does (ADR 0436 §9); a request without a valid warrant it refuses, deleting nothing and writing why into its answer; with one, it takes the entry's -stream snapshot first. `create` and `apply` need no warrant, since they only make or grow what an accepted manifest +stream snapshot first. **The process wakes on the warrant, never on a timer**: a warrant is said on the operator +channel's `decided` for the asker that raised the ask (ADR 0259 §6; ADR 0620 §2), here the bus module itself, which +hears its own `decided` through `consumes` on a durable consumer and runs its pass over the waiting `recreate` and +`drop` requests when one arrives, so a warranted `drop` acts within seconds of the operator's answer, and one given +while the process was down is heard when it is back. **A warrant acts once** (ADR 0259 §6): before it acts, the +process claims the warrant's ask id in its own state by a compare-and-set, and a request naming an ask it already +acted on is refused, deleting nothing and saying which act that warrant already performed. `create` and `apply` need no warrant, since they only make or grow what an accepted manifest asks for, and the process refuses either for an entry no accepted manifest asks for. A tool acts only for a caller whose role grants it; the process records each act as a hand act (`mesh-hand-acts`) and answers what it did. What stands between the tool runner's account and the process's delete power is that check of the warrant, so its tests @@ -1024,7 +1040,8 @@ not by the 19 the first plan counted; and 151 state entries were counted, not 15 the first count, which chose the templates). The owners first gain their events, first-view tools and read tools: the indexer a read tool per bucket its readers read, the assigner the same (§ 12.2 lists them). Then all 23 readers move in the milestone of ADR 0612, the four foundation readers included, by the first view of § 12.2 (ADR 0615 §1), the grants part's of the indexer's -`verdicts` by its first-view tool `verdicts` (ADR 0622) and then `manifest-accepted` and `manifest-refused`; their order is the module graph's, not +`verdicts` by its first-view tool `verdicts` (ADR 0622) and then `manifest-accepted` and `manifest-refused`, and the +assigner's of the indexer's `graph` by its first-view tool `graph` (ADR 0631) and then `indexer.views`; their order is the module graph's, not a review reading an owner delivered (ADR 0615 §2). The status view's move keeps every tool it serves, each answered by asking the owners' read tools of § 12.2. **The node-engine's reads granted in code stay**: the grants part's code grants each node's node-engine, with no manifest declaring them (`CandidateReads` and the composed reads beside it), @@ -1039,16 +1056,14 @@ issue 1966. |---|---| | A manifest's bus state is valid, once | the judge's unit tests, each refusal naming the field: an unknown template, an option outside its bound, past values 0, "when full" given, a fixed setting given, a name used twice across storage types, two modules' bus names alike, a `reads` in the new form, an effect outside the fixed set (ADR 0595 §8, ADR 0596 §2, ADR 0597 §2) | | 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; the process connects on its own process account; a `create` handed through `requests` is answered on the same key; `recreate` and `drop` without the operator's warrant are refused, and a warranted `drop` takes the entry's stream snapshot before it deletes; each event said is on `mesh.seat.mesh-broker.event.` and appended to the bus module's history stream, and `history` reads it back; 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 | +| 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; the process connects on its own process account, composed by the grants part with that account's grants and limits, never on an account without them; a `create` handed through `requests` is answered on the same key, which the tool watches; `recreate` and `drop` without the operator's warrant are refused, and a warranted `drop`, its warrant read from the operator channel's own record of the ask under the process's account and never from a stand-in, takes the entry's stream snapshot before it deletes, and acts within seconds of the bus module's `decided`, with no timer between; the same warrant handed in a second request is refused and deletes nothing; each event said is on `mesh.seat.mesh-broker.event.` and appended to the bus module's history stream, and `history` reads it back; 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 (`modules/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`modules/mesh-delivery-assigner`) and the grants part's (`modules/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; for the indexer's `verdicts` (ADR 0622), called by the grants part while the node's tool runner is stopped, it answers, and from any other account, the indexer's own included, it is refused; a missed revision on `manifest-refused` makes the grants part ask `verdicts` once more; the grants part and the indexer started at the same moment, `verdicts` answers within the bound with its revision; with the indexer down past the bound the grants part raises the condition naming the indexer and `verdicts` and never reads the indexer's state, and the answer clears it; the read tool shows the revision each reader holds, and the re-read tool asks once and records the hand act; in the +| 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 (`modules/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`modules/mesh-delivery-assigner`) and the grants part's (`modules/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; for the indexer's `verdicts` (ADR 0622), called by the grants part while the node's tool runner is stopped, it answers, and from any other account, the indexer's own included, it is refused; a missed revision on `manifest-refused` makes the grants part ask `verdicts` once more; the grants part and the indexer started at the same moment, `verdicts` answers within the bound with its revision; with the indexer down past the bound the grants part raises the condition naming the indexer and `verdicts` and never reads the indexer's state, and the answer clears it; for the indexer's `graph` (ADR 0631), called by the assigner it answers with its revision, and from any other account, the indexer's own included, it is refused; a missed revision of the bucket `graph` on `indexer.views` makes the assigner ask `graph` once more; started with the indexer down, the assigner raises past the bound the first-view condition naming the indexer and `graph` and reads nothing of the indexer's state, and the answer clears it; 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 `indexer_old_sections`, which the milestone extends to count the `reads` entries on each owner's state, reads 0 declared `reads` entries on the indexer's state and 0 on the assigner's, and says the node-engine's reads granted in the grants part's code remain (§ 12.6); and each owner's read tool of § 12.2 answers what its bucket holds, each status view tool answers a session's call as before the move, and `mesh_search` finds each owner's read tool | | The owners' first views are their own tools, in a runtime of their own (ADR 0621) | cases of the indexer's and the assigner's whole-module integration tests: each first-view tool, called from a reader's account while the node's tool runner is stopped, answers (§1); each answers its granted readers and refuses every other account, the owner's own included (§2); the two runtimes started at the same moment, each asking the other's first view at start, both answer within the first-view bound with their revisions (§3); and the milestone's group passes its merge check with no change to the judge's known fields for these verbs (§4) | -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 `indexer_old_sections`, which the milestone extends to count the `reads` entries on each owner's state, reads 0 declared `reads` entries on the indexer's state and 0 on the assigner's, and says the node-engine's reads granted in the grants part's code remain (§ 12.6); and each owner's read tool of § 12.2 answers what its bucket holds, each status view tool answers a session's call as before the move, and `mesh_search` finds each owner's read tool | | 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 | -| A person's request goes through `requests`, and the process verifies the warrant itself (ADR 0626 §4) | the process's unit tests: a `recreate` and a `drop` written to `requests` with no warrant, with a warrant for another act or entry, and with a warrant the operator channel's record does not hold are each refused, delete nothing and say why; a `create` or the seat's `apply` for an entry no accepted manifest asks for is refused; the stamp is the caller the tool runner proved, whatever the request's body names | +| A person's request goes through `requests`, and the process verifies the warrant itself and acts on it once (ADR 0626 §4, ADR 0259 §6) | the process's unit tests: a `recreate` and a `drop` written to `requests` with no warrant, with a warrant for another act or entry, with a warrant the operator channel's record does not hold, and with a warrant whose ask id the process already acted on are each refused, delete nothing and say why; a `create` or the seat's `apply` for an entry no accepted manifest asks for is refused; the stamp is the caller the tool runner proved, whatever the request's body names | | The process's account, and the bus module's only bus declaration (ADR 0626 §1 to §3) | the judge's unit test: the bus module's manifest with its process's `bus` and `keeps` is accepted; `keeps` on any other process or module, any other bus declaration of the bus module, and a subject of its process on which a tool is answered are refused; the composition test: the process is granted the create, update, delete and snapshot subjects under modules' names, nothing on which a tool or a verb is answered, and no subscription to a restricted stream's subjects beyond the snapshot request, its acknowledgements and its inbox; the snapshot account is granted the same subjects as before; no tool runner and no tool of the bus module holds the bus's create, update or delete subjects | | Drift and orphans, live | live, made only by a manifest change: a manifest that shrinks a setting raises `drifted`; the conditions clear as above. Nothing is filled on the live bus, and no orphan is made there | | Overdue and stopped are loud | live, carried by the change of the first module that moves in step 5, never by a merge made for the test alone: with the bus module's process stopped, an accepted manifest asking for an entry raises the overdue condition within five minutes, from the watchman, and a later `created` clears it; the bus module's health turns unhealthy when its pass is more than three minutes old | diff --git a/03-DESIGN/01-to-be/51-the-registries-keep-what-is-named.md b/03-DESIGN/01-to-be/51-the-registries-keep-what-is-named.md index 59323beb..f2a6cfbd 100644 --- a/03-DESIGN/01-to-be/51-the-registries-keep-what-is-named.md +++ b/03-DESIGN/01-to-be/51-the-registries-keep-what-is-named.md @@ -138,8 +138,10 @@ the verb. module sends only those through `publish-part` (transfer, part digest, sequence, last), each at most 1 MiB, with mesh-sdk's bus helper for sending in parts, added to mesh-sdk's runtime in the milestone's one rebuild. A `publish` opening a transfer already open answers the parts held, so a cut transfer goes on from there. The parts land in the holder's - own object store `incoming`, asked for as bus state in its manifest (design 25 § 12) with a cap of 20 GiB and a lifetime of 24 hours; a transfer with - no part for 24 hours is dropped and its parts deleted. The holder hashes every part and refuses one whose bytes do not + own object store `incoming`, asked for as bus state in its manifest (design 25 § 12) with a cap of 8 GiB, the most the + objects template allows (design 25 § 12.1), and no lifetime, since that template keeps for good; the holder counts its + fill against the cap its binding carries, never a number of its own. The holder itself drops a transfer with no part + for 24 hours and deletes its parts (ADR 0611 §3), so an abandoned transfer does not stay. The holder hashes every part and refuses one whose bytes do not match its digest. At 80 % of the cap it writes a finding (cleared below 80 %); at the cap it refuses a new transfer with `refused` naming the cap. Its tool `registry_incoming` lists open transfers and the fill, and drops one by hand. - **The holder asks the builder**, through `builder_versions`, whether the name, version and digest are recorded, and @@ -461,7 +463,8 @@ test). - **Holder (gitea, distribution).** A caller not on the caller list is refused for each verb, and one module naming another as the caller in the request's body is refused; a part sent by a module other than its transfer's opener is refused; a transfer cut in the middle resumes from the parts held, - and one left 24 hours is dropped; at the cap a new transfer is refused naming the cap; a version a `go.mod` requires + and one left 24 hours is dropped by the holder, its parts deleted; at the cap a new transfer is refused naming the cap + its binding carries, and the 80 % finding is written against that cap; a version a `go.mod` requires survives retention, and an unreadable `go.mod` stops the run; a part whose bytes do not match its digest is refused; only the missing layers are sent; `remove` of a version with no tag is refused; with no publish running, a Go seat that stops answering while its holder runs writes its finding and clears it when it