{
  "schema": "anu_v2.dispatch_decision.v1",
  "task_id": "task-2563",
  "track": "D",
  "rank": 4,
  "team": "dev6",
  "team_persona": "페룬",
  "level": "Lv.2~3",
  "level_kind": "capability-hardening",
  "dispatch_ts_utc": "2026-05-13T06:00:00Z",
  "owner_directive_ref": "회장 §명시 2026-05-13 OWNER_TRIGGER_ONLY_CAPABILITY hardening 승인",
  "draft_ref": "memory/tasks/task-2563.md",
  "predecessors": [
    {
      "track": "A",
      "task_id": "task-2558",
      "pr": 111,
      "evidence_ref": "memory/reports/task-2558.md"
    },
    {
      "track": "A",
      "task_id": "task-2560",
      "pr": 113,
      "evidence_ref": "memory/events/task-2560.reconcile-evidence.json"
    },
    {
      "track": "C",
      "task_id": "task-2562",
      "pr": 115,
      "evidence_ref": "memory/events/task-2562.dispatch-decision.json"
    }
  ],
  "essence": "OWNER_TRIGGER_ONLY_CAPABILITY 실전 활용 7회 경험 기반 3건 통합 hardening (FIRST_TRIGGER_PENDING 상태 분리 + http_post signature 회귀 + FUC-3 logger.exception 보강).",
  "core_decisions": {
    "fix_1_state_machine_split": {
      "new_state": "FIRST_TRIGGER_PENDING",
      "pending_window_seconds_default": 300,
      "first_timeout_seconds_1_to_1": 1800,
      "rationale": "PR open 직후 짧은 시간 동안 PENDING 으로 분류, FIRST_TIMEOUT_SECONDS 경과 후 MISSING 확정. polling_policy.FIRST_TIMEOUT_SECONDS == 1800s 와 1:1 정합."
    },
    "fix_2_signature_regression": {
      "callable_signature": "Callable[[str, str, dict, dict], dict]",
      "caller_paths": ["direct", "scheduler_invoke", "wrapper_di_mock"],
      "rationale": "runtime 에서 signature drift 가 처음 발견되어 silent fail 하지 않도록 3 caller path 모두 동일 signature 회귀 테스트."
    },
    "fix_3_logger_exception_redaction": {
      "logger_call": "logger.exception(...) BEFORE txn.record(FAILED)",
      "redact_keys_regex": "(?i)(token|authorization|api[_-]?key|secret|password)",
      "redact_value_sentinels": ["Bearer ", "ghp_", "github_pat_", "ghu_", "ghs_", "ghr_"],
      "diagnostic_fields_preserved": [
        "status",
        "x-github-request-id",
        "x-accepted-github-permissions",
        "documentation_url"
      ],
      "rationale": "logger.exception 으로 traceback 박제, secret masking 강제, fail-closed 속성 유지 (audit FAILED + POST 0 + side-effect 0)."
    },
    "owner_trigger_fast_path": false
  },
  "owner_trigger_fast_path": false,
  "expected_files": [
    "anu_v2/owner_trigger_only.py",
    "anu_v2/idle_pr_diagnoser.py",
    "anu_v2/executor_scheduler.py",
    "anu_v2/tests/test_owner_trigger_invocation_hardening_2563.py",
    "anu_v2/fixtures/first_trigger_pending_window.json",
    "anu_v2/fixtures/owner_trigger_signature_mismatch_repro.json",
    "anu_v2/fixtures/owner_trigger_failure_path_logger_exception.json",
    "memory/reports/task-2563.md",
    "memory/events/task-2563.dispatch-decision.json",
    "memory/plans/tasks/task-2563/plan.md",
    "memory/plans/tasks/task-2563/context-notes.md",
    "memory/plans/tasks/task-2563/checklist.md"
  ],
  "expected_files_count": 12,
  "forbidden_paths": {
    "pr_branches_98_to_116_untouched": true,
    "task_2558_area_lock": ["anu_v2/auto_gemini_triage.py"],
    "task_2559_area_lock": ["dashboard/", "traffic-light-spec.md"],
    "task_2560_area_lock": [],
    "task_2561_area_lock": [],
    "task_2562_area_lock": ["scripts/gemini_cli_gate_check.py", "scripts/finish-task.sh", "prompts/gate_instructions.py"],
    "dispatch_module_lock": [
      "dispatch/",
      "prompts/team_prompts.py",
      ".github/workflows/",
      ".env",
      ".env.keys"
    ],
    "control_plane_lock": [
      "scripts/finish-task.sh",
      "scripts/ci.sh"
    ],
    "spec_lock": ["traffic-light-spec.md"]
  },
  "regression_commands": {
    "pytest": [
      "python3 -m pytest anu_v2/tests/test_owner_trigger_invocation_hardening_2563.py -v",
      "python3 -m pytest anu_v2/tests/test_owner_trigger_only_2554.py anu_v2/tests/test_executor_first_gemini_trigger_missing.py anu_v2/tests/test_executor_scheduler_per_pr_isolation.py -v"
    ],
    "static": [
      "python3 -m py_compile anu_v2/owner_trigger_only.py anu_v2/idle_pr_diagnoser.py anu_v2/executor_scheduler.py"
    ]
  },
  "escalation_map": {
    "STATE_MACHINE_REGRESSION": "#6",
    "SIGNATURE_REGRESSION_GAP": "#6",
    "TOKEN_REDACTION_VIOLATION": "#1",
    "CAPABILITY_FAIL_CLOSED_REGRESSION": "#2",
    "FORBIDDEN_PATH_HIT": "#1",
    "FORBIDDEN_PATH_HIT_ORIGINAL_PR_BRANCH": "#1",
    "OUT_OF_SCOPE_MUTATE": "#1",
    "REGRESSION_TEST_FAIL": "#6",
    "CI_FAILURE": "#6"
  },
  "completion_conditions_11": [
    "FIRST_TRIGGER_PENDING / FIRST_GEMINI_TRIGGER_MISSING 상태 구분 테스트 PASS",
    "owner_trigger_fast_path=false 일 때 조기 trigger 차단 (테스트 어셀션)",
    "owner_trigger_fast_path=true 일 때 조기 trigger 허용 (테스트 어셀션)",
    "http_post signature mismatch 회귀 테스트 PASS (3 caller path 모두 동일 signature)",
    "logger.exception 보강 후 secret masking 테스트 PASS (token 원문 노출 0)",
    "fail-closed 속성 유지 (audit FAILED + POST 0 + side-effect 0)",
    "expected_files strict (dispatch_decision.json authoritative)",
    "forbidden path 0",
    "CI/Gemini/CLEAN",
    "BOT squash merge",
    "post-merge smoke + reconcile evidence"
  ],
  "report_format_1to1": {
    "Track": "D",
    "상태": "MERGED 또는 ESCALATED",
    "task_id": "task-2563",
    "수정/PR": "PR # / merge_commit",
    "expected_files": "12/12 strict (dispatch_decision.json authoritative)",
    "forbidden_path": 0,
    "Gemini_상태": "fresh + unresolved 0",
    "CI_상태": "11/11 / CLEAN",
    "핵심_evidence": "3 hardening 항목 PASS (PENDING split + signature regression + logger.exception redaction) + secret masking 검증",
    "회장_결정_필요": "N (완료 조건 11건 충족 시) / Y (regression FAIL 시)"
  }
}
