I0903 — Deployment reads are declared once and projected everywhere
Declare the read-only deployment operations as canonical capabilities so that the CLI, the HTTP API, MCP, OpenAPI and the generated documentation all derive from one declaration.
DONE wave 2 · p0 · implementation profile · parallel safe
Objective
Declare the read-only deployment operations as canonical capabilities so that the CLI, the HTTP API, MCP, OpenAPI and the generated documentation all derive from one declaration.
Why
The repository's rule is that an operation is declared once and projected; adding deployment to a transport registry, an OpenAPI file or a documentation table by hand is the defect ADR 0004 names.
Current state
The capability registry holds a deploy module (apps/majordomus-cli/src/capability/builtin/deploy.rs) beside the others. The statement this field used to carry -- that no deployment module exists -- was falsified before 2026-09-10 and never corrected. Measured on master 6042f4286, 2026-09-10.
Desired state
A deploy capability module declares the deployment reads, and every projection picks them up from generate with no second registration anywhere.
Scope
- apps/majordomus-cli/src/capability/builtin/deploy.rs
- apps/majordomus-cli/src/capability/builtin/mod.rs
Out of scope
- Mutating operations over HTTP or MCP; deployment mutation belongs to the trusted CLI and CI
- Hand-edited OpenAPI, route tables or documentation lists
Dependencies
What waits on this
- I0913CANCELLED The provider configuration is generated, and the cheap profile is declared
- I0914CANCELLED One deployment core, one command, and a dry run that mutates nothing
- I0926BLOCKED The deployment documentation is generated and reachable
- I0927READY The cockpit shows the deployment from the same data
Acceptance criteria
- Each operation is one capability! declaration with its input, output, stability, exposure and tags
- The operations appear in the CLI, the HTTP API, the MCP surface, openapi.json and the generated reference without any file listing them a second time
- No capability performs a mutating deployment action
- generate --check is green after regeneration and fails when a projection is edited by hand
- The benchmark coverage projection accounts for the new capabilities, as the coverage rule requires
Validation
- cargo test --workspace --all-features
- majordomus generate --check
Evidence required
- capability_declared
- projections_derived
- generate_check
- benchmark_coverage
Evidence
| covers | type | command | result | at commit |
|---|---|---|---|---|
| capability_declared | test | cargo test --locked --manifest-path apps/majordomus-cli/Cargo.toml --lib capability::builtin::deploy | test result: ok. 5 passed; 0 failed (run 2026-10-14 between 08:59Z and 09:04Z on master e28daccd9b) | e28dacc |
| projections_derived | test | majordomus capabilities validate | validate: 0 failure(s) (run 2026-10-14 between 08:59Z and 09:04Z on master e28daccd9b) | e28dacc |
| generate_check | test | majordomus generate --check | generate --check: in sync (run 2026-10-14 between 08:59Z and 09:04Z on master e28daccd9b) | e28dacc |
| benchmark_coverage | test | majordomus bench coverage --check | exit 0 (run 2026-10-14 between 08:59Z and 09:04Z on master e28daccd9b) | e28dacc |
Risk
A deployment status read wants to call flyctl, which turns a cheap capability into a network call on a hot path. Live provider state belongs behind an explicit operation with its own cost, not behind an ordinary read.
Timeline
- started
- 2026-10-14T09:04:28Z
- verified
- —
- completed
- 2026-10-14T09:04:42Z
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I0903.yaml. Read it back with majordomus plan show I0903.