{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "anu.watcher_dead_letter.v1",
  "title": "ANU watcher_dead_letter_v1",
  "description": "task-2643 Track B — watcher TTL 만료 후 4 dead-letter state. TTL 만료 → ANU 직접 polling 복귀 금지 (회장 verbatim).",
  "type": "object",
  "required": [
    "schema",
    "dead_letter_state",
    "task_id",
    "pr_number",
    "head_sha",
    "ttl_expired_at_kst",
    "watcher_owner",
    "fail_closed",
    "chair_report_required"
  ],
  "properties": {
    "schema": {
      "type": "string",
      "const": "anu.watcher_dead_letter.v1"
    },
    "dead_letter_state": {
      "type": "string",
      "enum": [
        "WATCHER_TIMEOUT_HOLD",
        "WATCHER_CALLBACK_MISSING",
        "WATCHER_STALE_HEAD",
        "DUPLICATE_WATCHER"
      ],
      "description": "4 dead-letter state. spec §3.3 매핑."
    },
    "task_id": {
      "type": "string",
      "minLength": 1
    },
    "pr_number": {
      "type": "integer",
      "minimum": 1
    },
    "head_sha": {
      "type": "string",
      "pattern": "^[0-9a-f]{40}$"
    },
    "ttl_expired_at_kst": {
      "type": "string",
      "description": "TTL 만료 ts (KST, ISO8601 권장)"
    },
    "watcher_owner": {
      "type": "string",
      "minLength": 1
    },
    "fail_closed": {
      "type": "boolean",
      "const": true,
      "description": "TTL 만료 후 ANU 직접 polling 복귀 금지 == fail-closed 항상 True"
    },
    "chair_report_required": {
      "type": "boolean",
      "const": true,
      "description": "dead-letter state 진입 시 회장 보고 강제"
    },
    "redispatch_decision": {
      "type": ["string", "null"],
      "description": "회장 결정에 의한 재발사 여부 (별도 결정 사항)"
    },
    "context": {
      "type": "object",
      "description": "dead-letter 별 추가 컨텍스트",
      "properties": {
        "WATCHER_TIMEOUT_HOLD": {
          "type": "object",
          "properties": {
            "last_terminal_state_attempt": { "type": ["string", "null"] },
            "elapsed_seconds_at_timeout": { "type": "integer" }
          }
        },
        "WATCHER_CALLBACK_MISSING": {
          "type": "object",
          "properties": {
            "terminal_state_reached": { "type": "string" },
            "callback_registrar_error": { "type": ["string", "null"] }
          }
        },
        "WATCHER_STALE_HEAD": {
          "type": "object",
          "properties": {
            "contract_head_sha": { "type": "string" },
            "current_head_sha": { "type": "string" },
            "force_pushed": { "type": "boolean" }
          }
        },
        "DUPLICATE_WATCHER": {
          "type": "object",
          "properties": {
            "existing_watcher_task_id": { "type": "string" },
            "existing_watcher_owner": { "type": "string" },
            "violating_owner_key": { "type": "string" }
          }
        }
      }
    }
  },
  "additionalProperties": true,
  "examples": [
    {
      "schema": "anu.watcher_dead_letter.v1",
      "dead_letter_state": "WATCHER_TIMEOUT_HOLD",
      "task_id": "task-2643",
      "pr_number": 146,
      "head_sha": "0e172435a2d7d3664ae63320c2f96c12882df0e3",
      "ttl_expired_at_kst": "2026-05-23T23:30:00+09:00",
      "watcher_owner": "dev6-perun",
      "fail_closed": true,
      "chair_report_required": true,
      "redispatch_decision": null,
      "context": {
        "WATCHER_TIMEOUT_HOLD": {
          "last_terminal_state_attempt": null,
          "elapsed_seconds_at_timeout": 7200
        }
      }
    },
    {
      "schema": "anu.watcher_dead_letter.v1",
      "dead_letter_state": "DUPLICATE_WATCHER",
      "task_id": "task-2643",
      "pr_number": 146,
      "head_sha": "0e172435a2d7d3664ae63320c2f96c12882df0e3",
      "ttl_expired_at_kst": "2026-05-23T22:50:00+09:00",
      "watcher_owner": "anu-bzaona6au-violation",
      "fail_closed": true,
      "chair_report_required": true,
      "context": {
        "DUPLICATE_WATCHER": {
          "existing_watcher_task_id": "dev6-588CA6A8",
          "existing_watcher_owner": "dev6-perun",
          "violating_owner_key": "anu_main"
        }
      }
    }
  ]
}
