{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://law.arxo.io/schema/task-guide-journal.schema.json",
  "title": "Arxo task guide passage journal 0.1",
  "description": "The journal of one passage of a task guide, written and checked by `law guide journal`. It records the steps taken, the answers attached (by path and hashes copied from the evaluation documents), the person's decisions and the document sections assembled by copying values from earlier records. It is outside the evaluation document and adds nothing to its byte contract; it computes nothing, chooses nothing among several values and has no defaults. `law guide journal check` replays the entries over the guide's step graph, re-reads the attached answers, re-assembles the sections and recomputes `state`; a completed state means the declared steps were performed, not the legal sufficiency of the document.",
  "$comment": "law.task-guide-journal/0.1; DECISION-0414",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "format",
    "guide",
    "context",
    "entries",
    "state"
  ],
  "properties": {
    "format": {
      "const": "law.task-guide-journal/0.1"
    },
    "guide": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "package",
        "id",
        "version",
        "catalogHash",
        "locator"
      ],
      "properties": {
        "package": {
          "type": "string",
          "minLength": 1
        },
        "id": {
          "$ref": "#/$defs/Id"
        },
        "version": {
          "type": "string",
          "minLength": 1
        },
        "catalogHash": {
          "$ref": "#/$defs/Sha256",
          "description": "sha256 of the exact bytes of the task-guide catalog the passage started with; a changed catalog refuses further records."
        },
        "locator": {
          "oneOf": [
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "package"
              ],
              "properties": {
                "package": {
                  "type": "string",
                  "minLength": 1,
                  "description": "Owner package directory relative to the journal's directory."
                }
              }
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "dependency",
                "project"
              ],
              "properties": {
                "dependency": {
                  "type": "string",
                  "minLength": 1
                },
                "project": {
                  "type": "string",
                  "minLength": 1,
                  "description": "Project directory (with law.lock and deps/) relative to the journal's directory."
                }
              }
            }
          ]
        }
      }
    },
    "case": {
      "type": "string",
      "minLength": 1,
      "description": "Label of the case; the case itself is given by the attached answers."
    },
    "context": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "legal_time"
      ],
      "properties": {
        "legal_time": {
          "type": "string",
          "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
          "description": "The date of law named by the person when the journal started; never today by default."
        },
        "decision_time": {
          "type": "string"
        },
        "knowledge_time": {
          "type": "string"
        },
        "timezone": {
          "type": "string"
        },
        "deadline_policy": {
          "type": "string",
          "description": "Copied from the case step of the guide."
        },
        "calendar": {
          "type": "string",
          "description": "Copied from the case step of the guide."
        }
      }
    },
    "entries": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Entry"
      }
    },
    "state": {
      "$ref": "#/$defs/State"
    }
  },
  "$defs": {
    "Id": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]*$"
    },
    "Sha256": {
      "type": "string",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "Answer": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path",
        "resultHash",
        "programHash",
        "legalTime",
        "evaluationStatus",
        "resultKind"
      ],
      "description": "Copied from the attached answer directory (`law ask … --out`): the journal records, never recomputes.",
      "properties": {
        "path": {
          "type": "string",
          "minLength": 1,
          "description": "Answer directory relative to the journal's directory."
        },
        "value": {
          "type": "string",
          "minLength": 1,
          "description": "`each` steps only: the value of the many slot this answer belongs to; its query names it."
        },
        "resultHash": {
          "$ref": "#/$defs/Sha256"
        },
        "programHash": {
          "type": "string"
        },
        "legalTime": {
          "type": "string"
        },
        "caseHash": {
          "type": "string",
          "description": "caseHash of the answer's manifest: the case revision the answer was computed on."
        },
        "evaluationStatus": {
          "type": "string"
        },
        "resultKind": {
          "type": "string"
        },
        "interpretations": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string"
          },
          "description": "Readings selected for this answer, copied from the manifest; absent when none was selected.",
          "$comment": "SPEC §152"
        },
        "adjudicated": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "predicate",
              "polarity",
              "args"
            ],
            "properties": {
              "predicate": {
                "type": "string",
                "minLength": 1
              },
              "polarity": {
                "enum": [
                  "positive",
                  "negative"
                ]
              },
              "args": {
                "type": "array",
                "description": "Entity ids or literal values of the assertion's arguments, in order."
              }
            }
          },
          "description": "Answers of authorities in the case of this answer: `origin adjudicated` assertions copied from request.json, sorted; absent when there is none. The journal checks them against the recorded judgment decisions.",
          "$comment": "SPEC §47.3; DECISION-0414 §18"
        },
        "queryId": {
          "type": "string"
        },
        "queryKind": {
          "type": "string"
        },
        "predicate": {
          "type": "string"
        },
        "outcome": {
          "type": "string",
          "description": "TRUE_ONLY/FALSE_ONLY/BOTH/NEITHER of a proposition, empty/single/multiple of a collection."
        },
        "values": {
          "type": "array",
          "description": "Collected values exactly as the evaluation document holds them."
        },
        "positions": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "modality",
              "status"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "modality": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "Entry": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind",
            "bindings"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "case"
            },
            "note": {
              "type": "string"
            },
            "bindings": {
              "type": "object",
              "additionalProperties": {
                "oneOf": [
                  {
                    "type": "string",
                    "minLength": 1
                  },
                  {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "minLength": 1
                    }
                  }
                ]
              },
              "description": "Slots fixed at the step: one value, or the ordered values of a many slot."
            }
          },
          "description": "Case slots fixed with the person; the context of the case step is added to the journal context."
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind",
            "bindings",
            "presented",
            "absent"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "collect"
            },
            "note": {
              "type": "string"
            },
            "bindings": {
              "type": "object",
              "additionalProperties": {
                "oneOf": [
                  {
                    "type": "string",
                    "minLength": 1
                  },
                  {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "minLength": 1
                    }
                  }
                ]
              },
              "description": "Slots fixed at the step: one value, or the ordered values of a many slot."
            },
            "presented": {
              "type": "array",
              "uniqueItems": true,
              "items": {
                "type": "string"
              }
            },
            "absent": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Facts of the step that were not presented, computed from the step."
            }
          },
          "description": "Facts presented at a collect step."
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind",
            "card"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "ask"
            },
            "note": {
              "type": "string"
            },
            "card": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "package",
                "id"
              ],
              "properties": {
                "package": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                }
              }
            },
            "answer": {
              "$ref": "#/$defs/Answer"
            },
            "each": {
              "$ref": "#/$defs/Id",
              "description": "The many slot iterated by the step."
            },
            "answers": {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/Answer"
              },
              "description": "`each` steps: one answer per value of the slot, in the slot's order."
            }
          },
          "description": "One attached answer to the step's card.",
          "oneOf": [
            {
              "required": [
                "answer"
              ],
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "each"
                    ]
                  },
                  {
                    "required": [
                      "answers"
                    ]
                  }
                ]
              }
            },
            {
              "required": [
                "each",
                "answers"
              ],
              "not": {
                "required": [
                  "answer"
                ]
              }
            }
          ]
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind",
            "answers"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "positions"
            },
            "note": {
              "type": "string"
            },
            "answers": {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/Answer"
              }
            }
          },
          "description": "Attached positions answers; every returned position is recorded."
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "decision"
            },
            "note": {
              "type": "string"
            },
            "values": {
              "type": "object",
              "additionalProperties": {
                "type": "string",
                "minLength": 1
              }
            },
            "choice": {
              "enum": [
                "selected",
                "declined",
                "affirmed",
                "denied",
                "pending"
              ]
            }
          },
          "description": "A decision of the person: free fields (`<section>/<field>`), the judgment (`judgment` value and/or `choice` affirmed, denied or pending — the authority's answer as the person reports it) or the reading choice (`selected`/`declined`).",
          "$comment": "SPEC §47.3; SPEC §152"
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "seq",
            "step",
            "kind",
            "section",
            "fields"
          ],
          "properties": {
            "seq": {
              "type": "integer",
              "minimum": 1
            },
            "step": {
              "$ref": "#/$defs/Id"
            },
            "kind": {
              "const": "section"
            },
            "note": {
              "type": "string"
            },
            "section": {
              "$ref": "#/$defs/Id"
            },
            "fields": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Field"
              }
            }
          },
          "description": "A document section assembled by copying from earlier records."
        }
      ]
    },
    "Field": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "value",
        "from"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/Id"
        },
        "value": {
          "description": "The copied value; null when the field is open."
        },
        "from": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "entry"
              ],
              "properties": {
                "entry": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "context"
              ],
              "properties": {
                "context": {
                  "type": "string"
                }
              }
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "boundaries"
              ],
              "properties": {
                "boundaries": {
                  "const": true
                }
              }
            }
          ]
        },
        "open": {
          "type": "string",
          "minLength": 1,
          "description": "Why the value is not available (an empty collection is not zero; several values are not chosen among)."
        },
        "outcome": {
          "enum": [
            "single",
            "empty",
            "multiple"
          ],
          "description": "The collect outcome of a result-sourced field, copied from the answer — readers copy it instead of inferring it from the open reason.",
          "$comment": "DECISION-0414 §23"
        }
      }
    },
    "State": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "status",
            "next"
          ],
          "properties": {
            "status": {
              "const": "open"
            },
            "next": {
              "$ref": "#/$defs/Id"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "status",
            "openFields"
          ],
          "properties": {
            "status": {
              "const": "completed"
            },
            "openFields": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "status",
            "at",
            "reason"
          ],
          "properties": {
            "status": {
              "const": "stopped"
            },
            "at": {
              "$ref": "#/$defs/Id"
            },
            "reason": {
              "enum": [
                "other_route",
                "both_supports",
                "negative_answer",
                "multiple_results",
                "out_of_scope",
                "evaluation_status",
                "no_continuation",
                "awaiting_judgment",
                "missing_facts"
              ],
              "description": "A stopped passage is not a negative answer. evaluation_status — the answer was not COMPUTED (judgment, interpretation, incomplete); awaiting_judgment — the guide waits for the authority's answer; missing_facts — after a why_not return the question gave the same answer: the facts it lacks are not in the case.",
              "$comment": "SPEC §47.3"
            },
            "boundary": {
              "$ref": "#/$defs/Id"
            },
            "evaluationStatus": {
              "type": "string"
            }
          }
        }
      ]
    }
  }
}
