The design pass, for review. Every record here is proposed. Nothing is implemented beyond what #63 and #69 already do, and both must be brought to this design before they merge.
This PR supersedes #111 and #112, which it contains in full.
A module requires, the mesh resolves (to-be 27, ADR 0112)
Everything a module needs is a requirement: a name, a contract, and one of four kinds of provider. Installing resolves every requirement or refuses, naming everything missing at once.
provider
answers
a module
a database, a bucket, a vhost, a route, a secret
the node's host
a directory, a port, facts about the machine
the mesh
the module's identity and names, and the delivery of every answer
the operator
a value a person chooses that isn't secret: a type and a default
A definition names no node, no mesh and no path. 789 host paths in 70 of 71 definitions today (issue 119).
A module is assigned at most once to a node, and that pair is its identity.
It retires settings, placeholders, facts, own secrets, the broker-account command, controller minting, and paths in definitions, in three phases, each ending at a check.
Which provider answers (ADR 0110, amends 0084 and to-be 23)
A requirement naming a seat is answered by that seat's holder. If the seat is unheld, it is refused. Foundation seats can't be named.
Otherwise a pin.
Otherwise co-location.
Otherwise the only provider.
Otherwise a person chooses at assignment. The delivering seat's holder is suggested first, and the choice is recorded as a pin.
Seats (ADR 0110)
An assignment holds a seat, not a definition.
The foundation's seats deliver nothing.
secret is reserved to mesh-vault (issue 106).
To-be 26 now has its own checks table.
Secrets (ADR 0113)
The vault makes every shared secret. Private keys are made where they're used.
A provider needing a secret for a consumer requires it from the vault. The controller's credentials become requirements of its own definition. A node's host is the one party without a definition.
Genesis delivers, the vault adopts.
Every genesis value is sealed to the control-node's key, so the controller can deliver it unattended.
It is also sealed to the operator key, as 0085's break-glass copy. That copy is what re-raising the vault or broker uses.
The applied / read-at-start marking is per recipient.
Rotation (ADR 0114, graduating research 016)
The survey covers 9 credential providers. mailu was missing from the first pass.
All 9 re-apply passwords in place.
8 of 9 name the resource after the login.
5 of 9 destroy data when a login is removed: postgres, mssql, mongodb, lavinmq and mailu. minio keeps a bucket that isn't empty.
The SDK harness is keyed by login, so a changed login deletes today.
8 of 9 can put two logins on one resource. mailu can't, because its user is the mailbox, but it can hold two tokens.
The decision:
Retiring a credential never removes the resource.
Adapters get four operations.
The harness keys by consumer.
Remove runs only when the requirement goes: unassigned, dropped, or re-resolved elsewhere.
Postgres resources become owned by a role nobody logs in as, and ownership moves once.
A credential two parties hold rotates over two credentials. What a credential is, is the adapter's choice: a second login, or for mailu a second token.
The vault drives the rotation and records each step durably.
Readers confirm by authenticating, never by merely restarting.
A reader that goes away leaves the rotation.
A rotation can be abandoned until the old credential is retired.
A credential one party holds rotates in place, staged. Five backends take their admin credential only at first init. The new value is delivered beside the current one, and becomes current only after the provisioner has applied it.
Left for you
0109 (the other session's, accepted) still uses "seat" for a provision and moves npm by assigning to verdaccio. That conflicts with 0110. It has no checks section.
To-be 22 still says package-registry in its body (the other session's edit).
Redis ACL users exist only in memory. A redis restart erases every consumer's user until the provisioner restarts. This is a live fault, noted in research 016 and not yet filed as an issue.
#69 (catalogue): claims become seats a module can hold.
First, per 0114:
adapters split retire from remove;
the harness keys by consumer.
This closes a data-loss path that exists today.
cycle.py, records.py and index.py pass. The leak scan is clean.
**The design pass, for review.** Every record here is `proposed`. Nothing is implemented beyond what #63 and #69 already do, and both must be brought to this design before they merge.
This PR **supersedes #111 and #112**, which it contains in full.
## A module requires, the mesh resolves (to-be 27, ADR 0112)
**Everything a module needs is a requirement**: a name, a contract, and one of four kinds of provider. Installing resolves every requirement or refuses, naming everything missing at once.
| provider | answers |
|---|---|
| a module | a database, a bucket, a vhost, a route, a secret |
| the node's host | a directory, a port, facts about the machine |
| the mesh | the module's identity and names, and the delivery of every answer |
| the operator | a value a person chooses that isn't secret: a type and a default |
- **A definition names no node, no mesh and no path.** 789 host paths in 70 of 71 definitions today (issue 119).
- **A module is assigned at most once to a node**, and that pair is its identity.
- It retires settings, placeholders, facts, own secrets, the broker-account command, controller minting, and paths in definitions, in three phases, each ending at a check.
## Which provider answers (ADR 0110, amends 0084 and to-be 23)
1. **A requirement naming a seat** is answered by that seat's holder. If the seat is unheld, it is refused. Foundation seats can't be named.
2. Otherwise a **pin**.
3. Otherwise **co-location**.
4. Otherwise **the only provider**.
5. Otherwise **a person chooses at assignment**. The delivering seat's holder is suggested first, and the choice is recorded as a pin.
## Seats (ADR 0110)
- **An assignment holds a seat, not a definition.**
- **The foundation's seats deliver nothing.**
- **`secret` is reserved to `mesh-vault`** (issue 106).
- To-be 26 now has its own checks table.
## Secrets (ADR 0113)
- **The vault makes every shared secret.** Private keys are made where they're used.
- **A provider needing a secret for a consumer requires it from the vault.** The controller's credentials become requirements of its own definition. A node's host is the one party without a definition.
- **Genesis delivers, the vault adopts.**
- Every genesis value is sealed to the control-node's key, so the controller can deliver it unattended.
- It is also sealed to the operator key, as 0085's break-glass copy. That copy is what re-raising the vault or broker uses.
- **The applied / read-at-start marking is per recipient.**
## Rotation (ADR 0114, graduating research 016)
The survey covers **9 credential providers**. mailu was missing from the first pass.
- **All 9** re-apply passwords in place.
- **8 of 9** name the resource after the login.
- **5 of 9** destroy data when a login is removed: postgres, mssql, mongodb, lavinmq and mailu. minio keeps a bucket that isn't empty.
- **The SDK harness** is keyed by login, so a changed login deletes today.
- **8 of 9** can put two logins on one resource. mailu can't, because its user *is* the mailbox, but it can hold two tokens.
The decision:
- **Retiring a credential never removes the resource.**
- Adapters get four operations.
- The harness keys by consumer.
- Remove runs only when the requirement goes: unassigned, dropped, or re-resolved elsewhere.
- Postgres resources become owned by a role nobody logs in as, and ownership moves once.
- **A credential two parties hold rotates over two credentials.** What a credential is, is the adapter's choice: a second login, or for mailu a second token.
- The vault drives the rotation and records each step durably.
- Readers confirm by authenticating, never by merely restarting.
- A reader that goes away leaves the rotation.
- A rotation can be abandoned until the old credential is retired.
- **A credential one party holds rotates in place, staged.** Five backends take their admin credential only at first init. The new value is delivered beside the current one, and becomes current only after the provisioner has applied it.
## Left for you
- **0109** (the other session's, `accepted`) still uses "seat" for a provision and moves npm by assigning to verdaccio. That conflicts with 0110. It has no checks section.
- **To-be 22** still says `package-registry` in its body (the other session's edit).
- **Redis ACL users** exist only in memory. A redis restart erases every consumer's user until the provisioner restarts. This is a live fault, noted in research 016 and not yet filed as an issue.
## Resolved on the way
- **Issue 103** is resolved by mesh-host PR #22.
- **Issue 119** is located, with 0112's decline of "twice per node" noted.
## What must follow in code
- **#63 (controller):**
- seats held by assignments;
- `mesh-vault` and its reservation;
- the foundation seats deliver nothing;
- requirements may name a seat;
- choosing among candidates at assignment.
- **#69 (catalogue):** claims become seats a module can hold.
- **First, per 0114:**
- adapters split retire from remove;
- the harness keys by consumer.
This closes a data-loss path that exists today.
`cycle.py`, `records.py` and `index.py` pass. The leak scan is clean.
Extends ADR 0075. Surfaced fixing builder's hand-faked package-registry
binding tonight: gitea's manifest declares the provision once with a single
npm-path, conflating what should be independently assignable per ecosystem
(npm/cargo/docker/...) the same way artifact-store and package-registry
were themselves split. Cited in 22-the-work-ahead.md's Phase 2, where the
target state this decision points at was already described a week ago.
Numbered 109, not 108: route-proxy's policy feature (mesh-controller PR
still-unwritten decision record — reserved but never committed. Renumbered
around it rather than colliding.
Seats have been doing two jobs and neither is written down. The mechanism ADR 0009 introduced is
enforced — a second holder is refused — but any well-formed name becomes a seat by being claimed,
and nothing can say which seats a mesh has or who holds them: holdings are assembled while planning
and discarded. The enumeration done while preparing this missed the control plane's own manifest,
because core modules' manifests live in its repository rather than the catalogue.
0110 closes the set. Each seat has a name, a scope, what occupying it delivers, and the record that
made it one; a claim outside the set is refused. A seat is held by a module assignment, and what the
mesh knows about the holder is what it knows about that assignment — nothing is stored beside it. A
seat may deliver a provision, and then its holder answers for it among several providers: pin, then
the holder, then the only provider, then refused. That keeps 0009's "refused, never guessed": the
seat is the choice made once, mesh-wide, instead of a pin per consumer node. The first set is the
eleven seats already claimed plus 0109's npm-package-registry, so nothing in use is refused.
Two concepts — seats for exclusion, a new word for consumable singulars — was rejected: both mean
"this mesh's one X", and the overview a person wants is one list.
0111 gives the mesh a git seat and makes a build source one of two explicit forms: a repository on
the seat's holder, recorded by its path and cloned from wherever the holder runs at build time; or
an external URL, recorded and cloned exactly as given. Recognising self-hosted sources by matching
URLs against the forge's address was rejected — it fails in the one case it exists for, after the
forge moves. Credentials for private repositories are left undecided and said so.
Design: new to-be 26 (the seats); 23 gains the seat step in resolution; 18's source entry names
the two forms; the glossary's seat and provision entries say where they meet. 0109 is carried from
its own branch so every link here resolves.
The enumeration behind the first set read manifests in two repositories and missed a claim made
in the control plane's own code: the private-network module it ships claims the-private-network at
node scope. A closed set without it would refuse the control plane's own module. Thirteen claims in
use, naming twelve seats.
Issue 118 records what a review of where module code reads its files found: 789 host-path strings
in 70 of the catalogue's 71 definitions, every one a decision the definition makes about a machine.
Mounts are checked (ADR 0091); the same paths retyped as values are not. It records what that has
already allowed — a DNS provider that would provision nobody silently, a contributions file that
names credentials by host path and so forces every provider to mount at the identical path, an SDK
loop that treats an unwritten contributions file as empty without a word, defaults in code that
disagree with their own manifests — and that no module can be assigned to one node twice, because
every identity is keyed by the module's name.
ADR 0112, proposed for review, answers it the way ADR 0038 answered ports: a definition names
variables, and installing it resolves every one or refuses, from three sources — the assignment's
own configuration, provisions the mesh resolves against a contract, and what the mesh generates or
knows. A directory becomes a provision: the module requires one by name with its owner, mode and
persistence, and where it lands is the assignment's. The mesh's own files stop carrying host paths.
An assignment gets an identity of its own, so a module may run twice on one node.
Checking copies for agreement was rejected as checking something that should not exist; rewriting
paths per assignment was rejected as inferring which strings are paths by their shape. Syntax, a
node's default layout, and when a second instance becomes possible are left to the design.
The first draft listed minted secrets under what the mesh generates. ADR 0085 made a module's own
secret — a password, an internal token, an external key it was handed — a secret provision answered
by the vault, like a database by the store. What the mesh still mints is the delivery credential for
each provision a module takes (ADR 0048), the vault's own included.
- Secrets follow ADR 0085 as amended: a module's own secret is a provision the controller mints and
the vault records. The previous commit had that backwards. Whether the vault should generate
instead is recorded as an open question, not decided.
- A directory's contract is owner and mode only. The persistence flag was the keep flag ADR 0030
refused; a directory is kept while it holds anything, and disposable data is a named volume (0107).
- An operator's shared data stays an access (ADR 0051), which rejected an operator-owned directory.
Only where its path is written moves to the assignment.
- The records it changes on acceptance are named: 0051, 0091, 0046 (settings keyed by instance),
0084 (a provider is a node and an instance), and the glossary, which gains its new words only
when the record is accepted.
- How it is checked covers every stated rule. Container-side paths are no longer flagged by the
host-path rule, and code fallbacks are covered.
- Provisions are what other modules provide. A seat's occupant is not listed as one, and the vault
is not described as selectable per assignment.
- 'Control plane' becomes 'controller'. The provider count is ten of eleven, not eleven of twelve.
The design pass. Everything a module needs is a requirement: a name, a contract, and one of four kinds
of provider — a module, the node's host, the mesh, the operator. Installing a module resolves every
requirement or refuses, naming everything missing at once. It retires six mechanisms that grew
separately: provisions through bindings, settings, assigned ports, machine facts, minted secrets and
literals in the definition.
ADR 0113, proposed: a provider makes what it provides, and the mesh carries it back sealed to the
consumer's node. It is the return path ADR 0048 left "to a separate decision", now needed three ways:
data provisions with nothing to answer with, contracts needing a value the controller cannot make, and
a vault that generates nothing. Who a consumer is stays the mesh's (ADR 0049). Genesis is the one
exception. On acceptance it supersedes 0048 and amends 0085.
ADR 0112 is revised from three sources to that single concept.
ADR 0110 is amended for two points raised in review. The vault gets the mesh-vault seat (issue 106).
A seat's holder outranks co-location for a provision it delivers. Writing that down exposed an
inconsistency: mesh-store delivering postgres-database would have sent every database consumer to the
control-node, against to-be 23's node-local stores. So a seat delivers a provision only where the mesh
has one answer for everyone — artifact store, npm registry, git, vault — and mesh-store and mesh-broker
deliver nothing. 23 and 26 follow.
'Control plane' becomes 'controller' in the records written today.
0113 — the plaintext claim was false under its own mechanism: handing a provider's answer to the
controller puts every secret on the broker and in the controller in the clear. The provider now seals
each secret field itself, to the consumer node's public key the mesh hands it, and the controller
carries sealed fields it cannot open. That is stricter than today, where the controller holds every
minted credential in the clear. Option 3 (plaintext to the controller) is recorded and rejected. The
foundation exception now covers root-secret rotation (0085) and forms like the broker admin's hash, so
no phase claims to remove the broker's bootstrap step. To-be 24 and 13 are named among what it amends.
27 — resolution is consistent with 0110: co-location and the only provider apply only where no seat
delivers the provision, so an unheld seat is refused even with one provider. The secret-field rule now
matches 0086 exactly (a declared env-file, never a container environment value). The seat placeholder
is the controller's, and the one module reading it moves to a host port. Contracts are held by the
controller and written down in phase 1, so they can be checked; every rule has a check. An operator's
secret is still the operator's, with the vault as custodian. Which seats a module holds is listed as
not settled.
0110 — the unheld-seat-with-one-provider case and the one-answer-for-everyone rule have checks; the
claim about moved manifests is corrected. 26 — the table governs and the code catches up, not the
reverse; scope and capacity agree with the glossary; moving a seat is described as it really is today.
0112 — aligned with 27, and lists 0049 and 26 among what it changes.
Issue 118 is renumbered 119: another branch took 118 first. 'Control-plane' is gone from 0110 and 0111.
A secret comes into being seven ways today: provider credentials, own secrets (54 modules), broker
accounts through a command that is easy to forget, a vault that only records what the controller
mints (6 modules), operator values, licences, and root secrets. The vault was built to end own secrets
and did not; the old path was never retired.
0113 is rewritten as a waterfall. The vault makes every secret and nothing else does. A provider that
needs a secret for a consumer requires it from the vault, declared once in its provision's contract
and expanded per consumer by resolution; the vault delivers it to both holders, each sealed to its own
node, so a provider's code is unchanged. Own secrets, broker passwords, operator values and licence
credentials take the same path. Genesis is not an exception: it raises the vault first and asks it,
so there is one way a secret is made from the first one on. The vault can sit at the bottom because it
requires nothing but a broker account.
One shared mint function in the SDK was considered and rejected: generation becomes uniform but custody
stays spread over every provider's machine, and each SDK language needs its own implementation.
Rotation is asked of the vault and is provider-first: the value goes to the holder that accepts it,
which confirms, before the holder that presents it gets it, so the lockout window shrinks to the
consumer's own restart, and an unconfirmed provider holds the rotation rather than half-doing it. The
host derives which processes to restart or recreate from the requirement a definition reads, so no
definition declares restart-on for a secret. A rotation shows unconfirmed until each consumer restarted
and passed its health check. Issue 103 becomes a prerequisite.
The file is renamed to match what it now decides. 0112 follows.
jschoubben
changed title from To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 118 to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 1192026-09-25 21:11:11 +00:00
Two decisions taken with the author:
- Genesis delivers and the vault adopts. The vault cannot run first — it is built on the runtime base
the installation makes after the store, broker and controller, and it learns its work over the bus.
Genesis generates the foundation's first shared secrets, seals them to the operator key, and
delivers them to the vault through the path an operator's value takes; from then on the vault holds
and rotates them. This answers ADR 0085's own reason for rejecting vault-only minting, which 0113
now names instead of stepping around.
- Rotation re-confirms on every pass. An applier repeats its confirmation until acknowledged, so a lost
message costs one pass; an applier that stops after applying locks readers out until its supervised
restart, and that window is stated and shown, not claimed away.
Fixes:
- Scope: a shared secret is made by the vault; a private key (node sealing keys, the operator's key,
the certificate authority) is made where it is used. The inventory adds the makers the first version
missed: node and builder broker passwords, and enrolment tokens.
- Broker accounts are created by the broker's provisioner, not the controller, so the controller never
holds their plaintext; mesh-broker delivers amqp again — one broker per mesh — and only mesh-store
delivers nothing.
- secret is a reserved provision: only the mesh-vault holder may provide it, and no pin routes around it.
- A secret's contract says whether a recipient applies it or reads it at start; appliers are never
restarted for it, init-only secrets are applied, and confirmation is to-be 13's standard.
- Operator secrets are one rule everywhere: a secret requirement answered by the vault (0112 no longer
says otherwise). A data provider's adapter may return fields; the data-return check names a lab consumer.
- 'Holder' now means a seat's holder only; a secret has recipients.
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.
Decided with the author. A credential is never changed in place: each consumer has two logins, both
derived by the mesh, and uses one at a time. An applier adds the new login beside the old through the
adapter's existing create, and confirms both work; only then are readers released to the new one and
restarted by derivation; only when every reader has confirmed is the old login retired through the
existing remove.
It closes the three cases review found in applier-first rotation: an offline reader keeps working on
the old login until it returns; a bus account's owner keeps its bus until it has moved; a provisioner
restarted mid-rotation is still delivered both values. Nobody is ever without a credential that works,
which replaces to-be 13's all-or-nothing rule with a stronger one.
No consumer module changes. The alternation is the provider loop's. A provider's adapter gains one duty,
giving both logins the same rights over the consumer's data — in postgres, membership of one role that
owns it. The mesh derives two logins per consumer, both within ADR 0049's limit, which 0113 now names
among what it amends. Every rule has a check: overlap, offline reader, bus account, restarted
provisioner, equal rights, login length, and confirmation only once the old login is gone.
Overlap as drafted in 0113 would have deleted consumer data: seven of
eight providers name the resource after the login and five drop it on
remove. Rotation is now undecided in 0113 and to-be 27, pending the
survey. Also: a requirement naming a seat resolves to its holder, a
person chooses among remaining candidates at assignment, the controller's
secrets are requirements of its definition, genesis seals to the
control-node key, and moving the vault or broker is break-glass.
jschoubben
changed title from To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 119 to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113, research 016 and issue 1192026-09-25 22:15:33 +00:00
Graduates research 016. Retiring a login is separated from removing a
consumer, which closes a data-loss path in five providers; single-party
secrets rotate in place; the number of parties decides, not the provider.
jschoubben
changed title from To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113, research 016 and issue 119 to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0114, research 016 and issue 1192026-09-25 22:22:41 +00:00
The fact-check found mailu, whose user is its mailbox, so 0114 rotates
over two credentials rather than two logins, the adapter choosing what a
credential is. Also: minio keeps non-empty buckets; five backends take
their admin credential only at first init, so single-party rotation is
staged; postgres ownership moves to a non-login role; the harness keys by
consumer; rotation state lives with the vault. Consistency fixes across
0110-0113, 26 and 27; issue 103 resolved by mesh-host PR #22.
Prepared for merge as the canonical version of ADRs 0109–0112, superseding #111, #112 and decision/0108-package-registry-seat-per-ecosystem — this PR's texts are the later ones (0110 with its corrected title and the count fixed from eleven claims to thirteen), and its numbering is self-consistent (ADR 0112 → issue 119, leaving 118 to the umami report).
Two things done here:
main merged in — the bus design (#93), issues 113/114/117/120 and research 017 have landed since this branch was cut. One conflict, on issue 103's fixed-by:: both this branch and #93 filled it with different prose, each carrying a fact the other lacked. Resolved by combining them — the digest mechanism and PR reference from here, the pre-upgrade label and plan from #93, and the residual restart-on caveat for mounted directories.
#111's glossary and 23-choosing-a-provider changes were not carried over. They were going to be, but records.py refuses them: a designed document may not rest on a proposed record, and 0110 is proposed here. The glossary on main likewise cites only accepted records. Both edits belong to the moment 0110 is accepted, not to this proposal — see the closing note on #111 for the exact content, so it is not lost.
Checks on the merge result: cycle 282 documents, the chain holds; records 104, all passed; index current.
Prepared for merge as the canonical version of ADRs 0109–0112, superseding #111, #112 and `decision/0108-package-registry-seat-per-ecosystem` — this PR's texts are the later ones (0110 with its corrected title and the count fixed from eleven claims to thirteen), and its numbering is self-consistent (ADR 0112 → issue **119**, leaving 118 to the umami report).
Two things done here:
1. **`main` merged in** — the bus design (#93), issues 113/114/117/120 and research 017 have landed since this branch was cut. One conflict, on issue 103's `fixed-by:`: both this branch and #93 filled it with different prose, each carrying a fact the other lacked. Resolved by combining them — the digest mechanism and PR reference from here, the pre-upgrade label and plan from #93, and the residual `restart-on` caveat for mounted directories.
2. **#111's glossary and `23-choosing-a-provider` changes were *not* carried over.** They were going to be, but `records.py` refuses them: a `designed` document may not rest on a `proposed` record, and 0110 is proposed here. The glossary on `main` likewise cites only accepted records. Both edits belong to the moment 0110 is accepted, not to this proposal — see the closing note on #111 for the exact content, so it is not lost.
Checks on the merge result: cycle 282 documents, the chain holds; records 104, all passed; index current.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The design pass, for review. Every record here is
proposed. Nothing is implemented beyond what #63 and #69 already do, and both must be brought to this design before they merge.This PR supersedes #111 and #112, which it contains in full.
A module requires, the mesh resolves (to-be 27, ADR 0112)
Everything a module needs is a requirement: a name, a contract, and one of four kinds of provider. Installing resolves every requirement or refuses, naming everything missing at once.
Which provider answers (ADR 0110, amends 0084 and to-be 23)
Seats (ADR 0110)
secretis reserved tomesh-vault(issue 106).Secrets (ADR 0113)
Rotation (ADR 0114, graduating research 016)
The survey covers 9 credential providers. mailu was missing from the first pass.
The decision:
Left for you
accepted) still uses "seat" for a provision and moves npm by assigning to verdaccio. That conflicts with 0110. It has no checks section.package-registryin its body (the other session's edit).Resolved on the way
What must follow in code
#63 (controller):
mesh-vaultand its reservation;#69 (catalogue): claims become seats a module can hold.
First, per 0114:
This closes a data-loss path that exists today.
cycle.py,records.pyandindex.pypass. The leak scan is clean.To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 118to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 119To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113 and issue 119to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113, research 016 and issue 119To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0113, research 016 and issue 119to To-be 27 (proposed): a module requires, the mesh resolves — with ADRs 0109–0114, research 016 and issue 119Prepared for merge as the canonical version of ADRs 0109–0112, superseding #111, #112 and
decision/0108-package-registry-seat-per-ecosystem— this PR's texts are the later ones (0110 with its corrected title and the count fixed from eleven claims to thirteen), and its numbering is self-consistent (ADR 0112 → issue 119, leaving 118 to the umami report).Two things done here:
mainmerged in — the bus design (#93), issues 113/114/117/120 and research 017 have landed since this branch was cut. One conflict, on issue 103'sfixed-by:: both this branch and #93 filled it with different prose, each carrying a fact the other lacked. Resolved by combining them — the digest mechanism and PR reference from here, the pre-upgrade label and plan from #93, and the residualrestart-oncaveat for mounted directories.#111's glossary and
23-choosing-a-providerchanges were not carried over. They were going to be, butrecords.pyrefuses them: adesigneddocument may not rest on aproposedrecord, and 0110 is proposed here. The glossary onmainlikewise cites only accepted records. Both edits belong to the moment 0110 is accepted, not to this proposal — see the closing note on #111 for the exact content, so it is not lost.Checks on the merge result: cycle 282 documents, the chain holds; records 104, all passed; index current.