I0902 — The deployment object becomes typed Rust that refuses nonsense
Parse the canonical deployment object into strongly typed Rust — enums and newtypes rather than strings — and validate it so that a deployment that cannot work is refused before anything is built.
DONE wave 1 · p0 · implementation profile · parallel safe
Objective
Parse the canonical deployment object into strongly typed Rust — enums and newtypes rather than strings — and validate it so that a deployment that cannot work is refused before anything is built.
Why
Generation from an unvalidated document produces a valid-looking Dockerfile pointing at a binary that does not exist. The validation is the point at which a deployment mistake costs a test failure instead of a failed production rollout.
Current state
apps/majordomus-cli/src/deploy/ exists and parses the deployment object into typed structures, and apps/majordomus-cli/src/capability/builtin/deploy.rs projects it through the registry. As with I0901 the work reached master without ever being recorded against the issue. Measured on master 6042f4286, 2026-09-10; not marked complete here because this issue's validation has not been rerun against that tree.
Desired state
A deploy module parses the object into typed structures, validates every invariant that can be decided locally, and reports a failure that names the file, the key, what was wrong and what to do.
Scope
- apps/majordomus-cli/src/deploy
Out of scope
- Provider projection; that is I0913
- Any network call, any process spawn, any Fly API access
- A generic multi-provider trait hierarchy for a single provider
Dependencies
What waits on this
- I0903DONE Deployment reads are declared once and projected everywhere
- I0904DONE The listen address is one fact with two projections
- I0905DONE Liveness and readiness are registered capabilities, not router hacks
- I0907READY The running process says what it is, from an allowlist
- I0908READY A hosted process has no repository, and says so instead of failing
- I0909READY The production image is a generated projection of the build specification
- I0913CANCELLED The provider configuration is generated, and the cheap profile is declared
- I0918CANCELLED The bootstrap credential is used once and belongs to nothing
Acceptance criteria
- Ports, memory, CPU class, machine counts and routes are typed rather than strings, and an invalid value cannot be constructed
- Validation refuses zero memory, an invalid port, a health or readiness route that no capability registers, a package or binary the workspace does not contain, a build input that does not resolve, and a minimum running count above the machine count
- Every refusal names the source file, the key, the observed value and the correction
- Property tests cover the invariants that must hold for any accepted object, not merely the examples in the repository
- Unit tests cover each refusal
Validation
- cargo test --workspace --all-features
- cargo clippy --workspace --all-targets --all-features -- -D warnings
Evidence required
- typed_parse
- validation_refuses
- property_invariants
Evidence
| covers | type | command | result | at commit |
|---|---|---|---|---|
| typed_parse | test | cargo test --locked --manifest-path apps/majordomus-cli/Cargo.toml --lib deploy::tests | test result: ok. 30 passed; 0 failed (run 2026-10-14 between 07:40Z and 07:58Z on master ce5959db59) | ce5959d |
| validation_refuses | test | cargo test --locked --manifest-path apps/majordomus-cli/Cargo.toml --lib deploy::tests | test result: ok. 30 passed; 0 failed (run 2026-10-14 between 07:40Z and 07:58Z on master ce5959db59) | ce5959d |
| property_invariants | test | cargo test --locked --manifest-path apps/majordomus-cli/Cargo.toml --lib deploy::tests | test result: ok. 30 passed; 0 failed (run 2026-10-14 between 07:40Z and 07:58Z on master ce5959db59) | ce5959d |
Risk
Route validation needs the capability registry, which makes the deployment model depend on the index. Reading the registry that already exists is correct; building a second route list to avoid the dependency is not.
Timeline
- started
- 2026-10-14T08:00:59Z
- verified
- —
- completed
- 2026-10-14T08:01:10Z
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/I0902.yaml. Read it back with majordomus plan show I0902.