{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://nova.cloudinit.dev/schemas/stack.schema.json",
  "title": "Nova 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", "array", "object"]}
        },
        "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."
        }
      }
    }
  }
}