The seats half of to-be 27's review is settled, so the two records it rests on are accepted and the vocabulary catches up: the glossary's *seat* becomes a named role from a closed set, held by an assignment and possibly delivering a provision, and 23 — Choosing a provider gains the seat step in resolution, with ambiguity still refused rather than guessed. Both were held back when 0110 was proposed, because a document may not rest on a record that is not accepted. 26 — The seats moves to in-progress rather than designed: it names the files that implement it, and naming a file claims implementation, which is only defensible once those files are on the owning repositories' main branches. It becomes implemented when mesh-controller #63 and mesh-catalog #69 land. 0112, 0113 and 0114 stay proposed; to-be 27 stays proposed with them.
106 lines
5.9 KiB
Markdown
106 lines
5.9 KiB
Markdown
---
|
|
topic: building it
|
|
status: accepted
|
|
date: 2026-09-25
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 0069-a-module-is-a-repository-and-a-path.md
|
|
---
|
|
|
|
# 111. A build source is on the mesh's git seat, or it is an external repository
|
|
|
|
## Context
|
|
|
|
[ADR 0069](0069-a-module-is-a-repository-and-a-path.md) made a module a repository, a path and a
|
|
ref, and the controller records all three against the module so it can rebuild it and say when
|
|
its source has moved ahead. **The repository is recorded exactly as a person typed it.** `build
|
|
<repository>` hands the string to a build machine, which runs `git clone` on it, and the same string
|
|
becomes the module's recorded source.
|
|
|
|
**So a self-hosted forge's address is written into every module built from it.** The mesh runs its
|
|
own forge, and most of what it builds lives there. Every one of those modules carries the forge's
|
|
scheme, host and port in its recorded source. Move the forge to another machine, or change the port
|
|
it is published on, and every recorded source is stale at once. Nothing notices until a rebuild fails
|
|
to clone.
|
|
|
|
**And nothing names the mesh's git at all.** gitea serves git over HTTP and over SSH, and the mesh's
|
|
vocabulary contains neither. No provision, no `serves`, no seat, as the forge survey
|
|
([research 013](../01-RESEARCH/013-the-forge-and-the-registries/the-survey.md)) found. The only trace
|
|
is a label on its public route, which the mesh is explicitly not meant to interpret.
|
|
|
|
**External repositories are ordinary, and must stay so.** An application the mesh hosts may live on a
|
|
public forge. Building it from its URL works today and must keep working unchanged.
|
|
|
|
## Considered Options
|
|
|
|
**1. Keep recording literal URLs.** Rejected. It is the problem: the forge's address copied into
|
|
every module built from it.
|
|
|
|
**2. Recognise a self-hosted source by matching its URL against the forge's current address.**
|
|
Rejected. It infers the kind of source from the shape of a string, and the inference fails in the
|
|
one case it exists for: after the forge moves, old URLs no longer match anything.
|
|
|
|
**3. Two explicit forms: a repository on the holder of the `git` seat, or an external URL.** Chosen.
|
|
|
|
## Decision
|
|
|
|
**The mesh has a `git` seat.** It is mesh-scoped and delivers the `git` provision, per
|
|
[ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md). Its holder provides `git`,
|
|
serving how a repository on it is cloned: the scheme and the port. A gitea assignment holds it.
|
|
|
|
**A source is on the git seat, or it is external, and the mesh records which.**
|
|
|
|
- `build --self <owner>/<repository>` builds from a repository on the seat's holder. The recorded
|
|
source is the repository's path on that holder, and the seat it is on. **It never contains an
|
|
address.** At the moment of building, the controller composes the clone URL from where the
|
|
holder runs and what it serves for `git`, so a moved forge changes nothing recorded.
|
|
- `build <url>` is unchanged: an external repository, recorded and cloned exactly as given. GitHub
|
|
and GitLab are the ordinary cases.
|
|
|
|
**An unheld seat refuses self-hosted builds and nothing else.** With nobody holding `git`, `build
|
|
--self` is refused, naming the seat and saying what would hold it. External builds are unaffected. A
|
|
mesh without a forge of its own builds from external repositories only, and says so rather than
|
|
failing to clone.
|
|
|
|
**The build machine is not told the difference.** It receives a URL either way. Composing the URL is
|
|
the controller's job, because only the controller knows where the seat's holder runs.
|
|
|
|
## What this changes in earlier records
|
|
|
|
On acceptance, each of these is amended by this record, not edited:
|
|
|
|
- [ADR 0069](0069-a-module-is-a-repository-and-a-path.md): a module's repository is recorded either as
|
|
a path on the `git` seat or as an external URL, never as an address of the mesh's own forge.
|
|
- [ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md): the closed set gains `git`,
|
|
mesh-scoped, delivering `git`, held by a gitea assignment.
|
|
|
|
## Consequences
|
|
|
|
- The controller's inventory gains a column saying which seat a source is on. It is empty for
|
|
every module recorded before this, which is correct: they were all recorded as literal URLs.
|
|
- `build`, `build --behind` and `build --dry-run` resolve a seat source before asking a builder. The
|
|
recorded source keeps the seat form; the build log keeps the URL that was actually cloned, because
|
|
that is what happened.
|
|
- gitea can hold `git` and provides it, serving HTTP clone on its web port; the forge's assignment holds the seat.
|
|
- **Not decided: credentials for private repositories.** The mesh's own repositories are public, and
|
|
clone without one. A private repository still works only if the build machine's own git
|
|
configuration authenticates, exactly as before. Delivering a clone credential through the `git`
|
|
provision's grant is the obvious next step, and it is its own decision.
|
|
- **Not changed:** modules already recorded from the forge keep their literal URLs until they are
|
|
rebuilt with `--self`. Rewriting them in place would be the URL-matching this record rejects.
|
|
|
|
## How it is checked
|
|
|
|
| Rule | Checked by |
|
|
|---|---|
|
|
| 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. |
|
|
|
|
## References
|
|
|
|
- [ADR 0069](0069-a-module-is-a-repository-and-a-path.md): a module is a repository, a path and a ref
|
|
- [ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md): seats, and a seat delivering a provision
|
|
- [Research 013](../01-RESEARCH/013-the-forge-and-the-registries/the-survey.md): git is served and declared nowhere
|
|
- `mesh-controller cmd/mesh-controller/build.go`, `internal/builder/builder.go`
|