{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://theamateur.co.uk/schemas/dpl/dpl.takes-1.schema.json",
  "title": "DPL take log (dpl.takes/1)",
  "description": "What was actually shot, logged on set against a plan's shot ids: one entry per recording, with its verdict, slate, camera files and timecodes. Entries are never edited; a correction is a new entry that names the one it replaces in `supersedes`. The same `op_id` with the same content is one take. This schema describes exactly what the dpl reader accepts: unknown members, misspelt terms and fractional numbers are refused.",
  "$comment": "Structure only. `dpl takes validate <plan> <takes>` also checks what a schema cannot: that each shot id is in the plan, that `supersedes` names an entry that exists and does not loop, that one `op_id` is not used for two different takes, slates that fit their system, and that the work is the plan's. A log that passes this schema is readable; it is valid only when `dpl takes validate` reports no error. `plan_hash` is the SHA-256 that `dpl readiness` reports.",
  "type": "object",
  "properties": {
    "format": {
      "type": "string",
      "const": "dpl.takes/1"
    },
    "work_id": {
      "description": "The work these takes belong to (the plan's work.id).",
      "type": "string",
      "pattern": "\\S"
    },
    "plan_hash": {
      "description": "The plan revision the shot ids were taken from (the SHA-256 that dpl readiness reports as plan_hash). When it differs from the plan being checked, a shot id may have moved.",
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9a-f]{64}$"
    },
    "takes": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/TakeEntry"
      }
    }
  },
  "required": [
    "format",
    "work_id",
    "takes"
  ],
  "additionalProperties": false,
  "$defs": {
    "Slate": {
      "type": "object",
      "description": "What was written on the slate. American slates give scene and angle (the take number is the take's own take); European slates give number (and the camera letter is the take's own camera).",
      "properties": {
        "system": {
          "$ref": "#/$defs/SlateSystem"
        },
        "scene": {
          "description": "American: the scene as slated (\"24\", \"12A\").",
          "type": [
            "string",
            "null"
          ]
        },
        "angle": {
          "description": "American: the camera angle or setup letter as slated (\"C\").",
          "type": [
            "string",
            "null"
          ]
        },
        "number": {
          "description": "European: the running slate number (\"256\").",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "system"
      ],
      "additionalProperties": false
    },
    "SlateSystem": {
      "type": "string",
      "description": "Which of the two slate conventions a take was slated in.",
      "enum": [
        "american",
        "european"
      ]
    },
    "TakeEntry": {
      "type": "object",
      "description": "One recording against one planned shot. Corrections are new entries with supersedes; nothing is edited in place.",
      "properties": {
        "op_id": {
          "description": "Names this entry for good. The same op_id logged twice with the same content is one take, so a retry or a merge never doubles a take. The same op_id with different content is a conflict.",
          "type": "string",
          "pattern": "^\\S{1,128}$"
        },
        "supersedes": {
          "description": "The op_id of the entry this one corrects. The corrected entry stops counting; it stays in the log.",
          "type": [
            "string",
            "null"
          ]
        },
        "shot": {
          "description": "The plan's shot id this recording is for.",
          "type": "string"
        },
        "setup": {
          "description": "The camera setup it was recorded from, when the plan's setup for the shot is not what the crew used.",
          "type": [
            "string",
            "null"
          ]
        },
        "take": {
          "description": "The take number (1 or more). A take with none is allowed: real logs have takes nobody numbered.",
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "slate": {
          "description": "The slate shown to camera, when there was one. A take with no slate is allowed.",
          "anyOf": [
            {
              "$ref": "#/$defs/Slate"
            },
            {
              "type": "null"
            }
          ]
        },
        "camera": {
          "description": "The camera letter (A, B, C, ...) of the camera that recorded it.",
          "type": [
            "string",
            "null"
          ],
          "pattern": "^[A-Z]{1,2}$"
        },
        "files": {
          "description": "The camera files this take made, one or more per camera. File names only, never paths.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/TakeFile"
          }
        },
        "kind": {
          "$ref": "#/$defs/TakeKind"
        },
        "verdict": {
          "$ref": "#/$defs/TakeVerdict"
        },
        "duration_ms": {
          "description": "How long the take ran, in whole milliseconds.",
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "note": {
          "type": [
            "string",
            "null"
          ]
        },
        "logged_at": {
          "description": "When it was logged: an ISO 8601 date and time with its offset, such as 2026-10-18T14:05:00+01:00.",
          "type": [
            "string",
            "null"
          ],
          "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})$"
        },
        "by": {
          "description": "Who logged it (a person, a device or an agent).",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "op_id",
        "shot",
        "kind",
        "verdict"
      ],
      "additionalProperties": false
    },
    "TakeFile": {
      "type": "object",
      "description": "One camera file a take made. The name is the file's own name, so the person's editing software can relink to it.",
      "properties": {
        "camera": {
          "description": "The camera that wrote the file (a letter).",
          "type": "string",
          "pattern": "^[A-Z]{1,2}$"
        },
        "name": {
          "description": "The file name only, such as A001C002_261018.mov.",
          "type": "string",
          "pattern": "^[^/\\\\]+$"
        },
        "tc_in": {
          "description": "Timecode at the start of the take in this file, HH:MM:SS:FF (HH:MM:SS;FF for drop frame).",
          "type": [
            "string",
            "null"
          ],
          "pattern": "^\\d{2}:\\d{2}:\\d{2}[:;]\\d{2,3}$"
        },
        "tc_out": {
          "type": [
            "string",
            "null"
          ],
          "pattern": "^\\d{2}:\\d{2}:\\d{2}[:;]\\d{2,3}$"
        }
      },
      "required": [
        "camera",
        "name"
      ],
      "additionalProperties": false
    },
    "TakeKind": {
      "type": "string",
      "description": "What kind of recording a take is. Only full and pickup can give the edit picture.",
      "enum": [
        "full",
        "pickup",
        "wild_track",
        "rehearsal",
        "room_tone"
      ]
    },
    "TakeVerdict": {
      "type": "string",
      "description": "The call made on a take. hold is the script supervisor's \"not wanted now, may be used\"; circled is the take the director chose to print (OMC circleTake).",
      "enum": [
        "good",
        "no_good",
        "hold",
        "circled"
      ]
    }
  }
}
