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.
BLOCKED wave 1 · p0 · implementation profile · parallel safe
Blocked. This issue cannot start until I0901 is done. The status is derived from that, not declared.
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
Nothing in apps/majordomus-cli reads a deployment object.
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
- I0903BLOCKED Deployment reads are declared once and projected everywhere
- I0904BLOCKED The listen address is one fact with two projections
- I0905BLOCKED Liveness and readiness are registered capabilities, not router hacks
- I0907BLOCKED The running process says what it is, from an allowlist
- I0908BLOCKED A hosted process has no repository, and says so instead of failing
- I0909BLOCKED The production image is a generated projection of the build specification
- I0913BLOCKED The provider configuration is generated, and the cheap profile is declared
- I0918BLOCKED 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
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
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
- —
- verified
- —
- completed
- —
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.