--- status: open opened: 2026-08-23 located-in: [hal] fixed-by: amended-design: --- # 007 — An installed package is not an available capability ## Symptom A module declares the virtualisation package the lab needs. The package is installed — version 7.3.0-1, recorded as explicitly installed. The client binary runs. The capability does not exist: | Checked | State | |---|---| | `incus.service` | disabled, inactive | | `incus.socket` | disabled, inactive | | `incus-user.socket` | disabled, inactive | | the operator's group membership | not a member of any incus group | | the client | reports **`Server version: unreachable`** | Nothing failed. Nothing reported anything. The declaration was satisfied exactly as written, and the thing it was declared for cannot be used. ## Why this is not issue 001 again [Issue 001](../001-failed-package-install-reports-success/00-report.md) is *the install failed and the job reported success*. This is the opposite and arguably worse: **the install succeeded, and success was not the point.** A package is a set of files. A capability is a running service, an enabled socket, and an identity permitted to reach it. The module model declares the first and has no vocabulary for the second, so the gap between them is invisible — there is no state in which the mesh believes this node has virtualisation and is wrong, because the mesh was never asked to believe it. The distance between the two is the same one the delivery layer already has a name for: **transport versus effect.** A package install reports that files arrived, which is transport. ## Why it matters now This is the first requirement of the lab ([ADR 0029](../../02-DECISIONS/0029-the-labs-first-scenario-has-no-pipeline.md)), which is phase 0 of the entire migration. The first capability the new work depends on is present, declared, and unusable — and would have stayed unusable silently. It also generalises. Every module that declares a package needing a unit enabled, a group joined, a kernel module loaded, or a socket activated has this gap. Post-install work lives in hooks, and hooks have their own recorded failure mode: thirteen were found that had never run. ## Evidence - Package recorded as installed 2026-08-23 00:02, explicitly. - Both units disabled and inactive; the operator in no incus group; client reports the server unreachable. ## Open questions - Should a module be able to declare a **capability** — a unit that must be enabled, a group the operator must be in — rather than only the package that provides it? - If that is what hooks are for, why is the gap invisible when a hook does not run? A hook that never fires and a hook that fires and does nothing are indistinguishable today. - Is this what the verify stage should be asserting? It exists, and a module's own assertions are meant to test outcomes rather than steps — "the socket accepts a connection" is exactly that shape. - How many other declared packages are in this state? Nothing currently reports it, which means the answer is unknown rather than zero.