Files
hq/03-DESIGN/00-as-is/12-the-seats.md
jochen 3ff38d2ee1 The seats as they run, and to-be 26 implemented
Both halves are on their main branches, so the seats stop being an intention. Writes the as-is
document from the controller's code and the catalogue's manifests: the closed set of fourteen, the
three refusals a claim meets, the holder being an assignment and nothing else, and the one place a
seat changes resolution — which of several providers answers, never whether a requirement may go
unanswered.

Two things the as-is layer exists for are stated rather than smoothed over: a seat cannot answer
before it is held, which is the standing condition issue 121 records; and capacity is not
implemented at all, so the design's bench has no counterpart in the code.
2026-09-26 14:49:44 +02:00

5.2 KiB

layer, status, code, updated, decisions
layer status code updated decisions
as-is implemented
mesh-controller
mesh-catalog
2026-09-26
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, 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 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.