Seats held by assignments, one assignment per module per node, and 0113's bottom of the stack
Decided with the author: - A seat is held by one assignment, not claimed by a definition. A definition says which seats a module can hold; an assignment says which it does. The store module can run on every node and one assignment holds mesh-store; moving a role changes an assignment, never a definition. The foundation's seats name what the mesh itself uses and route no consumer — database and amqp consumers use co-location, the holder included. This replaces the wrong rationale that the foundation's store is "provider to nobody", which contradicted ADR 0078 and to-be 21. 0079's one-postgres rule becomes one mesh-store holder. - A module is assigned at most once to a node. The instance identity in 0112 and 27 is withdrawn, and the login-length problem with it. Review fixes to 0113: - The bottom of the stack: the vault is installed as soon as the shared runtime base exists, and genesis generates everything needed until then — including the permanent controller's, the control-node agent's, the builder's and the broker provisioner's bus accounts, and the controller's store login. Genesis creates those accounts until the broker's provisioner runs and adopts them. - Genesis's values are delivered recorded as the mesh's own, so 0092's never-replace rule for operator values does not make them unrotatable. - Backend-issued secrets (a forge's once-only API token) enter through the vault. Non-module parties (the controller's logins, node agents' accounts) are answered the same way, the controller asking on their behalf; an enrolment token reaches the controller only as what verifies it. - A secret with no provisioner to apply it is marked not rotatable by the mesh and refused, instead of a restart reported as done. Unused password generators in six provider clients are removed, and a catalogue scan checks no module mints. - Rotation's lock-out cases (offline reader, bus account owner, restarted provisioner) are recorded as open, with overlap and re-confirm-with-safeguards as the two answers, to be chosen before acceptance. 0110, 0111 and 26 are marked proposed: they changed in meaning and are under review, and an accepted record must not rest on proposed ones. To-be 23 and the glossary are restored to main; they change when these records are accepted.
This commit is contained in:
@@ -2,11 +2,10 @@
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
updated: 2026-09-25
|
||||
updated: 2026-09-20
|
||||
decisions:
|
||||
- 02-DECISIONS/0084-which-provider-serves-a-consumer.md
|
||||
- 02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md
|
||||
- 02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md
|
||||
---
|
||||
|
||||
# 23 — Choosing a provider
|
||||
@@ -51,20 +50,9 @@ provider on a different node. That coupling is exactly what may not be guessed,
|
||||
names the provider. Naming it is also what makes a later move safe — the mesh knows the binding is
|
||||
to that provider and not to whichever one is nearest.
|
||||
|
||||
**Some provisions have one provider for the whole mesh, and a seat names it.** Where a seat delivers
|
||||
the provision, its holder answers for it, **and co-location does not apply**: a second provider on the
|
||||
consumer's own machine does not take over for that consumer. That is not picking: the choice was made
|
||||
once, mesh-wide, by assigning the holder, rather than once per consumer by naming it
|
||||
([ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md),
|
||||
[26 — The seats](26-the-seats.md)). A named provider still wins over the seat, because a consumer
|
||||
coupled to particular contents has said so, except for `secret`, which only the vault may provide.
|
||||
Only provisions the design makes one-per-mesh are delivered by a seat: the broker, the artifact store,
|
||||
a package registry, git and the vault. A database is not. Node-local stores, served by co-location,
|
||||
are the rule above.
|
||||
|
||||
**Ambiguity is refused, never resolved by picking.** If several providers of a kind exist, none is
|
||||
named, none is co-located, and no seat delivers it, the requirement is unsatisfiable and is refused
|
||||
with the candidates shown — the same stance
|
||||
named, and none is co-located, the requirement is unsatisfiable and is refused with the candidates
|
||||
shown — the same stance
|
||||
[ADR 0027](../../02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md) took
|
||||
against a confidently-wrong match, applied to the instance rather than the dialect. A wrong answer
|
||||
delivered quietly costs more than a refusal.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
layer: to-be
|
||||
status: in-progress
|
||||
status: proposed
|
||||
code:
|
||||
- mesh-controller internal/catalogue/seats.go
|
||||
- mesh-controller internal/catalogue/resolve.go
|
||||
@@ -17,8 +17,8 @@ decisions:
|
||||
|
||||
# 26 — The seats
|
||||
|
||||
**What a mesh can have one of, and who fills each.** A seat is a named role at a scope, taken by a
|
||||
module assignment. The mesh defines which seats exist. Occupying one may deliver a provision, and the
|
||||
**What a mesh can have one of, and who fills each.** A seat is a named role at a scope, held by one
|
||||
module assignment. The mesh defines which seats exist. Holding one may deliver a provision, and the
|
||||
list of seats with their holders is the quickest answer to "what is in this mesh".
|
||||
|
||||
## What a seat is
|
||||
@@ -27,28 +27,31 @@ A seat has four properties, fixed by the mesh rather than by any module:
|
||||
|
||||
| property | is |
|
||||
|---|---|
|
||||
| name | what a manifest claims, and what a person reads in the list |
|
||||
| name | what a definition names and an assignment holds, and what a person reads in the list |
|
||||
| scope | node, site or mesh: where its capacity applies. Every seat in the set has a capacity of one, so one holder per scope. A bench, a seat with several holders, is a word the glossary keeps and no seat uses yet |
|
||||
| delivers | the provision its holder answers for, or nothing |
|
||||
| decision | the record that made it a seat |
|
||||
|
||||
**A module assignment holds a seat by claiming it.** The claim is the manifest's `claims`, and it is
|
||||
satisfied by assigning the module somewhere. The seat is not a second record beside the assignment.
|
||||
It points at the assignment, and everything the mesh knows about the holder is what it knows about
|
||||
that assignment: the node, the node's settings for the module, and what the module serves.
|
||||
**A definition says which seats a module can hold. An assignment says which it does hold.** The store
|
||||
module can hold `mesh-store`, and it may run on every node whose capabilities match. Exactly one of
|
||||
those assignments holds the seat, because that assignment says so, and a second assignment saying so
|
||||
is refused. A seat makes a role singular, never a module.
|
||||
|
||||
**The set is closed.** A claim naming a seat the mesh does not define is refused, and so is a claim at
|
||||
the wrong scope. Adding a seat is a decision, recorded, for the reason every addition to the host's
|
||||
vocabulary is one: the set is what a person reads to learn what a mesh can have, and an entry nobody
|
||||
argued for is an entry nobody can explain.
|
||||
**The seat points at the assignment.** Everything the mesh knows about the holder is what it knows
|
||||
about that assignment: the node, the node's settings for the module, and what the module serves.
|
||||
|
||||
**The set is closed.** A seat the mesh does not define is refused wherever it is named, and so is one
|
||||
named at the wrong scope. Adding a seat is a decision, recorded, for the reason every addition to the
|
||||
host's vocabulary is one: the set is what a person reads to learn what a mesh can have, and an entry
|
||||
nobody argued for is an entry nobody can explain.
|
||||
|
||||
## The set
|
||||
|
||||
| seat | scope | delivers | typically held by |
|
||||
|---|---|---|---|
|
||||
| `mesh-controller` | mesh | — | the controller |
|
||||
| `mesh-store` | mesh | — | the foundation's store |
|
||||
| `mesh-broker` | mesh | `amqp` | the broker |
|
||||
| `mesh-store` | mesh | — | the store the mesh's own records live in |
|
||||
| `mesh-broker` | mesh | — | the broker carrying the mesh's own bus |
|
||||
| `mesh-vault` | mesh | `secret`, reserved | the vault |
|
||||
| `the-artifact-store` | mesh | `artifact-store` | the artifact registry |
|
||||
| `the-catalogue` | mesh | — | the catalogue |
|
||||
@@ -64,27 +67,24 @@ argued for is an entry nobody can explain.
|
||||
|
||||
The controller holds this set in code, and a test asserts both its size and that every entry names
|
||||
the record that made it a seat. **This table and [ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md)
|
||||
govern, and code that disagrees is what is wrong.** The implementation in progress predates three
|
||||
things here: the `mesh-vault` seat and its reservation, and the rule that `mesh-store` delivers
|
||||
nothing. It is brought to this table before it merges.
|
||||
govern, and code that disagrees is what is wrong.** The implementation in progress predates several
|
||||
things here: seats held by assignments rather than claimed by definitions, the `mesh-vault` seat and
|
||||
its reservation, and the foundation's seats delivering nothing. It is brought to this table before it
|
||||
merges.
|
||||
|
||||
## The foundation's seats
|
||||
|
||||
`mesh-controller`, `mesh-store` and `mesh-broker` name which assignment the mesh *itself* uses: the
|
||||
controller, the store holding its records, the broker carrying its bus. **They route no consumer.** The
|
||||
store and broker modules may run on other nodes too. A database or `amqp` consumer is served by
|
||||
co-location, from whichever runs on its own node, the seat's holder included
|
||||
([23 — Choosing a provider](23-choosing-a-provider.md)).
|
||||
|
||||
## A seat that delivers a provision
|
||||
|
||||
A seat that delivers a provision may only be held by a module that provides it, at the seat's scope.
|
||||
A mesh seat delivers a mesh-scoped provision.
|
||||
|
||||
**A seat delivers a provision only where the mesh has one answer for everyone.** The broker, the
|
||||
artifact store, the npm registry, git and the vault are each one per mesh by decision. The store is
|
||||
not: nodes run their own stores and a consumer uses the one on its machine
|
||||
([23 — Choosing a provider](23-choosing-a-provider.md)), and the foundation's store is the controller's
|
||||
own memory, provider to nobody. So `mesh-store` guards that the foundation's store is singular, and
|
||||
routes nobody.
|
||||
|
||||
**The vault's provision is reserved.** Only the holder of `mesh-vault` may provide `secret` at all: a
|
||||
module providing it without the seat is refused, and a pin cannot choose another provider, because
|
||||
there is none. A second provider of secrets would be a second place secrets live, which is what the
|
||||
vault being one per mesh exists to prevent. Every other delivered provision may have second
|
||||
providers, which a pin can choose.
|
||||
**A seat delivers a provision only where the mesh has one answer for everyone.** The artifact store,
|
||||
the npm registry, git and the vault are each one per mesh by decision. A seat that delivers a
|
||||
provision may only be held by an assignment of a module that provides it, at the seat's scope.
|
||||
|
||||
**Its holder answers for that provision.** A requirement for it resolves, in order, to:
|
||||
|
||||
@@ -96,21 +96,23 @@ providers, which a pin can choose.
|
||||
Co-location, which answers first for every other provision, does not apply here: a seat says which
|
||||
one is the mesh's, and co-location answering first would let any second provider on a consumer's
|
||||
machine take over for that consumer, silently. So a second provider can run beside the holder and
|
||||
harm nothing. The forge holds
|
||||
`npm-package-registry`. An npm proxy may provide the same provision on another machine, and a module
|
||||
requiring an npm registry is still served by the forge, without anybody pinning it.
|
||||
harm nothing. A forge assignment holds `npm-package-registry`. An npm proxy may provide the same
|
||||
provision on another machine, and a module requiring an npm registry is still served by the forge,
|
||||
without anybody pinning it.
|
||||
|
||||
**Moving the role is changing which module claims the seat, and today that is a definition change.**
|
||||
A claim is part of a module's definition, so the proxy's definition must claim the seat and the
|
||||
forge's must stop. The forge cannot simply be unassigned, because it holds `git` as well. Every
|
||||
consumer follows once the claim moves. Making *which* seats a module holds the assignment's choice,
|
||||
with the definition saying only which seats it *can* hold, is the consistent answer, and
|
||||
[27 — A module requires, the mesh resolves](27-a-module-requires-the-mesh-resolves.md) lists it as
|
||||
not yet settled.
|
||||
**Moving the role is changing which assignment holds the seat.** No definition changes and nothing is
|
||||
unassigned: the forge keeps running, and keeps holding `git`, when its npm role moves. A module can
|
||||
take the role only if its definition says it can hold the seat.
|
||||
|
||||
**What a consumer receives is a grant**, the same as for any provision: where the provider answers,
|
||||
what it serves, and a credential. A consumer never reads the seat directly. The one exception is the
|
||||
controller itself, which reaches the store and the broker through a narrow seat placeholder,
|
||||
**The vault's provision is reserved.** Only an assignment holding `mesh-vault` may provide `secret` at
|
||||
all: a definition providing it that cannot hold the seat is refused, an assignment providing it without
|
||||
holding the seat is refused, and a pin cannot choose another provider, because there is none. A second
|
||||
provider of secrets would be a second place secrets live, which is what the vault being one per mesh
|
||||
exists to prevent.
|
||||
|
||||
**What a consumer receives is what it required**, the same as for any provision: where the provider
|
||||
answers, what it serves, and a credential. A consumer never reads the seat directly. The one exception
|
||||
is the controller itself, which reaches the store and the broker through a narrow seat placeholder,
|
||||
because it made them before any module existed and cannot be their consumer. One foundation module
|
||||
also reads it today, to find its own server's port. [27](27-a-module-requires-the-mesh-resolves.md)
|
||||
moves that to a host port requirement.
|
||||
@@ -123,9 +125,9 @@ their job, and it is a real one: it is the mesh saying what a machine is, in wor
|
||||
|
||||
## The overview
|
||||
|
||||
The controller lists every seat in the set with its scope, what it delivers, and each holder as a
|
||||
node and a module. A seat nobody holds is listed as unheld. That is an answer, "this mesh has no
|
||||
forge", and not a fault.
|
||||
The controller lists every seat in the set with its scope, what it delivers, and its holder as a node
|
||||
and a module. A seat nobody holds is listed as unheld. That is an answer, "this mesh has no forge",
|
||||
and not a fault.
|
||||
|
||||
Holdings are derived from assignments whenever they are asked for, never stored. The list is always
|
||||
what the mesh is running, because it is computed from the same thing that decides what the mesh runs.
|
||||
@@ -140,13 +142,13 @@ mesh records which:
|
||||
| on the `git` seat | a repository on the forge that holds the seat | its path on the forge, and the seat |
|
||||
| external | a repository anywhere else, a public forge for instance | its URL, exactly as given |
|
||||
|
||||
For a repository on the seat, the controller composes the clone URL at the moment of building,
|
||||
from where the holder runs and the scheme and port it serves for `git`. The recorded source never
|
||||
contains an address, so moving the forge changes nothing that was recorded. The build machine is not
|
||||
told the difference: it receives a URL either way.
|
||||
For a repository on the seat, the controller composes the clone URL at the moment of building, from
|
||||
where the holder runs and the scheme and port it serves for `git`. The recorded source never contains
|
||||
an address, so moving the forge changes nothing that was recorded. The build machine is not told the
|
||||
difference: it receives a URL either way.
|
||||
|
||||
With the seat unheld, a build from the seat is refused and says why. External builds carry on.
|
||||
|
||||
**Not yet designed:** a credential for cloning a private repository. The mesh's own repositories are
|
||||
public. The natural place for a clone credential is the `git` provision's grant, and that is a
|
||||
decision still to take.
|
||||
public. The natural place for a clone credential is a `secret` from the vault, and that is a decision
|
||||
still to take.
|
||||
|
||||
@@ -96,9 +96,17 @@ per consumer, named for that consumer:
|
||||
|
||||
Every other shared secret takes the same path:
|
||||
- a module's own secret;
|
||||
- every broker account's password, where the broker's own provisioner creates the account;
|
||||
- an enrolment token;
|
||||
- a secret operator value, which the operator delivers to the vault.
|
||||
- every broker account's password on the mesh's bus, where the broker's own provisioner creates the
|
||||
account;
|
||||
- an enrolment token, which the operator receives and the controller can only verify;
|
||||
- a secret operator value, which the operator delivers to the vault;
|
||||
- a secret a backend issues itself, such as a forge's API token, which the module that received it
|
||||
delivers to the vault.
|
||||
|
||||
**Parties that are not modules take the same path too.** The controller's own store login and bus
|
||||
account, and each node agent's bus account, have no definition to require them, because the controller
|
||||
and a node agent are the mesh itself. The controller asks the vault on its own behalf or a node's, and
|
||||
the answer is made, sealed and carried exactly as for a module.
|
||||
|
||||
**A provider makes resources and data.** Beyond secrets, a provider's adapter may answer with its
|
||||
contract's non-secret fields: an analytics site id, a registered public name. The mesh carries them
|
||||
@@ -116,7 +124,7 @@ lost is a named volume, not a directory ([ADR 0030](../../02-DECISIONS/0030-data
|
||||
|
||||
*Where* a directory is on the machine is the assignment's:
|
||||
|
||||
- **a node's default layout**, a root per node with one directory per instance beneath it, used when
|
||||
- **a node's default layout**, a root per node with one directory per assignment beneath it, used when
|
||||
the assignment says nothing;
|
||||
- **a placement**, where the assignment puts one directory elsewhere: on a second disk, or where an
|
||||
adopted machine's data already is ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)).
|
||||
@@ -175,35 +183,39 @@ module uses the seat placeholder.
|
||||
decided. The one exception 0086 allows is a declared env-file with its reason; a secret field as a
|
||||
value in a container's environment is refused when the definition is parsed, with no exception.
|
||||
|
||||
## An instance
|
||||
## An assignment
|
||||
|
||||
An assignment has an identity: an **instance name**, which defaults to the module's name. Everything
|
||||
keyed by the module's name today is keyed by the instance: directories, containers, the login it
|
||||
presents, its broker account, the seats it holds, its settings and its identity as a provider.
|
||||
**A module is assigned at most once to a node**, and that pair is the assignment's identity
|
||||
([ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md)). Its directories,
|
||||
containers, login, broker account and settings are keyed by it, as today, and a login still fits the
|
||||
tightest backend ([ADR 0049](../../02-DECISIONS/0049-a-consumers-identity-fits-the-tightest-backend.md)).
|
||||
|
||||
So a module may run twice on one node, under two instance names. What must stay singular stays so:
|
||||
by a seat, or by an operator value colliding, as with a public name.
|
||||
**A module may run on many nodes, and one assignment may hold a seat**
|
||||
([ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md)). The definition
|
||||
says which seats the module can hold; the assignment says which it does. So the store module can run
|
||||
on every node, one of those assignments holds `mesh-store`, and moving that role changes an
|
||||
assignment, not a definition.
|
||||
|
||||
**A login still has to fit the tightest backend**, which is twenty characters today
|
||||
([ADR 0049](../../02-DECISIONS/0049-a-consumers-identity-fits-the-tightest-backend.md)). A node name and
|
||||
an instance name will not fit in full. The instance therefore gets a short form alongside the module's
|
||||
slug, under the same rules as a slug. This has to be settled before a second instance is allowed.
|
||||
What must stay singular stays so: by a seat, or by an operator value colliding, as with a public name.
|
||||
|
||||
## Genesis
|
||||
|
||||
**Genesis delivers, and the vault adopts.** The vault cannot run first: it is built on the shared
|
||||
runtime base, which the installation makes only after the store, the broker and the controller exist
|
||||
([21 — The installation in full](21-the-installation-in-full.md)), and it learns what to answer from
|
||||
the controller over the bus. So genesis generates the foundation's first shared secrets itself:
|
||||
- the store's superuser;
|
||||
- the broker's admin, in the hashed form the broker needs;
|
||||
- the bus accounts of the temporary controller and of the vault;
|
||||
- the first enrolment token.
|
||||
the controller over the bus. So the vault is installed **as soon as that base exists**, before any other
|
||||
module built on it, and genesis generates what is needed until then:
|
||||
- the store's superuser, and the broker's admin in the hashed form the broker needs;
|
||||
- the bus accounts of the temporary and permanent controller, the control-node's agent, the builder,
|
||||
the broker's own provisioner and the vault;
|
||||
- the controller's store login, and the first enrolment token.
|
||||
|
||||
It seals them to the operator key as today ([ADR 0085](../../02-DECISIONS/0085-a-secret-is-a-provision.md)).
|
||||
When the vault is installed, genesis **delivers them to it**, through the same path an operator's value
|
||||
takes. From then on the vault holds, audits and rotates them. It can make their replacements, unlike
|
||||
an operator's external key.
|
||||
Until the broker's provisioner runs, genesis creates those bus accounts with the broker's admin, as the
|
||||
controller does today; the provisioner adopts them when it starts. Genesis seals everything to the
|
||||
operator key as today ([ADR 0085](../../02-DECISIONS/0085-a-secret-is-a-provision.md)), and when the
|
||||
vault is installed it **delivers the values to it, recorded as the mesh's own**. That distinction keeps
|
||||
them rotatable: an operator's value is never replaced, and these are, because the vault can make their
|
||||
replacements.
|
||||
|
||||
That is the one time anything but the vault generates a shared secret, and it ends by handing them
|
||||
over. It is also the answer to the objection ADR 0085 had to the vault being the only maker: the
|
||||
@@ -235,10 +247,16 @@ only when it first initialises is marked applied, because a restart would change
|
||||
recipient that reads at start has restarted and passed its health check, where its definition
|
||||
declares one. Delivered and working are shown as different things.
|
||||
|
||||
**The remaining window is stated.** An applier whose provisioner stops after applying and before
|
||||
confirming leaves the recipients that read at start locked out: the old value no longer works, and
|
||||
they have not been sent the new one. A provisioner is supervised and restarted when it exits, so the
|
||||
window lasts until that restart. The rotation shows as waiting on that applier throughout, never as done.
|
||||
**Open: keeping readers from being locked out.** Steps 2 and 3 leave a reader locked out when its
|
||||
machine is offline after an applier applied, when the secret is a bus account whose owner loses the bus
|
||||
it would hear the new value on, or when a restarted provisioner can no longer check the old value.
|
||||
[ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md) records the two answers, overlapping
|
||||
old and new credentials or re-confirming with safeguards, and one is chosen before it is accepted.
|
||||
Neither changes a consumer module.
|
||||
|
||||
A secret some service reads only when it first initialises cannot be rotated by restarting it. It is
|
||||
applied by a provisioner, or, where none exists, marked not rotatable by the mesh, and a rotation is
|
||||
refused rather than reported done.
|
||||
|
||||
## Refusing
|
||||
|
||||
@@ -258,10 +276,11 @@ as waiting, and nothing is delivered until the answer arrives.
|
||||
| mechanism | becomes |
|
||||
|---|---|
|
||||
| provisions read through bindings | a module requirement; its answer is the contract's fields |
|
||||
| settings on an assignment ([ADR 0046](../../02-DECISIONS/0046-a-module-configuration-is-its-assignments-not-its-manifest.md)) | operator requirements, addressed to an instance |
|
||||
| settings on an assignment ([ADR 0046](../../02-DECISIONS/0046-a-module-configuration-is-its-assignments-not-its-manifest.md)) | operator requirements on an assignment |
|
||||
| a port the mesh assigns | a host requirement |
|
||||
| machine facts and machine placeholders | host requirements |
|
||||
| every secret the controller mints: provider credentials, own secrets, broker passwords, root secrets | a secret the vault makes ([ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md)) |
|
||||
| every secret the controller mints: provider credentials, own secrets, broker passwords, enrolment tokens | a secret the vault makes ([ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md)) |
|
||||
| root secrets genesis mints and keeps apart | made by genesis once, then delivered to the vault, which holds and rotates them |
|
||||
| a separate command issuing a broker account | a requirement resolved on assignment |
|
||||
| `restart-on` naming a secret's file | a restart the host derives |
|
||||
| paths in resources, mounts, bindings, secrets and received files | host directory requirements, placed by the assignment |
|
||||
@@ -287,11 +306,11 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
is fixed first. *Ends when* nothing outside the vault generates a shared secret after genesis, a lab
|
||||
consumer of analytics receives its site id, and a database credential rotates applier-first, with
|
||||
the consumer restarted by derivation and the rotation confirmed.
|
||||
3. **Definitions move.** Every catalogue definition is rewritten, adopted and running assignments
|
||||
placed where their data already is. *Ends when* the list of definitions using an old form is
|
||||
empty, and the old forms are removed.
|
||||
4. **Instances.** The instance name and its short form, and everything keyed by it. *Ends when* one
|
||||
module runs twice on one lab machine with two public names.
|
||||
3. **Definitions move, and seats move to assignments.** Every catalogue definition is rewritten, adopted
|
||||
and running assignments placed where their data already is, and each claim becomes a seat the
|
||||
module can hold, held by the assignment that holds it today. *Ends when* the list of definitions
|
||||
using an old form is empty, the old forms are removed, and the store module runs on two lab
|
||||
machines with one holding `mesh-store`.
|
||||
|
||||
## How it is checked
|
||||
|
||||
@@ -305,8 +324,9 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
| A host requirement is answered on its own node | A resolution test placing one elsewhere: refused. |
|
||||
| An operator value needs no provider module | A resolution test: a requirement with a default resolves with no module assigned anywhere. |
|
||||
| A secret field reaches a process as a file | The parser refuses a secret field as a container environment value, and accepts it in a file or a declared env-file with its reason. |
|
||||
| A public name already held is refused | A resolution test: a second instance asking for a public name the first holds is refused, naming the first. |
|
||||
| Everything keyed by a module is keyed by its instance | A resolution test: two instances of one module on one node get two directories, two containers, two logins and separate settings. |
|
||||
| A public name already held is refused | A resolution test: a second assignment asking for a public name another holds is refused, naming the holder. |
|
||||
| A module is assigned at most once to a node | A resolution test: assigning a module to a node that already runs it is refused. |
|
||||
| A seat is held by an assignment, not a module | A resolution test: the store module on two nodes, one holding `mesh-store`; a second assignment asking to hold it is refused. |
|
||||
| A consumer waits for its provider | A resolution test with a provider that has not answered: shown as waiting, and nothing delivered. |
|
||||
| Only the vault generates a shared secret after genesis | A controller test: no code path generates one. An installer test: genesis generates exactly the foundation's first secrets and delivers them to the vault. |
|
||||
| Only the vault provides `secret` | The parser refuses another provider of it, and resolution refuses a pin on a `secret` requirement. |
|
||||
@@ -318,11 +338,8 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
## Not settled here
|
||||
|
||||
- The exact spelling of the one form. It must name a requirement and a field and nothing else.
|
||||
- The layout a node's default root uses beneath it, beyond one directory per instance.
|
||||
- The layout a node's default root uses beneath it, beyond one directory per assignment.
|
||||
- Whether a module provider's answer can change without the provider being asked, for example a
|
||||
provider moving. The rule so far is that it cannot, and moving is re-resolving.
|
||||
- **Which seats a module holds.** Today a claim is part of the definition, so moving a seat is a
|
||||
definition change ([26 — The seats](26-the-seats.md)). By this document's own logic it belongs to
|
||||
the assignment: a definition says which seats a module *can* hold, and the assignment says which it
|
||||
*does*. That changes [ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md),
|
||||
and is its own decision.
|
||||
- **How rotation keeps a recipient from being locked out.** Under review: see
|
||||
[ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md), rotation.
|
||||
|
||||
Reference in New Issue
Block a user