From 20157fcafe38a63803ebef32c81cf8e9022cb676 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 18:02:09 +0100 Subject: [PATCH] Designs 51, 26, 32: answer the first review by architectural domain (ADR 0596 paths, holder-side caller lists, the file in the publish verb, findings for the condition keeper, windows on node-engine reports) Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig --- 03-DESIGN/01-to-be/26-the-seats.md | 36 ++-- .../01-to-be/32-what-a-module-declares.md | 49 +++-- .../51-the-registries-keep-what-is-named.md | 196 +++++++++++------- 3 files changed, 180 insertions(+), 101 deletions(-) diff --git a/03-DESIGN/01-to-be/26-the-seats.md b/03-DESIGN/01-to-be/26-the-seats.md index 4ea5fb1a..688ba837 100644 --- a/03-DESIGN/01-to-be/26-the-seats.md +++ b/03-DESIGN/01-to-be/26-the-seats.md @@ -178,21 +178,27 @@ research 081). The registry seats (design 51) are the first defined this way, th bodies, its state and the forms of its provisions. It lives in the contracts module of its area. Its Go and TypeScript types are generated from it and committed beside it; nobody writes them by hand. - **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 belongs to the module whose work it is). A check regenerates and fails, - naming the file, when a committed type differs. -- **On the bus**: the indexer reads every seat definition from every trunk and open pull request and keeps them in its - state `seat-definitions`, keyed by seat and source (the trunk, or a pull request's head), as their only writer, and - emits `seat-definition-changed`. 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). -- **Conditions**, each raised and cleared by the indexer: a seat definition that does not parse; generated types out - of step with their definition. **Tools** of the indexer: `indexer_seat_definition` (read one), + build module's for TypeScript (the logic is the module's whose work it is). The check of a change regenerates and + fails, naming the file, when a committed type differs; its verdict event names the out-of-step files, and that is + how the indexer learns of them. The indexer runs no generator. +- **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 the trunk's entry is the seat's contract**: the readers (the contracts + modules' builds, the tool runner's descriptions, 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 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 (a pull request's is its check's verdict, not a condition); generated + types on a trunk out of step with their definition. **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 contracts only (every file generated from a seat definition) and no seat; the seat's holder implements it. The seat contracts mesh-sdk holds - move into `mesh-contracts` in one change, delivered with the first numbered publish (design 51, *The move*); an - area's contracts move into `mesh--contracts` when the area's contract next changes, and that change creates + move into `mesh-contracts` in one change, delivered with the first numbered publish (design 51, *The move*, step 2); + an area's contracts move into `mesh--contracts` when the area's contract next changes, and that change creates the module. mesh-sdk keeps its name and the shared runtime. A catalog check refuses a contracts module holding a file its generator did not write, and a seat-specific type in mesh-sdk once `mesh-contracts` publishes. - **Older readers keep working**: a moved contract keeps its subjects, keys and message shapes, and a reader ignores @@ -201,9 +207,11 @@ research 081). The registry seats (design 51) are the first defined this way, th like any package; a later holder of the seat may publish its own the same way. A seat's definition stays vendor-neutral, which the seams review checks. -Acceptance tests: research 081's 14, 21, 25 and 26, and an integration test of the indexer: a definition that does not -parse raises its condition and a fixed one clears it; a generated type changed by hand raises the out-of-step condition -and regenerating clears it; each of the three tools answers. +Acceptance tests: research 081's 14, 21, 25 and 26, 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 check verdict naming out-of-step types +writes the finding and a clean one 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; each of the three +tools answers. ## The foundation's seats diff --git a/03-DESIGN/01-to-be/32-what-a-module-declares.md b/03-DESIGN/01-to-be/32-what-a-module-declares.md index e749369f..37054c73 100644 --- a/03-DESIGN/01-to-be/32-what-a-module-declares.md +++ b/03-DESIGN/01-to-be/32-what-a-module-declares.md @@ -481,40 +481,55 @@ complete, because a team that believes it is complete stops reviewing for the ca way; one that declares none is numbered in `0.1`. Nobody types a version: the builder counts it (design 51). - **Raising a package series** is a reviewed change of the package's manifest, for a change that breaks its users. The checker's verdict names every change of a package series it sees, so the review of the change sees it. -- **A user names, in each `uses` of a mesh package, the package series it accepts.** It builds, and is checked, - against the newest version of that series; a publish in another series does not move it, and moving is a reviewed - change of the user's manifest. A user that names none accepts the series of the package's first numbered version, - so nothing is edited in today's users. +- **A user names the mesh packages it takes in a section of its own, `packages`**, each with the package series it + accepts. It is not `uses`, which grants publishing on a seat's `accepts` subjects (§ 3); a package is not a seat. A + user builds, and is checked, against the newest version of that series; a publish in another series does not move + it, and moving is a reviewed change of the user's manifest. A user that names none accepts the series of the + package's first numbered version, so nothing is edited in today's users. The indexer's tool `indexer_package_users` + lists, per package, its users and the series each accepts, so a user left on an older series is seen. - **Inside one repository** a module uses its sibling package by path, from the same commit, and waits for no publish. - **A user outside the package's delivery group is not built before the merge**: it is built after it, when the new version is in its series. A user that breaks fails its own build, is not wanted, keeps its previous build, and a condition tells the operator. A group's members are built in the group's check, against the group's tagged version. +- **Cost**: the new manifest fields are read through mesh-sdk's manifest types, so their change rebuilds every module + once; it is delivered with design 51's step 2, the one rebuild that step already takes. ### A config value renamed (from 2026-11-03) (ADR 0609 §4.) A config value's declaration may name its old name, `renamed-from`. On the merge, mesh-config moves the -value it holds under the old name to the new name in its own state, without the operator giving it again, and records -the move. This design decides what ADR 0609 leaves open: +value it holds under the old name to the new name in its own state, without the operator giving it again, emits +`renamed` (module, old name, new name, when) and records it. This design decides what ADR 0609 leaves open: -- **Which values**: a module's own config values only, never a secret, and never another module's value. -- **How long the old name is read**: until every node's want of the module names a build that reads the new name, as - the delivery view's wants show; until then mesh-config answers both names. A later change may drop `renamed-from` - only after that, and the checker refuses it before. -- **Tools of mesh-config**: `config_renames` (what moved, from which name, when) and `config_rename_again` (move one - value by hand when a move was refused). +- **Which values**: a module's own config values only, never a secret, never another module's value. A rename keeps + the value's trust: a value set without the operator's Approve stays untrusted under its new name (ADR 0348 §8), and + the checker refuses a rename that would change a value's trust. +- **How long the old name is read**: until every node-engine reports applied a build of the module that reads the new + name, as the node-engine seat's reports answer; until then mesh-config answers both names. A later change may drop + `renamed-from` only after that, and the checker refuses it before. The checker also refuses `renamed-from` in any + manifest until a build of mesh-config that understands it is delivered. +- **A refused move** (the old name holds nothing, or a secret) is mesh-config's finding, from which the condition keeper + raises the condition. **Tools of mesh-config**: `config_renames` (what moved, from which name, when) and + `config_rename_again` (move one value by hand when a move was refused). + +### A value no longer read (from 2026-11-03) + +A config value or secret no manifest reads any more is marked retiring by mesh-config, which emits `retiring` and asks +the operator once, through the operator channel, whether to remove it; it is removed only on the operator's Approve. +`config_retiring` lists what is retiring and since when. ### The mesh delivery cases this design carries -Research 081 listed the mesh delivery cases; these are the ones it handed to a design, each with its acceptance test. +Research 081 listed the mesh delivery cases; these are the ones it handed to a design, each with its acceptance test, +each a case of its module's one whole-module integration test unless it says live. | case | what holds | acceptance test | |---|---|---| -| C6, a package series raised | users on `0.1` keep the newest `0.1`; a reviewed change moves a user | integration, builder: a `0.2.0` publish moves no `0.1` user, its check takes the newest `0.1` too, a reviewed change naming `0.2` moves it, a user naming no series builds against the newest `0.1` | -| C14, a provision's form gains a field | the provider serves it in a new version; the consumer reads it once rebuilt; an older consumer ignores it | integration, mesh-sdk: a consumer built against the older form reads a provision with the new field | +| C6, a package series raised | users on `0.1` keep the newest `0.1`; a reviewed change moves a user | builder: a `0.2.0` publish moves no `0.1` user, its check takes the newest `0.1` too, a reviewed change naming `0.2` moves it, a user naming no series builds against the newest `0.1` | +| C14, a provision's form gains a field | the provider serves it in a new version; the consumer reads it once rebuilt; an older consumer ignores it | mesh-sdk: a consumer built against the older form reads a provision with the new field | | C18, a new required config value with no default | the check names the nodes that lack it; the want waits; the operator is asked once | live: a module gaining such a value waits on each node lacking it, the operator is asked once naming the nodes, and once given the module is applied | -| C20, a config value renamed | the value moves; both names read until every node runs the new build | integration, mesh-config: a renamed value is present under the new name with no operator input, the old name answers until the wants show the new build everywhere, and dropping `renamed-from` early is refused | +| C20, a config value renamed | the value moves, keeps its trust, both names read until every node runs the new build | mesh-config: a renamed value is present under the new name with no operator input and its trust; the old name answers until the node-engines report the new build; dropping `renamed-from` early, or changing trust, is refused; a refused move writes its finding | | C22, a secret only a person can give | the want waits; the operator is asked once what to give and where | live: a module requiring such a secret waits, one ask names it and where, and once given the module starts | -| C24, a config value or secret no longer read | it is retiring, removed only on the operator's Approve | integration, mesh-config: a value no manifest reads any more is marked retiring and stays until an Approve removes it | +| C24, a config value or secret no longer read | it is retiring, the operator is asked, removed only on the Approve | mesh-config: a value no manifest reads is marked retiring, `retiring` is emitted, one ask reaches the operator, and it stays until an Approve removes it | ## 9. Provisioning over the bus 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 2a3bdd57..d3a61983 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 @@ -11,6 +11,7 @@ decisions: - "ADR 0605" - "ADR 0606" - "ADR 0607" + - "ADR 0610" - "ADR 0311" - "ADR 0251" - "ADR 0189" @@ -30,8 +31,9 @@ extending ADR 0189.) ## What is published, and how (from 2026-11-03) **Every registry is a seat; a build module publishes into it over the bus; the builder gives every version.** -(ADR 0605, ADR 0606, ADR 0607, from research 081.) What follows is the to-be shape; the sections from *The parts* -on keep what the registries hold, and stand. +(ADR 0605, ADR 0606, ADR 0607, ADR 0610, from research 081.) What follows is the to-be shape; the sections from +*The parts* on keep what the registries hold, and stand. Every interaction below is a seat verb, a module's tool or an +event: no module reads or writes another's bus state (ADR 0596). ### The four registry seats @@ -43,101 +45,155 @@ on keep what the registries hold, and stand. | `oci-artifact-registry` | bundles and archives, by digest | OCI distribution | `distribution` | Each is held once for the mesh. The last two replace the seat `mesh-artifact-store` and front the one artifact store; -the provision `artifact-store` keeps its name. `mesh-artifact-store` stays readable until every node's want of the -node-engine names a build that reads the new names, which the delivery view's wants show. `cargo-package-registry` -stays named, without a holder, until a build module publishes cargo packages. +while one module holds both, both deliver the provision `artifact-store`, and splitting them between two holders takes a +decision of its own. `mesh-artifact-store` stays served until every node-engine reports applied a build that reads the +new names (ADR 0610 §4); a sleeping node holds it open. `cargo-package-registry` stays named, without a holder, until a +build module publishes cargo packages. -**One contract, a seat definition** (design 26, *A seat's definition*): the verbs `publish`, `versions` and -`remove` (a tagged version only), and the events `published` and `removed`, each carrying the name, version, kind, -tag, digest, fingerprint, commit and holder. A holder stores under the version it is given and counts nothing. +**One contract, a seat definition** (design 26, *A seat's definition*). Verbs: `publish`, `versions`, `remove` (a +tagged version only; the holder itself refuses `remove` of a version with no tag), and on `container-image-registry` +`mirror` and `tags`. Events: `published`, `refused` (added to ADR 0605 §2's two, additively) and `removed`, each +carrying the name, version, kind, tag, digest, fingerprint, commit and holder, and `refused` its reason. A holder stores +under the version it is given and counts nothing. + +**Who may call which verb is the holder's to say**, in a trusted config value of the holder listing its callers, the +form ADR 0363 gives a restricted family: `publish` the build modules; `mirror` mesh-build-image; `remove` the builder. +Declaring `invokes` alone grants nothing. The holder answers any other caller with a refusal naming the verb. ### Publishing ``` builder ── build request (name, version or tag) ──▶ build module - │ hands the file: object store `publish-handoff` - │ calls .publish + │ publish(name, version, digests of every part) ▼ - registry seat's holder ── reads the builder's `versions` (announced state) - │ stores, deletes the handed object - └── emits `published` ──▶ builder (entry → published), indexer, status view + registry seat's holder ── answers the parts it lacks + │ the build module sends those parts, in chunks, by `publish` + holder: hashes what it received, asks `builder_versions`, + stores in its own store, emits `published` or `refused` + ▼ + builder (durable consumer: entry, done key), indexer, status view, checker ``` -- **Only build modules may call `publish`**, and only from a trunk build or for a tagged version; the bus grants - nothing else. No build module holds a registry's write credential: the npm write token and the image push - credential go, and each holder keeps its write credential as an own secret beside a read-only tool token (the forge - module: `write:package`, its tool token `read:package`). -- **The handed object** lives in the object store `publish-handoff`, which the builder owns: build modules write, - holders read and delete. An image is handed as an OCI layout holding only the layers the holder lacks: `publish` - names every layer's digest, the holder answers the digests it is missing, and only those are handed. The store is - capped at 20 GiB, an object lives at most 24 hours, and a publish not stored within 10 minutes is refused by its - build module, naming the seat, which leaves the entry `refused` (the condition below). -- **A holder refuses loudly**: a version or digest the builder's `versions` do not record, and a held version or tag - offered with other bytes. A rebuild of a held fingerprint answers the held version and stores nothing. -- **The done key** names the reference the seat answered: `//@sha256:` for an - image, bundle or archive, `@` for a package. -- **Go packages** are fetched through the Go seat's provision first and Go's public proxy second, with no - `GOPRIVATE` and the checksum database off for the forge's paths; `go.sum` and the recorded digest refuse a mesh - package with other content. Outside Go modules keep coming from the public proxy; no mirror is built, and one could - come later as a holder of a seat of its own without any build module changing. +- **The file travels in the verb.** `publish` opens with every part's digest (an image's layers, a package's file, + a bundle's blob); the holder answers the digests it lacks, and the build module sends only those, in chunks no + larger than the bus's message limit, into the holder's own store. This is how ADR 0605 §3's hand-off holds under ADR + 0596: no store is reached by two modules. The holder hashes every part it received and refuses one whose bytes do + not match its digest; a part it never received completed is dropped after 24 hours. The holder's tool + `registry_incoming` lists what is in transit, its fill against a 20 GiB cap, and drops one by hand; past 80 % of the + cap the holder writes a finding. +- **The holder asks the builder**, through `builder_versions`, whether the name, version and digest are recorded, and + refuses loudly otherwise (ADR 0605 §4). A rebuild of a held fingerprint answers the held version and stores nothing. +- **How a publish ends**: the holder emits `published` or `refused`. The build module waits for one of them, at most + 10 minutes, narrating "waiting on " at least every five minutes; past the bound it writes the key refused, + naming the seat. A `published` that arrives after that is still heard by the builder on its durable consumer: the + entry turns `published` and the builder writes the done key then, so a late store is never lost. +- **What is published when**: a package or an image from a trunk build under its version, or as a tagged version; a + bundle or an archive from every done key by its digest alone, a candidate's included, and at the trunk's claim the + build module calls `publish` with the version and the held digest, which stores nothing. An upstream image is copied + by `mirror` with its pinned digest. The done key names the reference the seat answered; a key in the old + `artifact-store://` form keeps it, every reader reads both forms, and none is built again for its form. +- **No build module holds a registry's write credential**: the npm write token, the image push credential and the + artifact store's write binding go in step 4. Each holder keeps its write side as an own secret beside a read-only + tool token (the forge module: `write:package`, its tool token `read:package`). +- **Go packages** are fetched through the Go seat's provision first and Go's public proxy second, with no `GOPRIVATE` + and the checksum database off for the forge's paths; `go.sum` and the digest the builder records (Go's `h1:` hash, + computed by the Go build module at the publish) refuse a mesh package with other content. The builder also tags + each Go version in git (`go/v0.1.`), so a user that names a version can fetch it from the forge's git as well. + No mirror of outside modules is built; one could come later as a holder of a seat of its own. ### The versions - **The builder numbers every trunk build** of a package, image, bundle or archive at its claim: the package series - its manifest declares (design 32 § 6; `0.1` when it declares none) and the next count for that name, under - compare-and-set. Numbers follow merge order. -- **The builder's state `versions`** (announced, the builder its only writer, readable by the indexer, the registry - seats' holders and the status view) holds per name, and per tag, every version with its fingerprint, commit, - digest, time and state: `numbered`, `published`, `refused` with its reason, or `removed` with the time, the branch - and the forge bridge's event that removed it. The build log carries each change too. + its manifest declares (design 32; `0.1` when it declares none) and the next count for that name, under + compare-and-set. Numbers follow the order of the forge bridge's merge events: a claim of a later merge waits until + every earlier merge of the same name is numbered. A fingerprint already numbered keeps its number. +- **The builder's state `versions`** holds one key per name, tag and version, with its fingerprint, commit, digest, + time and state: `numbered`, `published`, `refused` with its reason, or `removed` with the time, the reason (a + branch's end, retention, the sweep) and the event that removed it. History one, cap 1 GiB; past 80 % the builder + writes a finding. Only the builder reaches it; others call `builder_versions` or hear its events. The build log + carries each change too. - **The floor**: on a name's first claim, or when `versions` holds nothing for it, the count starts above the highest - of what the seat's `versions` answers, the package's highest git tag (the forge bridge's state) and the highest - pseudo-version a consumer requires (the indexer's state); a name with none starts at `0.1.0`. Today that gives Go - `v0.1.14` and npm `0.1.18`. -- **A trunk build that declares a package is done** only once its done key names a published version for each. -- **Events of the builder**: `numbered`. **Tools of the builder**: `builder_versions` (a name's versions in order, - one call), `builder_publish_again` (one fingerprint under its number, after a holder failed; it refuses a version - refused for other bytes), `builder_tag` (ask a tagged version) and `builder_untag` (remove a branch's tagged versions). + of the seat's `versions`, the package's highest git tag (the forge bridge's tool `bridge_tags`) and the highest + pseudo-version a consumer requires (the indexer's tool `indexer_requirements`). The builder numbers nothing for that + name until all three answered, and writes a finding naming the silent one meanwhile. Today that gives Go `v0.1.14` + and npm `0.1.18`; a name with none starts at `0.1.0`. +- **Events of the builder**: `numbered` (name, version, tag, fingerprint, commit, head when it answers an ask), on its + own family, kept seven days; a waiter on a build's end does not wake on it. **Tools of the builder**: + `builder_versions` (a name's versions in order, one call), `builder_publish_again` (one fingerprint under its number, + after a holder failed; when the build's file is gone it builds the fingerprint again under the same number; it + refuses a version refused for other bytes), `builder_tag` (ask a tagged version), `builder_tag_asks` (open asks and + their state) and `builder_untag` (remove a branch's tagged versions). ### Tagged versions -- **A tagged version is asked by a key, never by a push.** The checker, for each head of a delivery group member that - declares a package, and a person, through `builder_tag`, write an ask in the builder's state `tag-asks`, keyed by - repository, branch and head; the builder watches it. The tag is cleaned to Semantic Versioning's characters. -- **It is numbered below the next version** (`0.1.15-feat-x.2`), never the latest; npm keeps it under a dist-tag of its - own and Go's `@latest` skips it. A package new in a group is numbered from its floor (`0.1.0-feat-x.1`). -- **A group's check takes it from the registry**: Go members by the tagged version, TypeScript members with their lock - naming it and the registry's integrity. Nothing is packed for a check, and a lone pull request's check publishes - nothing. -- **It is removed** when its branch is merged or deleted: the builder hears the forge bridge's event on a durable - consumer, calls each seat's `remove`, the seat emits `removed`, and the entry turns `removed`. A version without a - tag is never removed. +- **Asked by an event, never by a push** (ADR 0610 §1). The checker emits `tag-wanted` (repository, branch, head, + tag) for each head of a delivery group member that declares a package; a person asks through `builder_tag`. The + builder consumes the event on a durable consumer and keeps the ask in its own state `tag-asks`, removed when its + branch is merged or deleted. An ask the builder has not answered within five minutes is narrated in the build log + with what it waits on. +- **Numbered below the next version** (`0.1.15-feat-x.2`), never the latest; npm keeps it under a dist-tag of its own + and Go's `@latest` skips it. A package new in a group is numbered from its floor (`0.1.0-feat-x.1`). +- **A group's check builds after `published`**: Go members by the tagged version, TypeScript members with their lock + naming it and the registry's integrity; nothing is packed for a check, and a lone pull request's check publishes + nothing. No `published` within the publish's bound (10 minutes) fails the check naming the package. +- **Removed with its branch**: on the forge bridge's merged or deleted event, heard on a durable consumer, the builder + calls each seat's `remove`. It acknowledges the event only once every seat emitted `removed`; until then it retries + every minute and, past 15 minutes, writes a finding naming the seat. A version with no tag is not removed by a + branch's end; retention may remove an old unreferenced one (below). + +### Retention + +The retention of *The package registry* below, and the artifact sweep, keep working, now through the seats: each +removal emits `removed` and the builder marks its entry, so `versions` never says `published` for bytes that are gone. +The Go seat keeps what the npm seat keeps: every referenced version and the newest five of each package series. ### Health and conditions -Every holder declares a health check. Conditions, each raised and cleared: a publish refused (cleared when it is -stored), a registry seat not answering (cleared when it answers). A build narrates its publish: asked, stored, refused. +Observers write findings; the condition keeper raises and clears the conditions from them (ADR 0564). Findings: a +publish refused (the holder; cleared when it is stored), a registry seat not answering (each holder's health check, +which calls `versions` on each seat it holds and probes the read side every minute, so a dead seat is seen with no +publish running), a removal not done (the builder), a floor source silent (the builder), a store past 80 % (the holder, +the builder). A build narrates its publish: asked, waiting on a seat, stored, refused. ### The move, in four steps -Each step is its own delivery. 1: the holders serve the verbs and `versions` exists. 2: mesh-sdk's first publish -through the seats, read back, delivered together with the move of mesh-sdk's seat contracts into `mesh-contracts` -(design 26), so every module is rebuilt once for both. 3: the Go fetch switches to the seat. 4: the old credentials -and `package-version.sum` go. Steps 1 to 3 are rolled back by reverting their pull request; step 4 by reverting it, -which mints the build modules' credentials again. On a fresh mesh the builder publishes into a holder the -foundation's bootstrap raised. +Each step is its own delivery, and no credential goes before its replacement works (ADR 0605 §7). + +1. The holders serve every verb of the four seats with their caller lists; the builder's `versions`, `tag-asks`, its + events and tools; the forge bridge's `bridge_tags` and the indexer's `indexer_requirements`. +2. Every build module publishes through the seats: mesh-sdk's first numbered publish, images, bundles, archives and + upstream copies, each read back; delivered with the move of mesh-sdk's seat contracts into `mesh-contracts` (design + 26), so every module is rebuilt once for both. The checker emits `tag-wanted`. Until step 3, Go users fetch from the + forge's git, where the builder's tags let them take the numbered version. +3. The Go fetch switches to the Go seat. Its rollback stays safe after a user moved, since the git tags exist. +4. The three credentials go, and `package-version.sum`. The old seat name retires after it, on the node-engines' + reports. + +Steps 1 to 3 are rolled back by reverting their pull request; step 4 by reverting it, which mints the build modules' +credentials again. **On a fresh mesh** the foundation's bootstrap (research 075) pushes the holders' own images with a +one-off credential of the bootstrap, discarded once the holders serve `publish`. ### Acceptance tests -Research 081's tests 1-3, 5-7, 9, 10, 12, 13, 15-20, 22 and 23 (its Direction) are this design's, with their labels -(live or integration, and the module). Added here: +Research 081's tests 1-3, 5-7, 9, 10, 12, 13, 15-20, 22 and 23 (its Direction) are this design's, with their labels. +Each integration test below is a case of its module's one whole-module integration test, which starts the module +against the real bus (test budget: mesh-delivery holds 76 integration tests today, over its 50; these add cases, not +tests, and each change that touches the builder's or the indexer's tests merges two old ones into its whole-module +test). -- **Integration, builder.** A branch pushed with no ask publishes nothing; a lone pull request's check publishes - nothing; a group introducing a new package takes `0.1.0-.1`; `builder_untag` removes a branch's tagged - versions with `removed`, and the entry shows the branch and the event. -- **Integration, builder.** An image whose layers the holder holds hands only the missing ones; a publish not stored - within 10 minutes leaves the entry `refused` and raises the condition. -- **Live.** A revert of step 4 on one node mints the build modules' credentials again before it reaches the others. +- **Builder.** A branch pushed with no ask publishes nothing; a lone pull request's check publishes nothing; a group + introducing a new package takes `0.1.0-.1`; the checker's `tag-wanted` yields `numbered` and `published`, and + members are built only after `published`; no `published` in 10 minutes fails the check naming the package; + `builder_untag` removes a branch's tagged versions with `removed`; a `remove` while the holder is down is retried and + past 15 minutes writes its finding; a late `published` after the bound writes the done key; `builder_publish_again` + after the build's file is gone builds again under the same number; with the seat's holder stopped at a first claim + nothing is numbered and the finding names it; two merges claimed in reverse order are numbered in merge order; a + retention removal turns the entry `removed`. +- **Holder (gitea, distribution).** A caller not on the caller list is refused for each verb; 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 stopped Go seat writes its finding and clears it when it answers; `registry_incoming` + lists and drops. +- **Vault.** Reverting step 4 mints the build modules' credentials again. ## The parts