031887ec56
Contract surface redesign: - New top-level fields: id (3-6 char acronym → stack.name), name (full → stack.title), infrastructure (map keyed by module name, replaces module:) - Drop uses: field (dead reference; version pin lives in CI workflow uses: line) - Drop top-level module/inputs (now nested under infrastructure map) - Per-module optional version (defaults to latest published from registry) - Multi-module contracts: one file deploys N modules in one pipeline run, resource IDs namespaced with module name to avoid collisions - stack.schema.json: add optional title field for display name Rename: - pipelines/deploy.yaml → pipelines/contract.yml (declarative spec, not a pipeline) - pipelines/ci.yaml → pipelines/ci.yml - All 44 .yaml files → .yml repo-wide (contracts, module examples, kyverno policies) - .acdl/contract.yaml → .acdl/contract.yml Resolver (core/contract_resolver.py): - Rewrite resolve() to loop infrastructure map, default version to latest, merge module fragments into one stack with namespaced resource IDs - _latest_version() picks highest non-deprecated from registry - _namespace_resources() prefixes IDs + rewrites ref: expressions for multi-module - Single-module path: unprefixed IDs (backward compatible) Verification: - 494 tests pass (0 contract-shape failures) - Local E2E passes (contract → resolver → adapter → local ECS HTTP 200 → outbox) ---ci--- project: acdl phase: 57 milestone: v1.10.2 status: execute ---/ci---
103 lines
3.6 KiB
Markdown
103 lines
3.6 KiB
Markdown
# Contracts
|
|
|
|
A consumer declares intent in a **contract** — a small YAML file that
|
|
names infrastructure (one or more modules), selects an environment, and
|
|
supplies module-specific inputs. The platform validates, resolves, and
|
|
deploys it.
|
|
|
|
## The contract file
|
|
|
|
A consumer repo keeps its contract at `.acdl/contract.yml`. A minimal
|
|
example (the `static-assets` module):
|
|
|
|
```yaml
|
|
id: assets
|
|
name: static-assets
|
|
environment: dev
|
|
infrastructure:
|
|
static-assets:
|
|
version: "1.0.0"
|
|
inputs:
|
|
bucket_name: my-static-site-assets
|
|
region: us-east-1
|
|
```
|
|
|
|
A `microservice` example:
|
|
|
|
```yaml
|
|
id: msvc
|
|
name: microservice
|
|
environment: dev
|
|
infrastructure:
|
|
microservice:
|
|
version: "1.0.0"
|
|
inputs:
|
|
image: my-registry/my-microservice:latest
|
|
port: 8080
|
|
env:
|
|
LOG_LEVEL: info
|
|
```
|
|
|
|
## Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `id` | string | yes | Short operational acronym (3-6 chars, `^[a-z][a-z0-9-]{2,5}$`). Becomes the stack name used for the Terraform state key, ECS service name, outbox event identity, and resource naming prefix. |
|
|
| `name` | string | yes | Full human-readable stack name (min 3 chars). Becomes the stack title used for display in PR comments, evidence records, and leadership dashboards. |
|
|
| `environment` | string | yes | The platform-managed environment to deploy to (`dev`/`qa`/`prod`/`dr`). See [Environments](../environments/). |
|
|
| `infrastructure` | object | yes | Map of modules to deploy, keyed by module registry name. Each entry has an optional `version` (defaults to latest published) and required `inputs`. One entry = single-module deploy; N entries = multi-module manifest deployed in one pipeline run. |
|
|
|
|
### Infrastructure entry fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `version` | string | no | Module version pin (semver `X.Y.Z`). Omitted = latest non-deprecated version from the registry. |
|
|
| `inputs` | object | yes | Module-specific inputs (see the module's README). |
|
|
|
|
## Validation
|
|
|
|
The contract is validated against
|
|
[`schemas/contract.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/contract.schema.json).
|
|
An invalid contract (missing field, unknown module, wrong type) fails at the
|
|
validate-contract stage with a clear error.
|
|
|
|
## Sample contracts
|
|
|
|
Two reference examples exist in `contracts/`:
|
|
|
|
- [`contracts/static-assets.yml`](https://github.com/acdl/acdl/blob/main/contracts/static-assets.yml)
|
|
— the `static-assets` module.
|
|
- [`contracts/microservice.yml`](https://github.com/acdl/acdl/blob/main/contracts/microservice.yml)
|
|
— the `microservice` module.
|
|
|
|
Additionally, every module has a `modules/<name>/examples/` directory with
|
|
validated example contracts (`simple.yml` + `complex.yml` + variation
|
|
files). See the [module catalog](../modules/) for the full list.
|
|
|
|
## Multiple modules per contract
|
|
|
|
A contract may declare multiple modules under the `infrastructure` map.
|
|
All modules deploy to the same `environment` in one pipeline run. Resource
|
|
IDs are namespaced with the module name to avoid collisions (e.g.
|
|
`microservice-vpc`, `static-assets-s3`).
|
|
|
|
```yaml
|
|
id: app
|
|
name: pricing-service-api
|
|
environment: dev
|
|
infrastructure:
|
|
microservice:
|
|
version: "1.0.0"
|
|
inputs: { ... }
|
|
static-assets:
|
|
version: "1.0.0"
|
|
inputs: { ... }
|
|
```
|
|
|
|
## Multiple contracts
|
|
|
|
A consumer repo may also contain more than one contract file (e.g. one per
|
|
environment). Each contract is a separate deployment; each is referenced by a
|
|
CI definition in `.github/workflows/` that invokes the central reusable
|
|
workflow with the contract path. See the
|
|
[Consumer Guide](../consumer-guide/) for the multi-contract pattern. |