{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://heartcortex.ai/schemas/1.0/action.schema.json",
  "title": "Action",
  "description": "One request to do something, and its whole story. Carries exactly one of capability or operation.",
  "type": "object",
  "required": [
    "id",
    "status",
    "risk",
    "createdAt"
  ],
  "oneOf": [
    {
      "required": [
        "capability"
      ],
      "not": {
        "required": [
          "operation"
        ]
      }
    },
    {
      "required": [
        "operation"
      ],
      "not": {
        "required": [
          "capability"
        ]
      }
    }
  ],
  "properties": {
    "id": {
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "public",
      "description": "The Action ID: the actionId the client chose in its request, or one the system chose (API Standard 6.3, rule 1)."
    },
    "capability": {
      "$ref": "common.schema.json#/$defs/capabilityName",
      "x-heart-privacy": "public",
      "description": "The capability being run. Exactly one of capability or operation is present."
    },
    "status": {
      "enum": [
        "awaiting-approval",
        "approved",
        "running",
        "succeeded",
        "failed",
        "denied",
        "cancelled",
        "expired",
        "cancelling",
        "refused"
      ],
      "x-heart-privacy": "public",
      "description": "awaiting-approval: held for a person. approved: may run. running: being carried out. cancelling: a cancel was asked for and takes effect at the next safe point (D30). succeeded, failed, denied (a person said no), refused (the system said no: a guard, a precondition or the mode), cancelled, expired (no decision in time)."
    },
    "risk": {
      "$ref": "common.schema.json#/$defs/risk",
      "x-heart-privacy": "public",
      "description": "The risk the gate applied: the capability's or operation's own risk, raised to destructive where API Standard 6.3 says so (a physical Action started by ai or peer, or a change to authority)."
    },
    "digest": {
      "description": "SHA-256 over the RFC 8785 canonical JSON of {\"system\", \"id\", \"operation\", \"arguments\", \"physical\"}, where operation is the capability name or the operation string. Fixed once awaiting approval. For the first Action of a Trial it also covers every later step's arguments and the values the undo will restore (Core Standard 7.5).",
      "$ref": "common.schema.json#/$defs/sha256",
      "x-heart-privacy": "internal"
    },
    "createdAt": {
      "$ref": "common.schema.json#/$defs/timestamp",
      "x-heart-privacy": "public"
    },
    "updatedAt": {
      "$ref": "common.schema.json#/$defs/timestamp",
      "x-heart-privacy": "public"
    },
    "expiresAt": {
      "description": "When an Action still awaiting approval expires. Set from the control policy's approvalTimeoutSec (default 24 hours).",
      "$ref": "common.schema.json#/$defs/timestamp",
      "x-heart-privacy": "public"
    },
    "dryRun": {
      "type": "boolean",
      "x-heart-privacy": "public"
    },
    "initiator": {
      "type": "object",
      "x-heart-privacy": "internal",
      "required": [
        "kind"
      ],
      "properties": {
        "kind": {
          "enum": [
            "human",
            "peer",
            "ai",
            "rule"
          ]
        },
        "id": {
          "type": "string",
          "x-heart-privacy": "private"
        },
        "onBehalfOf": {
          "description": "Principal whose authority an AI-initiated action runs under.",
          "type": "string",
          "x-heart-privacy": "private"
        }
      }
    },
    "arrhythmiaId": {
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "internal"
    },
    "explanation": {
      "type": "string",
      "x-heart-privacy": "internal"
    },
    "decision": {
      "type": "object",
      "x-heart-privacy": "internal",
      "required": [
        "decision",
        "at"
      ],
      "properties": {
        "decision": {
          "enum": [
            "approve",
            "deny",
            "cancel"
          ],
          "description": "cancel is accepted while the Action is awaiting approval, approved, or running with cancellable true. It needs no proof of presence, because it can only lower risk."
        },
        "at": {
          "$ref": "common.schema.json#/$defs/timestamp"
        },
        "by": {
          "type": "string",
          "x-heart-privacy": "private"
        },
        "note": {
          "type": "string",
          "x-heart-privacy": "private"
        },
        "presenceMethod": {
          "$ref": "common.schema.json#/$defs/presence/properties/method"
        }
      }
    },
    "arguments": {
      "type": "object",
      "x-heart-privacy": "private"
    },
    "result": {
      "x-heart-privacy": "private"
    },
    "error": {
      "type": "string",
      "x-heart-privacy": "internal",
      "description": "Plain-language reason it failed."
    },
    "progress": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "x-heart-privacy": "public",
      "description": "Share done, 0 to 1. A cancelled Action keeps the share that was done before it stopped."
    },
    "operation": {
      "description": "The API operation behind this Action when it is not a capability, written \"METHOD /path\", such as \"PUT /heart/v1/tending/autonomy\". Exactly one of capability or operation is present.",
      "type": "string",
      "pattern": "^(GET|POST|PUT|PATCH|DELETE) /heart/v1/[^\\s]*$",
      "x-heart-privacy": "internal"
    },
    "physical": {
      "type": "boolean",
      "x-heart-privacy": "public"
    },
    "proposalId": {
      "description": "The Proposal this Action came from (Core Standard, Section 7.3).",
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "internal"
    },
    "trialId": {
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "internal"
    },
    "scheduleId": {
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "internal",
      "description": "The schedule whose run this Action is (module schedules)."
    },
    "approvedBy": {
      "description": "For a later step or the undo of a Trial: the id of the Trial's first Action, whose approval covered the whole plan. Such Actions pass guards, not the gate (Core Standard 7.5).",
      "$ref": "common.schema.json#/$defs/uuid",
      "x-heart-privacy": "internal"
    },
    "cancellable": {
      "type": "boolean",
      "x-heart-privacy": "public",
      "description": "True while a cancel can still take effect at a safe point. A running Action with cancellable false answers a cancel with 409 conflict (D30)."
    },
    "nextReachableAt": {
      "anyOf": [
        {
          "$ref": "common.schema.json#/$defs/timestamp"
        },
        {
          "type": "null"
        }
      ],
      "x-heart-privacy": "public",
      "description": "shutdown, sleep, restart and power-cycle: when the system expects to answer again (API Standard 13.2 rule 3). null when it cannot know; nextReachableNote then says why."
    },
    "nextReachableNote": {
      "type": "string",
      "x-heart-privacy": "internal",
      "description": "Why nextReachableAt is null, in plain words, for example 'Until someone presses the button'."
    },
    "ext": {
      "$ref": "common.schema.json#/$defs/ext",
      "x-heart-privacy": "private"
    }
  }
}
