Merge pull request 'Issues 173 and 174 resolved; the installation check refuses at registration' (#236) from feat/the-mesh-places-its-own-files into main
This commit was merged in pull request #236.
This commit is contained in:
@@ -67,6 +67,8 @@ registration**, because the list it prints is the list that shrinks, and a regis
|
|||||||
manifest whose only remedy is a merge elsewhere would refuse the mesh's own catalogue on the day the
|
manifest whose only remedy is a merge elsewhere would refuse the mesh's own catalogue on the day the
|
||||||
check landed. It moves to registration when the list has been empty for a release.
|
check landed. It moves to registration when the list has been empty for a release.
|
||||||
|
|
||||||
|
> **Progressive insight — 2026-09-30.** The list was empty the day the check landed — every remaining name declared with its reason — and the operator asked for registration to refuse at once rather than after a release. It does, since mesh-controller PR 175: `module add` and a build's result are refused in the check's words, naming the way out, and the build stays recorded. The decision stands; only the day moved.
|
||||||
|
|
||||||
**A name a definition means is declared with its reason.** `names-on-purpose` on a resource maps each
|
**A name a definition means is declared with its reason.** `names-on-purpose` on a resource maps each
|
||||||
such name to why: *the federation's public key server, the world's*; *built outside the mesh, from the
|
such name to why: *the federation's public key server, the world's*; *built outside the mesh, from the
|
||||||
application's own repository, until that repository is a build source on the git seat*. A name the map
|
application's own repository, until that repository is a build source on the git seat*. A name the map
|
||||||
@@ -113,6 +115,7 @@ no base for a seat a context names refuses the build by the seat's name rather t
|
|||||||
| An image from an installation's registry needs a reason | a test without and with the word |
|
| An image from an installation's registry needs a reason | a test without and with the word |
|
||||||
| A module named after a domain is reported | a test |
|
| A module named after a domain is reported | a test |
|
||||||
| No definition in the catalogue names an installation | `TestNoCatalogueManifestNamesAnInstallation` over the checkout, and `module check modules/` |
|
| No definition in the catalogue names an installation | `TestNoCatalogueManifestNamesAnInstallation` over the checkout, and `module check modules/` |
|
||||||
|
| A definition naming an installation is refused at registration, and one declaring its names passes | `TestRegistrationRefusesADefinitionNamingAnInstallation` (2026-09-30) |
|
||||||
| `${setting:key}` fills from the layers, node over mesh; refused by name when unset; not stray when set | three tests |
|
| `${setting:key}` fills from the layers, node over mesh; refused by name when unset; not stray when set | three tests |
|
||||||
| A context on a seat is cloned from the base the mesh sent; a seat with no base is refused by name | the builder's test |
|
| A context on a seat is cloned from the base the mesh sent; a seat with no base is refused by name | the builder's test |
|
||||||
|
|
||||||
|
|||||||
@@ -234,10 +234,10 @@ counts as a copy and what as a base.
|
|||||||
|
|
||||||
| resource | is | a module may |
|
| resource | is | a module may |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `directory` | a directory with a mode and an owner | ✅ |
|
| `directory` | a directory with a mode and an owner, **placed by the mesh** under the node's root: `place: "."` is the assignment's own root, `place: "mesh"` the mesh's directory for the module, a pathless one sits beneath the root by its id; a stated path is the placement for data that must stay where it is, and may itself sit beneath a placed one (`${dir:<id>}/…`). Everything else names it as `${dir:<id>}` ([issue 119](../../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md), [174](../../04-ISSUES/174-the-meshs-own-files-for-a-module-are-placed-by-the-definition/00-report.md)) | ✅ |
|
||||||
| `file` | literal content, with `${bound:…}`, `${secret:…}`, `${dir:…}`, `${port:…}`, `${machine:…}` and `${setting:…}` filled in — the last an operator's value from the assignment's settings, refused by name when unset ([ADR 0155](../../02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md)) | ✅ |
|
| `file` | literal content, with `${bound:…}`, `${secret:…}`, `${dir:…}`, `${port:…}`, `${machine:…}` and `${setting:…}` filled in — the last an operator's value from the assignment's settings, refused by name when unset ([ADR 0155](../../02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md)) | ✅ |
|
||||||
| `user` | a login | ✅ |
|
| `user` | a login | ✅ |
|
||||||
| `access` | a pre-existing path it may use and must not own | ✅ |
|
| `access` | a pre-existing path it may use and must not own, **named by id** and placed by the assignment (`accesses: {<id>: <path>}` on its settings); mounts say `${access:<id>}`; a path in the definition is the default an assignment replaces, tolerated while the catalogue converts ([issue 153](../../04-ISSUES/153-an-adopted-machines-data-cannot-be-placed-where-it-is/00-report.md)) | ✅ |
|
||||||
| `archive` | files fetched by digest and unpacked | ✅ |
|
| `archive` | files fetched by digest and unpacked | ✅ |
|
||||||
| `package` | a package that must be present | ✅ |
|
| `package` | a package that must be present | ✅ |
|
||||||
| `network` | a named container network | ✅ |
|
| `network` | a named container network | ✅ |
|
||||||
|
|||||||
@@ -137,6 +137,12 @@ lost is a named volume, not a directory ([ADR 0030](../../02-DECISIONS/0030-data
|
|||||||
the assignment says nothing;
|
the assignment says nothing;
|
||||||
- **a placement**, where the assignment puts one directory elsewhere: on a second disk, or where an
|
- **a placement**, where the assignment puts one directory elsewhere: on a second disk, or where an
|
||||||
adopted machine's data already is ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)).
|
adopted machine's data already is ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)).
|
||||||
|
*Built 2026-10-01 ([issue 153](../../04-ISSUES/153-an-adopted-machines-data-cannot-be-placed-where-it-is/00-report.md)):*
|
||||||
|
`places` on the assignment's settings, by directory id, with an owner where the data already has
|
||||||
|
one; and `accesses`, by access id, for the operator's data — an access has an id and its mounts
|
||||||
|
name it as `${access:<id>}`. Both validated as `endpoints` is: an id the definition does not
|
||||||
|
declare is refused. *How it is checked:* the controller's placement tests, and the
|
||||||
|
path-preservation proof extended to accesses.
|
||||||
|
|
||||||
**An operator's shared data** is an access, as before ([ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md)):
|
**An operator's shared data** is an access, as before ([ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md)):
|
||||||
never created, owned or removed by the mesh. The module requires read or read-write access. Where
|
never created, owned or removed by the mesh. The module requires read or read-write access. Where
|
||||||
@@ -184,9 +190,21 @@ placeholders have, not yet the one requirement form below; they are phase 1's fi
|
|||||||
*Phase 3, in part (2026-09-30):* every definition's **own** data directory is placed; the conversion
|
*Phase 3, in part (2026-09-30):* every definition's **own** data directory is placed; the conversion
|
||||||
moved no data, proven by resolving both catalogues with the controller's rule and comparing
|
moved no data, proven by resolving both catalogues with the controller's rule and comparing
|
||||||
([issue 119](../../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md)).
|
([issue 119](../../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md)).
|
||||||
What the mesh writes *for* a module is still placed by the definition
|
What the mesh writes *for* a module was still placed by the definition
|
||||||
([issue 174](../../04-ISSUES/174-the-meshs-own-files-for-a-module-are-placed-by-the-definition/00-report.md)),
|
([issue 174](../../04-ISSUES/174-the-meshs-own-files-for-a-module-are-placed-by-the-definition/00-report.md)),
|
||||||
which is the gap this design answered on 2026-09-26 and has not built.
|
the gap this design answered on 2026-09-26; built later the same day: a directory saying
|
||||||
|
`place: "mesh"` is `<root>/mesh/<module>`, a directory beneath a placed one states its path as
|
||||||
|
`${dir:<id>}/<rest>` and moves with it, and the same proof — both catalogues resolved and compared —
|
||||||
|
shows forty-eight definitions naming the paths they named before.
|
||||||
|
|
||||||
|
*The operator's value travels only where it is asked for (2026-09-30,
|
||||||
|
[issue 173](../../04-ISSUES/173-a-modules-settings-reach-every-fact-it-contributes/00-report.md)):*
|
||||||
|
a setting overrides a key a contribution or a served fact declares and adds none; a file keeps taking
|
||||||
|
any key. A provider that must tell its consumers an operator's value — a mail server's domain, an
|
||||||
|
identity provider's issuer — declares it in what it serves as `${setting:<key>}`, and it is refused by
|
||||||
|
name when nothing sets it. That is the contract half of this design's operator provider in the shape
|
||||||
|
the placeholder allows: the definition says which values reach which requirement, and nothing else
|
||||||
|
does. *How it is checked:* the unit tests named in issue 173, and the plan comparison that closed it.
|
||||||
|
|
||||||
## How a definition reads what was resolved
|
## How a definition reads what was resolved
|
||||||
|
|
||||||
@@ -396,7 +414,9 @@ writes (`/var/lib/mesh/<module>`: sealed credentials, composed bindings) need a
|
|||||||
module-visible reservation. They do not: a module *requires* a `host-path` and receives a
|
module-visible reservation. They do not: a module *requires* a `host-path` and receives a
|
||||||
location; what the mesh writes for the module is the mesh's plumbing, placed where the mesh
|
location; what the mesh writes for the module is the mesh's plumbing, placed where the mesh
|
||||||
chooses and mounted in — never part of the module's contract. One reservation per
|
chooses and mounted in — never part of the module's contract. One reservation per
|
||||||
requirement, `<root>/<module>/<name>`.
|
requirement, `<root>/<module>/<name>`. *(Built 2026-09-30: the mesh's directory for a module is
|
||||||
|
`<root>/mesh/<module>`, named in the definition as a placed directory and nowhere as a path —
|
||||||
|
issue 174.)*
|
||||||
|
|
||||||
**Resolution happens in the controller, at declaration composition.** The node receives
|
**Resolution happens in the controller, at declaration composition.** The node receives
|
||||||
concrete paths exactly as today — the wire format and the host's apply do not change for
|
concrete paths exactly as today — the wire format and the host's apply do not change for
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ not exist.
|
|||||||
|
|
||||||
**What remains is not this record's.** The 232 host paths still in the catalogue are where the mesh
|
**What remains is not this record's.** The 232 host paths still in the catalogue are where the mesh
|
||||||
writes what it makes for a module, under `/var/lib/mesh/<module>`; design 27 says the mesh places
|
writes what it makes for a module, under `/var/lib/mesh/<module>`; design 27 says the mesh places
|
||||||
those itself, and it does not yet. That is [issue 174](../174-the-meshs-own-files-for-a-module-are-placed-by-the-definition/00-report.md).
|
those itself, and it does not yet. That is [issue 174](../174-the-meshs-own-files-for-a-module-are-placed-by-the-definition/00-report.md). *Placed since later the same day: `place: "mesh"` — issue 174 is resolved.*
|
||||||
The defects this record listed under *where that has already gone wrong* are unchanged by this and
|
The defects this record listed under *where that has already gone wrong* are unchanged by this and
|
||||||
stay in 174's scope where they concern the mesh's files; the operator's shared data stays an access
|
stay in 174's scope where they concern the mesh's files; the operator's shared data stays an access
|
||||||
([ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md)).
|
([ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md)).
|
||||||
|
|||||||
@@ -77,4 +77,4 @@ composes for its route**, read through the route's binding, and an operator's ow
|
|||||||
another mesh's forge stays a URL, which the check reports and `names-on-purpose` would declare. The
|
another mesh's forge stays a URL, which the check reports and `names-on-purpose` would declare. The
|
||||||
seven values that remain are declared with their reason — four applications built outside the mesh —
|
seven values that remain are declared with their reason — four applications built outside the mesh —
|
||||||
and are the list that shrinks ([ADR 0155](../../02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md)).
|
and are the list that shrinks ([ADR 0155](../../02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md)).
|
||||||
Registration does not refuse yet; it will when the list has been empty for a release.
|
Registration does not refuse yet; it will when the list has been empty for a release. *2026-09-30, later the same day:* it refuses — the list was empty the day the check landed, and the operator asked for it (mesh-controller PR 175); `module add` and a build's result are refused in the check's words, with the way out, and the build stays recorded.
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
status: open
|
status: resolved
|
||||||
opened: 2026-09-29
|
opened: 2026-09-29
|
||||||
located-in:
|
located-in:
|
||||||
- mesh-controller internal/catalogue/dir_into.go (dirsFor: a stated path or <data root>/<module>/<id>, nothing else)
|
- mesh-controller internal/catalogue/dir_into.go (dirsFor: a stated path or <data root>/<module>/<id>, nothing else)
|
||||||
- mesh-controller (accesses: the path is the manifest's literal)
|
- mesh-controller (accesses: the path is the manifest's literal)
|
||||||
fixed-by:
|
fixed-by: mesh-controller PR 176 (`places` and `accesses` on an assignment, `${access:<id>}`, an owner the data already has); mesh-catalog PR 198 (ten definitions name their accesses by id)
|
||||||
amended-design:
|
amended-design: [03-DESIGN/01-to-be/27-a-module-requires-the-mesh-resolves.md, 03-DESIGN/01-to-be/18-building-a-module.md]
|
||||||
---
|
---
|
||||||
|
|
||||||
# 153 — An adopted machine's data cannot be placed where it is
|
# 153 — An adopted machine's data cannot be placed where it is
|
||||||
@@ -55,3 +55,25 @@ The two assignment halves 0112 decided: a setting that places a declared directo
|
|||||||
path on this node, and a setting that says where an access's data is — both validated like
|
path on this node, and a setting that says where an access's data is — both validated like
|
||||||
`endpoints` (unknown ids refused), and an access placed by the assignment still never created,
|
`endpoints` (unknown ids refused), and an access placed by the assignment still never created,
|
||||||
chowned or removed.
|
chowned or removed.
|
||||||
|
|
||||||
|
## Resolved, 2026-10-01
|
||||||
|
|
||||||
|
The two assignment halves ADR 0112 decided exist. On an assignment's settings, `places` puts a
|
||||||
|
declared directory (by id) at a path on this node, with an owner where the data already has one —
|
||||||
|
`{"config": "/where/it/is", "data": {"path": "…", "owner": "1001:2000"}}` — and `accesses` says where
|
||||||
|
the operator's data is, by the access's id. Both are validated the way `endpoints` is: an id the
|
||||||
|
definition does not declare is refused, naming what it does declare; a relative path and a
|
||||||
|
non-numeric owner are refused; an access nothing places and whose definition carries no path is
|
||||||
|
refused with the setting to write, rather than mounted as nothing. A placed directory is still the
|
||||||
|
mesh's — created, owned as said, removed when empty and undeclared. A placed access is still the
|
||||||
|
operator's — mounted, never created, owned or removed.
|
||||||
|
|
||||||
|
An access now has an **id**, and the definition's mounts name it as `${access:<id>}`, so a placement
|
||||||
|
moves the mount with it. Ten catalogue definitions were given ids; each keeps its path as the default
|
||||||
|
an assignment may replace, so the machine that said nothing received exactly the paths it had before
|
||||||
|
(the path-preservation proof, extended to accesses). That default is still a host path in a
|
||||||
|
definition, tolerated as the transition: the media modules on the control node hold it until their
|
||||||
|
assignments say where the data is, and then the defaults go.
|
||||||
|
|
||||||
|
What the home server's assignments say next is the operator's: per media module, `places` for the
|
||||||
|
configuration on the second disk and `accesses` for the pool, with the owner the predecessor ran as.
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
status: located
|
status: resolved
|
||||||
opened: 2026-09-30
|
opened: 2026-09-30
|
||||||
located-in: [mesh-controller internal/catalogue/settings.go (settle), mesh-controller internal/catalogue/declaration.go (composed, ownNames)]
|
located-in: [mesh-controller internal/catalogue/settings.go (settle), mesh-controller internal/catalogue/declaration.go (composed, ownNames)]
|
||||||
fixed-by:
|
fixed-by: mesh-controller PR 175 (a setting overrides a declared key and adds none; `${setting:…}` in a served or contributed value); mesh-catalog PR 196 (mail declares its domain, the identity provider its issuer)
|
||||||
amended-design:
|
amended-design: 03-DESIGN/01-to-be/27-a-module-requires-the-mesh-resolves.md
|
||||||
---
|
---
|
||||||
|
|
||||||
# 173 — A module's settings reach every fact it contributes, not only the file that asked
|
# 173 — A module's settings reach every fact it contributes, not only the file that asked
|
||||||
@@ -45,3 +45,28 @@ asked for it. Until that form exists, this is the cost of the placeholder being
|
|||||||
- What does a consumer do with a served key it did not expect? Today: nothing, silently. A served
|
- What does a consumer do with a served key it did not expect? Today: nothing, silently. A served
|
||||||
map is not checked against what the provision's contract says it carries, because there is no such
|
map is not checked against what the provision's contract says it carries, because there is no such
|
||||||
contract yet.
|
contract yet.
|
||||||
|
|
||||||
|
## Resolved, 2026-09-30
|
||||||
|
|
||||||
|
**A setting overrides a key a contribution or a served fact declares, and adds none.** A file keeps
|
||||||
|
taking any key, because a configuration file is where an operator adds things; a contribution and a
|
||||||
|
served fact are a contract the other side reads, and a setting made for one of the module's files is
|
||||||
|
no part of it. A key that lands nowhere — no mergeable file, no `${setting:…}` asking for it, no
|
||||||
|
contribution or served fact declaring it — is named as stray when the node is planned, rather than
|
||||||
|
dropped.
|
||||||
|
|
||||||
|
The first open question is answered the smaller way, and it turned out to be the right one: the two
|
||||||
|
keys consumers actually read through the leak — the mail provider's `domain`, the identity provider's
|
||||||
|
`issuer` — are now **declared** by the provider in what it serves, as the operator's value
|
||||||
|
(`${setting:domain}`, `${setting:issuer}`), filled from the same setting that used to leak and refused
|
||||||
|
by name when nothing sets it. So the contract says what travels, which is the shape design 27 draws,
|
||||||
|
without a second key for overrides. The second question stands: a consumer still checks nothing
|
||||||
|
against a contract, because there is none yet; what it is told is now only what the provider
|
||||||
|
declared.
|
||||||
|
|
||||||
|
*How it was checked:* the plans of all four nodes, under the running controller and the one with the
|
||||||
|
rule, compared resource by resource — every key that disappears from a contribution is a leaked file
|
||||||
|
setting or one of the mesh's own words (`expose`, `endpoints`), and nothing a provider reads goes
|
||||||
|
away; the two served keys were declared before the controller rolled. Unit tests: a setting a route
|
||||||
|
never declared does not reach the proxy; a served value nothing sets is refused by name; the setting
|
||||||
|
a served fact asks for is not stray.
|
||||||
|
|||||||
+21
-3
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
status: located
|
status: resolved
|
||||||
opened: 2026-09-30
|
opened: 2026-09-30
|
||||||
located-in: [mesh-controller internal/catalogue/dir_into.go, mesh-controller internal/catalogue/declaration.go, mesh-catalog modules]
|
located-in: [mesh-controller internal/catalogue/dir_into.go, mesh-controller internal/catalogue/declaration.go, mesh-catalog modules]
|
||||||
fixed-by:
|
fixed-by: mesh-controller PR 175 (`place: "mesh"`, a directory beneath a placed one, the proof test resolving both sides); mesh-catalog PR 197 (48 definitions converted)
|
||||||
amended-design:
|
amended-design: [03-DESIGN/01-to-be/27-a-module-requires-the-mesh-resolves.md, 03-DESIGN/01-to-be/18-building-a-module.md]
|
||||||
---
|
---
|
||||||
|
|
||||||
# 174 — The mesh's own files for a module are placed by the definition, not by the mesh
|
# 174 — The mesh's own files for a module are placed by the definition, not by the mesh
|
||||||
@@ -46,3 +46,21 @@ test that proved 119 can prove again with the rule extended.
|
|||||||
- A binding file today lands wherever `binds` says; a module's code reads it from an environment
|
- A binding file today lands wherever `binds` says; a module's code reads it from an environment
|
||||||
variable naming the container path. If the host side is the mesh's, is the container side still the
|
variable naming the container path. If the host side is the mesh's, is the container side still the
|
||||||
definition's to choose? It should be: it is the software's contract.
|
definition's to choose? It should be: it is the software's contract.
|
||||||
|
|
||||||
|
## Resolved, 2026-09-30
|
||||||
|
|
||||||
|
The word is the one issue 119 introduced, with a second place: a directory saying `place: "mesh"` is
|
||||||
|
the mesh's directory for the module, `<root>/mesh/<module>`, beside the assignment's own root and
|
||||||
|
under the same node setting. The mesh's files keep their map shape and the container side of every
|
||||||
|
mount stays the definition's — only the host side changed, to `${dir:mesh-state}/…`. A directory that
|
||||||
|
sat beneath the mesh's (a forge's runtime state, a manager's output) states its path as
|
||||||
|
`${dir:mesh-state}/<rest>` and moves with it; one that sits elsewhere by adoption (the registry's data)
|
||||||
|
keeps its literal path as the exception it is.
|
||||||
|
|
||||||
|
Forty-eight catalogue definitions and the controller's own manifest were converted mechanically. The
|
||||||
|
proof is the same test that let issue 119 close, now resolving *both* checkouts before comparing,
|
||||||
|
because the earlier manifest already placed its own directories: resolved on the default root, every
|
||||||
|
converted definition names exactly the paths it named before. Nothing moved.
|
||||||
|
|
||||||
|
Both open questions are answered by keeping what exists: the map stays, the host side is placed; the
|
||||||
|
container side is the software's contract and stays where the definition says.
|
||||||
|
|||||||
Reference in New Issue
Block a user