Design 51: follow ADR 0624, every build keeps each counted node-engine's form
mesh/delivery merged: source.main moved to novox/hq@273d608d9faa
mesh/check being carried to cac55dc2543a on 273d608d9faa | from 6cd965b3cdf6

ADR 0624 supersedes ADR 0623, which could find the node-engine's own
builds only by the module's name. Every build now keeps each form a
counted node-engine states, the oldest in the single reference, and a
node is held only when it reads none of them.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 09:59:44 +01:00
parent 01d4f2781e
commit cac55dc254
@@ -19,7 +19,7 @@ decisions:
- "ADR 0613"
- "ADR 0617"
- "ADR 0618"
- "ADR 0623"
- "ADR 0624"
- "ADR 0606"
- "ADR 0607"
- "ADR 0610"
@@ -380,30 +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** while any node-engine the mesh counts states only it,
away ones included (ADR 0623 §1-2). For the module that holds the seat `node-engine`, the builder writes into each
build key every reference form a counted node-engine states, beside the new form, which it writes there as in every
other build only once every present node-engine states it (ADR 0618 §2); a node leaves the count only when it is
retired, never because it is away (ADR 0623 §1). The assigner moves the node-engine's own build to a node once that
node's engine states any one form the build carries (ADR 0623 §2), so a node back from being away moves to the new
node-engine through the old form, states the new capabilities from then on, and can always update itself (ADR 0603
§7, §9). Every other module's builds keep ADR 0618 §1-2: they carry the new form once every present node-engine
states it, each names the reader capabilities its forms need, and the assigner holds a node's want while that node's
engine does not state one, so a node that was away is held from them, never handed a form it cannot read, until its
new node-engine states the form. The old form in the node-engine's own builds 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 drops it from those builds. 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
nothing: 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 only the old form, 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.
**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
@@ -433,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; each names the forms it needs, so a node whose node-engine does not
state them is held by the assigner, never handed them (ADR 0618 §1). **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
@@ -494,13 +495,14 @@ test).
`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; 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 once every present
node states it (ADR 0618 §2); with one node away whose node-engine lacks the capability, the node-engine's own build
still carries the old form beside the new and is moved to that node, while another module's build in the new form
is held by the assigner for it (ADR 0623 §1-2, ADR 0618 §1), `builder_old_form` naming that node meanwhile and
dropping a retired one from the count by hand with a hand act; 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 dropped
from the node-engine's own builds, with `old-form-closed` emitted and its build-log line written, and a waiter on a
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*).