diff --git a/02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md b/02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md index c4fd56b0..1eba9012 100644 --- a/02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md +++ b/02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md @@ -184,6 +184,11 @@ that provision's provider for this consumer is unhealthy on the record, the cons the provider's condition — listed there as waiting on it, raised as nothing of its own — and the consumer's gate waits rather than fails. What a consumer finds while its provider is healthy is its own. +> **The mechanism changed — 2026-10-11, by [ADR 0292](0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md).** The hold under an unhealthy provider, and its consumer's gate +> waiting, stand. A provider that only waits for the operator (ADR 0283) now holds the consumers of a provision one +> of its waits covers, listed at its `needs-operator` condition, which stays a warning; their gate passes as a wait +> for a person, carrying the wait. A consumer no wait covers is said on its own. + **6. Nothing is restarted for being unhealthy.** The runtime restarts what exits, as now. A condition reaches a person through the operator's conversation, or a healer; a healer that restarts on health is its own decision. diff --git a/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 b/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 index 90d9b0a5..4bebbcff 100644 --- a/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 +++ b/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 @@ -99,6 +99,10 @@ named exactly, once. Nothing here conflicts with GENESIS. that reason. The type, its constructors and its reader are mesh-sdk's (`go/health`), so the module and the node-engine read one shape; an answer without `state` is read from `healthy` as before. + > **The mechanism changed — 2026-10-11, by [ADR 0292](0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md).** The three answers stand. Which consumers a waiting module + > holds is now read from its waits: a wait covers a provision when its `part` is that provision's name, or when + > the secret it waits for is the provision's shared credential; a wait that covers nothing holds no consumer. + 2. **The node-engine states such a resource `waiting`**, a fifth state beside healthy, unhealthy, starting, held and unknown (ADR 0240 §4), with its waits. One look that says it is enough, inside the grace too: it is a statement, not a flake that a second look might not repeat. The next look that says diff --git a/02-DECISIONS/0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md b/02-DECISIONS/0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md new file mode 100644 index 00000000..7ddf8e8e --- /dev/null +++ b/02-DECISIONS/0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md @@ -0,0 +1,111 @@ +--- +topic: what runs on it +status: accepted +date: 2026-10-11 +deciders: an agent session on the workstation, under jochen's standing rule that small design limits are decided by the session and recorded; jochen may supersede it +reconstructed: false +extends: 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 +--- + +# 292. A consumer of the part a provider waits on is held under the wait, and passes its gate as a wait for a person + +## Context + +[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) +gave a module a fifth state, *waiting* for the operator's secret or setting, said as `needs-operator`, and +passed the waiting module's own first-node gate as a wait for a person. It said nothing of the module's consumers. +[ADR 0240](0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md) rule 5 holds a consumer's +findings under its provider while the provider is *unhealthy*, and makes the consumer's gate wait. + +Issue 405, found in the review of ADR 0283's controller change, saw the gap: a provider whose only part not +healthy waits for the operator held nothing. Every consumer that failed because of it raised its own `unhealthy` +condition, whose words say "nothing for you to do", about a fault only the operator could end. The controller +change that closes it is mesh-controller #216. + +Holding consumers under a waiting provider raises three questions ADR 0283 did not answer: which consumers a wait +covers, what the held consumer's gate reads, and whether the provider's condition grows urgent while consumers +wait. This record answers them. It was decided by the agent session that built #216, under the operator's standing +rule that an agent decides a small design limit itself and records it; the operator may supersede it. + +**Checked against GENESIS.** *Failure must be loud*: a consumer's fault is never hidden behind a wait that does not +cover it. *Evidence over assertion*: a consumer is held only where a wait the provider stated names what the consumer +needs. Nothing here conflicts with GENESIS. + +## Considered Options + +**Which consumers a waiting provider holds.** + +1. *Every consumer of the provider.* ADR 0283 decision 1 says a module that waits is otherwise sound, and each wait + names its part; a consumer of another part fails for a reason of its own, and holding it would hide that. + Rejected. +2. **Only the consumers of a provision a wait covers.** Chosen. + +**How a wait is known to cover a provision.** + +3. *A declared mapping: a manifest field naming, for each waiting part, the provision it gives.* Exact, and + `module check` could prove it against the module's offers. Rejected for now: it is a change to the manifest + schema, to `module check` and to every waiting module, for a hold no provider needs today — the one waiting + module, mounts, provides nothing. It becomes worth it once a provider gives several provisions from parts that + wait separately, or a convention-named part is found to mislead the hold. +4. **The convention on the free-text `part`**: the part named after the provision, or the wait for the provision's + shared credential. Chosen: no schema change, and dormant until a provider follows it. + +**What the held consumer's gate reads.** + +5. *Waiting, as ADR 0240 rule 5 says for an unhealthy provider.* The walk then waits for the operator, possibly for + days, and every walk behind it — ADR 0283 option 4, rejected there for this reason. Rejected. +6. **A wait for a person ([ADR 0254](0254-a-wait-for-a-persons-new-login-is-not-a-gates-failure-and-each-module-of-a-send-keeps-its-own-pass.md)): + a pass, the wait carried in the verdict**, as ADR 0283 decision 4 reads the waiting module itself. Chosen. + +**The provider's severity while consumers wait.** + +7. *Urgent, as an unhealthy provider's condition is while consumers wait on it.* ADR 0283 decision 5 says + `needs-operator` is "a warning, the operator's, never escalated by age"; the act is the same act whoever + waits on it, and urgency would page the operator for something only they can do and already know of. Rejected. +8. **A warning, listing who waits on it.** Chosen. + +## Decision + +1. **A wait covers a provision** when its `part` is that provision's name, or when the secret it waits for is the + provision's shared credential ([ADR 0158](0158-a-provider-with-one-credential-shares-it-with-every-consumer.md)). + This is the convention for module authors: a provider whose waiting part gives a provision names the part after + it, or waits for that provision's shared credential. +2. **A consumer is held under a provider that only waits for the operator** when every finding of it that is not + healthy is of a check naming a provision a wait of that provider covers. It is listed at the provider's + `needs-operator` condition and raises nothing of its own. A provider that is unhealthy holds as ADR 0240 rule 5 + says. +3. **A consumer a wait does not cover is said on its own**: its `unhealthy` condition, whose evidence says its + provider waits for the operator, but not for anything the consumer is known to need. So is a consumer whose + provider's waits are not known (its `needs-operator` open, its statement naming none). +4. **The held consumer's first-node gate reads a wait for a person**: a pass, the verdict carrying "… waits on + on , which waits for you: ". Under an unhealthy provider the gate waits, as before. +5. **The provider's `needs-operator` stays a warning** while consumers wait on it. + +## Consequences + +- No walk waits for the operator's secret, whichever module owes it. +- **The blind spot accepted.** While a wait covers a consumer's provision, a build of the consumer that breaks its + own use of that provision passes its gate; the fault is said once the operator gives what is owed, as the + consumer's own `unhealthy`, and a newer build or a person's push is the way — what ADR 0283 accepts for the + waiting module itself. +- **Dormant today.** No provider names a part after a provision: the mounts module says "the source …" and provides + nothing. The hold acts once a provider follows the convention of decision 1. +- A provider whose wait fails the controller's check is unhealthy and holds as ADR 0240 rule 5 says; whether its + consumers are then listed at its condition is issue 450. + +## How it is checked + +| Rule | Checked by | +|---|---| +| 1, 2, 3 | mesh-controller `TestAProviderWaitingForTheOperatorHoldsOnlyTheConsumersOfTheWaitingPart`: held by part and by shared credential; not held for another part or when the waits are not known; an unhealthy provider holds; a healthy one does not | +| 3 | `TestAConsumerOfAnotherPartIsRaisedOnItsOwn`: the consumer's own condition, its evidence saying the provider waits | +| 4 | `TestAConsumersGateUnderAWaitingProviderPassesCarryingTheWait`: a wait for a person carrying the wait; waiting under an unhealthy provider | +| 2, 5 | `TestAWaitingProvidersConditionListsWhoWaitsOnItAndStaysAWarning`: one condition, at the provider, listing the consumer, a warning; and `TestAConsumerHeldOnceItsProviderWaitsSaysWhichItIs` | + +## References + +- Issue 405; mesh-controller #216; issue 450. +- [ADR 0240](0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md) rule 5, + [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) + option 4 and decisions 1, 4 and 5, [ADR 0254](0254-a-wait-for-a-persons-new-login-is-not-a-gates-failure-and-each-module-of-a-send-keeps-its-own-pass.md), + [ADR 0158](0158-a-provider-with-one-credential-shares-it-with-every-consumer.md). diff --git a/03-DESIGN/01-to-be/48-a-module-says-how-it-is-healthy.md b/03-DESIGN/01-to-be/48-a-module-says-how-it-is-healthy.md index 59be9292..711593e4 100644 --- a/03-DESIGN/01-to-be/48-a-module-says-how-it-is-healthy.md +++ b/03-DESIGN/01-to-be/48-a-module-says-how-it-is-healthy.md @@ -2,8 +2,9 @@ layer: to-be status: in-progress code: [mesh-host, mesh-controller, mesh-lab, mesh-catalog, mesh-sdk] -updated: 2026-10-10 +updated: 2026-10-11 decisions: + - 02-DECISIONS/0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.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 - 02-DECISIONS/0254-a-wait-for-a-persons-new-login-is-not-a-gates-failure-and-each-module-of-a-send-keeps-its-own-pass.md - 02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md @@ -218,6 +219,20 @@ condition is open: P healthy again ─► held findings released: a consumer still failing is now its own ``` +**A provider that only waits for the operator holds the consumers of the part it waits for** +([ADR 0292](../../02-DECISIONS/0292-a-consumer-of-the-part-a-provider-waits-on-is-held-under-the-wait-and-passes-its-gate-as-a-wait-for-a-person.md), +issue 405). A wait covers a provision when its `part` is that provision's name, or when the secret it waits for is +the provision's shared credential: + +``` + provider P waits ─► module.P..needs-operator (a warning, whoever waits on it) + evidence: waiting on it — consumer A + consumer A failing, ─► no condition of its own; its gate passes as a wait for a person, + its provision covered carrying P's wait + consumer B failing, ─► module.B..unhealthy, saying P waits, but not for anything B + no wait covers it is known to need +``` + What a consumer finds while its provider is healthy, or by a check that names no provision, is its own. A machine-level condition is never pinned on a module ([issue 281](../../04-ISSUES/281-a-tier-sent-one-module-at-a-time-blamed-a-module-for-its-machine/00-report.md)).