|
|
|
@@ -0,0 +1,91 @@
|
|
|
|
|
---
|
|
|
|
|
layer: as-is
|
|
|
|
|
status: implemented
|
|
|
|
|
code: [mesh-controller, mesh-catalog]
|
|
|
|
|
updated: 2026-09-26
|
|
|
|
|
decisions:
|
|
|
|
|
- 02-DECISIONS/0109-a-package-registry-seat-is-one-per-ecosystem.md
|
|
|
|
|
- 02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md
|
|
|
|
|
- 02-DECISIONS/0111-a-build-source-is-on-the-git-seat-or-external.md
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# The seats, as they run
|
|
|
|
|
|
|
|
|
|
Written from the controller's code and the catalogue's manifests on their main branches. This is
|
|
|
|
|
the second piece of the new shape to exist, after [the lab](11-the-lab.md), and the first that the
|
|
|
|
|
predecessor has no equivalent of: there, any well-formed name became a seat by being claimed.
|
|
|
|
|
|
|
|
|
|
## The set is closed, and it lives in the controller
|
|
|
|
|
|
|
|
|
|
Fourteen seats are defined in the controller — seven at mesh scope, seven at node scope. Each entry
|
|
|
|
|
carries a name, the scope at which there may be only one holder, the provision its holder answers
|
|
|
|
|
for (or none), and the record that made it a seat. A person reads the set to learn what a mesh can
|
|
|
|
|
have; nothing else can add to it.
|
|
|
|
|
|
|
|
|
|
Five seats deliver a provision: the mesh's store delivers the relational database, the mesh's broker
|
|
|
|
|
the message transport, the artifact-store seat the registry, and two more the package registry for
|
|
|
|
|
one ecosystem and the git service. The remaining nine — the controller and catalogue seats, and the
|
|
|
|
|
node-scope ones for the build machine, the DNS port, the packet filter, intrusion prevention, the
|
|
|
|
|
private network, the resolver's configuration and the showcase — mark a role without answering for
|
|
|
|
|
anything a consumer requires.
|
|
|
|
|
|
|
|
|
|
## A claim is checked against the set
|
|
|
|
|
|
|
|
|
|
Parsing a manifest refuses three things, in this order: a claim that is not a usable name or not at
|
|
|
|
|
node, site or mesh scope; then a claim naming a seat the mesh does not define, answered with the
|
|
|
|
|
whole set so the writer can see what was available; then a claim at the wrong scope for that seat.
|
|
|
|
|
A malformed claim is refused once, for being malformed, and not a second time for being unknown.
|
|
|
|
|
|
|
|
|
|
One further refusal ties a seat to what it promises: claiming a seat that delivers a provision is
|
|
|
|
|
refused unless the claiming module actually provides that provision, at the seat's scope. A seat
|
|
|
|
|
cannot be held by something that could not answer for it.
|
|
|
|
|
|
|
|
|
|
## A seat is held by an assignment, and nothing else is recorded
|
|
|
|
|
|
|
|
|
|
The holder is a module assignment — a node and a module together. There is no separate record of
|
|
|
|
|
holders: what the mesh knows about one is what it already knows about that assignment. The pair is
|
|
|
|
|
also what tells a seat's holder apart from another module providing the same thing on another node.
|
|
|
|
|
|
|
|
|
|
## Where a seat changes resolution, and where it does not
|
|
|
|
|
|
|
|
|
|
Resolution runs in two passes. The first learns only what each node offers and takes requirements
|
|
|
|
|
on trust; no declaration is ever built from it. In the second:
|
|
|
|
|
|
|
|
|
|
- **nothing provides the wanted provision** — refused, naming what would answer it ("assign X to a
|
|
|
|
|
node");
|
|
|
|
|
- **one provider** — taken, unless a pin names a different node, which is refused rather than
|
|
|
|
|
silently overruled;
|
|
|
|
|
- **several providers** — a pin wins; failing that, the holder of the seat that delivers the
|
|
|
|
|
provision answers; failing that, refused with the candidates listed.
|
|
|
|
|
|
|
|
|
|
So a seat decides **which** of several providers answers. It does not make a requirement optional:
|
|
|
|
|
before the seat is held, a requirement for what it delivers is refused like any other unanswerable
|
|
|
|
|
one. That is the standing condition [issue 121](../../04-ISSUES/121-builders-real-package-registry-grant-deadlocks-genesis/00-report.md)
|
|
|
|
|
records, where the module that builds the forge's image requires a registry only the forge provides.
|
|
|
|
|
|
|
|
|
|
## The mesh can be asked
|
|
|
|
|
|
|
|
|
|
A `seats` command prints every seat with its scope, what it delivers and who holds it, in reading
|
|
|
|
|
order, and the same as JSON. An unheld seat prints as an answer — this mesh has no such thing — not
|
|
|
|
|
as a fault. Claims held that are **outside** the set are listed separately rather than hidden, so a
|
|
|
|
|
mesh carrying one from before the set existed says so.
|
|
|
|
|
|
|
|
|
|
## A build source may name the git seat
|
|
|
|
|
|
|
|
|
|
A module's repository is either a URL, recorded and cloned exactly as given, or a path on the forge
|
|
|
|
|
holding the git seat, recorded as that path plus the seat. The clone URL is composed from wherever
|
|
|
|
|
the holder runs at the moment of building, so the build machine is never told an address that could
|
|
|
|
|
go stale. Before this, a self-hosted forge's scheme, host and port were written into every module
|
|
|
|
|
built from it, and moving the forge made every record stale at once — noticed when a rebuild failed
|
|
|
|
|
to clone.
|
|
|
|
|
|
|
|
|
|
The schema column added for this defaults to empty rather than null, because "not on a seat" is a
|
|
|
|
|
real answer, so every row recorded before the change keeps exactly the meaning it had.
|
|
|
|
|
|
|
|
|
|
## Where this differs from the design
|
|
|
|
|
|
|
|
|
|
**Capacity is not implemented.** The design's vocabulary has a seat with a capacity, and a
|
|
|
|
|
higher-capacity seat is a bench several holders share. Neither exists in the code: a seat as it runs
|
|
|
|
|
is one role with one holder at its scope, and nothing expresses a bench. Every seat in the set today
|
|
|
|
|
is exclusive, so nothing has yet needed it — but a design that says capacity and an implementation
|
|
|
|
|
that has none is a disagreement worth reading here rather than discovering in the type.
|