Point ADRs 0240 and 0254 at ADR 0283, bound a family member's name, and say the cost of a setting wait
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/386-a-wait-for-the-operator delivered: every member is delivered

From the review of hq#294.
This commit is contained in:
jochen
2026-10-10 21:08:40 +02:00
parent 242a6c548b
commit 2648d571b3
5 changed files with 25 additions and 11 deletions
+3 -2
View File
@@ -265,8 +265,9 @@ and the operator act. **Recorded by** the controller's `identity` and `licences`
is the two ends of one credential, the consumer's and the provider's. is the two ends of one credential, the consumer's and the provider's.
- **secret** — a credential or other value the vault keeps sealed and the node-engine unseals into a - **secret** — a credential or other value the vault keeps sealed and the node-engine unseals into a
file at apply ([ADR 0085](../02-DECISIONS/0085-a-secret-is-a-provision.md)). file at apply ([ADR 0085](../02-DECISIONS/0085-a-secret-is-a-provision.md)).
- **secret family** — a module's own secrets declared as one name ending in `-*`, one member per part its - **secret family** — a module's own secrets declared as one name ending in `-*`; each member is the prefix
settings name (`smb-password-<source>`), each given by its full name and never made by the mesh and a name (`smb-password-<source>`, one per source the module's settings name), given by its full name
and never made by the mesh
([ADR 0283](../02-DECISIONS/0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md)). ([ADR 0283](../02-DECISIONS/0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md)).
- **vault** — the module that owns every secret (`mesh-vault`, - **vault** — the module that owns every secret (`mesh-vault`,
[24 — The secrets vault](../03-DESIGN/01-to-be/24-the-secrets-vault.md)). [24 — The secrets vault](../03-DESIGN/01-to-be/24-the-secrets-vault.md)).
@@ -172,6 +172,13 @@ send* holds the module on this condition. Every start begins in `starting`, so a
send clears at the new build's start and anything after it is the new build's. At the gate's bound the send clears at the new build's start and anything after it is the new build's. At the gate's bound the
build is put back, as ADR 0236 §3 says. build is put back, as ADR 0236 §3 says.
> **The mechanism changed — 2026-10-10, by [ADR 0283](0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md).** The four states, the
> condition and the gate's reading stand. A fifth state, `waiting`, now sits beside them: a tool check
> (rule 2) may answer *waits* as well as healthy or not, naming an own secret or a setting the operator has
> yet to give, and one look that says so is enough, inside the grace too. The controller checks the wait,
> says it as `needs-operator` rather than `unhealthy`, and the gate reads it as ADR 0254's *waits for a
> person*: a pass.
**5. A provider down is said once, at the provider.** A check names the provision it exercises. While **5. A provider down is said once, at the provider.** A check names the provision it exercises. While
that provision's provider for this consumer is unhealthy on the record, the consumer's finding is held under that provision's provider for this consumer is unhealthy on the record, the consumer's finding is held under
the provider's condition — listed there as waiting on it, raised as nothing of its own — and the consumer's the provider's condition — listed there as waiting on it, raised as nothing of its own — and the consumer's
@@ -101,6 +101,12 @@ anyway, since the unit that cannot run is what the gate names first.
> **Narrowed — 2026-10-08.** Read with the dated correction under "What the gate cannot tell" in the > **Narrowed — 2026-10-08.** Read with the dated correction under "What the gate cannot tell" in the
> consequences: only a move whose build puts an account in a group its previous build did not is > consequences: only a move whose build puts an account in a group its previous build did not is
> excused, and what that costs while a login stays owed. > excused, and what that costs while a login stays owed.
> **The mechanism changed — 2026-10-10, by [ADR 0283](0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md).** The reading
> *waits for a person* now has a second source: a resource whose tool check says it waits for an own
> secret or a setting the operator has yet to give, checked by the controller. Unlike a new login, such a
> wait is excused for any build of the module, since every build owes it alike; the narrowing above still
> holds for the login.
2. **The gate passes a module that waits for a person, and carries the wait.** The reading counts as a 2. **The gate passes a module that waits for a person, and carries the wait.** The reading counts as a
pass. The verdict says the wait ("… and it waits for a person: relogin needed on the laptop: …"), in the pass. The verdict says the wait ("… and it waits for a person: relogin needed on the laptop: …"), in the
plan, in the gate's record and in each carried build's verdict. Nothing is put back for it, so the group plan, in the gate's record and in each carried build's verdict. Nothing is put back for it, so the group
@@ -126,7 +126,8 @@ named exactly, once. Nothing here conflicts with GENESIS.
6. **An own secret may be a family.** A name ending in `-*` in `own-secrets` declares one: its path holds 6. **An own secret may be a family.** A name ending in `-*` in `own-secrets` declares one: its path holds
exactly one `*`, and it must say `"issued-by": "outside"`. A member is the prefix followed by a name's exactly one `*`, and it must say `"issued-by": "outside"`. A member is the prefix followed by a name's
characters (`smb-password-games`), given by that full name through `secret accept` or `secret-ask`, and characters — a lower-case letter or digit, then lower-case letters, digits and hyphens, so never a `/`, a
`.` or anything else a path could be steered by (`smb-password-games`); any other name is refused, given by that full name through `secret accept` or `secret-ask`, and
placed at the path with `*` replaced by what follows the prefix. **The mesh never makes a member**: one placed at the path with `*` replaced by what follows the prefix. **The mesh never makes a member**: one
not given is no file, and the module reads its absence as not given. `module check` refuses a family not given is no file, and the module reads its absence as not given. `module check` refuses a family
without `issued-by: outside`, or whose path does not hold exactly one `*`. without `issued-by: outside`, or whose path does not hold exactly one `*`.
@@ -150,20 +151,19 @@ named exactly, once. Nothing here conflicts with GENESIS.
person's push is the way, as ADR 0254 already accepts for its wait. person's push is the way, as ADR 0254 already accepts for its wait.
- **A setting's wait is checked by name only.** The controller cannot read whether a free-form setting - **A setting's wait is checked by name only.** The controller cannot read whether a free-form setting
covers a part. A module that says it waits for a setting it declares is believed; the needs-operator covers a part. A module that says it waits for a setting it declares is believed; the needs-operator
condition says it in front of the operator, which is where a false one shows. condition says it in front of the operator, which is where a false one shows. Since that condition is
never escalated by age, a module that wrongly says it waits passes its gates for as long as the operator
leaves the condition standing; that is accepted, because the operator sees it every time the conditions
are read.
- **The state is new on the wire.** A controller older than this reads `waiting` as not healthy and raises - **The state is new on the wire.** A controller older than this reads `waiting` as not healthy and raises
nothing, so the gate fails at the bound as before. A node-engine older than this reads `waits` as not nothing, so the gate fails at the bound as before. A node-engine older than this reads `waits` as not
healthy, as before. Rollout order: mesh-sdk, then the controller, then the node-engine, then the module. healthy, as before. Order of delivery: mesh-sdk, then the controller, then the node-engine, then the module.
- **An outside secret not given stops being made only for a family.** A plain own secret marked - **An outside secret not given stops being made only for a family.** A plain own secret marked
`issued-by: outside` is still made when not given; changing that touches every module that declares one, `issued-by: outside` is still made when not given; changing that touches every module that declares one,
and is tracked by issue 401. and is tracked by issue 401.
- **The workstation's fstab line for the device** is adopted only once the source is mounted by the module - **The workstation's fstab line for the device** is adopted only once the source is mounted by the module
(issue 379). (issue 379).
> **The mechanism changed — 2026-10-10, by this record.** ADR 0263 rule 7 named one own secret,
> `smb-credentials`, holding every SMB login. Decision 7 above replaces it with the setting `smb-users` and
> the secret family `smb-password-*`. That a credential for a share is an operator-delivered secret stands.
## How it is checked ## How it is checked
| Rule | Checked by | | Rule | Checked by |
@@ -173,7 +173,7 @@ named exactly, once. Nothing here conflicts with GENESIS.
| 3 The check | controller tests: a wait for an outside secret not given is excused; for one given, for one not declared, for one not `issued-by: outside`, and for a setting not declared, it is not, each with its reason | | 3 The check | controller tests: a wait for an outside secret not given is excused; for one given, for one not declared, for one not `issued-by: outside`, and for a setting not declared, it is not, each with its reason |
| 4 The gate | controller tests: a module whose only resource not healthy is an excused wait passes with the wait in the verdict; the same with a second resource unhealthy is not yet; a later build is excused too | | 4 The gate | controller tests: a module whose only resource not healthy is an excused wait passes with the wait in the verdict; the same with a second resource unhealthy is not yet; a later build is excused too |
| 5 The condition | controller tests: two statements of an excused wait raise `needs-operator`, a warning, resolver operator, its needs naming the desk prompt for a secret and the approval for a setting, never "nothing for you to do"; a statement without it clears it; a wait that fails the check raises `unhealthy` | | 5 The condition | controller tests: two statements of an excused wait raise `needs-operator`, a warning, resolver operator, its needs naming the desk prompt for a secret and the approval for a setting, never "nothing for you to do"; a statement without it clears it; a wait that fails the check raises `unhealthy` |
| 6 Families | controller tests: `module check` refuses each malformed family; a member is accepted and asked for at the desk by its full name, a name outside the family is refused; a member given is placed at its path; a member not given places nothing and composes | | 6 Families | controller tests: `module check` refuses each malformed family; a member is accepted and asked for at the desk by its full name, a name outside the family is refused, and so is a member whose suffix holds a `/`, a `.` or an upper-case letter; a member given is placed at its path; a member not given places nothing and composes |
| 7 mounts | the module's tests: a source without username waits for `smb-users`, without password waits for `smb-password-<source>`, with both is written; a password file is read as one line; health answers `waits` and not `unhealthy`; nothing logs or answers a password | | 7 mounts | the module's tests: a source without username waits for `smb-users`, without password waits for `smb-password-<source>`, with both is written; a password file is read as one line; health answers `waits` and not `unhealthy`; nothing logs or answers a password |
| live | on the workstation, before the password: `conditions` shows `module.mounts.<machine>.needs-operator` naming the desk prompt, no `unhealthy`, and the next mounts walk passes its gate. After `secret-ask` and the operator's typing: the condition clears, and the source mounts when the device is on | | live | on the workstation, before the password: `conditions` shows `module.mounts.<machine>.needs-operator` naming the desk prompt, no `unhealthy`, and the next mounts walk passes its gate. After `secret-ask` and the operator's typing: the condition clears, and the source mounts when the device is on |
@@ -1,7 +1,7 @@
--- ---
layer: to-be layer: to-be
status: in-progress status: in-progress
code: [mesh-host, mesh-controller, mesh-lab, mesh-catalog] code: [mesh-host, mesh-controller, mesh-lab, mesh-catalog, mesh-sdk]
updated: 2026-10-10 updated: 2026-10-10
decisions: decisions:
- 02-DECISIONS/0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md - 02-DECISIONS/0283-a-part-that-waits-for-the-operators-secret-or-setting-is-said-as-waiting-passes-the-first-node-gate-and-names-the-act.md