{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/kitepon/Lattice/blob/main/docs/schemas/lattice.todo_revision_set.v3.schema.json",
  "title": "lattice.todo_revision_set.v3",
  "description": "`lattice todo revise-set`が受理する最新契約。複数planへ跨がるrevisionを1つのatomic書込みへ束ねる。v3のmemberは`lattice.todo_revision.v1/v2`（非phase plan）と`lattice.phase_todo_revision.v1/v2`（phase-audited plan）のいずれかであり、`lattice.phase_todo_revision.v3`はmemberとして受理されない——v3固有のruntime_task_migration/source_cutover_batchはrevise-setの外で単独revise-phaseとして扱う契約になっている。",
  "$comment": "Runtime validation (src/todo-revision.mjs validateTodoRevisionSet) additionally enforces: canonical JSON+LF bytes; revisions.length in [2, 64]; each member's own digest chain (validateTodoRevision / validatePhaseTodoRevision); every member.project_id === project_id; v3はrevisions内に最低1つphase_todo_revision memberを含む必要がある; revisionsが厳密にplan_key昇順でソートされている（重複plan_key禁止）; revision_set_digestは他の全top-level fieldへの正準self-digest。",
  "type": "object",
  "additionalProperties": false,
  "required": ["schema", "project_id", "revisions", "revision_set_digest"],
  "properties": {
    "schema": { "const": "lattice.todo_revision_set.v3" },
    "project_id": { "$ref": "#/$defs/identifier" },
    "revisions": {
      "type": "array", "minItems": 2, "maxItems": 64,
      "items": {
        "oneOf": [
          { "$ref": "#/$defs/todoRevisionMember" },
          { "$ref": "#/$defs/phaseTodoRevisionMember" }
        ]
      }
    },
    "revision_set_digest": { "$ref": "#/$defs/digest" }
  },
  "$defs": {
    "identifier": { "type": "string", "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$" },
    "digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
    "nullableDigest": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/digest" }] },
    "gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
    "repoRef": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1024,
      "pattern": "^(?!/)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*\\\\)(?!.*[\\u0000-\\u001f\\u007f])[^/]+(?:/[^/]+)*$"
    },
    "sourceLineRef": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1024,
      "pattern": "^(?!/)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*\\\\)(?!.*[\\u0000-\\u001f\\u007f])[^/]+(?:/[^/]+)*#L[1-9][0-9]*$"
    },
    "nullableRepoRef": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/repoRef" }] },
    "text": { "type": "string", "minLength": 1, "maxLength": 16384 },
    "nullableText": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/text" }] },
    "nodeRef": {
      "type": "object", "additionalProperties": false,
      "required": ["project_id", "plan_key", "task_id"],
      "properties": {
        "project_id": { "$ref": "#/$defs/identifier" },
        "plan_key": { "$ref": "#/$defs/identifier" },
        "task_id": { "$ref": "#/$defs/identifier" },
        "expected_topology_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "phaseRef": {
      "type": "object", "additionalProperties": false,
      "required": ["project_id", "plan_key", "phase_id"],
      "properties": {
        "project_id": { "$ref": "#/$defs/identifier" },
        "plan_key": { "$ref": "#/$defs/identifier" },
        "phase_id": { "$ref": "#/$defs/identifier" },
        "expected_topology_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "edge": {
      "type": "object", "additionalProperties": false, "required": ["from", "to"],
      "properties": { "from": { "$ref": "#/$defs/nodeRef" }, "to": { "$ref": "#/$defs/nodeRef" } }
    },
    "phaseAcceptDependency": {
      "type": "object", "additionalProperties": false, "required": ["from", "to"],
      "properties": { "from": { "$ref": "#/$defs/phaseRef" }, "to": { "$ref": "#/$defs/nodeRef" } }
    },
    "join": {
      "type": "object", "additionalProperties": false, "required": ["id", "after", "before"],
      "properties": {
        "id": { "$ref": "#/$defs/identifier" },
        "after": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/nodeRef" } },
        "before": { "$ref": "#/$defs/nodeRef" }
      }
    },
    "narrativeAnchor": {
      "type": "object", "additionalProperties": false,
      "required": ["origin_plan_ref", "origin_line", "source_commit", "source_line_digest"],
      "properties": {
        "origin_plan_ref": { "$ref": "#/$defs/repoRef" },
        "origin_line": { "type": "integer", "minimum": 1 },
        "source_commit": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
        "source_line_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "compileBinding": {
      "oneOf": [
        { "type": "null" },
        {
          "type": "object", "additionalProperties": false,
          "required": ["boundary_manifest_digest", "compiled_plan_digest", "topology_digest", "base_sha"],
          "properties": {
            "boundary_manifest_digest": { "$ref": "#/$defs/digest" },
            "compiled_plan_digest": { "$ref": "#/$defs/digest" },
            "topology_digest": { "$ref": "#/$defs/digest" },
            "base_sha": { "$ref": "#/$defs/gitSha" }
          }
        }
      ]
    },
    "predecessor": {
      "type": "object", "additionalProperties": false,
      "required": ["plan_digest", "journal_head_digest", "plan_version"],
      "properties": {
        "plan_digest": { "$ref": "#/$defs/digest" },
        "journal_head_digest": { "$ref": "#/$defs/digest" },
        "plan_version": { "$ref": "#/$defs/identifier" }
      }
    },
    "taskV3": {
      "type": "object", "additionalProperties": false,
      "required": [
        "task_id", "title", "lane", "narrative_ref", "narrative_anchor", "compile_binding", "parent_task_id"
      ],
      "properties": {
        "task_id": { "$ref": "#/$defs/identifier" },
        "title": { "$ref": "#/$defs/nullableText" },
        "lane": { "$ref": "#/$defs/identifier" },
        "narrative_ref": { "$ref": "#/$defs/nullableRepoRef" },
        "narrative_anchor": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/narrativeAnchor" }] },
        "compile_binding": { "$ref": "#/$defs/compileBinding" },
        "parent_task_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] }
      }
    },
    "taskV4": {
      "type": "object", "additionalProperties": false,
      "required": [
        "task_id", "title", "lane", "narrative_ref", "narrative_anchor", "compile_binding",
        "parent_task_id", "phase_id"
      ],
      "properties": {
        "task_id": { "$ref": "#/$defs/identifier" },
        "title": { "$ref": "#/$defs/nullableText" },
        "lane": { "$ref": "#/$defs/identifier" },
        "narrative_ref": { "$ref": "#/$defs/nullableRepoRef" },
        "narrative_anchor": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/narrativeAnchor" }] },
        "compile_binding": { "$ref": "#/$defs/compileBinding" },
        "parent_task_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
        "phase_id": { "$ref": "#/$defs/identifier" }
      }
    },
    "phase": {
      "type": "object", "additionalProperties": false,
      "required": ["phase_id", "title", "gate_policy", "predecessor_phase_ids", "required_evidence_slots"],
      "properties": {
        "phase_id": { "$ref": "#/$defs/identifier" },
        "title": { "$ref": "#/$defs/nullableText" },
        "gate_policy": { "$ref": "#/$defs/identifier" },
        "predecessor_phase_ids": {
          "type": "array", "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true
        },
        "required_evidence_slots": {
          "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true
        }
      }
    },
    "desiredPlanV3": {
      "type": "object", "additionalProperties": false,
      "required": [
        "schema", "project_id", "plan_key", "plan_version", "predecessor_plan_digest",
        "tasks", "hard_dependencies", "joins", "topology_digest", "plan_digest"
      ],
      "properties": {
        "schema": { "const": "lattice.todo_plan.v3" },
        "project_id": { "$ref": "#/$defs/identifier" },
        "plan_key": { "$ref": "#/$defs/identifier" },
        "plan_version": { "$ref": "#/$defs/identifier" },
        "predecessor_plan_digest": { "$ref": "#/$defs/nullableDigest" },
        "tasks": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskV3" } },
        "hard_dependencies": { "type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/edge" } },
        "joins": { "type": "array", "maxItems": 128, "items": { "$ref": "#/$defs/join" } },
        "topology_digest": { "$ref": "#/$defs/digest" },
        "plan_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "desiredPlanV4orV5": {
      "type": "object", "additionalProperties": false,
      "required": [
        "schema", "project_id", "plan_key", "plan_version", "predecessor_plan_digest",
        "tasks", "hard_dependencies", "joins", "phases", "topology_digest", "plan_digest"
      ],
      "$comment": "schemaがv5の時だけphase_accept_dependenciesも必須keyに加わる（runtime-only cross-check、oneOfでは表現しない）。",
      "properties": {
        "schema": { "enum": ["lattice.todo_plan.v4", "lattice.todo_plan.v5"] },
        "project_id": { "$ref": "#/$defs/identifier" },
        "plan_key": { "$ref": "#/$defs/identifier" },
        "plan_version": { "$ref": "#/$defs/identifier" },
        "predecessor_plan_digest": { "$ref": "#/$defs/nullableDigest" },
        "tasks": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskV4" } },
        "hard_dependencies": { "type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/edge" } },
        "joins": { "type": "array", "maxItems": 128, "items": { "$ref": "#/$defs/join" } },
        "phases": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/phase" } },
        "phase_accept_dependencies": {
          "type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/phaseAcceptDependency" }
        },
        "topology_digest": { "$ref": "#/$defs/digest" },
        "plan_digest": { "$ref": "#/$defs/digest" }
      },
      "if": { "properties": { "schema": { "const": "lattice.todo_plan.v5" } }, "required": ["schema"] },
      "then": { "required": ["phase_accept_dependencies"] }
    },
    "taskMigrationEntry": {
      "type": "object", "additionalProperties": false,
      "required": ["from_task_id", "to_task_id", "state_policy"],
      "properties": {
        "from_task_id": { "$ref": "#/$defs/identifier" },
        "to_task_id": { "oneOf": [{ "const": "removed" }, { "$ref": "#/$defs/identifier" }] },
        "state_policy": { "enum": ["carry", "carry_reconciled_metadata", "acquire_phase", "reset_pending", "removed"] }
      }
    },
    "phaseMigrationEntry": {
      "type": "object", "additionalProperties": false,
      "required": ["from_phase_id", "to_phase_id", "state_policy"],
      "properties": {
        "from_phase_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
        "to_phase_id": { "oneOf": [{ "const": "removed" }, { "$ref": "#/$defs/identifier" }] },
        "state_policy": { "enum": ["carry", "reset", "removed"] }
      }
    },
    "sourceInventoryActiveEntry": {
      "type": "object", "additionalProperties": false,
      "required": ["task_id", "source_ref", "source_digest"],
      "properties": {
        "task_id": { "$ref": "#/$defs/identifier" },
        "source_ref": { "$ref": "#/$defs/sourceLineRef" },
        "source_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "sourceInventoryTombstone": {
      "type": "object", "additionalProperties": false,
      "required": ["source_ref", "source_digest", "exclusion_reason"],
      "properties": {
        "source_ref": { "$ref": "#/$defs/sourceLineRef" },
        "source_digest": { "$ref": "#/$defs/digest" },
        "exclusion_reason": { "$ref": "#/$defs/text" }
      }
    },
    "sourceInventory": {
      "type": "object", "additionalProperties": false,
      "required": ["active", "excluded_tombstones"],
      "properties": {
        "active": {
          "type": "array", "maxItems": 512, "items": { "$ref": "#/$defs/sourceInventoryActiveEntry" }
        },
        "excluded_tombstones": {
          "type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/sourceInventoryTombstone" }
        }
      }
    },
    "sourceCutoverOperation": {
      "type": "object", "additionalProperties": false,
      "required": ["task_id", "disposition", "source_ref", "source_digest", "live_replacement"],
      "properties": {
        "task_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
        "disposition": { "enum": ["active", "excluded"] },
        "source_ref": { "$ref": "#/$defs/sourceLineRef" },
        "source_digest": { "$ref": "#/$defs/digest" },
        "live_replacement": { "type": "string", "minLength": 1, "maxLength": 4096 }
      }
    },
    "sourceCutoverBatch": {
      "type": "object", "additionalProperties": false,
      "required": ["batch_id", "archive_ref", "operations", "batch_digest"],
      "properties": {
        "batch_id": { "$ref": "#/$defs/identifier" },
        "archive_ref": { "allOf": [{ "$ref": "#/$defs/repoRef" }, { "pattern": "\\.md$" }] },
        "operations": {
          "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/sourceCutoverOperation" }
        },
        "batch_digest": { "$ref": "#/$defs/digest" }
      }
    },
    "todoRevisionMember": {
      "description": "非phase planのrevision member。'lattice.todo_revision.v1'（source_cutover_batchなし）と'lattice.todo_revision.v2'（source_cutover_batchあり）のいずれか。",
      "type": "object",
      "if": { "properties": { "schema": { "const": "lattice.todo_revision.v2" } }, "required": ["schema"] },
      "then": {
        "additionalProperties": false,
        "required": [
          "schema", "project_id", "plan_key", "predecessor", "desired_plan", "task_migration",
          "source_inventory", "reconciliation", "source_cutover_batch", "revision_digest"
        ],
        "properties": {
          "schema": { "const": "lattice.todo_revision.v2" },
          "project_id": { "$ref": "#/$defs/identifier" },
          "plan_key": { "$ref": "#/$defs/identifier" },
          "predecessor": { "$ref": "#/$defs/predecessor" },
          "desired_plan": { "$ref": "#/$defs/desiredPlanV3" },
          "task_migration": {
            "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskMigrationEntry" }
          },
          "source_inventory": { "$ref": "#/$defs/sourceInventory" },
          "reconciliation": {
            "type": "object", "additionalProperties": false,
            "required": ["predecessor_reconciliation_digest", "source_inventory_digest", "reconciliation_digest"],
            "properties": {
              "predecessor_reconciliation_digest": { "$ref": "#/$defs/digest" },
              "source_inventory_digest": { "$ref": "#/$defs/digest" },
              "reconciliation_digest": { "$ref": "#/$defs/digest" }
            }
          },
          "source_cutover_batch": { "$ref": "#/$defs/sourceCutoverBatch" },
          "revision_digest": { "$ref": "#/$defs/digest" }
        }
      },
      "else": {
        "additionalProperties": false,
        "required": [
          "schema", "project_id", "plan_key", "predecessor", "desired_plan", "task_migration",
          "source_inventory", "reconciliation", "revision_digest"
        ],
        "properties": {
          "schema": { "const": "lattice.todo_revision.v1" },
          "project_id": { "$ref": "#/$defs/identifier" },
          "plan_key": { "$ref": "#/$defs/identifier" },
          "predecessor": { "$ref": "#/$defs/predecessor" },
          "desired_plan": { "$ref": "#/$defs/desiredPlanV3" },
          "task_migration": {
            "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskMigrationEntry" }
          },
          "source_inventory": { "$ref": "#/$defs/sourceInventory" },
          "reconciliation": {
            "type": "object", "additionalProperties": false,
            "required": ["predecessor_reconciliation_digest", "source_inventory_digest", "reconciliation_digest"],
            "properties": {
              "predecessor_reconciliation_digest": { "$ref": "#/$defs/digest" },
              "source_inventory_digest": { "$ref": "#/$defs/digest" },
              "reconciliation_digest": { "$ref": "#/$defs/digest" }
            }
          },
          "revision_digest": { "$ref": "#/$defs/digest" }
        }
      }
    },
    "phaseTodoRevisionMember": {
      "description": "phase-audited planのrevision member。'lattice.phase_todo_revision.v1'（desired_planはv4）と'v2'（desired_planはv5）のいずれかだけを受理する——'v3'（runtime_task_migration・source_cutover_batch付き）はrevise-set memberとしては受理されない。",
      "type": "object", "additionalProperties": false,
      "required": [
        "schema", "project_id", "plan_key", "predecessor", "desired_plan",
        "task_migration", "phase_migration", "revision_digest"
      ],
      "properties": {
        "schema": { "enum": ["lattice.phase_todo_revision.v1", "lattice.phase_todo_revision.v2"] },
        "project_id": { "$ref": "#/$defs/identifier" },
        "plan_key": { "$ref": "#/$defs/identifier" },
        "predecessor": { "$ref": "#/$defs/predecessor" },
        "desired_plan": { "$ref": "#/$defs/desiredPlanV4orV5" },
        "task_migration": {
          "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskMigrationEntry" }
        },
        "phase_migration": {
          "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/phaseMigrationEntry" }
        },
        "revision_digest": { "$ref": "#/$defs/digest" }
      },
      "$comment": "schemaが'lattice.phase_todo_revision.v1'ならdesired_plan.schemaは'lattice.todo_plan.v4'、'v2'なら'lattice.todo_plan.v5'（runtime cross-check）。"
    }
  }
}
