core/env.py dual-read helper (D-108); 21 ACDL_*→NOVA_* env vars migrated across core/scripts/adapters/tests/workflows + .env/.env.secrets (key rename, values stay). G-106 binding: run_platform.sh:288-289 + regression_verify.py:309-312 dual-read (NOVA first, ACDL fallback). G-108 binding: Gitea NOVA_* secrets created via API + workflow secrets: refs updated (deploy.yml + modules-lifecycle.yml, .gitea + .github). acdl_tagging.py→nova_tagging.py (D-109 warn mode, nova:* enforced). .acdl/→.nova/ consumer path (resolver + deploy workflow + schema + tests + docs). Test fixtures updated; pytest + run_ci.sh PASS. ---ci--- project: acdl phase: 2 milestone: v1.15 status: execute ---/ci---
3.6 KiB
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 .nova/contract.yml. A minimal
example (the static-assets module):
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:
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. |
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.
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— thestatic-assetsmodule.contracts/microservice.yml— themicroservicemodule.
Additionally, every module has a modules/<name>/examples/ directory with
validated example contracts (simple.yml + complex.yml + variation
files). See the module catalog 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).
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 for the multi-contract pattern.