{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://forms.takoform.com/schemas/v1/form-definition.schema.json",
  "title": "Takoform data-only Form Definition v1",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "apiVersion",
    "kind",
    "definitionVersion",
    "title",
    "role",
    "requiresHostApi",
    "desiredSchema",
    "lifecycleCapabilities"
  ],
  "properties": {
    "apiVersion": {
      "type": "string",
      "maxLength": 320,
      "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$",
      "not": {
        "enum": [
          "forms.takoform.com/v1alpha1",
          "forms.takoform.com/v1alpha2"
        ]
      },
      "description": "Versionless namespaced DNS-like Form group. Current Forms version independently through definitionVersion and schemaDigest; a family-wide version is not part of their identity. Published family-versioned Definitions remain under their retained profile (decision 0049)."
    },
    "kind": {
      "type": "string",
      "pattern": "^[A-Z][A-Za-z0-9]{0,63}$"
    },
    "definitionVersion": {
      "type": "string",
      "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(\\.(0|[1-9][0-9]*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(\\+([0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*))?$"
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 160
    },
    "description": {
      "type": "string",
      "maxLength": 4096
    },
    "role": {
      "enum": [
        "identity",
        "revision",
        "deployment",
        "attachment",
        "policy"
      ],
      "description": "Closed resource role. Revisions are immutable snapshots and never declare the update capability; attachments and policies reference a parent resource; deleting an attachment or policy never deletes the parent."
    },
    "requiresHostApi": {
      "const": "forms.takoform.com/v1",
      "description": "The stable Host API lane this stable Form Definition profile requires. A host serving an earlier lane refuses this Form with unsupported_capability at install time, naming both identities (decisions 0039 and 0047)."
    },
    "constraints": {
      "type": "array",
      "uniqueItems": true,
      "maxItems": 32,
      "description": "The closed list of rules about RESOURCES this Form declares. These are not the shape of one schema node, so they are not expressible in the desired JSON Schema alone. The stable v1 profile adds orderedPair and uniqueBy for cross-property and per-list structural rules, plus four narrowly typed rules whose comparisons use resolved resource UIDs only: acyclic, distinctPair, uniquePair, and sameResolvedTarget. Every pointer is an RFC 6901 JSON Pointer into the desired instance, except sameResolvedTarget.through, which addresses each resolved member target.",
      "items": {
        "description": "One closed constraint variant. The kind selects exactly one object shape; unknown and cross-variant members are forbidden.",
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "reference"
            ],
            "properties": {
              "kind": {
                "const": "exclusive"
              },
              "reference": {
                "type": "string",
                "pattern": "^/[^/]+$"
              },
              "keyedBy": {
                "type": "string",
                "pattern": "^/[^/]+$"
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "list",
              "member",
              "total"
            ],
            "properties": {
              "kind": {
                "const": "sum"
              },
              "list": {
                "type": "string",
                "pattern": "^/[^/]+$"
              },
              "member": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "total": {
                "type": "integer"
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "property"
            ],
            "properties": {
              "kind": {
                "const": "claim"
              },
              "property": {
                "type": "string",
                "pattern": "^/[^/]+$"
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "output"
            ],
            "properties": {
              "kind": {
                "const": "hostAssigned"
              },
              "output": {
                "type": "string",
                "pattern": "^/[^/]+$"
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "references"
            ],
            "properties": {
              "kind": {
                "const": "orderedPair"
              },
              "references": {
                "type": "array",
                "minItems": 2,
                "maxItems": 2,
                "uniqueItems": true,
                "items": {
                  "$ref": "#/$defs/resolvedRelationPointer"
                }
              }
            },
            "description": "Requires the numeric value at the first required desired pointer to be less than or equal to the value at the second required desired pointer."
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "list",
              "member"
            ],
            "properties": {
              "kind": {
                "const": "uniqueBy"
              },
              "list": {
                "$ref": "#/$defs/resolvedRelationPointer"
              },
              "member": {
                "type": "string",
                "pattern": "^[^~/]{1,64}$"
              }
            },
            "description": "Requires the named required scalar member to be unique within each value of the declared object list."
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "reference"
            ],
            "properties": {
              "kind": {
                "const": "acyclic"
              },
              "reference": {
                "$ref": "#/$defs/resolvedRelationPointer"
              }
            },
            "description": "Rejects a relation edge that would close a cycle through this declared relation. Nodes and edges are compared by resolved UID."
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "references"
            ],
            "properties": {
              "kind": {
                "const": "distinctPair"
              },
              "references": {
                "type": "array",
                "minItems": 2,
                "maxItems": 2,
                "uniqueItems": true,
                "items": {
                  "$ref": "#/$defs/resolvedRelationPointer"
                }
              }
            },
            "description": "Requires the two declared relations to resolve to different UIDs."
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "references"
            ],
            "properties": {
              "kind": {
                "const": "uniquePair"
              },
              "references": {
                "type": "array",
                "minItems": 2,
                "maxItems": 2,
                "uniqueItems": true,
                "items": {
                  "$ref": "#/$defs/resolvedRelationPointer"
                }
              }
            },
            "description": "Allows at most one live resource of this Form kind to hold the ordered pair of resolved UIDs."
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "anchor",
              "members",
              "through"
            ],
            "properties": {
              "kind": {
                "const": "sameResolvedTarget"
              },
              "anchor": {
                "$ref": "#/$defs/resolvedRelationPointer"
              },
              "members": {
                "$ref": "#/$defs/resolvedListRelationPointer"
              },
              "through": {
                "$ref": "#/$defs/resolvedRelationPointer"
              }
            },
            "description": "Requires every members relation target, followed through its through relation, to resolve to the anchor UID."
          }
        ]
      }
    },
    "desiredSchema": {
      "$ref": "#/$defs/jsonSchema"
    },
    "observedSchema": {
      "$ref": "#/$defs/jsonSchema"
    },
    "outputSchema": {
      "$ref": "#/$defs/jsonSchema"
    },
    "immutableFields": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "type": "string",
        "pattern": "^(?:/(?:[^~/]|~0|~1)*)+$"
      }
    },
    "lifecycleCapabilities": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "enum": [
          "create",
          "read",
          "update",
          "delete",
          "import",
          "observe"
        ]
      }
    },
    "providedInterfaces": {
      "type": "array",
      "maxItems": 64,
      "uniqueItems": true,
      "items": {
        "$ref": "https://forms.takoform.com/schemas/interfaces/v1alpha1/interface-ref.schema.json"
      },
      "description": "Exact Interface contracts every resource of this Form provides."
    },
    "acceptedBindings": {
      "type": "array",
      "maxItems": 64,
      "uniqueItems": true,
      "items": {
        "$ref": "https://forms.takoform.com/schemas/bindings/v1alpha2/binding-ref.schema.json"
      },
      "description": "Exact Binding contracts resources of this Form may hold as a source. Only revision-role Forms hold capability bindings."
    },
    "conformanceFixtures": {
      "type": "array",
      "maxItems": 32,
      "uniqueItems": true,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "desiredPath"
        ],
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9._-]{0,127}$"
          },
          "desiredPath": {
            "$ref": "#/$defs/packagePath"
          },
          "observedPath": {
            "$ref": "#/$defs/packagePath"
          },
          "outputPath": {
            "$ref": "#/$defs/packagePath"
          }
        }
      }
    },
    "negativeConformanceFixtures": {
      "type": "array",
      "maxItems": 32,
      "uniqueItems": true,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "stage",
          "inputPath",
          "expectedFailure"
        ],
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9._-]{0,127}$"
          },
          "stage": {
            "enum": [
              "desired",
              "observed",
              "output"
            ]
          },
          "inputPath": {
            "$ref": "#/$defs/packagePath"
          },
          "expectedFailure": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9._-]{2,127}$"
          }
        }
      }
    }
  },
  "allOf": [
    {
      "if": {
        "properties": {
          "role": {
            "const": "revision"
          }
        },
        "required": [
          "role"
        ]
      },
      "then": {
        "properties": {
          "lifecycleCapabilities": {
            "items": {
              "enum": [
                "create",
                "read",
                "delete",
                "import",
                "observe"
              ]
            }
          }
        }
      }
    }
  ],
  "$defs": {
    "jsonSchema": {
      "type": "object",
      "required": [
        "$schema",
        "type"
      ],
      "properties": {
        "$schema": {
          "const": "https://json-schema.org/draft/2020-12/schema"
        },
        "type": {}
      }
    },
    "packagePath": {
      "type": "string",
      "minLength": 1,
      "maxLength": 240,
      "pattern": "^[A-Za-z0-9._-]+(/[A-Za-z0-9._-]+)*$",
      "not": {
        "pattern": "(^|/)\\.\\.?($|/)"
      }
    },
    "resolvedRelationPointer": {
      "type": "string",
      "pattern": "^(?:/(?:[^~/*]|~0|~1)+)+$"
    },
    "resolvedListRelationPointer": {
      "type": "string",
      "pattern": "^(?:/(?:[^~/*]|~0|~1)+)+/\\*(?:/(?:[^~/*]|~0|~1)+)*$"
    }
  }
}
