Files
mesh-catalog/modules/mesh-config
jschoubben d34645361d Build config's switch from the controller's records: declared, compare, take-over and hand-back, so the operator approves the last move only once nothing differs (issue 1953)
compare also resolves every placed module's values on every node both ways, as ADR 0565's insight of 2026-10-29 asks after #558. After the take-over the predefined list and pull requests' config come from the indexer and pull-declares is refused; a hand-back returns to the mirrors until the lease write. From the lease write a trusted value is set only on an Approve. Acts are recorded through mesh-hand-acts. Pins mesh-sdk 2e5cc4f.
2026-10-29 22:27:23 +01:00
..

mesh-config

Holds the mesh-config seat: the owner of every config value (novox/hq ADR 0348 §9, design 57 K3). Go, one binary (cmd/mesh-config), served by a runtime of its own on its own bus account (runs-as), so that its account alone writes its buckets.

What it keeps

  • mesh-config_values: each value set, keyed by its level: mesh.<key> (mesh config), node.<node>.<key> (node config) and module.<node>.<module>.<key> (a module's own value on one node), each with who set it, through which account, why and when.
  • mesh-config_resolved: each assigned module's value for each key it declares on its node, keyed <node>.<module>.<key>, with its source: default, mesh, node, module, or unset for a required value nothing sets.
  • mesh-config_predefined: the list of predefined keys, published from the list the controller kept (its mirror mesh-controller.predefined), the newest trunk build winning. A newer list dropping a key that still holds a value at the mesh or a node is withheld, and every listing says why, until that value is cleared.
  • mesh-config_proposals: each value proposed for the operator's Approve, whole, with the value stored at its level when it was proposed (what the operator is shown the change against), who proposed it, why, and what came of it.
  • the log history: every set, clear and move of resolved values, with the proven caller and why.

How a value resolves

For every module the seat mesh-placement places on a node (mesh-delivery-assigner.placement), from the module's own manifests as the delivery built them, never from the controller (issue 1953): the trunk's, which the indexer's modules.<module> names in its manifests by digest (mesh-delivery-indexer.modules, .manifests), with the build the node's want names (mesh-delivery-assigner.wants, the builder's mesh-delivery-builder.builds naming its manifest) laid over it key by key on that node. So a module from its own repository resolves as a catalogue module does. A placed module none of whose manifests can be read is listed under unresolved with why and said in the log, and keeps the values last resolved for it. Then: the manifest's default; mesh config for the predefined key the value falls back to; node config for that key on the node; the module's own value on that node, the most specific winning. A value naming no predefined key resolves from its default and the module's own value only (ADR 0348 §2). It resolves at start, whenever a placement, a want or a trunk module moves, and every five minutes, writing only the values that moved.

The verb

mesh-config.config with action list (the default), set, clear or history, narrowed by module, node and key. A set or a clear names one level (no module and no node for mesh config, a node for node config, both for a module's own value), needs why, refuses a key the module or the predefined list does not declare (naming the declared keys), validates the value, writes it and the resolved values it moves, keeps it in the history and the controller's hand-act log, raises config-changed, and answers with each module on each node whose value moved. It opens no walk. A trusted value is taken only from the controller, which carries it from its terminal and names who gave it in by, or on the operator's Approve of a proposal.

Proposing a value (ADR 0348 §8, design 57 K4)

action propose (with value, or clear) judges the value as a set would, keeps it in mesh-config_proposals, and asks the operator under mesh-config's own name on the operator-channel seat (its own grant, from uses, and its own cap of three open asks; the same change twice is refused, and a newer proposal for the same level and key replaces the older). The ask says the level, the key and the value, exact where who answers is proven, and that, approved, it takes effect at once on every node it reaches; Approve and Decline are both at the level approve and each binds the proposal's level, key, value and the value it was shown against. On the answer mesh-config reads the router's own record of its ask and holds the warrant to the ask composed again from the proposal; it refuses, and sets nothing, when the proposal or the value stored at the level changed since. An Approve that holds sets the value as a set does, keeps who approved it beside the value (approved), and asks the controller to record the warrant in its hand-act log. A Decline, an expiry or the router's refusal sets nothing. action proposals lists them, newest first; with proposal, one read whole, with whether the router's ask is the one composed from it.

Files it does not know

Each directory or archive this module declares says how it treats a file it did not write (ADR 0422, ADR 0416).

  • ${dir:state}: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).

The switch from the controller's records (novox/hq ADR 0565 §3, §4, §13)

  • mesh-config_declared: each placed module's declarations at the trunk, with the manifest and commit they come from, written only when they differ.
  • mesh-config_takeover: the key switch names the source that holds: none (the interim since mesh-catalog #558: declarations from the modules' own manifests, the list of predefined keys and pull requests' config from the controller), indexer after the operator's take-over (the list and pull requests' config from the indexer's predefined and config-candidates; the controller's pull-declares refused), controller after a hand-back (declarations, list and pull requests' config from the controller's records). Each take-over ask is kept beside it.
  • config_compare lists every difference between the own sources and the controller's records: each module's declarations, the list, each open pull request's config, and every placed module's value on every node resolved both ways. config_take_over asks the operator's Approve, refused while any difference stands and switched on the Approve only if none stands then. config_hand_back returns to the controller's records until its lease is handed away. config_declared and config_resync read and write again what it keeps.
  • From the controller's lease write a trusted value is set only through propose and the operator's Approve.
  • Its sets, clears and warrants are recorded in the hand-act log of the seat mesh-hand-acts, falling back to the controller's while that seat has no holder and the controller holds its lease.