Expand description
Projection closure: a declared exposure is answered by the surface that would carry it.
project.interfaces-are-projections@1 says a capability is defined once and every
external interface is derived from that definition. Three of the four interfaces prove
it by construction — the MCP tool list, the HTTP route table and the OpenAPI document
are each built by walking the registry, so an entry cannot exist without a descriptor
and a descriptor cannot fail to produce one. The command line is the exception. It is
declared a second time, in clap, in cli.rs; CliExposure is a
claim about that declaration, and until this module nothing compared the two.
The gap was not theoretical. tests/projections.rs checked the CLI half with
registry.by_cli(&cli.path).unwrap().id == c.id, which asks the registry whether it
agrees with itself and is satisfied by any path at all, including one clap has never
heard of. A capability could declare cli: ["worktree", "topology"] with no such
subcommand and nothing — not the build, not the tests, not generate --check — would
say so; the failure surfaced at run time, to whoever typed the command, as “no
capability is exposed as majordomus …”.
So this module compares the two declarations, in both directions:
- declared, not present — a capability claims a CLI path the clap tree does not
have, or has only as a group that cannot be run. That is a broken promise and a
failure (
Finding). - present, not declared — a runnable clap command that no capability claims. That
is not automatically wrong:
serve,mcpandgenerateare infrastructure and have no capability behind them by design. It is, however, the measure of how much of the command line is still hand-written rather than derived, so it is reported as an inventory (unbacked). What is refused is the silent case: of that inventory, the commandscrate::cli::local::LOCALdoes not explain either (Matrix’sunclassified), whichscripts/ci/projection-checkexits 10 on.
Everything here is a pure function of the registry and the clap tree. Nothing reads the repository, the environment or the network, so the whole check costs a walk of two in-memory structures and runs inside a unit test.
Structs§
- Finding
- One broken promise: a capability declared an exposure and the surface does not carry it.
- Matrix
- The whole matrix, with the findings and the debt beside it: one value that answers “where does each capability appear, and is any claim unmet”.
- Row
- Where one capability is projected, and where it is not.
- Unbacked
- A runnable command of the command line that no capability claims.
Enums§
- Projection
- Which interface a finding is about. Only the command line can be closed by comparison today, because it is the only interface with a declaration of its own to compare against; the variant exists so that a surface which grows one later says which it is rather than being told apart by the text of its message.