diff --git a/00-META/glossary.md b/00-META/glossary.md index cd2afab5..230d0ed5 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -305,7 +305,7 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 `placement`, `proposals` and `candidates`, and its seven verbs `placement`, `proposals`, `propose`, `withdraw`, `again`, `adopt` and `hand-back`. Only the holder writes its states (ADR 0567, renamed by ADR 0634 §9). Its contract is in `mesh-placement-contracts` (ADR 0634 §7). - *Not:* ~~mesh-placement~~ (hq) + *Not:* ~~mesh-placement~~ - **mesh-wants** — the seat, held once for the mesh by the assigner, that keeps what each node should run, one want per node and module (`want..`), and a person's upgrade policy, served as its verb `upgrade` (ADR 0565 §7, ADR 0571 §8). Its contract is in `mesh-placement-contracts` (ADR 0634 §6, §7). @@ -357,7 +357,7 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 composition `.node`. Its digest, with the controller's judgement of the move from what the node runs now, is kept under the same key in `mesh-controller_composed`; a want names that digest. Derived state, kept while its fingerprint is among the module's five newest or a want names it, and no link of the chain - (ADR 0539 §1 to §4). From release 6. Not mesh-sdk's composition, the function that composes it (see + (ADR 0539 §1 to §4). From release 6. Not the composition of `mesh-delivery-sdk`, the function that composes it (see [Homonyms](#homonyms)), nor the **composition check** (Delivery). - **send** — the controller giving a node its declaration, until release 6 of ADR 0429. The controller's verb `push` asked for a send (of one node, or of every node); prose says send. From release 6 nothing is sent: the @@ -454,6 +454,8 @@ and the operator act. **Recorded by** the controller's `identity` and `licences` is the two ends of one credential, the consumer's and the provider's. - **secret** — a credential or other value the vault keeps sealed and the node-engine unseals into a file at apply (ADR 0085). +- **secret service** — a node's store of a person's secrets that the programs of a desktop session ask, the node seat + `node-secret-service`, of this domain. - **mesh-node-enroller** — the seat, held once for the mesh by the module `mesh-enrolment`, through which a new machine joins: a one-time token issued on the operator's Approve, redeemed once by the machine's node-engine, the node's account minted and signed by the vault (ADR 0587 §1, renamed by ADR 0634 §9). The module keeps its name; @@ -528,7 +530,7 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel §1, §2, ADR 0614). Nothing stores the order. *Not:* ~~build graph~~ - **composition check** — whether the machines a change touches still compose with it, run by the assigner - from the modules the indexer and the builder hold, with mesh-sdk's composition, the one the controller + from the modules the indexer and the builder hold, with the composition of `mesh-delivery-sdk`, the one the controller composes with (ADR 0446). It replaces the controller's check of that kind, which composed every machine from release 4 of ADR 0429 back (issue 1303). @@ -750,6 +752,9 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel judged (a witness, ADR 0236). - **the lab**, **scenario**, **replay** — a real mesh raised to run a change against before it reaches nodes; what a lab run declares; and a recorded failure run again to prove a fix (ADR 0016, ADR 0237). +- **git seat** — the seat `git`, held once for the mesh by the forge, delivering the provision `git`: the + repositories a build comes from ([26 — The seats](../03-DESIGN/01-to-be/26-the-seats.md) *The git seat*). A seat of + this domain. ## Health and repair — what is wrong, and putting it right @@ -872,15 +877,17 @@ it should not. **Recorded by** the controller. **Upstream of** Provisioning and address and a mesh name (ADR 0226). The network the machine sits on without it is the **underlay**. *Not:* ~~overlay~~ (hq) -- **the-private-network** — the seat of the private network, whose provision is the value a module reads to reach - the private network; its contract, holding that value's layout, and its client, holding the private network's own - manifest that its callers compose, are in `mesh-connectivity-contracts` (ADR 0634 §4, §6, §7, ADR 0635 §4). +- **the-private-network** — the node seat of the private network, held by the module `mesh-wireguard`, whose + provision is the value a module reads to reach the private network. Its contract and its client, which keeps only + that value's layout and no key material, are in `mesh-connectivity-contracts`, a folder module of the + mesh-networking repository beside its holder; the private network's manifest and peer generator are the holder's own + (ADR 0634 §6, ADR 0636 §4). - **anchor** and **hub** — the roles a node plays for the private network: the anchor is reachable from outside and every node reaches it; a hub relays for nodes that cannot reach each other directly. -- **resolver** — a seat holder that answers the mesh's names; a node lists only the mesh's resolvers - (ADR 0223), or, where it holds one, its own resolver, which asks them. **uplink** — a node's - connection to the outside network, a seat (ADR 0117). **hostname** — a node's own name, - a seat. +- **resolver** — a seat holder that answers the mesh's names, of the replicated seat `mesh-dns-resolver`; a node + lists only the mesh's resolvers (ADR 0223), or, where it holds one, its own resolver, which asks them. **uplink** — a + node's connection to the outside network, the node seat `node-uplink` (ADR 0117). **hostname** — a node's own name, + the node seat `node-hostname`. All three seats are of this domain. - **split DNS** — resolving names by domain on one machine: a VPN's domains through the VPN's servers over its link, every other name through the mesh's resolvers. The provision `split-dns`, provided by the holder of the node seat `node-resolver`, the machine's **own resolver**, which exists only where @@ -890,7 +897,8 @@ it should not. **Recorded by** the controller. **Upstream of** Provisioning and - **packet filter** — what the mesh enforces on a node about which packets pass, the `node-packet-filter` seat and its verb `rules`. A **found firewall** is a program the mesh found on a machine and keeps retired or in force; *firewall* says that, and a wrapped program's firewall is its own. -- **intrusion prevention** and **ban** — refusing a source that misbehaved, and the refusal itself. +- **intrusion prevention** and **ban** — refusing a source that misbehaved, and the refusal itself; the node seat + `node-intrusion-prevention` is of this domain. - **reach** — how far an assignment's endpoint may be reached from: the node, the private network, or the outside (ADR 0138). @@ -1196,7 +1204,7 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical. | | the sending of one batch of commits across nodes, until release 6 | **rollout** (verb `plans`) | Delivery | | | a step a person starts, like the bus's | **planned step** | Core | | composition | one module's resources for one node at one fingerprint, signed, from release 6 | **composition** | Placement | -| | the function in mesh-sdk that composes them, which the controller and the assigner both run | **mesh-sdk's composition** | Placement | +| | the function in `mesh-delivery-sdk` that composes them, which the node agents, the assigner and the grants part run (ADR 0635 §4) | **the composition of `mesh-delivery-sdk`** | Placement | | | whether the machines a change touches still compose | **composition check** | Delivery | | membership | the subjects a bus account is issued | **membership** | Provisioning | | binding | the names on the bus of a module's bus state, in its membership | **binding** of bus state | Data | diff --git a/03-DESIGN/01-to-be/20-writing-a-module.md b/03-DESIGN/01-to-be/20-writing-a-module.md index c4ee608c..4bbed995 100644 --- a/03-DESIGN/01-to-be/20-writing-a-module.md +++ b/03-DESIGN/01-to-be/20-writing-a-module.md @@ -15,6 +15,7 @@ decisions: - "ADR 0573" - "ADR 0606" - "ADR 0609" + - "ADR 0593" - "ADR 0150" - "ADR 0099" - "ADR 0053" @@ -74,7 +75,7 @@ a seat, or shares code with other modules, meets these places, and each piece of |---|---|---| | a seat's types, subjects, the layouts of its states and a typed call per verb or accept | the seat's **contract**: a package of its own per language in its domain's contracts module (`mesh--contracts`, or `mesh-contracts` for the Core domain and a domain with none), for a seat defined whole; a seat at the seat list's grain has only its definition, which every reader reads from the bus (ADR 0635 §1, §2) | generated from the seat's definition, never by hand | | logic two or more callers or holders would otherwise each write over that seat (an ask and its awaited answer, publishing a file in parts to a registry) | the seat's **client package**, beside its contract, owned by the contracts module | by hand; it uses only its own seat's contract, mesh-sdk's runtime and its own domain's SDK, never another seat's client, and names no holder, no module's tool and no module's subject | -| logic and state layouts one module owns, where it holds no seat for them | that module's **own package**, which other modules import from it: by path in the same repository (ADR 0609 §2), by a published version from another (ADR 0573 §1), so its manifest declares it as a package artifact | by hand, in the owner module | +| logic and state layouts one module owns, where it holds no seat for them | that module's **own package**, which other modules import from it: by path in the same repository (ADR 0609 §2), by a published version from another (ADR 0573 §1), so its manifest declares it as a package artifact; its fingerprint counts only that package's files (ADR 0593 §2), so its importers rebuild only when it changes | by hand, in the owner module | | logic and forms no seat carries and no one module owns, used by one domain's modules or seats only (moving a file in parts, the build steps' shared logic) | that domain's **domain SDK**, `mesh--sdk`, a package-only module (ADR 0634 §2) | by hand; it imports only mesh-sdk and contract packages, names no module's tool or subject, and holds no seat's type or state layout | | what every module needs whatever the seat (the bus connection, the tools bundle's runtime, state), and a part modules or seats of more than one domain share that names no seat, verb or seat's type | **mesh-sdk** | by hand; it takes no seat-specific type, imports no contracts module, and reads the seat list from the bus | | the seat's implementation | the **holder** module | by hand, against the contract; never the place of the contract or a client | diff --git a/03-DESIGN/01-to-be/26-the-seats.md b/03-DESIGN/01-to-be/26-the-seats.md index efaaf171..fc21773e 100644 --- a/03-DESIGN/01-to-be/26-the-seats.md +++ b/03-DESIGN/01-to-be/26-the-seats.md @@ -17,8 +17,11 @@ code: - mesh-controller internal/inventory/migrations/0064-the-resolver-file-is-the-uplinks.sql updated: 2026-11-05 decisions: + - "ADR 0636" - "ADR 0634" - "ADR 0635" + - "ADR 0596" + - "ADR 0593" - "ADR 0625" - "ADR 0573" - "ADR 0606" @@ -157,7 +160,7 @@ convention, which later seats departed from. | `mesh-vault` | — | mesh | `secret` | the vault (in the seed since ADR 0161; the earlier *reserved* named an effect no rule produced) | | `container-image-registry` | `mesh-artifact-store` for images (ADR 0605; the old name readable until every node-engine reads the new one) | mesh | `artifact-store` | the artifact registry (`distribution`) | | `oci-artifact-registry` | `mesh-artifact-store` for bundles and archives (ADR 0605) | mesh | `artifact-store` | the artifact registry (`distribution`) | -| `mesh-catalog` | `the-catalogue` | mesh | — | the catalog | +| `mesh-catalog` | `the-catalogue` | mesh | — | the indexer | | `npm-package-registry` | — (its rename to `mesh-*` stays deferred, ADR 0156 §8) | mesh | `npm-package-registry` | the forge | | `go-package-registry` | — (ADR 0605) | mesh | `go-package-registry` | the forge | | `mesh-git` | `git` | mesh | `git` | the forge | @@ -168,7 +171,7 @@ convention, which later seats departed from. | `node-resolver` | — | node | — | a machine's own resolver, held only where something requires `split-dns`: it writes `/etc/resolv.conf` there (the uplink's holder steps back from it) and routes a VPN's domains to the VPN's servers over its link through its verbs `routes`, `route`, `unroute` (ADR 0247). Held by the module `systemd-resolved` | | `mesh-intrusion-prevention` | `the-intrusion-prevention` | node | — | an intrusion-prevention service | | `mesh-packet-filter` | `the-packet-filter` | node | — | the packet filter | -| `mesh-private-network` | `the-private-network` | node | — | the private network the mesh runs over | +| `the-private-network` | — (it keeps its name, ADR 0636 §4) | node | — | `mesh-wireguard`, the private network the mesh runs over | | ~~`mesh-resolver-configuration`~~ | `the-resolver-configuration` | node | — | retired by ADR 0223: `/etc/resolv.conf` is written by the holder of `node-uplink`, the program that would otherwise rewrite it, and the need of the uplink beside it (ADR 0220) goes with it; deleted from the set, and from the store's table, once nothing claims it | | `mesh-showcase` | `the-showcase` | node | — | the showcase module | @@ -194,15 +197,23 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD TypeScript types are generated from it and committed beside it; nobody writes them by hand. The format is JSON, its messages and bodies JSON Schema, as the seat set's verb inputs already are, with the format's own schema checked in; the fixtures are data, never functions. -- **A definition names its states** (ADR 0608 §1; ADR 0634 §6 leaves the file's format to this design). The field - `states` lists each state the seat's holder keeps and others read: its local name, its template of ADR 0595 (state, - events, work queue, log, objects or ledger), who writes it (the holder, or each caller its own keys), each form of - its keys with the schema of the value under it, and how long it keeps its history. No entry names a holder module, - so another module can hold the seat by importing the contract alone (ADR 0625 §7). The generated package carries, - per state, its local name, a builder and a parser per key form, and the value types, decoded strictly; the - fixtures hold one value per key form. `operator-channel`'s `records` becomes one `states` entry in the same change, - so the format has one form for a state. The format's own schema refuses an entry with an unknown template or a - key form without a value, naming it. +- **A definition names its states** (ADR 0608 §1; ADR 0634 §6 leaves the file's format to this design). A `states` + entry is what any holder of the seat keeps and what the seat's verbs answer from: its local name, its template of + ADR 0595 (state, events, work queue, log, objects or ledger), who writes it, each form of its keys with the schema + of the value under it, how long it keeps its history, and its size cap. The holder writes every state; only a state + of the events or log template may name each caller as the writer of its own keys, granted on keys under the + caller's own name and no other. No entry names a holder module, so another module can hold the seat by importing + the contract alone (ADR 0625 §7). The generated package carries, per state, its local name, a builder and a parser + per key form, and the value types, decoded strictly; the fixtures hold one value per key form. + `operator-channel`'s `records` becomes one `states` entry in the same change, so the format has one form for a + state. The format's own schema refuses an entry with an unknown template or a key form without a value, naming it. + **A state is the holder's, asked through the seat's verbs** (ADR 0596 §2): the module that reads another module's + bucket directly today keeps doing so only as a reader in transition, through its own manifest's `reads`, until its + module moves to the owner's verbs or events (ADR 0596 §3, issue 1966). The bucket's name stays + `_`, the holder's own, so nothing moves under a seat's rename. **How it is checked**: the manifest + validator refuses a holder whose `requires` does not declare each of its seat's states with the same local name and + template, naming the state; the format's own schema refuses a caller-written state of another template and a state + with no size cap. - **What is defined whole.** Ten seats came first (ADR 0613; ADR 0620, on the operator's answer of 2026-11-04 to move them all; ADR 0627 §1): `npm-package-registry`, `go-package-registry`, `container-image-registry` and `oci-artifact-registry` (one common part of their shared verbs, written once, so the four cannot drift), @@ -248,7 +259,7 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD | `mesh-health-and-repair-contracts` | Health and repair | `mesh-conditions`, `mesh-self-check`, `mesh-healers`, `mesh-watchdogs`, `mesh-hand-acts` | the condition keeper, mesh-self-check, mesh-healers, the watchman, mesh-hand-acts | | `mesh-provisioning-contracts` | Provisioning | `mesh-provisioner` | mesh-provisioner | | `mesh-identity-and-access-contracts` | Identity and access | `mesh-vault`, `mesh-node-enroller` | the vault, the module `mesh-enrolment` | - | `mesh-connectivity-contracts` | Connectivity | `the-private-network` | its holder is named when its definition is written | + | `mesh-connectivity-contracts` (mesh-networking repository, ADR 0636 §4) | Connectivity | `the-private-network` | `mesh-wireguard` | | `mesh-operator-and-conversation-contracts` | Operator and conversation | `operator-channel` | the router | | `mesh-contracts` | Core, and Config | `node-engine`, `mesh-broker`, `mesh-config` | the node-engine, the bus module, mesh-config | @@ -267,18 +278,38 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD contracts module in that change (ADR 0613 §3); which domain moves when is tracked by issue 167 (ADR 0613 §4). - **Two seats renamed** (ADR 0634 §9): `mesh-placement` becomes `mesh-module-assigner`, and `mesh-enrolment` becomes `mesh-node-enroller`; the module `mesh-enrolment` keeps its name. Their definitions, the subjects of their - verbs and events, every holder's claim, every caller's `invokes` and grant, and the glossary take the new names in - the same delivery group, and nothing answers to the old ones. **How it is checked**: the manifest validator refuses a - claim of a seat no definition names, so a claim of an old name fails (ADR 0634 §10). -- **Every part learns the seat list from the bus** (ADR 0635 §1). The manifest validator, the node-engine, the tool - runner, claude-code and every other reader of the list of seats read the definitions the indexer keeps (*On the - bus*, below) through mesh-sdk's runtime, at the grain each definition holds, and learn a changed one from the - indexer's `seat-definition-changed`. No package carries the seat list, and mesh-sdk imports no contracts module. - **A reader that has not heard the indexer** knows the foundation's bootstrapped definitions, says in its health - that it waits for the rest, and a check that cannot read the definitions it needs fails, naming them, rather than - passing without them (ADR 0635 §3). **How it is checked** (ADR 0635 §6): a test of the readers' start reads the seat - list from a bus holding the foundation's definitions only, asserting that the reader says it waits, and then with - the indexer's; the indexer's tests read a seat-list-grain definition from a contracts module like a whole one. + verbs and events, every holder's claim, every caller's `invokes` and grant, the claude-code instructions' text, the + mesh MCP server's description and the glossary take the new names in the same delivery group, and nothing answers + to the old ones: a call on an old subject fails loudly, naming the seat. **No state moves**: a state's bucket is + the holder's (`_`), so placement keeps every revision. The old subjects' events keep only their + stream's own retention. **The order is the module graph's**: the grants of the new subjects are an ordering edge + that comes before the holders move, and the callers come after the holder that serves the renamed verbs; an older + node-engine takes its new build through `mesh-wants`, which is not renamed. **How it is checked**: the manifest + validator refuses a claim, an `invokes` or a grant naming a seat no definition names, so an old name fails + (ADR 0634 §10); the acceptance after the delivery is that `mesh-module-assigner.placement` answers and + `mesh-placement.placement` is not found, placement's revisions are those it had before, and no `seat-holders` key, + finding or condition stays under an old name. +- **Every part learns the seat list from the bus, through the seat `mesh-catalog`** (ADR 0635 §1, as ADR 0636 §2 + changes it). The manifest validator, the node-engine, the tool runner, claude-code and every other reader of the + list of seats call, through mesh-sdk's runtime, the verb of the seat `mesh-catalog` that answers every definition + on the trunks with its digest, at the grain each holds, and hear the seat's events `seat-definition-changed` and + `seat-definition-removed`. A reader names no module: it calls the seat, never its holder, the indexer, by name. + It acts only on definitions from a trunk, never on a pull request's head. No package carries the seat list, and + mesh-sdk imports no contracts module. + **A reader without the list acts on nothing new** (ADR 0636 §1, changing ADR 0635 §3). A reader that starts + without the seat's answer applies, composes, grants and judges nothing new and keeps running what it runs; it says + in its health what it waits for, and raises a condition when it has waited five minutes, cleared by its first full + read. It does act, from the bootstrapped definitions it carries (ADR 0608 §2), on the modules whose seats those + definitions name, which are the parts that serve the seat list, so they come back after a full restart. A reader + away longer than the events' retention reads the whole list again. A check that cannot read the definitions it + needs fails, naming them, rather than passing without them. + **Each reader's list has tools** (ADR 0636 §5): mesh-sdk's runtime bundle serves, in every reader, a tool that + reads which definitions it holds (their source, digests and what it waits for) and one that makes it read the + list again now. + **How it is checked** (ADR 0635 §6, ADR 0636 §5): a test of the readers' start, with the seat unanswered, asserts + the reader acts on nothing but the bootstrapped modules and says so, then acts once the seat answers; mesh-sdk's + unit test refuses a module's name in the runtime; the indexer's tests read a seat-list-grain definition from a + contracts module like a whole one, and a removed definition's seat is refused afterwards. - **The generator** is each language's build module's: the Go build module's package for Go, the Node and TypeScript build module's for TypeScript (the logic is the module's whose work it is). The generator's version is a build input of every contracts module, so a changed generator rebuilds each contracts module once (ADR 0603 §3). Each build @@ -292,18 +323,25 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD contracts module runs then. The indexer consumes both and writes the trunk's finding. - **On the bus**: the indexer reads every seat definition from every trunk and open pull request, from the forge bridge's messages, and keeps them in its own state `seat-definitions`, keyed by seat and source (the trunk, or a - pull request's head), as their only writer; a definition is at most 256 KiB. It emits `seat-definition-changed` - (seat, source, digest), kept seven days, only when a digest changed. **Only the trunk's entry is the seat's - contract**: the readers (every reader of the seat list, the contracts modules' builds and the review) ask - `indexer_seat_definition`, which answers the trunk's unless a pull request's head is named, and says which it - answered. A pull request's entries are removed on the forge bridge's event that it closed or merged. A definition + pull request's head), as their only writer; a definition is at most 256 KiB. As the holder of `mesh-catalog` it says + `seat-definition-changed` (seat, source, digest), kept seven days, only when a digest changed, and + `seat-definition-removed` when a trunk's definition goes, both as events of the seat (ADR 0636 §2, changing ADR 0608 + §3, §4). **Only the trunk's entry is the seat's contract**: the readers of the seat list read the trunks' through + the seat's verb; the contracts modules' builds and the review ask `indexer_seat_definition`, which answers the + trunk's unless a pull request's head is named, and says which it answered. **The delivery group's one check reads + the seat definitions at every member's head**, so a group that changes a definition is judged by what it merges. A + pull request's entries are removed on the forge bridge's event that it closed or merged. **A seat is defined only in + its domain's contracts module** (ADR 0636 §3, changing ADR 0608 §2): the indexer takes a seat's definition only from + the contracts module of the seat's glossary domain, `mesh-contracts` for a domain with none, and refuses one from any + other module with a finding naming both. A definition that does not parse fails its pull request's check; the trunk's stays. The merge is the only approval. The foundation's own definitions are bootstrapped before the bus exists, as the bootstrap of a fresh mesh has it (research 075). - **Findings**, written by the indexer, from which the condition keeper raises and clears the conditions (ADR 0564): a trunk's seat definition that does not parse, `seat-definition-unparsed` (a pull request's is its check's verdict, not a condition), cleared by a definition that parses; generated types on a trunk out of step with their definition, - `generated-types-out-of-step`, cleared only by a clean build end of the same contracts module. **Tools** of the indexer: `indexer_seat_definition` + `generated-types-out-of-step`, cleared only by a clean build end of the same contracts module, per module and not per repository, since several + contracts modules share one; a seat defined outside its domain's contracts module, naming both modules (ADR 0636 §3). **Tools** of the indexer: `indexer_seat_definition` (read one), `indexer_seat_definitions_again` (read a trunk's or a pull request's again now) and `indexer_out_of_step` (the generated types out of step). - **Contracts modules.** A seat's contract is published by a contracts module, which holds the seats' definitions, @@ -318,7 +356,10 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD inside one delivery group by the group's head. - **A contracts module and a domain SDK are modules like any other, found by their manifests** (ADR 0634 §8). `mesh-delivery-contracts` and the Delivery domain's SDK are folders of the mesh-delivery repository, and the other - domains' contracts modules folders of the mesh-contracts repository. Each is a package-only module, as mesh-sdk long + domains' contracts modules folders of the mesh-contracts repository, but the Connectivity domain's: + `mesh-connectivity-contracts` is a folder of the mesh-networking repository, beside `mesh-wireguard`, which holds + `the-private-network` with its manifest and peer generator its own (ADR 0636 §4, changing ADR 0634 §8). A + `mesh-connectivity-sdk` is made when that domain's modules share logic, not before. Each is a package-only module, as mesh-sdk long is: published from its trunk, rebuilding the modules that use it like any package (ADR 0573 §2, §3), and delivered to no node. A step of the build or the delivery that treats a module in a folder unlike one at a repository's root is a gap of the build and delivery system, fixed in the milestone, never worked around. **How it is checked**: the @@ -389,7 +430,8 @@ keeps only what modules or seats of more than one domain use. composer's shared logic, each made seat-neutral over its callers' types (ADR 0635 §4), and the rules the Delivery domain's modules share. - **A module's own package** (ADR 0634 §1) holds what that module owns and no seat carries: its state layouts that - other modules read and the logic over them. Another module of the same repository uses it by path, from the same + other modules read and the logic over them. Its fingerprint counts only that package's files (ADR 0593 §2), so a + change elsewhere in the owner module rebuilds none of the package's importers. Another module of the same repository uses it by path, from the same commit (ADR 0609 §2); a module of another repository uses it only by its name and a published version (ADR 0573 §1), so the owner's manifest declares it as a package artifact (ADR 0606 §4). - **The clients of the milestone of ADR 0612** (ADR 0627 §1, ADR 0634 §4, ADR 0635 §4), each moved out of mesh-sdk @@ -400,7 +442,8 @@ keeps only what modules or seats of more than one domain use. `container-image-registry` and `oci-artifact-registry` (publishing a file in parts, one client per seat, each binding the Delivery domain's SDK's transfer to its own seat's verbs and types); `mesh-hand-acts` (recording a hand act); `mesh-provisioner` (mesh-sdk's provider runtime and its harness, which only providers use); and - `the-private-network` (the private network's own manifest, which its callers compose). + `the-private-network` (only the layout of the value the seat provides, which holds no key material; the private + network's manifest and peer generator are `mesh-wireguard`'s own, ADR 0636 §4, changing ADR 0635 §4). - **Moving a file in parts is seat-neutral, in the Delivery domain's SDK, on both sides** (ADR 0627 §2, as ADR 0634 §3 changes it): it serves only the four registry seats, all of the Delivery domain. The sending side and the going on from what a holder already holds, and the holder's side (taking the parts into the holder's own objects, @@ -442,20 +485,30 @@ keeps only what modules or seats of more than one domain use. | A client uses only its own seat's contract and its domain's SDK | the catalog check of a client: its own test refuses a client importing another seat's client or another domain's SDK, and one naming a module's tool or subject, and passes every client of the milestone | | The parts transfer is seat-neutral | its unit test, in the Delivery domain's SDK, runs both sides against two different subjects and shapes the caller gives, and the seat-name check holds it seat-neutral; the review refuses a holder that takes parts in without it | | Only a client is written by hand in a published package | each build module's regenerate-and-compare test fails on a hand-written file outside a client package and passes a contracts module holding its definitions and fixtures; the step runs on every contracts module | -| A module in a folder is built and published as one at a root | the delivery group's one check builds and publishes every new contracts module and the domain SDK from its folder | +| A module in a folder is built and published as one at a root | the delivery group's one check builds and publishes every new contracts module and the domain SDK from its folder, and `mesh-wireguard` and `mesh-connectivity-contracts` from the mesh-networking repository | +| A seat is defined only in its domain's contracts module | the indexer refuses a second module's definition of a seat, with its finding naming both (ADR 0636 §3) | +| A holder keeps its seat's states | the manifest validator refuses a holder whose `requires` does not declare each of its seat's states with the same local name and template | | A contracts module holds no seat; a role only one module could ever play has none | the manifest validator's refusal of a contracts module that claims a seat; review both ways: a new seat definition's pull request is asked whether another module could take the role over, and a module's pull request is asked the same of each new tool or event family other modules call | | Each new exported name sits where this section puts it | the review of every pull request (playbooks 07 and 08, the code reviewer's definition) asks the home of each new exported type, field, constant, package or module against this section, a domain SDK's importers included | -Acceptance tests: research 081's 14, 21, 25 and 26; mesh-sdk's seat-naming and import tests; the start test of the -seat list's readers (*Every part learns the seat list from the bus*); each build module's compare step -failing on a differing, a missing and an unwritten file, naming each; the checker's `verdict` naming out-of-step -files; the manifest validator refusing a claim of `mesh-placement` and of the seat `mesh-enrolment`; and cases of -the indexer's whole-module integration test: a trunk -definition that does not parse writes its finding and a fixed one clears it; a trunk build end naming out-of-step types -writes the finding, a clean build end of another contracts module leaves it, and a clean one of the same module clears -it; `indexer_seat_definition` answers the trunk's entry while a pull request -holds another; a pull request's entries go when it closes; a definition over 256 KiB is refused; a seat-list-grain -definition is read from a contracts module like a whole one; each of the three tools answers. +**Acceptance tests**, each at its level (unit, or a case of the module's one whole-module integration test against the +real bus and store) and in its repository. The move raises no repository's test count, since mesh-delivery is already +over its budget: each case below replaces or joins an existing one. + +| Test | Level | Repository | +|---|---|---| +| research 081's 14, 21, 25 and 26 | as research 081 sets them | as research 081 sets them | +| mesh-sdk's seat-naming, import and package-list tests; no module's name in the runtime | unit | mesh-sdk | +| the readers' start: with the seat unanswered a reader acts on nothing but the bootstrapped modules and says so, raises its condition after five minutes, and acts once the seat answers; a reader away longer than the events' retention reads the whole list again; both list tools answer | unit, over a bus the test gives | mesh-sdk | +| the indexer stopped mid-run: readers keep running what they run and act on nothing new until it answers again | a case of the indexer's whole-module test | mesh-delivery | +| a trunk definition that does not parse writes its finding and a fixed one clears it; a trunk build end naming out-of-step types writes the finding, a clean build end of another contracts module of the same repository leaves it, and a clean one of the same module clears it | a case of the indexer's whole-module test | mesh-delivery | +| `indexer_seat_definition` answers the trunk's entry while a pull request holds another; a pull request's entries go when it closes; a definition over 256 KiB is refused; a seat-list-grain definition is read from a contracts module like a whole one; a removed definition says `seat-definition-removed` and its seat is refused afterwards; a second module defining a seat is refused with its finding; each of the indexer's tools answers | cases of the indexer's whole-module test | mesh-delivery | +| the manifest validator refuses a claim, an `invokes` or a grant naming `mesh-placement` or the seat `mesh-enrolment`, and a holder missing one of its seat's states in `requires` | unit | mesh-delivery | +| the checker's `verdict` names out-of-step files; the group's check reads seat definitions at every member's head | a case of the checker's whole-module test | mesh-delivery | +| each build module's compare step fails on a differing, a missing and an unwritten file, naming each, per contracts module | unit | mesh-catalog | +| a change in one folder module rebuilds and publishes only it and its importers; a module with both a deployed and a package artifact (the grants part or disk-load) is built, delivered and published | a case of the Go build module's whole-module test | mesh-catalog | +| after the delivery, `mesh-module-assigner.placement` answers and `mesh-placement.placement` is not found; placement keeps its revisions; no `seat-holders` key, finding or condition stays under an old name | live, read through the mesh's tools | the mesh | +| `mesh-wireguard` is built and delivered from the mesh-networking repository | the group's one check, then live | mesh-networking | ## The foundation's seats @@ -654,5 +707,7 @@ seat set's one source), with the amendment of 2026-11-04 (ADR 0625, ADR 0627: te seat, a package for the seats at the seat list's grain in `mesh-contracts`, the seven clients and the seat-neutral parts transfer, *Where a seat's code goes*), and the amendment of 2026-11-05 (ADR 0634, ADR 0635: shared code with its owner, the domain SDK, a module's own package, a contracts module per domain the milestone moves, 25 seats defined whole with their -states, the seat list read from the bus, two seats renamed), await their own review by architectural domain, which -rewrites this section. +states, the seat list read from the bus, two seats renamed), with ADR 0636 (the seat list through the seat +`mesh-catalog`, a reader without it acting on nothing new, a seat defined only in its domain's contracts module, the +Connectivity domain in the mesh-networking repository) and the lead's rulings on the first review by architectural +domain written in, await their final review, which rewrites this section. diff --git a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md index 552c30a6..c89ce45a 100644 --- a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md +++ b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md @@ -4,6 +4,8 @@ status: in-progress code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, hq 00-META/checks] updated: 2026-11-05 decisions: + - "ADR 0636" + - "ADR 0635" - "ADR 0634" - "ADR 0594" - "ADR 0572" @@ -173,13 +175,13 @@ source revision is derived from the keys: every **want** equals its module's **f a module on a node that the two do not both name, and raises a condition naming the pair while they differ. It also runs the **composition check**: whether the machines a change touches still compose with it, read from the keys the indexer and the builder hold and from the machines, settings and grants it reads, with - mesh-sdk's composition, the one every node agent composes with (ADR 0446, ADR 0547 §2). Its module was made in + the composition of `mesh-delivery-sdk`, the one every node agent composes with (ADR 0446, ADR 0547 §2, ADR 0635 §4). Its module was made in R4g with release 5; from release 6 it writes no difference (ADR 0524 §4, ADR 0528, ADR 0539 §8). The check composes no placement and waits for no node's answer: a pull request changes no placement, since placement is bus state changed by a proposal (ADR 0567; ADR 0446 §3 read as written). Its own composition stands in for every sealed value, so only a node's answer to a proposal can say that what the node would run is the same. - **The node agent**, the node-engine's own process, follows its node's wants, **composes each wanted module for - its own node** with mesh-sdk's composition from the manifest by digest, the module's resolved values from + its own node** with the composition of `mesh-delivery-sdk` from the manifest by digest, the module's resolved values from mesh-config, its secrets and bus credential asked of the vault sealed to the node's key, its licences and what its providers contribute, applies one module at a time and only what differs from what runs, backs up a data module first, and writes its haves with the fingerprint and the digest of the composition it runs (ADR 0547 §2, @@ -187,7 +189,8 @@ source revision is derived from the keys: every **want** equals its module's **f public records and the manifests wanted on them. On the node holding `mesh-broker` it also writes the bus's user list, alone and with no want (*The bus's user list*, below). - **The grants part** (module `mesh-grants`, holding the seat `mesh-grants`) composes who may say what on the bus - with mesh-sdk's bus composer: each module's membership, the buckets, logs and streams a manifest declares, the + with mesh-sdk's bus composer, whose parts that name a seat or a holder's state are the grants part's own package + (ADR 0635 §4): each module's membership, the buckets, logs and streams a manifest declares, the bus's user list, and `grants..`, written from L7's delivery once the list the bus loaded carries that build's accounts (ADR 0547 §5, §6; ADR 0571 §9). It keeps each module's membership in its own state `memberships`, which the runtime reads, and publishes memberships from the first milestone (ADR 0571 §10); until the operator's `take-over` it keeps the bus's user list, the @@ -592,8 +595,8 @@ From its delivery, a check is this: composes only the machines that run or could run a module the change moves or adds, or whose grants or providers it alters; for a group, once over every member's change, read from the indexer's candidates of the group, and while the indexer holds none the group's check waits and says why. It composes with the function - every node agent composes with, mesh-sdk's composition, so the two agree for one mesh-sdk version; its verdict - names the mesh-sdk version it composed with. No composing program is built from a change: a change to the + every node agent composes with, the composition of `mesh-delivery-sdk`, so the two agree for one version of that + package; its verdict names the version it composed with (ADR 0635 §4). No composing program is built from a change: a change to the composition is proved by its own tests, a field only a newer composition reads goes out as optional first, and the running composition refuses a manifest that uses a field it does not read, naming the field. What it fails on, and its warning past twelve rebuilt modules, are the composition check's, as they were the controller's composition check's (ADR 0446, ADR 0237 §2). The assigner writes the verdict under the checker's hash of the heads it judged, in its own bucket, and the checker reads it into the @@ -688,13 +691,14 @@ backup holder backs up nothing, and the have says so. *ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0547 §2 to §9, ADR 0549, ADR 0555.* - **Each node composes its own.** For each want `want..` the node agent composes that module for - its own node with mesh-sdk's composition from the manifest by digest the indexer wrote, the module's resolved + its own node with the composition of `mesh-delivery-sdk` from the manifest by digest the indexer wrote, the module's resolved values read from mesh-config's resolved state filtered to its node, its secrets and bus credential asked of the vault sealed to the node's key (ADR 0349 §11), its licences, and what its providers contribute; and the node's own composition (adoption, firewall openings, accounts, the resolver, identities and groups) from the same inputs. Of other nodes it reads only their public records and the manifests wanted on them, which its firewall and resolver need. Nothing composed crosses the bus, so nothing composed is signed (ADR 0547 §2). -- **What a node composes from, and who writes it.** One composer, mesh-sdk's, has three callers: the node agent for +- **What a node composes from, and who writes it.** One composer, `mesh-delivery-sdk`'s, made seat-neutral over its + callers' types (ADR 0635 §4), has three callers: the node agent for its own node, the assigner's composition check for every node, and the grants part. Each fills the composition's input from the bus with its own credential and nothing else (ADR 0547 §2, ADR 0549 §3): - **placement**, the state `placement` of the seat `mesh-module-assigner`, one key `placement.`, written by the @@ -702,7 +706,8 @@ backup holder backs up nothing, and the have says so. - **the node records**, each in its node's own have key `.node`, written by that node alone and heard as the key's change (ADR 0555 §3); - **the manifests**, the indexer's `modules.` and its manifests by digest, or the digest the composing - node's want names where it runs another build; the private network's manifest comes with mesh-sdk; + node's want names where it runs another build; the private network's manifest is its holder `mesh-wireguard`'s + own (ADR 0636 §4); - **the config values**, mesh-config's resolved state, the composing node's slice alone for a node agent; a module in the settings form (its manifest declares no config, so mesh-config holds none for it) has its values in the placement key instead; @@ -713,7 +718,8 @@ backup holder backs up nothing, and the have says so. where the placement says. - **How placement is changed.** The seat `mesh-module-assigner`, held once for the mesh by the assigner, keeps three states: `placement`, one key `placement.` per node; `proposals`; and `candidates`. Only the holder's - credential writes them, and the contract (the states' names among it) is mesh-sdk's. No repository holds + credential writes them, and the contract (the states' layouts among it) is the seat's, in + `mesh-placement-contracts` (ADR 0634 §6, §7). No repository holds placement and none names a node: what differs between nodes is bus state, and a build module's capacity and build hours are values on each node's layer of mesh-config. A key holds what a person decides of the node and nothing a machine observes: @@ -733,7 +739,7 @@ backup holder backs up nothing, and the have says so. changes (place a module, take one off, pin a provider, hold a seat, set a decided field of a node, set a module's config placement or values); who proposes is the caller as the runtime proves it. The holder lays the changes over the current keys, names the revision of each, and refuses at once, naming every finding, what - mesh-sdk's placement check refuses: a module the indexer does not hold or a node not enrolled, two modules of one + the placement check of the seat's client refuses (ADR 0634 §1): a module the indexer does not hold or a node not enrolled, two modules of one node on one host port, a pin, binding or holding naming a provider not placed where it says, a seat held once for the mesh held twice, two nodes with one address and more than one hub. Otherwise it writes the proposal and one candidate for each node whose key it changes, and the nodes answer. `withdraw` deletes both. Until the lease @@ -757,7 +763,9 @@ backup holder backs up nothing, and the have says so. holder hears that key's change; nothing polls. The nodes that must answer are each node whose key the proposal changes and each node whose composition the holder finds changed with the current inputs on both sides, not every placed node, so a node gone for good or asleep blocks only a proposal that touches it. The contract (the state, - its key, the answer, the composition with a given placement and the comparison) is mesh-sdk's (ADR 0567). + its key, the answer) is the seat's, in `mesh-placement-contracts` (ADR 0567, ADR 0634 §6, §7); the composition with + a given placement is the composition of `mesh-delivery-sdk` (ADR 0635 §4), and the comparison is the node-engine's + own package (ADR 0634 §1). - **The holder judges the answers and the operator approves.** The holder computes, by node, the modules the proposal changes and reads every answer. A proposal names no difference of its own, and the verdict fails on no difference: each difference, and each one the nodes answered that the holder did not compute, is shown by node in @@ -816,7 +824,8 @@ backup holder backs up nothing, and the have says so. rule reads, is written by the grants part from ADR 0547's third milestone; its account is minted by the vault (ADR 0547 §4, §5, §9). Until that milestone the issuer ADR 0539 §7 names writes both, so a want never waits on a key nobody writes. -- **The bus's user list.** The grants part composes the list with mesh-sdk's bus composer when an input changes, +- **The bus's user list.** The grants part composes the list with mesh-sdk's bus composer, its seat-named parts in + the grants part's own package (ADR 0635 §4), when an input changes, writes it as an object sealed to the bus node's key and writes the key `user-list` with its digest, revision, user count and the users left out; it says `user-list-changed`. The node agent of the bus node writes the bus module's user-list file alone, mode 0600, only when its digest differs, and the bus reloads it in place; no want