Designs 51, 32: the windows wake on the node-engine seat's manifest-reads-changed (ADR 0618), and every build stays readable by every counted node-engine (ADR 0624) #513

Merged
mesh-tools merged 4 commits from docs/cite-adr-0618 into main 2026-11-04 09:08:19 +00:00
2 changed files with 68 additions and 33 deletions
@@ -18,6 +18,7 @@ decisions:
- "ADR 0609"
- "ADR 0612"
- "ADR 0613"
- "ADR 0618"
- "ADR 0606"
- "ADR 0595"
- "ADR 0596"
@@ -516,10 +517,18 @@ value it holds under the old name to the new name in its own state, without the
module reports applied a build of it that reads the new name. mesh-config hears the status view's `delivered`
events and, at its start and on each, asks its `node_haves` for every node, away ones included, since `delivered`
counts only the nodes present (design 47); until then mesh-config answers both names. A node away when the last
`delivered` was said should close its window when it returns, with no other delivery: what wakes mesh-config then
is to be decided in ADR 0618 (reserved), the node-engine seat's event for a node's stated manifest-reads, said also
on its return, as for the old seat name (design 51), never a watch of the node-engine's have state (ADR 0596).
**Until ADR 0618 is accepted**, such a node closes the window on the next `delivered`, whichever delivery says it. A node holding a window open
`delivered` was said should close its window when it returns, with no other delivery: mesh-config also wakes on
the node-engine seat's event `mesh.seat.node-engine.event.manifest-reads-changed`, said when a node's stated
capabilities change and when it returns after being away (ADR 0618 §4), as for the old seat name (design 51), and
on it reads that node's stated capabilities through the seat's verb `manifest-reads` (ADR 0618 §3) and its applied
builds through `node_haves`, never a watch of the node-engine's have state (ADR 0596). mesh-config declares
`seat:node-engine.manifest-reads` in its `invokes`: that is the grant the grants part composes, and with it the
grants part grants mesh-config the subscription to the event's subject (its unit row is in design 51). A
node-engine that does not yet serve `manifest-reads` counts as stating nothing: the window stays open and
the seat's verb `renames` names the node. ADR 0618 does not cover a
returned node that applies the module's new build only after its return event, since that build changes what the
module reads, not what the node-engine states: such a node closes the window on the next `delivered`, whichever
delivery says it. A node holding a window open
for seven days is mesh-config's finding naming the node, cleared when the window closes; `config_rename_close`
drops a node from a window by hand, recorded as a hand act.
- **The checker asks the seat, never the module.** The seat `mesh-config` gains the optional verb `renames` (the
@@ -572,8 +581,8 @@ holder that does not serve it refuses `renamed-from` naming the verb, one meetin
`renamed-from` naming the nodes, and a check that cannot ask fails saying so; `retire` with the warrant removes the
secret and emits `retired` and `own-retired`, without it, with a warrant for another name, or from a caller not on the list it is
refused; a waiter on the vault's `rotated` or `own-replaced` does not wake on `own-retired`; a node that was away,
returning with a build that reads the new name, closes the rename window on the next `delivered` (until ADR 0618 is
accepted); `config_rename_close` drops a node from a window and records the hand act; a window held seven days and a
returning with a build that reads the new name, closes the rename window on its `manifest-reads-changed` event when
it applied that build before the event (ADR 0618 §4), and on the next `delivered` when it applies it after; `config_rename_close` drops a node from a window and records the hand act; a window held seven days and a
retirement held seven days each write their finding naming the node, cleared when it closes.
### The mesh delivery cases this design carries
@@ -18,6 +18,8 @@ decisions:
- "ADR 0614"
- "ADR 0613"
- "ADR 0617"
- "ADR 0618"
- "ADR 0624"
- "ADR 0606"
- "ADR 0607"
- "ADR 0610"
@@ -79,11 +81,16 @@ it open for seven days is a finding naming the node, cleared when the window clo
`distribution`'s own family `distribution.events`, kept seven days and capped at 16 MiB, dropping its oldest when
full (it carries a handful of events per window), never on a seat's `<seat>.events`: it is one module's window, not
the seats' contract. A node away when the last `delivered` was said should close the window when it returns and
applies the new build, with no other delivery: what wakes `distribution` then is to be decided in ADR 0618
(reserved), the node-engine seat's event for a change of a node's stated manifest-reads and the delivery view's read
of them, never a watch of the node-engine's have state (ADR 0596). **Until ADR 0618 is accepted**, such a node closes
the window on the next `delivered`, whichever delivery says it: `distribution` asks `node_haves` then, finds the
returned node's new build, and closes. `cargo-package-registry` stays
applies the new build, with no other delivery: `distribution` also wakes on the node-engine seat's event
`mesh.seat.node-engine.event.manifest-reads-changed`, which each node-engine says when the capabilities it states
change and when its node returns after being away (ADR 0618 §4), and on it reads that node's stated capabilities
through the seat's verb `manifest-reads` (ADR 0618 §3), and its applied build through `node_haves`, never a watch of
the node-engine's have state (ADR 0596). `distribution` declares `seat:node-engine.manifest-reads` in its `invokes`:
that is the grant the grants part composes, and with it the grants part grants `distribution` the subscription to
the event's subject. A node-engine that does not yet serve `manifest-reads` counts as stating nothing: the window stays
open and `registry_old_name` names the node. A returned node that then applies the build whose node-engine reads the new
names says the event again, as its stated capabilities change, so ADR 0618 covers every node of this window and no
`delivered` is waited for. `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`, `publish-part` (ADR 0611), `versions`, `remove` (a
@@ -373,19 +380,30 @@ publish of mesh-sdk or `mesh-contracts` triggers their users (ADR 0614 §6). The
build and adds none (ADR 0613 §1). ADR 0614 bounds nothing here; a bound, such as a settle before building a
fingerprint whose inputs still move, is a question for a record, put to the operator, and is not designed here.
**The node-engine's own build keeps the old reference form** until every node-engine states the capability to read
the new one: a node-engine away across the milestone must be able to read the build it wakes to, or it could never
update itself (ADR 0603 §7, §9). The builder writes the node-engine's done key in the old form until the stated
capabilities show it on every node; this is a window like the old seat name's. What should wake the builder for a
node that returns is to be decided in ADR 0618 (reserved): the node-engine seat's event for a change of a node's stated
manifest-reads and the delivery view's read of them, never a watch of the node-engine's have state (ADR 0596). **Until
ADR 0618 is accepted**, the builder hears the status view's `delivered` events, asks `node_haves` at its start and on
each, and a node that was away closes the window on the next `delivered`. Its tool `builder_old_form` lists whether the
window is open and the nodes whose node-engine does not yet state the capability, and drops a retired node from it by
hand, recorded as a hand act; a node holding it open for seven days is the builder's finding naming the node, cleared
when the window closes. Closing it says so in the build log and emits `old-form-closed` (the time, the nodes that held
it last, the nodes dropped by hand) on the builder's own family beside `numbered`; a waiter on a build's end does not
wake on it.
**Every build keeps the old reference form** while any node-engine the mesh counts states it alone, away ones
included, the node-engine's own builds as every other, never by a module's name (ADR 0624 §1; ADR 0601 §4). The
builder writes into every build key each reference form a counted node-engine states, beside the new form, which it
writes only once every present node-engine states it (ADR 0618 §2); a counted node whose engine states nothing counts
as stating the baseline's forms, and a node leaves the count only when it is retired, never because it is away (ADR
0624 §1). Of the forms kept, the oldest a counted engine states is written into the build key's single reference
(ADR 0605 §9) and the others are listed beside it, so an engine that predates the list still fetches the build (ADR
0624 §3). The assigner holds a node's want for a build's reference forms only when that node's engine states none of
them (ADR 0624 §2); a hold for a manifest word or a seat name the engine does not state stays as ADR 0614 §4 has it.
So a node back from being away with an old node-engine still gets any build, the node-engine's own included, through
the oldest form, and can always update itself (ADR 0603 §7, §9). The old form in the build keys is a window like the
old seat name's: it closes when no counted node-engine states the old form alone, and the builder then leaves it out
of new build keys. The builder reads each node's stated capabilities through the node-engine seat's verb
`manifest-reads` (ADR 0618 §3) at its start, and wakes on the seat's event
`mesh.seat.node-engine.event.manifest-reads-changed`, said when a node's stated capabilities change and when the node
returns after being away (ADR 0618 §4), never on a watch of the node-engine's have state (ADR 0596) and never on a
timer. The builder declares `seat:node-engine.manifest-reads` in its `invokes`: that is the grant the grants part
composes, and with it the grants part grants the builder the subscription to the event's subject. A node-engine that
does not yet serve `manifest-reads` counts as stating the baseline's forms: the window stays open and names the node.
Its tool `builder_old_form` lists whether the window is open and the counted nodes, present or away, whose
node-engine states the old form alone, and drops a retired node from the count by hand, recorded as a hand act; a
node holding it open for seven days is the builder's finding naming the node, cleared when the window closes. Closing
it says so in the build log and emits `old-form-closed` (the time, the nodes that held it last, the nodes dropped by
hand) on the builder's own family beside `numbered`; a waiter on a build's end does not wake on it.
**When the group is pushed.** Only once the release that adds the node-engine's stated capability (design 47) runs on
every node, read from the status view's haves before the push, and once the progressive insights of ADR 0595 and
@@ -415,8 +433,9 @@ reports (ADR 0610 §4). The revert's order is the module graph's, as the move's
is delivered before a build module's reverted build only where that build module's reverted manifest requires or
invokes something only `distribution`'s reverted build offers; the milestone's prepare step checks the build
modules' manifests for such an edge. The done keys written in the new form stay in the builder's state after a
revert and are not built again for their form; whether an older reader can read them is to be decided in ADR 0618
(reserved). **On a fresh mesh** the foundation's bootstrap (research 075) pushes the holders' own images
revert and are not built again for their form; each still carries every form a counted node-engine states, the
oldest in its single reference, so a node is held from them only when its engine reads none of those forms (ADR 0624
§1-3). **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
@@ -466,7 +485,7 @@ test).
module publishing through the seats, and refused after, naming `publish`, with `direct-writes-closed` emitted and
its log line written; `registry_direct_writes` names the node still running an old build module, and drops it by
hand with a hand act; a node that was away, returning with the new build, closes the old seat name's window on
the next `delivered` (until ADR 0618 is accepted); a waiter on a build's `published` does not wake on `held`,
its `manifest-reads-changed` event with no `delivered` said (ADR 0618 §4); a waiter on a build's `published` does not wake on `held`,
`released`, `old-name-closed` or `direct-writes-closed`.
- **Builder, added for the milestone, integration** (cases of the builder's whole-module test): with the seat's
holder down at a first claim, a bundle's trunk build is built unnumbered and published by its digest, the holder's
@@ -475,11 +494,16 @@ test).
source other than the publish target) the floor finding is written and cleared once it answers, and with
`bridge_tags` still silent after the by-digest publish, the build stays unnumbered until the forge bridge's health
clears (no timer runs), and is then numbered and published by version; `builder_floor_again` asks the three
sources at once and records the hand act; the node-engine's done key stays in the old form while one node's
node-engine lacks the capability and is written in the new form once every node states it, `builder_old_form`
naming that node meanwhile and dropping it by hand with a hand act; a node that was away, returning with the
capability, closes that window on the next `delivered` (until ADR 0618 is accepted), with `old-form-closed` emitted
and its build-log line written, and a waiter on a build's end does not wake on it; with the image's own seat silent
sources at once and records the hand act; a build key carries only the old form while one present node's
node-engine lacks the capability, or does not serve `manifest-reads`, and carries the new form beside it once every
present node states it (ADR 0618 §2), the old form in its single reference (ADR 0624 §3); with one node away whose
node-engine lacks the capability, or states nothing, every build still carries the old form beside the new, and any
build, the node-engine's own included, is moved to that node because it reads the oldest form (ADR 0624 §1-2),
`builder_old_form` naming that node meanwhile and dropping a retired one from the count by hand with a hand act; a
build whose forms that node reads none of is held for it; that node, back with the new node-engine, says
`manifest-reads-changed` and the window closes with no `delivered` and no timer (ADR 0618 §4), the old form left
out of new build keys, with `old-form-closed` emitted and its build-log line written, and a waiter on a
build's end does not wake on it; with the image's own seat silent
at the claim of `distribution`'s own image, the image is still built, published by its digest, and numbered once
its new build answers (ADR 0617 *How it is checked*).
- **Builder, added for the milestone, unit** (cases of the builder's numbering): a second trunk build of a package's
@@ -502,7 +526,9 @@ test).
the seat it came through and that seat's holder; a change of the seat's holder composes the declaration again with
the new holder named and recreates no container.
- **The grants part, unit** (a case of its composition test): a node-engine's subscriptions hold the status view's
`settled` family beside the backup holder's word, and nothing more.
`settled` family beside the backup holder's word, and nothing more; the subscriptions of `distribution`, the builder
and mesh-config, each declaring `seat:node-engine.manifest-reads` in `invokes`, hold the subject
`mesh.seat.node-engine.event.manifest-reads-changed`, and no other module's subscriptions hold it.
- **Checker.** A changed build module invoking a verb no running holder serves is not run, and the verdict names the
modules composed from their manifests instead, and the verb.
- **Vault.** Reverting the milestone's merge mints the build modules' credentials again; the bootstrap's one-off