Glossary, the mesh-controller/foundation vocabulary, ADR 0076, Phase 3 closed #43
@@ -0,0 +1,116 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: proposed
|
||||
date: 2026-09-15
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 0014-no-npm-workspace.md
|
||||
---
|
||||
|
||||
# 75. An artifact store is a provision; a package registry is a different one
|
||||
|
||||
## Context
|
||||
|
||||
Two questions have been circling, and they turn out to be one question asked twice.
|
||||
|
||||
**"Should gitea be the mesh's registry?"** It serves OCI images and a dozen package ecosystems, it
|
||||
is already needed — genesis clones from one — and the mesh's own registry has neither
|
||||
authentication ([issue 042](../04-ISSUES/042-nothing-gives-a-node-an-account-for-a-registry/00-report.md))
|
||||
nor a transport a runtime will accept over a network
|
||||
([issue 048](../04-ISSUES/048-nothing-makes-a-machine-trust-the-mesh-registry/00-report.md)). Gitea
|
||||
has both.
|
||||
|
||||
**"Where does the SDK come from?"** [ADR 0014](0014-no-npm-workspace.md) already answers it — each
|
||||
module consumes its dependencies, the mesh's own shared library included, *from the private
|
||||
registry* — and nothing installs one, so today it comes from a git URL, which is
|
||||
[issue 053](../04-ISSUES/053-the-sdk-is-pinned-twice-and-the-two-disagree/00-report.md).
|
||||
|
||||
**The framing that dissolves both:** `artifact-store` is already a provision, and `registry`
|
||||
already provides it. So "should gitea be the registry" is not a question about replacing a
|
||||
component. It is a question about **a second provider of an existing provision** — which this mesh
|
||||
has a mechanism for, and uses for certificate authorities and VPNs already.
|
||||
|
||||
## Decision
|
||||
|
||||
**Two provisions, because they are two jobs.**
|
||||
|
||||
| provision | is | for |
|
||||
|---|---|---|
|
||||
| `artifact-store` | content-addressed blobs, pinned by digest, no versions, no ranges | what the **mesh** delivers to **machines** |
|
||||
| `package-registry` | an ecosystem's own registry — npm, cargo, PyPI, Go | what **code** resolves when it is compiled |
|
||||
|
||||
They are not the same store with different clients. One is addressed by digest and immutable by
|
||||
construction; the other is addressed by name and version, and resolves ranges. Conflating them is
|
||||
how a mesh that pins everything ends up rebuilding one commit into two different things.
|
||||
|
||||
**`registry` remains the provider genesis installs.** Not because it is better, but because of what
|
||||
it is: a directory and one container, no database, no control plane, installable at step 8 of an
|
||||
install where neither exists yet. Gitea needs a store and provisioning, which means a control plane,
|
||||
which means the pivot has already happened — and the pivot needs somewhere to publish to.
|
||||
|
||||
**Gitea also provides `artifact-store`, and a mesh may choose it.** Two providers of one provision
|
||||
is a thing the mesh understands: it refuses, names both, and choosing is assigning the one you want.
|
||||
A mesh that assigns gitea gets authentication and TLS for its artifacts — which is to say, **issues
|
||||
042 and 048 are answered by choosing a provider that already solved them**, rather than by
|
||||
reimplementing accounts and certificates in a registry that has none.
|
||||
|
||||
**Gitea provides `package-registry`.** That is ADR 0014's private registry, and it is one service
|
||||
rather than one per ecosystem. `verdaccio` may provide it too, for npm alone, and is then a choice
|
||||
somebody makes rather than the answer.
|
||||
|
||||
**The registry is not removed at the end of installing.** A mesh that never runs gitea still has an
|
||||
artifact store. Retiring it is a migration a mesh performs, not a step an installation ends with.
|
||||
|
||||
## Why not simply gitea, from the start
|
||||
|
||||
Because genesis would need a control plane before the thing that stores the control plane's image,
|
||||
and that is circular rather than merely awkward. It would also make one of the three things the
|
||||
build loop cannot produce for itself into a stateful application with a database — the pivot is the
|
||||
hardest part of this design already.
|
||||
|
||||
And it puts every artifact in the service that is also the trust anchor for everything the mesh will
|
||||
ever run ([ADR 0071](0071-where-genesis-gets-its-source.md)), which records that forge serving a
|
||||
cryptominer with tampered git operations. Two blast radii are better than one.
|
||||
|
||||
## Moving from one provider to the other is a designed act
|
||||
|
||||
**Not a removal.** Every image a machine runs is pinned to a digest at a named store, the control
|
||||
plane's own included. Changing the provider means:
|
||||
|
||||
1. gitea installed, reachable, and holding an account the builder may publish with
|
||||
2. every artifact mirrored
|
||||
3. every declaration re-pinned, the control plane's **last**, because it is what performs the others
|
||||
4. **every machine verified to have converged and to be able to pull from the new store**
|
||||
5. only then the old provider unassigned, and its volume kept ([ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md))
|
||||
|
||||
Step 4 is the one that is easy to skip and the only thing between this and a mesh that cannot
|
||||
restart its own control plane. A machine that reboots mid-migration pulls from a store that no
|
||||
longer exists, and a local image cache hides that until exactly the moment it matters.
|
||||
|
||||
## Consequences
|
||||
|
||||
**The bootstrap is unchanged**, which is the point of keeping the small provider.
|
||||
|
||||
**042 and 048 gain a second answer.** They can be fixed in the registry, or dissolved by choosing a
|
||||
provider that already has accounts and TLS. The second is less work and more service.
|
||||
|
||||
**ADR 0014 becomes satisfiable.** There is a provision for the private registry, something that
|
||||
provides it, and a module may depend on it — so the SDK can be published and consumed rather than
|
||||
cloned, and issue 053 has somewhere to go.
|
||||
|
||||
**A mesh can be minimal or complete, and both are legitimate.** One with the small registry and no
|
||||
gitea builds and runs modules and cannot serve packages. That is a real configuration, not a broken
|
||||
one — the same way a partial host is real.
|
||||
|
||||
**And the bootstrap still has no package registry.** The first build of the shared base happens
|
||||
before anything has installed one. That is the same pivot as everything else and it is **not solved
|
||||
here**: it is named, so the next person does not discover it.
|
||||
|
||||
## How this is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| Genesis needs no database | The installer raises a mesh of one on a machine with nothing, and the artifact store it installs has no store of its own. |
|
||||
| Two providers are a choice, not a conflict | A mesh holding both is asked to resolve `artifact-store` and refuses, naming both, until one is assigned. |
|
||||
| The two stores are not interchangeable | A module depending on `package-registry` is not satisfied by `artifact-store`, and the refusal says why. |
|
||||
| A migration is verified before it is finished | The old provider cannot be unassigned while any machine's declaration still names it. |
|
||||
@@ -107,6 +107,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0072** — [Two graphs, and a build chain that orders itself](0072-two-graphs-and-the-build-chain.md)
|
||||
- **0073** — [The installer carries a builder, and the registry stays where it is](0073-the-installer-carries-a-builder.md)
|
||||
- **0074** — [The mesh defines a module protocol; an SDK is an implementation of it](0074-the-wire-is-specified-not-the-types.md)
|
||||
- **0075** — [An artifact store is a provision; a package registry is a different one](0075-two-stores-and-which-provides-what.md) *(proposed)*
|
||||
|
||||
### What runs on them, and how it gets there
|
||||
|
||||
|
||||
Reference in New Issue
Block a user