diff --git a/01-RESEARCH/011-the-module-graph/00-overview.md b/01-RESEARCH/011-the-module-graph/00-overview.md new file mode 100644 index 0000000..2fef368 --- /dev/null +++ b/01-RESEARCH/011-the-module-graph/00-overview.md @@ -0,0 +1,117 @@ +--- +status: active +initiated: 2026-08-25 +touches: + - 02-DECISIONS/0002-everything-is-a-module.md + - 02-DECISIONS/0017-modules-outside-the-core-are-grouped-by-domain.md + - 02-DECISIONS/0036-a-node-is-a-managed-machine.md + - 03-DESIGN/00-as-is/02-modules-and-manifests.md + - 03-DESIGN/00-as-is/10-module-catalogue.md + - 04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md +--- + +# 011 — The module graph + +## What is being investigated + +Whether the catalogue's missing structure is a **graph** — modules declaring what they need, +what they offer, and what they exclude — and what that replaces. + +[ADR 0017](../../02-DECISIONS/0017-modules-outside-the-core-are-grouped-by-domain.md) proposes +grouping modules by domain. [Research 005](../005-domain-grouping/analysis.md) measured that +proposal and found its evidence holds in exactly one place — reachability — which +[ADR 0037](../../02-DECISIONS/0037-the-host-applies-it-does-not-decide.md) has since absorbed +into the host. The measured case for domain grouping has therefore been consumed by a decision +taken for unrelated reasons, and what remains is fifty modules that co-change with nothing. + +That leaves the original complaint unanswered: the catalogue records **what was installed** +rather than **what anything is for**, and nothing in the system can see a relationship between +two modules. Grouping asserts relationships. A graph records them. + +## Why now + +A proposal to split modules into *provisioning services* and *applications* was worked through +and abandoned in favour of one concept with facets, for a reason worth keeping: + +- The split cannot be filed consistently. A git forge is consumed as a service *and* operated + through a web interface. An analytics service grants tracking identity *and* is a dashboard + somebody reads. An identity provider grants authentication *and* has an admin console. +- The operator's correction is the sharper form: **what runs on the machine is a supervised + container, not something a user started.** That is a fact about *how a thing runs*, not about + what kind of thing it is — so it is a facet, not a taxonomy. + +Filing decisions that follow from nothing are the disease research 005 measured. A second +taxonomy would reproduce it. + +So [ADR 0002](../../02-DECISIONS/0002-everything-is-a-module.md) survives, and the question +becomes what a module must be able to **declare**. + +## The shape being investigated + +Five declarations, of which two exist today. + +| Declaration | Today | Notes | +|---|---|---| +| **requires a resource** — a database, a bucket | yes | provisioning, [ADR 0005](../../02-DECISIONS/0005-capabilities-are-provisioned-on-declaration.md) | +| **provides a resource** | yes | as above | +| **requires another module** | **no** | the dependency edge — the graph's substance | +| **excludes another module** | **no** | installing A makes B unavailable | +| **requires a node capability** | **no** | a graphical session, a container runtime, an architecture | + +And one structural idea on top: **an interface module carries no implementation.** Adapters +provide it. An assistant interface with several model-provider adapters; a terminal interface +with several terminal adapters. A dependent names the interface and never an implementation. + +**Prior art to measure against, not invent past.** This is a package manager's model, and the +platform's own package manager already has all of it: `depends` is the dependency edge, +`conflicts` is exclusion, and `provides` is the interface — several packages provide one +virtual name, and a dependent names the virtual one. That the design arrived at the same shape +independently is evidence for it. It is also a warning: dependency resolution, version +constraints, conflict handling and rollback are a long-solved and easily-botched problem, and +the effort should establish what to **delegate** rather than reimplement. + +## Capabilities, and what may be installed + +The operator's formulation: *system specs are capabilities, and capabilities unlock installable +modules — you cannot install a graphical application on a node with no display server.* + +The question that follows is whether the mesh may install a capability. The effort's working +position, to be tested: + +- **Intrinsic capabilities** — hardware, architecture, network position — are facts about a + machine. They are detected, never installed, and a module requiring one it does not have is + not unresolved but **impossible** on that node. +- **Provided capabilities** — a display server, a container runtime — are not a separate kind + of thing at all. They are modules that provide a capability, and requiring one is an ordinary + edge the graph resolves by installing it. + +If that holds, "may the mesh install a capability" is not a policy question. It is dependency +resolution, and the only genuinely new thing is detection. + +Which is where [issue 007](../../04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md) +bears directly: *an installed package is not a capability*. A provided capability is not real +because a package is present — it is real when it is present, running and working, and the +difference is exactly the class of fault this repository keeps recording. + +## What it touches beyond the catalogue + +The operator's assessment is that the machinery around a module is wanted and its integration +is not: **scheduled tasks, hooks, migrations, configuration and environment settings are worth +keeping; seeds are not; and the current integration is wrong enough to need a major refactor.** + +That is a claim to test rather than adopt. Research 005 already found supporting evidence from +a different direction — that the densest apparent coupling in the catalogue is manifest +boilerplate churn, cross-cutting changes to the machinery applied N times — which is what an +integration being wrong looks like from the outside. + +## Open questions + +| Question | Why it is open | +|---|---| +| What does the graph **delete**? | If modules gain declarations and lose nothing, this is motion rather than progress. The effort has not finished until it names what stops existing. | +| Where does resolution happen — mesh or platform package manager? | The mesh must model mesh-level edges. Whether it also resolves operating-system packages, or delegates, decides whether a solver has to be written. | +| Is an interface a module, or a name? | Arch makes it a name that packages claim. Making it a module gives it a manifest, an owner and a place to document the contract — and a thing with no implementation to install. | +| What does an exclusion mean for something already installed? | Refuse the install, or make the conflict visible and let it be decided. The second is a policy surface; the first is a package manager. | +| Does node adoption scan for capabilities, applications, or both? | The operator proposes scanning an adopted node and enabling what it finds. Under the working position above, the scan is for capabilities — but a machine with a terminal already installed is also a module already satisfied, and whether that is adoption or drift is undecided. | +| One installation image, or several? | Proposed: pre-built images carrying different capability sets, so a machine is adopted quickly. Several images bake capability sets at image time, which is the filing problem in a new form and reintroduces what detection exists to avoid. One image carrying the host and nothing else is [ADR 0038](../../02-DECISIONS/0038-a-node-joins-by-linking-first.md)'s *one binary installed by hand*, automated. The effort should settle which. | +| What happens to domain grouping? | [ADR 0017](../../02-DECISIONS/0017-modules-outside-the-core-are-grouped-by-domain.md) is still `proposed`. If the graph is the answer, 0017 is superseded rather than narrowed — its text is never edited. |