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---
138 lines
6.5 KiB
JSON
138 lines
6.5 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://acdl.cloudinit.dev/schemas/stack.schema.json",
|
|
"title": "ACDL Target Stack",
|
|
"description": "Angine-neutral description of a target stack: resources with typed inputs/outputs/NFRs, relationships (single parent per child), composition tree (max depth 5), and policy hooks. The L1 registry, L2 composition tree, contract YML, and PolicyCheckResult schema are all defined against this stack schema. Angine adapters (the Terraform adapter in v1) are the only engine-specific code.",
|
|
"$comment": "v1 ships one adapter (Terraform). The stack is nearly isomorphic to Terraform in v1 (ARCHITECTURE.md §12.1); the adapter compiles resource.module -> module block, resource.inputs -> variable + arg, resource.outputs -> output, relationship.kind=uses_output -> interpolation, relationship.kind=parent -> composition ordering hint. As more adapters appear (v2+), the stack gains expressiveness; the L1 content + contract YML + composition tree do not change. The schema body is engine-agnostic: no Terraform block keywords (variable/output/resource as blocks) and no aws_ provider prefixes in the schema keywords; type values are stack types (aws:s3:bucket), not Terraform resource types (aws_s3_bucket).",
|
|
"type": "object",
|
|
"required": ["version", "stack", "resources"],
|
|
"properties": {
|
|
"version": {
|
|
"type": "string",
|
|
"description": "Stack schema version (semver).",
|
|
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
|
},
|
|
"stack": {
|
|
"type": "object",
|
|
"description": "The L1/L2 stack identity this instance represents.",
|
|
"required": ["name", "kind", "depth"],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"pattern": "^[a-z][a-z0-9-]*$",
|
|
"description": "Operational stack identity (short acronym from the contract id). Used for the Terraform state key (spike/<name>/terraform.tfstate), the ECS service name, and the outbox event identity."
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"description": "Human-readable stack name (from the contract name). Used for display in PR comments, evidence records, and leadership dashboards. Optional; omitted when the contract does not provide a name."
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"enum": ["l1", "l2"],
|
|
"description": "l1 = primitive; l2 = composition."
|
|
},
|
|
"depth": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 5,
|
|
"description": "Composition depth (ARCHITECTURE.md §3: max depth 5). L2->L1 is depth 1."
|
|
},
|
|
"features": {
|
|
"type": "object",
|
|
"description": "Optional feature flags for L2 modules (e.g. deletion_protection, uptime_enabled).",
|
|
"properties": {
|
|
"deletion_protection": {
|
|
"type": "boolean",
|
|
"description": "When true (default), all children get deletion_protection NFR. Set to false to disable (used by decommission).",
|
|
"default": true
|
|
},
|
|
"uptime_enabled": {
|
|
"type": "boolean",
|
|
"description": "When true (default), the uptime monitoring stack is deployed after the L2 module.",
|
|
"default": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"resources": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": {"$ref": "#/$defs/resource"}
|
|
},
|
|
"relationships": {
|
|
"type": "array",
|
|
"description": "Optional in v1; present when the adapter needs explicit ordering/output wiring hints beyond parent composition.",
|
|
"items": {"$ref": "#/$defs/relationship"}
|
|
}
|
|
},
|
|
"$defs": {
|
|
"resource": {
|
|
"type": "object",
|
|
"required": ["id", "type", "module", "inputs"],
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"pattern": "^[a-z][a-z0-9-]*$",
|
|
"description": "Local stack resource id (unique within the stack)."
|
|
},
|
|
"type": {
|
|
"type": "string",
|
|
"description": "Stack-typed resource identifier (engine-agnostic), e.g. 'aws:s3:bucket'. NOT a Terraform resource type ('aws_s3_bucket'); the adapter translates stack type -> engine type."
|
|
},
|
|
"module": {
|
|
"type": "string",
|
|
"pattern": "^[a-z][a-z0-9-]*@\\d+\\.\\d+\\.\\d+$",
|
|
"description": "Module registry reference: name@semver (W3.D). MAJOR bumps require a new registry entry (immutable publication); old entry enters a 12-month deprecation window."
|
|
},
|
|
"parent": {
|
|
"type": "string",
|
|
"description": "Parent resource id. Absent for the root. Single parent per child (ARCHITECTURE.md §12.1)."
|
|
},
|
|
"inputs": {
|
|
"type": "object",
|
|
"description": "Input values keyed by the module's declared inputs. Free-form in v1 (validated at contract->stack resolution against the module registry); typed per-module in v1.2.",
|
|
"additionalProperties": {"type": ["string", "number", "boolean"]}
|
|
},
|
|
"outputs": {
|
|
"type": "object",
|
|
"description": "Typed output contract. The adapter translates this to a engine output block (e.g. Terraform output).",
|
|
"additionalProperties": {"$ref": "#/$defs/outputSpec"}
|
|
},
|
|
"nfrs": {
|
|
"type": "object",
|
|
"description": "Declared non-functional requirements (latency, throughput, error rate). Opaque to the adapter; consumed by the confidence signal's NFR input.",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
},
|
|
"outputSpec": {
|
|
"type": "object",
|
|
"required": ["type"],
|
|
"properties": {
|
|
"type": {
|
|
"type": "string",
|
|
"description": "Stack-typed output type: a primitive ('string', 'arn') or a reference ('ref:<resourceId>.<outputName>')."
|
|
},
|
|
"description": {"type": "string"}
|
|
}
|
|
},
|
|
"relationship": {
|
|
"type": "object",
|
|
"required": ["from", "to", "kind"],
|
|
"properties": {
|
|
"from": {"type": "string", "description": "Source resource id."},
|
|
"to": {"type": "string", "description": "Target resource id."},
|
|
"kind": {
|
|
"type": "string",
|
|
"enum": ["parent", "depends_on", "uses_output"],
|
|
"description": "v1 uses 'parent' (composition ordering) + 'uses_output' (interpolation). 'depends_on' is reserved for v2 explicit-dependency cases."
|
|
},
|
|
"shared_keyword": {
|
|
"type": "string",
|
|
"description": "Reserved for v2 multi-relationship dependencies. Unused in v1."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |