diff --git a/00-META/glossary.md b/00-META/glossary.md index a46638cf..21075c43 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -69,7 +69,8 @@ is listed under [Homonyms](#homonyms), with the qualified form each domain uses. **Recorded in** the catalogue, one manifest per module. **Upstream of** every other domain; its words are a published vocabulary, fixed by the manifest's schema. **Decided by** ADR 0040, 0126, 0174, 0188, 0207, 0236, 0262. -**Uses:** module, seat, provision (Provisioning), data class (Data), health (Health and repair). +**Uses:** module, seat, config value (Config), provision (Provisioning), data class (Data), health (Health +and repair). - **manifest** — the file a module is defined by (`module.json`): what it is, what it provides and requires, the seats it claims, the resources it declares, its tools, its data and its health. Say @@ -83,18 +84,9 @@ are a published vocabulary, fixed by the manifest's schema. **Decided by** ADR 0 it guards: the `mesh-controller`, `postgres` and `nats` modules claim the `mesh-controller`, `mesh-store` and `mesh-broker` seats (ADR 0079, ADR 0116). -- **setting** — a value a manifest declares and an assignment gives, one of the two ways a node varies - a module (ADR 0174). - What a "flavor" once varied is a setting or a separate module. - *Not:* ~~flavor~~ -- **preference** — a setting whose manifest gives it a default, because its value is true of the - software and only tuned per node: a font size, a width - (ADR 0262). - A setting with no default is the operator's own value: a domain, an identity. - *Not:* ~~tunable~~ (hq) - **kept region** — a marked block in a managed file the mesh writes *into*, where the operator's own lines survive every send and are given back when the module goes (ADR 0174). The other way a node - varies a module. + varies a module, besides a config value; a **managed** file's marked block is one (Provisioning). - **bundle** — the artifact a module's own code is built into — its tools, a seat's implementation, a daemon — in any language the mesh has a toolchain for; never an image. A **tools bundle** speaks MCP to the tool runner. One module may declare several @@ -111,6 +103,55 @@ are a published vocabulary, fixed by the manifest's schema. **Decided by** ADR 0 (ADR 0236). The controller's verb `upgrade` shows it. +## Config — the values someone may change + +**Purpose.** To hold, check and resolve every value a module reads that someone may change, and to say +where each resolved value came from. **Recorded by** the `mesh-config` module, in its buckets on the bus, +with its store as the history behind them. **Upstream of** Provisioning, which places the values; +downstream of Module and Placement. **Decided by** ADR 0262, 0277, 0348. +**Uses:** module, node, manifest (Module), assignment (Placement), provision (Provisioning), proposal +(Operator and conversation). + +- **config value** — anything a module reads that someone may change: a font size, a domain, an address. + A module declares every one it reads under `config` in its manifest, with a type, a description, + validation, whether it is trusted, optionally the predefined key it falls back to, and a default or + `required`; it lands in a template file as `${config:}` or is read by the module's code at runtime. + It resolves from four sources, the most specific winning: the default in the manifest; **mesh config**, + the value of the predefined key it falls back to for the whole mesh; **node config**, that key's value + on one node; and **module-assignment config**, the module's own value on one node. There is no module + value for the whole mesh. *Config* is the concept, the verb (`config`) and the manifest field + (ADR 0348). Mesh config is a source level, the value set for the whole mesh; `mesh-config` is the module + that keeps every level. The controller holds, mirrors and resolves no config value (ADR 0348 §9). + Older records and documents say "setting" for a config value and "settings" for the concept; new writing + says config value and config. The word goes on this entry's *Not:* line once the documents in force that + still use it in running prose are reworded, which is issue 683; until then it is checked by review. The + manifest field and the verb "settings" are kept as aliases until every module has moved (ADR 0348 §1, + issue 630), and are named on the line below with the rest once issue 683 is done. + *Identifier until renamed:* `takes-settings`, `${setting:}` — manifest forms kept as aliases until every + module has moved to their config names (ADR 0348 §1, issue 630). + What a "flavor" once varied is a config value or a separate module. + *Not:* ~~flavor~~ +- **predefined key** — a key of the catalogue's `predefined.json`, the fixed list of keys for which mesh + config and node config hold values, each with its type, description, validation and whether it is + trusted, such as `font-size`. A config value may name the predefined key it falls back to, of its own + type; one that names none resolves from its default and the module's own value only. The list is the + catalogue build's: a change to it is validated with every manifest naming a key, and removing a key still + named or still holding a value is refused (ADR 0348). +- **trusted** — said of a config value that decides what runs or who can reach what. At every level it is + set only at the controller's terminal or through `config` with propose, on the operator's Approve; a + module value that falls back to a trusted predefined key is itself trusted (ADR 0277, ADR 0348 §8). Not + the trusted sender of an operator message (see [Homonyms](#homonyms)). +- **preference** — a config value whose manifest gives it a default, because its value is true of the + software and only tuned per node: a font size, a width + (ADR 0262). + A config value with no default is `required`: the operator's own value, such as a domain or an + identity, and while nothing sets it the module's files are not written (ADR 0348). + *Not:* ~~tunable~~ (hq) +- **`mesh-config`** — the module that owns every config value, and not the source level mesh config: it + holds the seat `mesh-config` once for the mesh, validates, takes a trusted value only from the + controller's terminal or the operator's Approve, keeps the history with who set it and why, and resolves + the four sources (ADR 0348). + ## Core — the mesh's own machinery **Purpose.** To keep the controller, the bus, the store and every node's engine running and agreed, so @@ -190,9 +231,10 @@ every other domain has something to run on. **Recorded by** the controller and t **Purpose.** To decide, send and apply what each node runs, and to say why. **Recorded by** the controller's `inventory` database. **Upstream of** Provisioning, Connectivity, Data and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261. -**Uses:** node, machine, module, seat, setting (Module), manifest (Module). +**Uses:** node, machine, module, seat, manifest (Module), config value (Config). -- **assignment** — a module put on a node, with the settings that node gives it. +- **assignment** — a module put on a node. Its config values on that node (module-assignment config, + Config) are `mesh-config`'s, never part of what the controller records (ADR 0348 §9). - **pending assignment** — an assignment of a module whose build is still running, kept, and made by the controller when that build registers the module, or ended with why when it does not (ADR 0261). @@ -227,7 +269,7 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 (ADR 0181). Not a name a manifest carries. - **agent account** — the login every coding agent on a node runs as, when the node names one of its own; - stated on the node record at the controller's terminal, never by a verb or a setting. Empty means agents + stated on the node record at the controller's terminal, never by a verb or a config value. Empty means agents run as the operator account. It cannot become root without a person, and the node-engine judges that on every look (ADR 0266). - **account group** — a group of the machine's group database that a module puts an account in, by @@ -238,15 +280,21 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 ## Provisioning — one module serving another -**Purpose.** To resolve which module serves a provision for which consumer, and to wire the two. -**Recorded by** the controller. **Upstream of** Data; downstream of Module, Placement and Identity. -**Decided by** ADR 0027, 0084, 0138, 0225, 0230, 0263. -**Uses:** module, seat, credential (Identity and access). +**Purpose.** To resolve which module serves a provision for which consumer, to wire the two, and to +place every value a module needs into its files on its node. **Recorded by** the controller and +`mesh-provisioner`. **Upstream of** Data; downstream of Module, Placement, Config and Identity. +**Decided by** ADR 0027, 0084, 0138, 0225, 0230, 0263, 0349. +**Uses:** module, seat, node-engine (Core), declaration (Placement), config value (Config), credential +and vault (Identity and access). - **provision** — a service one module `provides` and others `require`; the mesh resolves a provider and wires the two with an endpoint and a credential. A provision is a service you offer, a seat is a role you occupy, and the two meet where a seat delivers a provision: occupying the seat is what makes a module *the* provider of it. + Every value a module needs is a provision from the domain that owns it: placement from the controller, + config values from `mesh-config`, shared secrets from the vault, a consumer's values from the module + providing it, an item of a collection from its contributor. A module says only what it needs and where + it lands (ADR 0349). - **provider** and **consumer** — the module that provides a provision, and the module that requires it. Which of several providers serves a consumer is resolved (ADR 0084). @@ -264,6 +312,28 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 node seat `node-mounts`, as a mount unit and an automount unit, mounted on access (ADR 0263). - **occasional source** — a share on a device that is not a node and comes and goes, such as a USB disk; its absence is a state, *not present*, never a fault (ADR 0263). +- **mesh-provisioner** — the module that places provisions on the nodes: it holds the seat + `mesh-provisioner` once for the mesh, keeping which domain answers which kind of placeholder, what each + module on each node needs, what is applied where and the items of every collection, and the seat + `node-provisioner` on every node, which its provisioner client serves (ADR 0349). +- **provisioner client** — mesh-provisioner's part on one node. For each module there it reads the + placeholders of its template files, records the needs, watches each owner's values for the node, fills a + template only once every value is there, has the node-engine write the file through a narrow local verb, + makes the program take the change as the file declares (`restart-on`, `reload-on`, `read-on-use`), and + reports `prov.applied`. It runs as a service with a bus account of its own, never in the tool runner + (ADR 0349). +- **collection** — a provision with many providers. The **collector**, a module that takes additions from + others (a shell's snippets, a bar's blocks), requires it; each **contributor** ships its **item** as a + template in its own repository and provides it. The provisioner client fills the collector's template + from the items of the contributors placed on its node, and an item goes when its contributor leaves the + node (ADR 0349). +- **owned** — a placed file that is the mesh's whole: the provisioner writes it back whenever it differs. + It is one of three answers a manifest gives for each file it places (`owner-at-runtime`): **owned**, + **seed** or **managed**. Whichever it is, the file has one writer: the node-engine writes it only on the + provisioner client's word (ADR 0349). +- **seed** — a placed file the provisioner writes once; from then on it is the program's. +- **managed** — a placed file of which only its named keys or a marked block (a kept region, Module) are + the mesh's; the program keeps the rest. ## Identity and access — who may do what @@ -278,7 +348,7 @@ and the operator act. **Recorded by** the controller's `identity` and `licences` - **secret** — a credential or other value the vault keeps sealed and the node-engine unseals into a file at apply (ADR 0085). - **secret family** — a module's own secrets declared as one name ending in `-*`; each member is the prefix - and a name (`smb-password-`, one per source the module's settings name), given by its full name + and a name (`smb-password-`, one per source the module's config values name), given by its full name and never made by the mesh (ADR 0283). - **vault** — the module that owns every secret (`mesh-vault`, @@ -438,7 +508,7 @@ becomes a message). **Decided by** ADR 0227, 0231, 0240, 0252, 0283. running session, started before, does not have that group yet. Said by the node-engine as the module's resource of kind `account`; it clears at the first look after a new login (ADR 0252). - **waiting** — a resource's health when its module's tool check says it waits for the operator: a named own - secret or setting of the module, not given yet, without which a part cannot work. Not a fault: the + secret or config value of the module, not given yet, without which a part cannot work. Not a fault: the controller checks it and says it as the condition `needs-operator`, naming the act, and the first-node gate reads it as *waits for a person* (ADR 0283). @@ -562,7 +632,7 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03 published for that asker alone. The only thing an asker acts on (ADR 0259). - **proposal** — a change an agent, or anyone the bus admits, puts forward through a verb and that takes effect only on the operator's warrant, bound to the exact thing shown: a shared instruction section (ADR - 0274), a trusted setting's layer (ADR 0277). + 0274), a trusted config value (ADR 0277, ADR 0348). A proposal changes nothing by itself; declined, expired or refused, it is discarded. - **approval mark** — a tool's or verb's declaration in its manifest (`needs-approval`) that each call to it runs only on the operator's warrant for that one call, with its exact arguments; the tool runner that serves it, or @@ -592,7 +662,7 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03 (ADR 0390). - **instruction section** — one named section of the managed instruction file, which every agent session on the nodes it is for reads first, as the mesh's word: set at the controller's terminal in the agent module's - settings, or **proposed** by an agent and made active on each node only by the operator's warrant, which that node + config, or **proposed** by an agent and made active on each node only by the operator's warrant, which that node proves itself (ADR 0274). A hand-over between sessions is one. - **personal rule** — one short text in the operator's own words about how the operator wants their agent to work with them, registered for the operator (the **operator scope** of the agent module) and rendered @@ -607,10 +677,10 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03 ## Media — what a person watches, listens to and reads **Purpose.** To find, fetch and file copies of the works a person watches, listens to and reads, each in -the library its kind names. **Recorded by** the `media-importer` module's settings and its memory of what +the library its kind names. **Recorded by** the `media-importer` module's config values and its memory of what it was told, and the servarr apps' own libraries. **Upstream of** nothing. **Decided by** ADR 0295, 0296, 0302. -**Uses:** module, seat, setting (Module). +**Uses:** module, seat, config value (Config). - **content** — a work a person watches, listens to or reads: a film, an album and its tracks, an episode, a book, a session of a sport event. It is known by an identity from a catalogue outside the @@ -621,7 +691,7 @@ it was told, and the servarr apps' own libraries. **Upstream of** nothing. **Dec - **media release** — one copy of a work an engine can fetch, such as an NZB or a video. Downloaded, it sits in the downloads folder, not yet filed. ADR 0302 says *release*. - **library** — one folder of one kind, filed by one importer: the media-importer's, named in its - settings, or a servarr app's. Several libraries may hold one kind, as TV Shows and Anime both hold + config, or a servarr app's. Several libraries may hold one kind, as TV Shows and Anime both hold series. - **media file** — a file on disk together with its metadata: its kind, the fields that identify the work, and what part of the work the file is. It is what the media-importer takes. @@ -746,6 +816,10 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical. | | a question someone must answer | **issue** | The record | | deploy | the per-node part of a delivery plan | **deploy plan** | Change and delivery | | | a wrapped program's own deploy | its own word | — | +| managed | a placed file of which only named keys or a marked block are the mesh's | **managed** (`owner-at-runtime`) | Provisioning | +| | a file the mesh writes, such as the agent's instruction file or `managed_settings` | the file's own name, or *a file the mesh places* | — | +| trusted | a config value that decides what runs or who can reach what | **trusted** config value | Config | +| | a sender on the operator's own list | **trusted** sender, its message an **operator message** | Operator and conversation | ## How this page is kept diff --git a/00-META/how-we-build.md b/00-META/how-we-build.md index 465b692c..80d0b6f9 100644 --- a/00-META/how-we-build.md +++ b/00-META/how-we-build.md @@ -1,9 +1,10 @@ --- status: canonical -updated: 2026-10-11 +updated: 2026-10-16 derives: the constitution page decisions: - "ADR 0020" + - "ADR 0391" --- # How we build @@ -172,6 +173,30 @@ quietly stop being true, and nobody will learn that from a document. Not test-driven development as a blanket rule — a test written first against undiscovered behaviour asserts a guess. The obligation is that every decision has a defender. +### Tests run at the lowest level that proves them, within a time budget + +Three levels, by how much real system a test uses (ADR 0391): + +| Level | Uses | Budget | Runs | +|---|---|---|---| +| **Unit** | one piece of logic alone: no database, network, bus, running service or other process | well under a second per test | locally, the tests of what changed, while working; and in the forge's checks | +| **Integration** | the real thing beside it: a database, the bus, a catalogue tree | the repository's whole suite in seconds, never over sixty | only in the forge's checks, once per push | +| **End to end** | the whole mesh, or a lab mesh, from the outside | — | only when the operator asks | + +- **Test each behaviour at the lowest level that can prove it.** A defect found higher up gets a test at the + lowest level that reproduces it, before its fix. +- **A test that needs longer than a second, or a database, the network or a service, is not a unit test.** +- **A suite over sixty seconds is a defect with its own issue**: it is made faster or split, not accepted. +- **Never run a merge check, a throwaway database or an integration suite locally.** The forge's checks do, + on the builder. +- **A report names its tests and how long they took**, so a test over its budget is seen when it is added. + +### Tests within a time budget — how it was earned + +On 2026-10-16 a feature's fixing agents ran the catalogue's whole merge check (about ten minutes), a +throwaway database and a locally built gate during local development. Each round cost tens of minutes and +caught neither real failure; the forge's checks found both. + ### A report is read from the system, never from what asked for it The same rule as the two above, pointed at reporting rather than at verification. **Anything diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 7e8d31b2..1b569c75 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -61,7 +61,8 @@ never into the running one, unless it blocks the running one. hold, and the patterns to copy (file:line); - what not to touch, and what lands beside it in other repositories; - the local facts: the worktree, the branch, the check commands, a temporary directory for tests outside - the home (`TMPDIR`), a throwaway database server if the store tests need one. + the home (`TMPDIR`), and the unit tests to run (never a database server: tests that need one are + integration tests, which the forge's checks run). When the reading is large, a read-only agent on the smaller model answers the lead's exact questions with file:line, and the lead writes the file from its answers. 5. **Move the issues to `fixing`**, `by` naming the feature's agent for that repository. @@ -72,7 +73,8 @@ never into the running one, unless it blocks the running one. issues one after another, committing each locally with a message naming the issue ("Keep the assignments on the bus (issue 652)"). It is not replaced per issue: the lead continues the same agent (by its id) with the next instruction, so its context is paid for once. -- **Unit tests only.** Each issue's first test fails before its change and passes after; `gofmt`, `go vet` +- **Unit tests only, of what changed, each well under a second** (how-we-build §5, ADR 0391). Each issue's + first test fails before its change and passes after; `gofmt`, `go vet` and the repository's unit tests stay green. The integration tests (`merge-check.sh` with the store and the bus) wait for phase 3. - **Nothing is pushed** and no pull request is opened in this phase. Never land on a red check: run the diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index f65de946..83912b18 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -26,7 +26,8 @@ one delivery**. Everything before the push is local and fast. need a decision or a second repository stops here and becomes a feature. 2. **Move the issue to `fixing`** with `by` as who@node. 3. **Build on a local branch** `fix/-`, in a worktree of its own branched from `main`. Write the - test that fails today first; make the change; keep `gofmt`, `go vet` and the repository's unit tests green. + test that fails today first; make the change; keep `gofmt`, `go vet` and the unit tests of what changed green + (each well under a second; never a merge check or a database locally: how-we-build §5, ADR 0391). Commit, naming the issue. For a playbook or design edit, run the repository's own checks (in hq, `sh merge-check.sh`). 4. **One review of the local commit, before anything is pushed** (a reviewer that did not write it, larger diff --git a/RELEASE-57.md b/RELEASE-57.md new file mode 100644 index 00000000..2fccdd30 --- /dev/null +++ b/RELEASE-57.md @@ -0,0 +1,6 @@ +# Release 57: config and provisioning + +This branch carries the work of design 57 (ADR 0348, ADR 0349) in this repository. Each package +merges here through its own reviewed pull request; the branch reaches main as one pull request, in one +delivery group with the branch of the same name in mesh-controller, mesh-host, mesh-sdk, mesh-catalog +and hq, after a rehearsal in the lab. This file is deleted by the last commit before that pull request.