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
This commit is contained in:
@@ -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-<area>-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-<area>-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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 <registry seat>.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: `<registry>/<module>/<artifact>@sha256:<digest>` for an
|
||||
image, bundle or archive, `<name>@<version>` 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 <seat>" 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.<n>`), 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-<tag>.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-<tag>.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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user