Designs 51, 26, 32: answer the second review by architectural domain (ADR 0611, caller identity, node-engine reports, families and retention, Go references); add each design's review record
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -395,3 +395,11 @@ checked as their tables say:
|
||||
| The uplink's step-back comes from the seat | 0287: the composition tests for the uplink and the resolver on one machine pass with the case in the collision check removed. |
|
||||
| Holdings are derived, and the overview lists every seat | 0118: the `seats` command test, including an unheld seat. |
|
||||
| A build source on the seat records no address; an unheld seat refuses only self-hosted builds | 0111's tests. |
|
||||
|
||||
## Reviewed by architectural domain
|
||||
|
||||
The amendment of 2026-11-03 for research 081 (ADR 0605 to 0611; *A seat's definition*) was reviewed with designs 51
|
||||
and 32 by the four reviewers by architectural domain; the findings and what answers them are listed in design 51's
|
||||
*Reviewed by architectural domain*. For this design: only the trunk's definition is the contract (security), the
|
||||
indexer learns out-of-step types from the check's verdict event and runs no generator (seams), findings go to the
|
||||
condition keeper (health), a pull request's entries are removed when it closes (running qualities).
|
||||
|
||||
@@ -498,24 +498,30 @@ complete, because a team that believes it is complete stops reviewing for the ca
|
||||
|
||||
(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, emits
|
||||
`renamed` (module, old name, new name, when) and records it. This design decides what ADR 0609 leaves open:
|
||||
`renamed` (module, old name, new name, when; its family `config.events`, kept seven days) and records it. This design decides what ADR 0609 leaves open:
|
||||
|
||||
- **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
|
||||
- **How long the old name is read**: until every node-engine whose node has a want of the module reports applied a
|
||||
build of it that reads the new name: mesh-config hears the node-engine seat's `applied` events, and asks each node's
|
||||
`node-engine.haves` at its start; 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.
|
||||
manifest until a build of mesh-config that understands it is delivered, which it learns from the node-engine seat's
|
||||
`applied` events for mesh-config. `config_renames` names, per rename, the nodes still holding the old name open.
|
||||
- **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.
|
||||
A config value or secret no manifest on any trunk reads any more (mesh-config learns it from the indexer's
|
||||
`indexer_config_readers`, on each of the indexer's events that a manifest was taken in) is marked retiring only once no
|
||||
node-engine reports applied a build that reads it, as the rename's window is (§ above). mesh-config then emits
|
||||
`retiring` (family `config.events`, kept seven days) and asks the operator once, through the operator channel, whether
|
||||
to remove it, naming any node that still read it until lately; it is removed only on the operator's Approve. An ask
|
||||
unanswered for seven days is asked once more, and then written as a finding. `config_retiring` lists what is retiring,
|
||||
since when, and its ask.
|
||||
|
||||
### The mesh delivery cases this design carries
|
||||
|
||||
@@ -727,3 +733,10 @@ ruled on every finding. What was found, and what answers it:
|
||||
condition `full` (ADR 0595 §6 raises and clears it at 75 percent, so an entry sitting there flaps), and an event of
|
||||
its own for `drop` and `recreate`. **A correction of fact** for ADR 0595 §4: the bus module deletes through `recreate`
|
||||
as well as `drop`. Each is noted on issue 1966.
|
||||
|
||||
The amendment of 2026-11-03 for research 081 (ADR 0606, ADR 0609; the package, rename, retiring and delivery-case
|
||||
sections of § 8) was reviewed with designs 51 and 26 by the four reviewers by architectural domain; the findings and
|
||||
what answers them are listed in design 51's *Reviewed by architectural domain*. For this design: a rename keeps a
|
||||
value's trust (security), `packages` is a section of its own, not `uses`, and mesh-config hears the node-engines'
|
||||
`applied` events (seams), a value retires only once no node-engine runs a build reading it (security), and `renamed`
|
||||
and `retiring` have a family and an ask that is asked again (events).
|
||||
|
||||
@@ -31,9 +31,10 @@ 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, ADR 0610, from research 081.) What follows is the to-be shape; the sections from
|
||||
(ADR 0605, ADR 0606, ADR 0607, ADR 0610, ADR 0611, 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).
|
||||
event: no module reads or writes another's bus state (ADR 0596). A module asks another's data through its tools, and
|
||||
asks work of another by an event of its own (ADR 0610 §1).
|
||||
|
||||
### The four registry seats
|
||||
|
||||
@@ -47,18 +48,24 @@ event: no module reads or writes another's bus state (ADR 0596).
|
||||
Each is held once for the mesh. The last two replace the seat `mesh-artifact-store` and front the one artifact store;
|
||||
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
|
||||
new names (ADR 0610 §4); a sleeping node holds it open. `distribution` closes it itself: it hears the node-engine
|
||||
seat's `applied` events (and asks each node's `node-engine.haves` at its start), stops serving the old name once every
|
||||
node whose declaration names an artifact reports the new build, and its tool `registry_old_name` lists the nodes still
|
||||
holding 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*). 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
|
||||
carrying the name, version, kind, tag, digest, fingerprint, commit and holder, and `refused` its reason; each seat's
|
||||
events are its own family, `<seat>.events`, kept seven days. 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.
|
||||
Declaring `invokes` alone grants nothing. The holder checks the caller identity the tool runner proved and stamps on
|
||||
the request (design 25 § 12.4), never a name in the request's body, and answers any other caller with a refusal naming
|
||||
the verb.
|
||||
|
||||
### Publishing
|
||||
|
||||
@@ -74,18 +81,20 @@ Declaring `invokes` alone grants nothing. The holder answers any other caller wi
|
||||
builder (durable consumer: entry, done key), indexer, status view, checker
|
||||
```
|
||||
|
||||
- **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 file travels in parts through the seat** (ADR 0611). `publish` opens a transfer, naming it and the digest of
|
||||
every part (an image's layers, a package's file, a bundle's blob); the holder answers the digests it lacks. The build
|
||||
module sends only those through `publish-part` (transfer, part digest, sequence, last), each at most 1 MiB, with
|
||||
mesh-sdk's bus helper for sending in parts, added to mesh-sdk's runtime in step 2's rebuild. A `publish` opening a
|
||||
transfer already open answers the parts held, so a cut transfer goes on from there. The parts land in the holder's
|
||||
own object store `incoming`, declared in its manifest with a cap of 20 GiB and a lifetime of 24 hours; a transfer with
|
||||
no part for 24 hours is dropped and its parts deleted. The holder hashes every part and refuses one whose bytes do not
|
||||
match its digest. At 80 % of the cap it writes a finding (cleared below 80 %); at the cap it refuses a new transfer
|
||||
with `refused` naming the cap. Its tool `registry_incoming` lists open transfers and the fill, and drops one by hand.
|
||||
- **The holder asks the builder**, through `builder_versions`, whether the name, version and digest are recorded, and
|
||||
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
|
||||
naming the seat, and the builder writes the finding for a refused publish. 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
|
||||
@@ -106,28 +115,32 @@ Declaring `invokes` alone grants nothing. The holder answers any other caller wi
|
||||
- **The builder numbers every trunk build** of a package, image, bundle or archive at its claim: the package series
|
||||
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.
|
||||
every earlier merge of the same name whose fingerprint the indexer still holds is numbered (a fingerprint replaced
|
||||
by a later merge before its claim is skipped, design 47 *After the merge*); a wait past 30 minutes writes a finding
|
||||
naming the merge it waits on. 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
|
||||
writes a finding, cleared below it. 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 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`
|
||||
name until all three answered, and writes a finding naming the silent one meanwhile, cleared once all three answer. 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
|
||||
after a holder failed; when the build's file is gone it builds the fingerprint again under the same number, and the
|
||||
new digest replaces the recorded one only if no `published` was ever emitted for that number, else it takes a new
|
||||
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
|
||||
|
||||
- **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
|
||||
tag), on a family of its own, `checker.asks`, kept seven days, apart from its verdicts, so a waiter on a verdict does
|
||||
not wake on it, 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.
|
||||
@@ -145,12 +158,16 @@ Declaring `invokes` alone grants nothing. The holder answers any other caller wi
|
||||
|
||||
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.
|
||||
The Go seat keeps what the npm seat keeps: every referenced version and the newest five of each package series. A
|
||||
Go version is referenced when a `go.mod` on a repository's default branch requires it; the forge module reads every
|
||||
`go.mod` as it reads lockfiles, and a `go.mod` it could not read stops a real run before anything is deleted, as an
|
||||
unread lockfile does.
|
||||
|
||||
### Health and conditions
|
||||
|
||||
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,
|
||||
publish refused (the holder when it refuses, the builder when a build module's bound ran out; cleared when that version
|
||||
is stored, or when a later version of the name is published), 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.
|
||||
@@ -159,9 +176,11 @@ the builder). A build narrates its publish: asked, waiting on a seat, stored, re
|
||||
|
||||
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
|
||||
1. A node-engine that reads both reference forms and both seat names; the holders serve every verb of the four seats
|
||||
with their caller lists, and `incoming`; 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
|
||||
2. Starts only once every node-engine reports step 1's build applied (a sleeping node holds it). 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.
|
||||
@@ -169,7 +188,8 @@ Each step is its own delivery, and no credential goes before its replacement wor
|
||||
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'
|
||||
Steps are rolled back in reverse order. 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`.
|
||||
|
||||
@@ -189,11 +209,40 @@ test).
|
||||
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
|
||||
- **Builder, added in round 2.** Two merges close together, the first replaced before its claim: the second is
|
||||
numbered at once; a build module's bound running out writes the builder's finding, and a later version of the name
|
||||
clears it; `builder_publish_again` after a `published` takes a new number.
|
||||
- **Holder (gitea, distribution).** A caller not on the caller list is refused for each verb, and one module naming
|
||||
another as the caller in the request's body is refused; a transfer cut in the middle resumes from the parts held,
|
||||
and one left 24 hours is dropped; at the cap a new transfer is refused naming the cap; a version a `go.mod` requires
|
||||
survives retention, and an unreadable `go.mod` stops the run; a part whose bytes do
|
||||
not match its digest is refused; only the missing layers are sent; `remove` of a version with no tag is refused;
|
||||
with no publish running, a stopped Go seat writes its finding and clears it when it answers; `registry_incoming`
|
||||
with no publish running, a Go seat that stops answering while its holder runs writes its finding and clears it when it
|
||||
answers (a holder down whole is its module's own health check's); `registry_incoming`
|
||||
lists and drops.
|
||||
- **Vault.** Reverting step 4 mints the build modules' credentials again.
|
||||
- **Vault.** Reverting step 4 mints the build modules' credentials again; the bootstrap's one-off credential is gone
|
||||
once the holders serve `publish`.
|
||||
- **Live.** Step 2 waits while one node-engine has not reported step 1's build; `registry_old_name` names the nodes
|
||||
holding the old name open.
|
||||
|
||||
## Reviewed by architectural domain
|
||||
|
||||
The amendment of 2026-11-03 (ADR 0605 to 0611, research 081's graduation, designs 51, 26 and 32 together) was reviewed
|
||||
by the four reviewers by architectural domain side by side (playbook 01), and the lead ruled on every finding. Two
|
||||
findings reached a decision and became records: ADR 0610 (a module's bus state is its own, ADR 0596, so the checker
|
||||
asks by an event and holders ask the builder's tool; retention; the old seat name closes on what node-engines applied)
|
||||
and ADR 0611 (the file travels in parts through the seat). What was found, and what answers it:
|
||||
|
||||
| Domain | Found | Answered by |
|
||||
|---|---|---|
|
||||
| security | caller lists named only on the caller's side; the handed object's bytes unchecked; no caller identity; pull request seat definitions served as contracts; the bootstrap's credential | *Who may call which verb* (holder-side lists, the identity the tool runner proved); *Publishing* (parts hashed); design 26 (only the trunk's entry is the contract); *The move* (a one-off bootstrap credential) |
|
||||
| upgrade | the steps moved no image, bundle or archive before their credentials went; Go users between steps 2 and 3; no node-engine reading the new forms before step 2 | *The move* (every move in step 2, a node-engine reading both forms in step 1, step 2 waiting on the node-engines' reports, git tags for Go, reverse-order rollback) |
|
||||
| seams | five reaches into another module's bus state; a shared hand-off store; how a publish ends; how the indexer learns out-of-step types; no named path for the node-engines' reports | ADR 0610, ADR 0611; *Publishing* (`published` or `refused`); design 26 (the check's verdict event); `applied` and `node-engine.haves` |
|
||||
| tools | no read or drop tool for asks, transfers, the old name's window | `builder_tag_asks`, `registry_incoming`, `registry_old_name`, design 32's `config_renames` and `config_retiring` |
|
||||
| running qualities | the versions value growing; the floor with a part down; merge order and a replaced merge; windows closing on wants; retention against "never removed"; a Go reference undefined; the in-transit cap | *The versions* (one key per version, a cap, the floor's wait, merge order skipping a replaced fingerprint); *Retention* (a Go reference); *Publishing* (the cap refused) |
|
||||
| testing | failure paths untested; the test budget | cases of each module's one whole-module integration test, listed under *Acceptance tests* |
|
||||
| health | conditions raised by their observers; no health check of a seat between publishes; a refused publish with no clearing | findings for the condition keeper (ADR 0564); the holder's health check; *Health and conditions* (each finding with what clears it) |
|
||||
| events and logs | removal and `published` failing silently; a publish silent for 10 minutes; events with no family or retention | the builder's durable consumers and acknowledgement rule; narration every five minutes; each event's family and seven days |
|
||||
|
||||
## The parts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user