011: measure the graph against every facet a module carries #11

Merged
jschoubben merged 1 commits from research/011-facet-coverage into main 2026-09-05 00:53:20 +00:00
@@ -7,6 +7,9 @@ touches:
- 02-DECISIONS/0036-a-node-is-a-managed-machine.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/02-modules-and-manifests.md
- 03-DESIGN/00-as-is/10-module-catalogue.md - 03-DESIGN/00-as-is/10-module-catalogue.md
- 02-DECISIONS/0006-schema-changes-are-numbered-migrations.md
- 02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md
- 04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md
- 04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md - 04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md
--- ---
@@ -104,6 +107,54 @@ a different direction — that the densest apparent coupling in the catalogue is
boilerplate churn, cross-cutting changes to the machinery applied N times — which is what an boilerplate churn, cross-cutting changes to the machinery applied N times — which is what an
integration being wrong looks like from the outside. integration being wrong looks like from the outside.
## Coverage against what a module carries today
The five declarations describe how modules **relate**. A module is more than its relations,
and the as-is manifest surface
([`02-modules-and-manifests.md`](../../03-DESIGN/00-as-is/02-modules-and-manifests.md)) is the
checklist the graph has to be measured against facet by facet — otherwise the effort can look
finished while most of what a module actually carries is unplaced. Weighed one at a time:
| Facet today | Likely landing | Weighing |
|---|---|---|
| requires / provides a resource | the graph | exists today; carried over |
| service shape, data directories, firewall rules, managed configuration, service units | typed resources in the host declaration ([ADR 0043](../../02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md)) | covered — and refusal-on-unknown is what closes the class of fault in [issue 003](../../04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md), where a manifest key restricted nothing in silence |
| environment | resolved by the control plane; reaches the node inside declared resources | covered in principle |
| migrations | module runtime — never host-declared resources | [ADR 0006](../../02-DECISIONS/0006-schema-changes-are-numbered-migrations.md) stands. What must survive any re-integration is the two-kinds distinction: migrations against a module's own state, and migrations against a provisioned resource, which run where the resource is consumed |
| scheduled tasks | a declared resource (a timer) or module runtime | minor either way |
| per-node selections | partly dissolves: the accelerator variant is *requires a node capability*; the public-versus-private variant is configuration, not a variant | to test — if it dissolves fully, it belongs on the list of what the graph deletes |
| the tool surface | **no home — open** | below |
| verification | **open** | below |
| cross-component contributions | **probably dissolves — confirm, don't assume** | below |
| lifecycle hooks | shrink toward module-side; host-side effects become declared resources | inside the recorded "integration is wrong" claim; the code/data boundary is already set by ADRs 0039/0043, not by this effort |
Three of these are genuinely open rather than mapping work.
**The tool surface has no home in the tier model.** Most of the catalogue carries tools — they
are how an operator drives a module. Tier 3 is "thin, no logic", but a module's tools are
module-specific logic: a media library's queue commands do not belong in a generic surface. No
record says whether tools are a facet the module carries — discovered by the control plane,
served through tier 3 — or something else. By count of affected modules this is the largest
unscoped facet.
**When is a provides-edge true?** [Issue 007](../../04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md)
answers negatively: not when the package is installed. The strong candidate — every `provides`
names its verifier, and the resolver trusts only verified edges — would make health checks the
graph's truth condition, and satisfies the rule that a rule states how it is checked. The step
too far to avoid adopting untested: intrinsic capabilities are already detection, and a
mandatory verifier on every edge invites trivial verifiers — which are worse than none,
because they are believed. What to require, and on which edges, is open.
**Cross-component contributions probably dissolve, and should be confirmed rather than
assumed.** The candidate sixth relation — module A contributes something to component B's
feature: a log pattern to the intrusion filter, a dashboard to the metrics stack — looks like
a new edge type. For the intrusion filter it is not: that concern is absorbed into the host,
so the contribution is an ordinary typed resource in the declaration and no edge exists. What
remains open is whether the module-to-module cases also reduce to a typed resource the
consumer reads, or genuinely need an edge. The answer decides whether the vocabulary grows —
and per ADR 0043 every added type is reviewed as a security artefact, so it should be
measured, not defaulted.
## Open questions ## Open questions
| Question | Why it is open | | Question | Why it is open |
@@ -115,3 +166,6 @@ integration being wrong looks like from the outside.
| 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. | | 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. | | 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. | | 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. |
| Where does the tool surface live, and how is it discovered? | The largest unscoped facet — see the coverage table. Tier 3's "no logic" rule and module-specific tools pull in opposite directions, and no record resolves them. |
| When is a provides-edge true? | Issue 007 rules out "when installed". Whether every `provides` must name a verifier — and what stops verifiers from being trivial — is undecided, and the resolver's trust model depends on it. |
| Do cross-component contributions need an edge? | Probably not — host absorption turns the measured case into a declared resource — but the module-to-module cases are unmeasured, and a new edge type versus a new resource type is a security-vocabulary decision either way. |