# The graph is not missing Measured against `origin/main` of the code repository, 2026-08-26. Every manifest, read through git refs rather than a checkout. The effort was opened to ask whether the catalogue's missing structure is a graph. It is not missing. **It exists, it is healthy, and three separate parts of the system already use it.** That is the finding, and it changes what is worth asking. ## Finding 1 — the graph is already declared, and it is clean | | | |---|---| | manifests | 126 | | declare a dependency on another module | 64 | | declare a requirement on a provision | 11 | | **edges** | **103** | | declare neither | 62 — 49% | | **cycles** | **0** | | **dependencies declared but absent** | **0** | | deepest chain | 5 | Half the catalogue is unconnected, which matches [research 005](../005-domain-grouping/analysis.md)'s finding that fifty modules co-change with nothing. The connected half is well formed: no cycles, nothing dangling. ## Finding 2 — it is already resolved, and already used The platform SDK carries a dependency resolver that topologically sorts modules, and it is called from three places: the tool loader at startup, the installer when syncing modules onto a node, and the delivery coordinator when expanding what a change affects. It also already does something the effort assumed would need designing: **a requirement on another module's provision is treated as an implicit edge to that module**, so a consumer does not have to declare the same relationship twice. So *ordering by the graph* — which [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) says the control plane will do — is not a thing to build. It is a thing to call. ## Finding 3 — the most important edges in the mesh are invisible The one place the graph is wrong, and it is wrong about the substrate. A module that needs a database declares it like this: ```yaml provisions: - name: mesh-db provider: postgres # ← a dependency on the postgres module node: # ← and where it must run ``` `provider:` names a module. It is a dependency, declared, in the manifest — and it sits inside `provisions:`, which is what a module *offers*. The resolver reads `dependencies:` and `requires:`, so it never sees it. | | | |---|---| | provider references that name a real module | 4 | | **invisible to the resolver** | **3, across 2 modules** | Three edges is nothing, and they are the mesh's own database, the mesh's own broker, and the work engine's database. The most load-bearing relationships in the system are the ones the graph cannot see. **The consequence is measurable.** Computing what a working mesh needs, from the declared graph: ``` registry → sdk → mesh → meshware 4 modules, 4 levels ``` No database. No broker. A closure that is arithmetically correct and obviously wrong, and wrong for exactly one reason: a field that means *depends on* is not read as one. This is [04-ISSUES/003](../../04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md) again, in a new place — not a key nothing reads, but a key read as something other than what it means. ## Finding 4 — the resolver continues past faults it should stop on Two behaviours, both contrary to [ADR 0010](../../02-DECISIONS/0010-delivery.md): - **A cycle warns and falls back to input order.** A cycle means no correct order exists; the resolver proceeds with an arbitrary one and logs a line. - **A dependency that does not exist warns and continues.** The validation is documented as *non-fatal, logged as warnings*. Neither has fired in the current catalogue — there are no cycles and nothing dangling — which is why nobody has noticed. They are latent, and they are in the component that [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) makes responsible for the ordering a host will apply without question. ## Finding 5 — placement is decided in the catalogue `node:` in a provision pins it to a named node, in the manifest. Two modules do this today, and they are the substrate ones. Which node runs what is an inventory and placement decision — tier 2 by the skeleton's own test. Having it in a manifest means the catalogue decides placement, and a second node cannot provide the mesh's database without editing the module that consumes it. ## What this means for the effort **The opening question — "what does the graph delete?" — has an answer: nothing, because the graph is already there.** The premise was wrong, and finding that out is the effort's first result rather than a setback. The questions that survive are narrower and answerable: | Missing declaration | Manifests using it today | |---|---| | `excludes` — installing A makes B unavailable | **0** | | a required node capability | **0** | | an interface, with adapters providing it | **0** | Those are what a graph would *add*. What it would delete is a different and smaller list, and the honest version of it is: nothing yet. **And two defects worth fixing regardless of what else this effort concludes:** 1. `provider:` is a dependency edge and is not read as one. Fixing it makes the closure correct — which is what [research 012](../012-the-minimum-viable-node/00-overview.md) needs in order to answer what a one-node mesh requires. 2. The resolver continues past a cycle and past a missing dependency. Both should refuse. ## What was not measured - **Whether the missing declarations would be used.** Zero manifests declare exclusions or capabilities, and that is equally consistent with *nobody needs them* and *nobody can express them*. Nothing here separates those. - **Whether the interface-and-adapter idea has a consumer.** It is a good shape, and it is argued for rather than measured. - **What the closure should be.** Finding 3 says the computed one is wrong. It does not say what the right one is; that needs the fix first.