I0901 — The deployment description is a kind of the layer, not a provider file
Register `deployment` as a kind of the AI layer — allowed keys, schema, directory contract — and describe this repository's own deployment as one object under .ai/repo/deployments/, so that every later projection reads one file and no provider file is ever authoritative.
DONE wave 0 · p0 · deep-work profile · parallel safe
Objective
Register `deployment` as a kind of the AI layer — allowed keys, schema, directory contract — and describe this repository's own deployment as one object under .ai/repo/deployments/, so that every later projection reads one file and no provider file is ever authoritative.
Why
A Dockerfile and a fly.toml written by hand would restate the port, the routes, the resources and the build inputs that the repository already knows. The layer already has a mechanism for canonical facts: a kind, its allowed keys, its schema and its directory contract. Deployment is a kind, and everything downstream is a projection.
Current state
The kind exists on the trunk: share/kinds.yaml declares deployment against the schema majordomus.deployment/v1, share/allow/deployment.txt closes its keys and is generated from that schema, and .ai/repo/deployments/majordomus.yaml describes this repository's own deployment beside the directory's README. The work reached master with feature/deployment-core and nothing was ever recorded against this issue, so the milestone reads PLANNED 0/32 while its first artifacts are on the trunk. Measured on master 6042f4286, 2026-09-10; not marked complete here because this issue's own validation (bash test/run.sh, bin/majordomus doctor) has not been rerun against that tree.
Desired state
A deployment object is indexed, readable through the same object surface as every other kind, closed by an allow file, described by a schema, and living in a directory that carries its own context document.
Scope
- .ai/repo/deployments
- share/kinds.yaml
- share/allow/deployment.txt
- share/schemas
Out of scope
- Any provider artifact; this issue writes no Dockerfile and no fly.toml
- Any Rust; the typed model is I0902
- Any secret value, credential name or token
Dependencies
None. This issue is a root of the graph.
What waits on this
- I0902DONE The deployment object becomes typed Rust that refuses nonsense
- I0924CANCELLED The decision is recorded where architecture decisions are recorded
Acceptance criteria
- The object states the generic deployment facts — application identity, package and binary, listen port, health and readiness routes, resources, machine count, region, autostart and autostop, build inputs, budgets — and keeps provider-specific facts in a named provider block rather than mixed through the generic ones
- Keys are closed by share/allow/deployment.txt and an unknown key is refused
- The directory carries a context README that says what is authoritative, what is generated and how to regenerate it, per ADR 0011
- The object is listed and read through the existing object surface with no code that special-cases it
- No secret value or credential name appears in the object
Validation
- bash test/run.sh
- bin/majordomus doctor
Evidence required
- kind_registered
- keys_closed
- directory_contract
- object_indexed
Evidence
| covers | type | command | result | at commit |
|---|---|---|---|---|
| kind_registered | artifact | grep -n -A3 '^ deployment:' share/kinds.yaml | share/kinds.yaml declares kind deployment against schema majordomus.deployment/v1; share/allow/deployment.txt (41 keys) is generated from that schema | f075170 |
| object_indexed | test | bin/majordomus-cli run objects.list --input '{\"kind\":\"deployment\"}' --format json; bin/majordomus-cli run objects.get --input '{\"uri\":\"majordomus://deployment/majordomus\"}' | objects.list returns one object majordomus://deployment/majordomus at .ai/repo/deployments/majordomus.yaml; objects.get reads it (state succeeded); the generic object surface, no deployment-specific listing code | f075170 |
| keys_closed | test | bash test/run.sh 84_deployment_contract | ok 84_deployment_contract: doctor refuses an unknown key by name (key(s) the contract does not have: fly_api_token), a foreign schema, a missing region, a credential, a duplicate identity; the restored object is accepted | f075170 |
| directory_contract | artifact | grep -nE 'uthoritative|enerated|egenerat' .ai/repo/deployments/README.md; bin/majordomus doctor | grep deployment | the context/v1 README ai.repo.deployments has sections 'What is authoritative and what is generated' and 'Regenerate' (ADR 0011); doctor: OK deployment .ai/repo/deployments/ — 1 deployment(s), no credential, one identity each | f075170 |
Risk
A schema written for one deployment becomes either a Kubernetes-grade abstraction nobody needs or a Fly file with a different extension. It has to be generic where a second provider would plausibly reuse it and concrete everywhere else.
Timeline
- started
- 2026-10-04T09:55:21Z
- verified
- 2026-10-04T09:59:52Z
- completed
- 2026-10-04T10:00:11Z
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/I0901.yaml. Read it back with majordomus plan show I0901.