To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0114, research 016 and issue 119 #113
@@ -24,8 +24,7 @@ The names in use were each invented by the module that claims them: `the-showcas
|
||||
**Nothing can say what a mesh has, or who fills it.** There is no seat table and no command that
|
||||
lists seats. Holdings are assembled while planning, one node at a time, and discarded afterwards.
|
||||
The only way to answer "which seats does this mesh have, and which module holds each" is to read
|
||||
every manifest in two repositories, because the core modules' manifests moved into the controller's
|
||||
own repository ([ADR 0069](0069-a-module-is-a-repository-and-a-path.md)), and then the controller's
|
||||
every manifest in two repositories, because the controller's own manifest lives in its own repository ([ADR 0069](0069-a-module-is-a-repository-and-a-path.md)), and then the controller's
|
||||
code, because one module it ships has its manifest composed there. While this
|
||||
record was being prepared, that enumeration was done by hand, and it missed both of the last two
|
||||
sources: eleven claims were reported where there are thirteen.
|
||||
@@ -163,10 +162,11 @@ question real.
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| The set is closed, and every entry names its decision | A control-plane unit test asserts the set's size and a non-empty decision for every entry. |
|
||||
| The set is closed, and every entry names its decision | A controller unit test asserts the set's size and a non-empty decision for every entry. |
|
||||
| A claim outside the set is refused | Manifest-validation tests for an unknown seat, the wrong scope, and a delivering seat whose claimant does not provide. |
|
||||
| Every module in use claims a seat in the set | A control-plane test parses every catalogue manifest and fails on any refused claim. The lab's beds read the same manifests ([ADR 0089](0089-a-bed-reads-the-catalogue-it-proves.md)). |
|
||||
| The holder answers among several providers | Resolution tests: two providers with the seat held, two with a pin overriding the seat, two with the seat unheld (refused). |
|
||||
| Every module in use claims a seat in the set | A controller test parses every catalogue manifest and fails on any refused claim. The lab's beds read the same manifests ([ADR 0089](0089-a-bed-reads-the-catalogue-it-proves.md)). |
|
||||
| The holder answers for a provision its seat delivers | Resolution tests: two providers with the seat held; a pin overriding the seat; a second provider on the consumer's own machine, where the holder still answers; the seat unheld with two providers, and with **one** provider, both refused naming the seat. |
|
||||
| A seat delivers only a one-per-mesh provision | A controller unit test: `mesh-store` and `mesh-broker` deliver nothing, so a database consumer is still served by co-location. |
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ the controller's job, because only the controller knows where the seat's holder
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| A seat source records no address | A control-plane test resolves a seat source and asserts the recorded repository is the path alone. |
|
||||
| A seat source records no address | A controller test resolves a seat source and asserts the recorded repository is the path alone. |
|
||||
| The URL comes from the holder | A test composes the clone URL from a holder's node address and served `git` scheme and port, and a second where the port was moved on the node. |
|
||||
| An unheld seat refuses self-hosted builds only | A test with no holder: `--self` is refused naming the seat; an external URL passes through unchanged. |
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ extends: 0046-a-module-configuration-is-its-assignments-not-its-manifest.md
|
||||
|
||||
## Context
|
||||
|
||||
[Issue 118](../04-ISSUES/118-a-module-definition-decides-where-its-files-live/00-report.md) found
|
||||
[Issue 119](../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md) found
|
||||
**789 host-path strings in 70 of the catalogue's 71 module definitions.** Each definition chooses
|
||||
where on the machine its directories, mounts, bindings, secrets, env-files and received files live,
|
||||
and often repeats that path in an environment variable or in code. Mounts are checked against what
|
||||
@@ -67,19 +67,20 @@ unresolved requirement and what could answer it, all at once.
|
||||
|---|---|---|
|
||||
| **another module** | a database, a bucket, a vhost, a secret, a route | provisions and bindings |
|
||||
| **the node's host** | a directory, a port, facts about the machine | resource paths, `${port:}`, `${machine:}`, facts |
|
||||
| **the mesh** | the module's identity and names, and the delivery of every answer | derived logins, minted delivery |
|
||||
| **the mesh** | the module's identity and names, and the delivery of every answer | derived logins and generated names; the controller's delivery |
|
||||
| **the operator, through the assignment** | a value a person chooses: a public name, a greeting, an external key | settings, carried literals |
|
||||
|
||||
A module provider is chosen as [ADR 0084](0084-which-provider-serves-a-consumer.md) and
|
||||
[ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md) say: a pin, then the holder of a
|
||||
seat that delivers the provision, then co-location, then the only one. A host provider is always the
|
||||
module's own node, because a host path or a port means nothing on any other. An operator value is the
|
||||
assignment's, or the requirement's default, or unresolved.
|
||||
seat that delivers the provision; for a provision no seat delivers, co-location and then the only one.
|
||||
A host provider is always the module's own node, because a host path or a port means nothing on any
|
||||
other. An operator value is the assignment's, or the requirement's default, or unresolved.
|
||||
|
||||
**A person's value stays cheap.** An operator requirement's contract is a type and, optionally, a
|
||||
default. It needs no provider module, no grant and no credential. An operator value that is secret,
|
||||
like an external API key, is kept by the vault as an operator-delivered value
|
||||
([ADR 0092](0092-an-operator-delivers-a-pair-credential.md)).
|
||||
like an external API key, is still the operator's: the vault is where it is *kept*, as an
|
||||
operator-delivered value ([ADR 0092](0092-an-operator-delivers-a-pair-credential.md)), not who
|
||||
provides it.
|
||||
|
||||
**What a provider answers with is its contract's fields**, made by the provider and carried back to
|
||||
the consumer by the mesh ([ADR 0113](0113-a-provider-makes-what-it-provides-and-the-mesh-carries-it.md)).
|
||||
@@ -127,6 +128,10 @@ On acceptance, each of these is amended by a record of its own, not edited:
|
||||
checked as resolved rather than as a path the definition declares.
|
||||
- [ADR 0084](0084-which-provider-serves-a-consumer.md): a provider is a (node, instance) pair, not a
|
||||
(node, module) pair, so a consumer can name one of two instances on one node.
|
||||
- [ADR 0049](0049-a-consumers-identity-fits-the-tightest-backend.md): a login is built from the
|
||||
instance, which gets a short form under the same rules as a slug, so it still fits the tightest
|
||||
backend.
|
||||
- [To-be 26](../03-DESIGN/01-to-be/26-the-seats.md): a seat's holder is an instance.
|
||||
- The [glossary](../00-META/glossary.md): *provision* widens from "a service one module provides" to a
|
||||
requirement answered by any of the four providers, and *instance* is added. Neither lands while this
|
||||
record is only proposed, because the glossary is the authority on the words in use, not on words
|
||||
@@ -168,7 +173,7 @@ On acceptance, each of these is amended by a record of its own, not edited:
|
||||
|
||||
## References
|
||||
|
||||
- [Issue 118](../04-ISSUES/118-a-module-definition-decides-where-its-files-live/00-report.md): the evidence
|
||||
- [Issue 119](../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md): the evidence
|
||||
- [ADR 0038](0038-the-mesh-assigns-the-port.md), [ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md),
|
||||
[ADR 0084](0084-which-provider-serves-a-consumer.md): the parts already unified
|
||||
- [ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md): which module provider answers
|
||||
|
||||
@@ -27,7 +27,9 @@ repeatedly:
|
||||
back, and say so in their code.
|
||||
- **Some contracts need a value the controller cannot make.** The broker needs its admin password in
|
||||
a hashed form the mesh's plain secret delivery cannot produce, so a module-specific bootstrap step
|
||||
was written to derive it. A provider making the value to its own contract would not need one.
|
||||
was written to derive it. That admin is a foundation credential, which genesis makes, so this
|
||||
record does not remove that step. It is the clearest instance of the general problem, though: a
|
||||
contract can require a form only the party that understands the software can produce.
|
||||
- **The vault is a ledger.** A module's own secret is "a `secret` provision the controller mints and
|
||||
the vault records" ([ADR 0085](0085-a-secret-is-a-provision.md), as amended). The one module whose
|
||||
job is secrets generates none, and cannot apply a policy (length, form, lifetime) because it never
|
||||
@@ -43,14 +45,21 @@ this one kind of answer on the provider's behalf" is a special case the model wo
|
||||
Rejected. The vault stays a ledger, contracts needing a derived form keep needing bespoke steps, and
|
||||
a data provision stays unable to answer at all.
|
||||
|
||||
**2. The provider makes the value and hands it to the consumer itself.** Rejected. This is the fault
|
||||
0048 fixed. The provider cannot seal to the consumer's node, the two may be on different machines,
|
||||
and a key both ends hold is the distribution problem one level down.
|
||||
**2. The provider makes the value and hands it to the consumer itself.** Rejected. The two may be on
|
||||
different machines with no path between them the mesh has agreed to, and a provider reaching
|
||||
consumers directly is a second delivery system beside the mesh's. 0048's objection, a symmetric key
|
||||
both ends hold, is not what rules this out: node keys are asymmetric, and a provider can seal to a
|
||||
node's public key without sharing anything.
|
||||
|
||||
**3. The provider makes the value and gives it to the mesh, and the mesh carries it to the consumer.**
|
||||
Chosen. The provider answers over its own scoped account. The controller, which already seals to
|
||||
every node, seals each secret field to the consumer's node and delivers it the way it delivers
|
||||
everything else.
|
||||
**3. The provider makes the value and gives it to the controller in plaintext, which seals and
|
||||
delivers it.** Rejected. It works, and it puts every secret in the controller's memory and on the
|
||||
broker in the clear, a surface today's design does not have for provider-side values.
|
||||
|
||||
**4. The provider makes the value, seals each secret field to the consumer's node itself, and the
|
||||
mesh carries the sealed answer.** Chosen. The mesh already tells a provider who each consumer is and
|
||||
where; it also hands it the consumer node's public key. The provider seals to it, and answers over
|
||||
its own scoped account. The controller delivers the sealed fields as it delivers everything else,
|
||||
and can open none of them.
|
||||
|
||||
## Decision
|
||||
|
||||
@@ -58,11 +67,13 @@ everything else.
|
||||
the fields its contract names: a password, an access key, a site id, a registered name, a hashed
|
||||
admin secret. The vault generates the secrets it provides, to their contract, and rotates them.
|
||||
|
||||
**The mesh carries the answer back.** The provider hands its answer to the controller over its own
|
||||
scoped broker account. The controller seals every field the contract marks secret to the consumer's
|
||||
node, and delivers the answer as the consumer's resolved values. A provider never reaches a consumer
|
||||
directly. Plaintext exists on the provider's machine, as it does today, and on the consumer's, and
|
||||
nowhere between.
|
||||
**The provider seals, and the mesh carries.** With each consumer, the mesh hands the provider that
|
||||
consumer node's public key. The provider seals every field its contract marks secret to it, and
|
||||
hands the answer to the controller over its own scoped broker account. The controller delivers the
|
||||
answer as the consumer's resolved values, and can open none of the sealed fields. A provider never
|
||||
reaches a consumer directly. A secret's plaintext exists where it is made, on the provider's machine,
|
||||
and where it is used, on the consumer's, and nowhere between. That is stricter than today, where the
|
||||
controller holds every minted credential in the clear when it makes it.
|
||||
|
||||
**Who a consumer is stays the mesh's.** The login a consumer presents is the mesh's derivation, which
|
||||
both ends agree on by construction ([ADR 0049](0049-a-consumers-identity-fits-the-tightest-backend.md),
|
||||
@@ -72,9 +83,11 @@ issue 023). A provider makes what a consumer is *given*, never what it is *calle
|
||||
and the mesh redelivers it. An operator-delivered value ([ADR 0092](0092-an-operator-delivers-a-pair-credential.md))
|
||||
is still never replaced by the mesh: its provider is the operator.
|
||||
|
||||
**Genesis is the one exception.** The foundation's own credentials and the vault's own access exist
|
||||
before any provider can answer. Genesis mints those itself, seals them to the operator key as today,
|
||||
and hands them to their holders. Nothing else is minted by the controller.
|
||||
**The foundation is the one exception.** The foundation's own credentials, the vault's own access and
|
||||
the mesh's root secrets exist before any provider can answer. The controller mints those: at genesis,
|
||||
and when an operator rotates a root secret ([ADR 0085](0085-a-secret-is-a-provision.md)). It seals
|
||||
them to the operator key as today, including any form the foundation's software needs, such as the
|
||||
broker admin's hash. Nothing else is minted by the controller.
|
||||
|
||||
## What this changes in earlier records
|
||||
|
||||
@@ -85,7 +98,11 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
option 2 is rejected here.
|
||||
- [ADR 0085](0085-a-secret-is-a-provision.md) is amended: the vault generates a module's own secret
|
||||
rather than recording one the controller minted. "The vault stores no plaintext, ever" stands. It
|
||||
makes a value, hands it to the mesh and keeps only what it keeps today.
|
||||
makes a value, seals it, hands it to the mesh and keeps only what it keeps today.
|
||||
- [To-be 24](../03-DESIGN/01-to-be/24-the-secrets-vault.md) and
|
||||
[to-be 13](../03-DESIGN/01-to-be/13-credentials-and-their-rotation.md) are amended: both describe
|
||||
the controller minting a module's credentials and rotating them. After this, the controller mints
|
||||
only the foundation's, and a provider rotates by answering again.
|
||||
|
||||
## Consequences
|
||||
|
||||
@@ -96,11 +113,11 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
- The provider harness in the SDK changes: an adapter's create answers with its contract's fields
|
||||
instead of returning nothing, and every provider in the catalogue moves to it. This is one
|
||||
migration per provider, the cost 0048 named for changing the contract, and it is paid once.
|
||||
- The controller gains the return path: receiving an answer on a provider's account, sealing its
|
||||
secret fields, and delivering them. Data provisions gain the same path, so the analytics and DNS
|
||||
providers can finally answer.
|
||||
- Bespoke derivation steps, like the broker's admin-hash bootstrap, become the provider's own
|
||||
answer and can be removed.
|
||||
- The controller gains the return path: receiving a sealed answer on a provider's account and
|
||||
delivering it. Each contribution gains the consumer node's public key. Data provisions gain the same
|
||||
path, so the analytics and DNS providers can finally answer.
|
||||
- A contract needing a derived form is met by its provider. The broker admin's hash stays with the
|
||||
controller, because that admin is a foundation credential.
|
||||
- **What got harder:** a provider that is down cannot hand out credentials, where today the controller
|
||||
could mint one in its absence. That is honest, because a credential for a resource that does not
|
||||
exist yet was never usable, but it moves a failure from later and silent to earlier and visible.
|
||||
@@ -109,10 +126,11 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| A provider's answer reaches the consumer sealed to its node | A controller test delivering a provider's answer: each secret field is sealed to the consumer's node key and to nothing else. |
|
||||
| A provider's secret fields are sealed before they leave it | An SDK test: an answer whose contract marks a field secret cannot be handed over unsealed. A controller test: an unsealed secret field in an answer is refused, not delivered. |
|
||||
| A provider's answer reaches the consumer sealed to its node | A controller test delivering a provider's answer: each secret field opens with the consumer node's key and with no other, the controller's included. |
|
||||
| A consumer's identity is still the mesh's | A resolution test: the login a consumer presents is the mesh's derivation, whatever the provider answers. |
|
||||
| A consumer waits for its provider | A resolution test with no answer yet: the requirement shows as waiting on a provider, and nothing is delivered. |
|
||||
| The controller mints nothing outside genesis | A controller test: outside genesis, no code path mints a credential. The minting function is reachable only from genesis. |
|
||||
| The controller mints only the foundation's credentials | A controller test: the minting function is reachable only from genesis and from root-secret rotation, and never for a module's provision. |
|
||||
| The vault generates and rotates | A vault test: a requested secret is generated to its contract, and a rotation answers with a new value. |
|
||||
|
||||
## References
|
||||
|
||||
@@ -28,7 +28,7 @@ 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 |
|
||||
| scope | node, site or mesh: where there may be only one holder |
|
||||
| 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 |
|
||||
|
||||
@@ -63,8 +63,10 @@ argued for is an entry nobody can explain.
|
||||
| `the-showcase` | node | — | the showcase module |
|
||||
|
||||
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 document follows the code, not the reverse. If the two disagree,
|
||||
the test has been changed without this table, and the table is what is wrong.
|
||||
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 two
|
||||
things here: the `mesh-vault` seat, and the rule that `mesh-store` and `mesh-broker` deliver
|
||||
nothing. It is brought to this table before it merges.
|
||||
|
||||
## A seat that delivers a provision
|
||||
|
||||
@@ -89,14 +91,22 @@ one is the mesh's, and co-location answering first would let any second provider
|
||||
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. Moving the role
|
||||
to the proxy is moving the seat: unassign the claim from one, assign it to the other, and every
|
||||
consumer follows.
|
||||
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.
|
||||
|
||||
**What a consumer receives is a grant**, the same as for any provision: where the provider answers,
|
||||
what it serves, and a credential where one is minted. 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.
|
||||
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.
|
||||
|
||||
## A seat that delivers nothing
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ beside the model, no literal it carries.
|
||||
This replaces six mechanisms that grew separately: provisions read through bindings, settings,
|
||||
assigned ports, machine facts, minted or accepted secrets, and literals in the definition. Each
|
||||
resolved, validated and failed in its own way ([ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md),
|
||||
[issue 118](../../04-ISSUES/118-a-module-definition-decides-where-its-files-live/00-report.md)).
|
||||
[issue 119](../../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md)).
|
||||
|
||||
## A requirement
|
||||
|
||||
@@ -36,9 +36,12 @@ A requirement has three parts:
|
||||
| provider kind | which of the four kinds of provider answers it |
|
||||
|
||||
**A contract is shared, not per module.** A database's contract is the database's, whoever requires
|
||||
it. The mesh knows each contract, and a provider is checked against the one it claims to answer. A
|
||||
module's own specification may narrow a contract (a password of at least this length, a directory
|
||||
owned by this user) and never widen it.
|
||||
it. **The controller holds every contract**, one per provision name, declared where the provision is
|
||||
defined in the catalogue. Today contracts are implicit in each provider's served fields; the first
|
||||
phase below makes them explicit, because nothing can be checked against a contract that is not
|
||||
written down. A provider is checked against the contract it claims to answer. A module's own
|
||||
specification may narrow a contract (a password of at least this length, a directory owned by this
|
||||
user) and never widen it.
|
||||
|
||||
## The four kinds of provider
|
||||
|
||||
@@ -49,7 +52,7 @@ can come from and a reviewer has to know every one.
|
||||
|---|---|---|---|
|
||||
| **a module** | a database, a bucket, a vhost, a route, a secret | the rule below | provisions and bindings |
|
||||
| **the node's host** | a directory, a port, a fact about the machine | always the module's own node | resource paths, assigned ports, machine placeholders, facts |
|
||||
| **the mesh** | the module's identity and names | the controller | derived logins, generated names |
|
||||
| **the mesh** | the module's identity and names, and the delivery of every answer | the controller | derived logins and generated names; the controller's delivery |
|
||||
| **the operator** | a value a person chooses | the assignment, else the requirement's default | settings, carried literals |
|
||||
|
||||
### A module provider
|
||||
@@ -61,9 +64,10 @@ Which module answers, in order:
|
||||
2. **the holder of a seat** that delivers the provision, where one does. Co-location does not apply
|
||||
to these: the seat is the mesh's one answer for everyone ([ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md),
|
||||
[26 — The seats](26-the-seats.md));
|
||||
3. **the provider on the consumer's own node**, for a provision no seat delivers;
|
||||
4. **the only provider** in the mesh;
|
||||
5. otherwise **refused**, naming the candidates, or the unheld seat.
|
||||
3. for a provision no seat delivers, **the provider on the consumer's own node**;
|
||||
4. for a provision no seat delivers, **the only provider** in the mesh;
|
||||
5. otherwise **refused**: naming the unheld seat, for a provision a seat delivers, even when exactly
|
||||
one provider exists; naming the candidates otherwise.
|
||||
|
||||
The provider makes what it provides and answers with its contract's fields. The mesh carries the
|
||||
answer back to the consumer, sealing every secret field to the consumer's node
|
||||
@@ -112,9 +116,11 @@ A value a person chooses: a public name for an endpoint, a greeting, how many wo
|
||||
needs no provider module, no grant and no credential. If asking a person for a value took more than
|
||||
that, module authors would route around it, and the literals this replaces would come back.
|
||||
|
||||
**A secret operator value**, such as an external API key, is held by the vault as an
|
||||
**A secret operator value**, such as an external API key, is still an operator requirement: its
|
||||
provider is the operator. What differs is where it is kept. The vault holds it as an
|
||||
operator-delivered value ([ADR 0092](../../02-DECISIONS/0092-an-operator-delivers-a-pair-credential.md)),
|
||||
never stored as a setting.
|
||||
never as a setting, because anything secret belongs in one place that can seal and audit it. The
|
||||
vault is its custodian, not its provider.
|
||||
|
||||
**An endpoint** is an operator value inside a route requirement: the public name is chosen on the
|
||||
assignment, and the route provider answers. A public name already held by another assignment is
|
||||
@@ -128,13 +134,17 @@ name in a configuration file writes the same thing: the requirement's name and t
|
||||
controller fills it at resolution.
|
||||
|
||||
This one form replaces the placeholders that exist today, one per mechanism: bound values, secrets,
|
||||
ports, machine facts and seats. The seat placeholder the controller uses to reach its own foundation
|
||||
stays, because the controller cannot be a consumer of a foundation it made before any module
|
||||
existed. It is the controller's own and no module uses it.
|
||||
ports and machine facts.
|
||||
|
||||
**A secret field reaches a process as a file**, as today ([ADR 0086](../../02-DECISIONS/0086-a-secret-reaches-a-process-as-a-file.md)).
|
||||
Reading one into a plain value, such as an environment variable, is refused when the definition is
|
||||
parsed, unless the definition declares the exception 0086 allows, with its reason.
|
||||
**The seat placeholder stays, for the controller alone.** The controller composes its own
|
||||
declaration and reaches the store and broker it made before any module existed, so it cannot be
|
||||
their consumer. One module reads the placeholder today: the store module, to find its own server's
|
||||
port. That is its own port, so it becomes a host port requirement in phase 3, and after that no
|
||||
module uses the seat placeholder.
|
||||
|
||||
**A secret field reaches a process as a file**, as [ADR 0086](../../02-DECISIONS/0086-a-secret-reaches-a-process-as-a-file.md)
|
||||
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
|
||||
|
||||
@@ -190,12 +200,14 @@ removed from the parser.
|
||||
|
||||
Each phase ends at a check that holds, so none of them leaves a mechanism half-replaced.
|
||||
|
||||
1. **Resolution and the new form.** The controller resolves requirements from the four providers,
|
||||
refuses as above, and fills the one form. Old mechanisms keep working beside it. *Ends when* a
|
||||
definition written entirely in the new form installs on a lab machine.
|
||||
2. **Providers answer.** The SDK harness answers with contract fields, the controller carries answers
|
||||
back and seals them, and the vault holds its seat and generates. *Ends when* the analytics and DNS
|
||||
providers answer their consumers and the broker's bootstrap step is removed.
|
||||
1. **Contracts, resolution and the new form.** Every provision's contract is written down and held by
|
||||
the controller. The controller resolves requirements from the four providers, refuses as above,
|
||||
and fills the one form. Old mechanisms keep working beside it. *Ends when* a definition written
|
||||
entirely in the new form installs on a lab machine.
|
||||
2. **Providers answer.** The SDK harness answers with contract fields and seals the secret ones, the
|
||||
controller carries answers back, and the vault holds its seat and generates. *Ends when* the
|
||||
analytics and DNS providers answer their consumers, and a module's own secret is generated by the
|
||||
vault and rotated by it.
|
||||
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.
|
||||
@@ -208,10 +220,15 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
|---|---|
|
||||
| Every requirement has one of the four provider kinds | The parser refuses any other. |
|
||||
| A definition names no host path, node or mesh | The catalogue tests of [ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md). |
|
||||
| A module provider is chosen by pin, seat, co-location, only one, refusal | Resolution tests for each step, and for a second provider on a consumer's own machine when a seat delivers the provision. |
|
||||
| A module provider is chosen by pin, seat, co-location, only one, refusal | Resolution tests for each step; for a second provider on a consumer's own machine when a seat delivers the provision; and for an unheld seat with exactly one provider, refused. |
|
||||
| A provider answers within its contract | A controller test: an answer carrying a field its contract does not name, or missing one it does, is refused and not delivered. |
|
||||
| A module narrows a contract and never widens it | The parser refuses a module specification that loosens a contract's field. |
|
||||
| A host requirement is answered on its own node | A resolution test placing one elsewhere: refused. |
|
||||
| An operator value needs no provider | 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 read into a plain value, unless the definition declares the 0086 exception with a reason. |
|
||||
| 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 consumer waits for its provider | A resolution test with a provider that has not answered: shown as waiting, and nothing delivered. |
|
||||
| Refusal names everything at once | A resolution test with three unresolved requirements of different kinds: one refusal naming all three. |
|
||||
| The old forms retire | The catalogue test listing definitions still using one. It must be empty before a form is removed. |
|
||||
|
||||
@@ -221,5 +238,8 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
- The layout a node's default root uses beneath it, beyond one directory per instance.
|
||||
- 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.
|
||||
- A contract registry: where contracts live, and how a new provision gets one. Today contracts are
|
||||
implicit in each provider's served fields.
|
||||
- **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.
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 118 — A module definition decides where its files live on the machine
|
||||
# 119 — A module definition decides where its files live on the machine
|
||||
|
||||
## What was observed
|
||||
|
||||
Reference in New Issue
Block a user