{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://runninglake.com/schema/v1alpha1/aipolicy.json",
  "title": "AIPolicy",
  "description": "A AIPolicy as RunningLake's configuration repository declares it, at ai/policy.yaml. Generated from the Go types the control plane decodes this file into, so it checks the shape the gate reads — field names and types, and which fields may exist. The gate also applies rules no schema can express — required fields inside spec among them — so a file this schema accepts can still be refused by `rl diff`. Take #/properties/spec for the spec alone.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "apiVersion",
    "kind",
    "metadata"
  ],
  "properties": {
    "apiVersion": {
      "type": "string",
      "const": "runninglake.io/v1alpha1",
      "description": "The config schema's version, which is independent of the HTTP API's (rule unsupported-api-version)."
    },
    "kind": {
      "type": "string",
      "const": "AIPolicy",
      "description": "The kind this file declares. A kind that disagrees with the file's path is refused (rule kind-mismatch)."
    },
    "metadata": {
      "required": [
        "name"
      ],
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^[a-z0-9_-]{1,63}$",
          "description": "The resource's name, which is also its path segment. It must be the name this file's path gives it (rule name-mismatch)."
        },
        "labels": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "annotations": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        }
      }
    },
    "spec": {
      "description": "AIPolicySpec is what AI may do in one project, and for how long it may keep what it sees. One per project, named default, at ai/policy.yaml, the same in every environment. Recorded and checked here; nothing asks it before an AI task starts yet, so it limits nothing today.",
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": false,
      "properties": {
        "enabled": {
          "description": "Enabled turns AI on for the project. Left out, it follows the plan: on for a trial, off for a team. Turning it on needs an owner or admin to approve.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "sampling": {
          "description": "Sampling lets AI read sample rows and column profiles. Default off. Turning it on needs an owner or admin to approve.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "promptText": {
          "description": "PromptText keeps the prompts and replies of the project's AI tasks, for a few days. Default off, and never offered on a trial. Turning it on needs an owner or admin to approve, with a fresh sign-in.",
          "type": [
            "object",
            "null"
          ],
          "additionalProperties": false,
          "properties": {
            "enabled": {
              "description": "Enabled keeps prompt text. Default off.",
              "type": [
                "boolean",
                "null"
              ]
            },
            "retentionDays": {
              "description": "RetentionDays is how many days prompt text is kept: 1 to 30. A longer period needs an owner or admin to approve.",
              "type": [
                "integer",
                "null"
              ],
              "minimum": -9223372036854775808,
              "maximum": 9223372036854775807
            }
          }
        },
        "excludedLayers": {
          "description": "ExcludedLayers are the layers AI never reads. Left out, every restricted layer is excluded; written, the list is the whole exclusion, so an empty list excludes none. Removing a layer from it, and writing it where it was left out, need an owner or admin to approve. Once the project declares a layer, a name that no Layer declares is refused, because it would exclude nothing; before that, a name that is no layer excludes nothing.",
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "release": {
          "description": "Release is the AI release the project uses: follow_default, or the id of one to pin. Default follow_default. Pinning a release, or moving the pin, needs an owner or admin to approve.",
          "type": [
            "string",
            "null"
          ]
        },
        "logExcerpts": {
          "description": "LogExcerpts lets a failed task's log lines be sent to the model. Default off. Turning it on needs an owner or admin to approve.",
          "type": [
            "boolean",
            "null"
          ]
        }
      }
    }
  }
}
