diff --git a/schemas/contract.schema.json b/schemas/contract.schema.json new file mode 100644 index 0000000..70d23c8 --- /dev/null +++ b/schemas/contract.schema.json @@ -0,0 +1,82 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://acdl.cloudinit.dev/schemas/contract.schema.json", + "title": "ACDL Contract", + "description": "Consumer-declared intent. The central pipeline resolves a contract to a Target Stack IR (schemas/ir.schema.json), the Terraform adapter compiles the IR to a plan. Strict fail-fast at schema stage with reason codes from a published vocabulary.", + "$comment": "Per-env mandatory inputs per W3.E (PROJECT.md). dev requires stack+environment; qa adds validation.e2eSuite + validation.loadTest; prod adds runbook+dashboard+oncall; dr adds drDrillRef. inputs always optional. profile: agentic fields optional everywhere (naturalLanguageIntent required when profile is agentic). W2.A (tag for dev/qa, SHA for prod) is a workflow-reference concern, not a schema field; the platform CLI resolves tag->SHA for prod-bound workflows.", + "type": "object", + "required": ["stack", "environment"], + "properties": { + "stack": { + "type": "string", + "pattern": "^l2-[a-z][a-z0-9-]*$", + "description": "L2 thin-composition reference (resolved by the pipeline to a Target Stack IR)." + }, + "environment": { + "type": "string", + "enum": ["dev", "qa", "prod", "dr"], + "description": "Target environment. Staging does not exist (Path A locked, ARCHITECTURE.md §5)." + }, + "inputs": { + "type": "object", + "description": "L2-level parameter map. Free-form in v1, typed per-L1 in v1.2 (W3.E).", + "additionalProperties": {"type": ["string", "number", "boolean"]} + }, + "validation": { + "type": "object", + "description": "Validation evidence required in qa (W3.E).", + "properties": { + "e2eSuite": {"type": "string", "description": "Reference to the contract-declared e2e suite (last 24h, pass rate >= 99%)."}, + "loadTest": {"type": "string", "description": "Reference to the load test report (last 7d, p99 < declared NFR)."} + } + }, + "runbook": {"type": "string", "description": "Runbook reference, mandatory in prod (W3.E)."}, + "dashboard": {"type": "string", "description": "Dashboard reference, mandatory in prod (W3.E)."}, + "oncall": {"type": "string", "description": "On-call rotation reference, mandatory in prod (W3.E)."}, + "drDrillRef": {"type": "string", "description": "DR drill report reference (last 180d), mandatory in dr (W3.E)."}, + "profile": { + "type": "string", + "enum": ["developer", "agentic"], + "default": "developer", + "description": "Consumer surface. 'agentic' unlocks L3B fields (ARCHITECTURE.md §5)." + }, + "naturalLanguageIntent": { + "type": "string", + "description": "L3B: the original natural-language prompt. Required when profile is agentic (W3.E)." + }, + "confidenceAtSubmission": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "L3B: the agent's self-reported confidence at submission time." + }, + "agentTrace": { + "type": "string", + "description": "L3B: reference to the agent's execution trace." + }, + "supersedes": { + "type": "string", + "format": "uuid", + "description": "Prior contractId this re-submission replaces (after rejection — ARCHITECTURE.md §10.6)." + } + }, + "allOf": [ + { + "if": {"properties": {"environment": {"const": "qa"}}}, + "then": {"required": ["validation"], + "properties": {"validation": {"required": ["e2eSuite", "loadTest"]}}} + }, + { + "if": {"properties": {"environment": {"const": "prod"}}}, + "then": {"required": ["runbook", "dashboard", "oncall"]} + }, + { + "if": {"properties": {"environment": {"const": "dr"}}}, + "then": {"required": ["drDrillRef"]} + }, + { + "if": {"required": ["profile"], "properties": {"profile": {"const": "agentic"}}}, + "then": {"required": ["naturalLanguageIntent"]} + } + ] +} \ No newline at end of file diff --git a/schemas/ir.schema.json b/schemas/ir.schema.json new file mode 100644 index 0000000..a0c508e --- /dev/null +++ b/schemas/ir.schema.json @@ -0,0 +1,118 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://acdl.cloudinit.dev/schemas/ir.schema.json", + "title": "ACDL Target Stack IR", + "description": "Substrate-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 thin-composition tree, contract YML, and PolicyCheckResult schema are all defined against this IR. Substrate adapters (the Terraform adapter in v1) are the only substrate-specific code.", + "$comment": "v1 ships one adapter (Terraform). The IR 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 IR gains expressiveness; the L1 content + contract YML + thin-composition tree do not change. The schema body is substrate-agnostic: no Terraform block keywords (variable/output/resource as blocks) and no aws_ provider prefixes in the schema keywords; type values are IR types (aws:s3:bucket), not Terraform resource types (aws_s3_bucket).", + "type": "object", + "required": ["version", "stack", "resources"], + "properties": { + "version": { + "type": "string", + "description": "IR schema version (semver).", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, + "stack": { + "type": "object", + "description": "The L1/L2 stack identity this IR represents.", + "required": ["name", "kind", "depth"], + "properties": { + "name": { + "type": "string", + "pattern": "^l[12]-[a-z][a-z0-9-]*$", + "description": "Stack name matching the L1/L2 folder name." + }, + "kind": { + "type": "string", + "enum": ["l1", "l2"], + "description": "l1 = primitive; l2 = thin-composition." + }, + "depth": { + "type": "integer", + "minimum": 1, + "maximum": 5, + "description": "Composition depth (ARCHITECTURE.md §3: max depth 5). L2->L1 is depth 1." + } + } + }, + "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 IR resource id (unique within the stack)." + }, + "type": { + "type": "string", + "description": "IR-typed resource identifier (substrate-agnostic), e.g. 'aws:s3:bucket'. NOT a Terraform resource type ('aws_s3_bucket'); the adapter translates IR type -> substrate type." + }, + "module": { + "type": "string", + "pattern": "^l1-[a-z][a-z0-9-]*@\\d+\\.\\d+\\.\\d+$", + "description": "L1 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 L1 module's declared inputs. Free-form in v1 (validated at contract->IR resolution against the L1 registry); typed per-L1 in v1.2.", + "additionalProperties": {"type": ["string", "number", "boolean"]} + }, + "outputs": { + "type": "object", + "description": "Typed output contract. The adapter translates this to a substrate 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": "IR-typed output type: a primitive ('string', 'arn') or a reference ('ref:.')." + }, + "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." + } + } + } + } +} \ No newline at end of file