{
  "schema_version": "source_control_primary_rollback_adr_v1",
  "status": "draft_waiting_owner_review",
  "date": "2026-06-11",
  "mode": "rollback_adr_only",
  "runtime_execution_authorized": false,
  "source_indexes": [
    "docs/security/source-control-primary-readiness-gate.snapshot.json",
    "docs/security/source-control-ref-truth-classification.snapshot.json",
    "docs/security/source-control-workflow-secret-name-inventory.snapshot.json",
    "docs/security/source-control-workflow-secret-name-export-request.snapshot.json",
    "docs/security/source-control-approval-board.snapshot.json",
    "docs/security/security-followup-runtime-gate.snapshot.json",
    "docs/security/security-rollout-policy.snapshot.json"
  ],
  "summary": {
    "candidate_repo_count": 10,
    "in_scope_repo_count": 9,
    "external_scope_count": 1,
    "repo_rollback_plan_count": 9,
    "owner_approved_count": 0,
    "dry_run_completed_count": 0,
    "active_cutover_count": 0,
    "rollback_owner_handoff_package_ready": true,
    "rollback_owner_handoff_completion_percent": 100,
    "rollback_owner_handoff_check_count": 6,
    "rollback_owner_handoff_packet_field_count": 11,
    "rollback_owner_request_dispatch_authorized": false,
    "rollback_owner_response_received_count": 0,
    "rollback_owner_response_accepted_count": 0,
    "rollback_owner_response_rejected_count": 0,
    "rollback_execution_authorized": false,
    "github_primary_switch_authorized": false,
    "gitea_disable_authorized": false,
    "action_buttons_allowed": false
  },
  "rollback_principles": [
    "GitHub primary 是長期方向，但每個 repo 必須先有 owner-approved rollback plan 才能進入 cutover review。",
    "Gitea 在 cutover 前後都必須保留為本地 mirror / fallback，不得因 GitHub primary 準備而停用、刪除或封存。",
    "Rollback ADR 只定義人工決策、驗證窗口與回退條件；不授權任何 refs sync、primary switch 或 webhook 修改。",
    "任何回退都必須有新的 runtime gate、人工批准與 evidence snapshot，不得由本 ADR 自動觸發。",
    "初期只做 observe / approval_required，不把缺 LOW / MEDIUM evidence 變成 production blocker。"
  ],
  "cutover_preconditions": [
    {
      "gate_id": "gitea_authenticated_inventory_approved",
      "title": "Gitea private/internal 全量 inventory 已完成",
      "required_evidence": [
        "Gitea authenticated inventory 或 redacted admin export status=ok",
        "確認所有 private/internal repos 都在 migration matrix",
        "只保存 token_present=true/false，不保存 token value"
      ],
      "current_status": "blocked",
      "execution_authorized": false
    },
    {
      "gate_id": "refs_truth_and_parity_approved",
      "title": "refs truth / branch-tag parity 已由 owner 批准",
      "required_evidence": [
        "main/dev 真相來源已人工判定",
        "release tags 保留 / 棄用決策完成",
        "deprecated refs 已由 repo owner review"
      ],
      "current_status": "waiting_owner_review",
      "execution_authorized": false
    },
    {
      "gate_id": "workflow_secret_export_accepted",
      "title": "workflow / runner / webhook / secret name redacted export 已驗收",
      "required_evidence": [
        "S4.3 export request 對應的 webhook、runner、deploy key、branch protection 與 repository secret name parity evidence 已補齊",
        "任何 secret value、token value、private key 或 webhook secret 都未被保存",
        "GitHub hosted runner 額度風險與 self-hosted runner owner 已確認"
      ],
      "current_status": "draft_only",
      "execution_authorized": false
    },
    {
      "gate_id": "owner_visibility_canonical_approved",
      "title": "owner / visibility / canonical 已批准",
      "required_evidence": [
        "9 個 in-scope repos 都有 owner approval",
        "not_found_or_private repo 已明確判定建立、取得權限或排除",
        "ewoooc / momo-pro-system canonical 關係已定案"
      ],
      "current_status": "waiting_owner_review",
      "execution_authorized": false
    },
    {
      "gate_id": "rollback_owner_and_monitoring_approved",
      "title": "rollback owner、監控窗口與通知責任已批准",
      "required_evidence": [
        "每個 repo 都有 rollback owner 與值班窗口",
        "cutover 後 1h / 24h 的驗證項目已明確",
        "失敗時的人工停損與回退 decision record 格式已確認"
      ],
      "current_status": "draft_only",
      "execution_authorized": false
    }
  ],
  "repo_rollback_plans": [
    {
      "repo_key": "awoooi",
      "github_repo": "owenhytsai/awoooi",
      "source_key": "wooo/awoooi",
      "scope_status": "in_scope",
      "risk": "HIGH",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Gitea remains protected local fallback until owner-approved cutover and rollback drill are complete.",
      "required_owner_decisions": [
        "main/dev 真相來源",
        "production deploy workflow canonical",
        "webhook single-sender policy",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "main SHA / tag parity evidence",
        "deployment marker workflow evidence",
        "runner owner / self-hosted evidence",
        "repository secret name parity evidence",
        "post-cutover health and deploy verification checklist"
      ],
      "rollback_triggers": [
        "production deploy workflow fails after primary switch",
        "duplicate webhook causes duplicate deploy or duplicate notification",
        "required runner label unavailable",
        "secret name parity gap blocks deployment"
      ],
      "manual_recovery_outline": [
        "Freeze additional refs changes and record decision in approval audit.",
        "Keep Gitea fallback intact and route deploy decision back to approved source after runtime gate approval.",
        "Collect post-rollback evidence before re-entering primary readiness review."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "switch_github_primary",
        "disable_gitea",
        "sync_refs",
        "modify_workflow",
        "move_secret_values"
      ]
    },
    {
      "repo_key": "clawbot-v5",
      "github_repo": "owenhytsai/clawbot-v5",
      "source_key": "wooo/clawbot-v5",
      "scope_status": "in_scope",
      "risk": "MEDIUM",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Gitea remains fallback until tag retention and refs truth are approved.",
      "required_owner_decisions": [
        "main 真相來源",
        "Gitea-only tag 保留或棄用",
        "是否需要 workflow / secret inventory",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "branch/tag parity evidence",
        "owner-approved tag policy",
        "repository secret name parity or no-secret attestation",
        "post-cutover smoke check"
      ],
      "rollback_triggers": [
        "GitHub target misses owner-approved tag",
        "automation expects a Gitea-only ref",
        "repo owner rejects target canonical decision"
      ],
      "manual_recovery_outline": [
        "Pause primary review and keep Gitea as canonical fallback.",
        "Ask owner to classify missing refs before any retry.",
        "Require new approval record before resuming cutover preparation."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "push_refs",
        "delete_refs",
        "switch_github_primary",
        "delete_gitea_repo"
      ]
    },
    {
      "repo_key": "wooo-aiops",
      "github_repo": "owenhytsai/wooo-aiops",
      "source_key": "wooo/wooo-aiops",
      "scope_status": "in_scope",
      "risk": "MEDIUM",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Gitea remains fallback until GitHub-only refs and workflow ownership are resolved.",
      "required_owner_decisions": [
        "GitHub-only branch / tag 來源",
        "webhook owner",
        "runner / workflow owner",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "GitHub-only refs classification",
        "webhook redacted export",
        "runner owner evidence",
        "repository secret name parity evidence"
      ],
      "rollback_triggers": [
        "GitHub-only refs are later classified as active source",
        "webhook route changes produce duplicate events",
        "workflow runner mismatch increases hosted runner usage unexpectedly"
      ],
      "manual_recovery_outline": [
        "Stop cutover review and preserve both remote states.",
        "Route owner decision back through source-control approval board.",
        "Re-run readiness gate only after redacted evidence is updated."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "delete_github_only_refs",
        "modify_webhook",
        "switch_github_primary",
        "force_push"
      ]
    },
    {
      "repo_key": "wooo-infra-config",
      "github_repo": "owenhytsai/wooo-infra-config",
      "source_key": "wooo/wooo-infra-config",
      "scope_status": "in_scope",
      "risk": "MEDIUM",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Gitea and internal 110 remote roles stay unchanged until infra owner signs off.",
      "required_owner_decisions": [
        "110 internal remote purpose",
        "deploy key owner",
        "infra secret name owner",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "internal remote purpose decision",
        "deploy key redacted inventory",
        "branch protection / required check export",
        "infra secret name parity evidence"
      ],
      "rollback_triggers": [
        "internal remote is still an active source",
        "deploy key ownership is ambiguous",
        "required status checks are missing on GitHub target",
        "infra secret parity gap blocks validation"
      ],
      "manual_recovery_outline": [
        "Keep current infra source untouched and do not delete remotes.",
        "Escalate to infra owner for manual source-of-truth decision.",
        "Resume only after a new redacted export snapshot is committed."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "delete_remote",
        "move_secret_values",
        "export_private_key",
        "switch_github_primary"
      ]
    },
    {
      "repo_key": "ewoooc",
      "github_repo": "owenhytsai/ewoooc",
      "source_key": "wooo/ewoooc / root/momo-pro-system / momo working trees",
      "scope_status": "in_scope",
      "risk": "HIGH",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "No primary decision until canonical repository and unrelated history risk are resolved.",
      "required_owner_decisions": [
        "GitHub target access or creation decision",
        "ewoooc / momo-pro-system canonical decision",
        "unrelated history handling",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "canonical repo decision record",
        "server-side refs diff",
        "workflow / secret name redacted export",
        "post-cutover web and deploy health checks"
      ],
      "rollback_triggers": [
        "target repo access remains unresolved",
        "canonical decision conflicts with local lineage evidence",
        "unrelated histories cannot be reconciled without data loss risk"
      ],
      "manual_recovery_outline": [
        "Keep all existing working trees untouched.",
        "Do not create or merge GitHub target automatically.",
        "Require canonical owner approval before any new cutover attempt."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "auto_create_repo",
        "auto_merge_unrelated_histories",
        "delete_working_tree",
        "switch_github_primary"
      ]
    },
    {
      "repo_key": "bitan-pharmacy",
      "github_repo": "owenhytsai/bitan-pharmacy",
      "source_key": "bitan-pharmacy",
      "scope_status": "in_scope",
      "risk": "MEDIUM",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Current local / 110 source remains evidence source until active-state and GitHub target are approved.",
      "required_owner_decisions": [
        "repo active or archive decision",
        "GitHub target decision",
        "secret name / deploy owner decision",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "GitHub target visibility decision",
        "repository secret name parity or no-secret attestation",
        "active-state owner decision",
        "post-cutover smoke check if active"
      ],
      "rollback_triggers": [
        "repo is confirmed inactive or out of scope",
        "GitHub target cannot be verified",
        "owner cannot confirm deploy / secret requirements"
      ],
      "manual_recovery_outline": [
        "Keep repo out of primary cutover queue until owner decision exists.",
        "Do not create GitHub target automatically.",
        "If inactive, record owner decision rather than deleting source."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "auto_create_repo",
        "push_refs",
        "delete_110_remote",
        "switch_github_primary"
      ]
    },
    {
      "repo_key": "tsenyang-website",
      "github_repo": "owenhytsai/tsenyang-website",
      "source_key": "tsenyang-website",
      "scope_status": "in_scope",
      "risk": "MEDIUM",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Current local / 110 source remains evidence source until active-state and GitHub target are approved.",
      "required_owner_decisions": [
        "repo active or archive decision",
        "GitHub target decision",
        "secret name / deploy owner decision",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "GitHub target visibility decision",
        "repository secret name parity or no-secret attestation",
        "active-state owner decision",
        "post-cutover smoke check if active"
      ],
      "rollback_triggers": [
        "repo is confirmed inactive or out of scope",
        "GitHub target cannot be verified",
        "owner cannot confirm deploy / secret requirements"
      ],
      "manual_recovery_outline": [
        "Keep repo out of primary cutover queue until owner decision exists.",
        "Do not create GitHub target automatically.",
        "If inactive, record owner decision rather than deleting source."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "auto_create_repo",
        "push_refs",
        "delete_110_remote",
        "switch_github_primary"
      ]
    },
    {
      "repo_key": "open-design",
      "github_repo": "nexu-io/open-design",
      "source_key": "open-design",
      "scope_status": "external_scope_review",
      "risk": "LOW",
      "rollback_state": "scope_review_only",
      "primary_ready": false,
      "fallback_role": "Not in AWOOOI primary cutover scope until ownership is confirmed.",
      "required_owner_decisions": [
        "scope ownership decision"
      ],
      "rollback_evidence_required": [
        "scope review evidence"
      ],
      "rollback_triggers": [
        "repo is later confirmed in scope and needs a separate ADR"
      ],
      "manual_recovery_outline": [
        "Keep out of primary queue.",
        "Create a separate in-scope approval item if ownership changes."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "加入 primary cutover queue",
        "修改 repo visibility",
        "sync refs"
      ]
    },
    {
      "repo_key": "vibework",
      "github_repo": "owenhytsai/VibeWork",
      "source_key": "vibework",
      "scope_status": "in_scope",
      "risk": "HIGH",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "VibeWork remains an independent product source until owner-approved canonical, target, secret parity, and rollback decisions exist.",
      "required_owner_decisions": [
        "VibeWork independent product boundary decision",
        "GitHub / Gitea target and canonical source decision",
        "secret name / deploy owner decision",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "repo / product / surface / owner evidence refs",
        "workflow or no-workflow owner attestation",
        "repository secret name parity or no-secret attestation",
        "post-cutover product smoke checklist if later approved"
      ],
      "rollback_triggers": [
        "VibeWork product boundary becomes ambiguous",
        "GitHub target or canonical source cannot be verified",
        "owner cannot confirm deploy / secret requirements"
      ],
      "manual_recovery_outline": [
        "Keep VibeWork out of primary cutover queue until owner decision exists.",
        "Do not create or push GitHub target automatically.",
        "If out of scope or independent-only, record owner decision rather than changing source control."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "auto_create_repo",
        "push_refs",
        "modify_workflow",
        "move_secret_values",
        "switch_github_primary",
        "merge_product_boundary"
      ]
    },
    {
      "repo_key": "agent-bounty-protocol",
      "github_repo": "owenhytsai/agent-bounty-protocol",
      "source_key": "agent-bounty-protocol",
      "scope_status": "in_scope",
      "risk": "HIGH",
      "rollback_state": "draft_waiting_owner_review",
      "primary_ready": false,
      "fallback_role": "Current local / Gitea workflow evidence remains read-only source until owner-approved target, runner, secret parity, and execution-boundary decisions exist.",
      "required_owner_decisions": [
        "GitHub / Gitea target and canonical source decision",
        "agent / bounty / treasury / MCP / A2A execution surface decision",
        "runner label / branch protection / secret name owner decision",
        "rollback owner"
      ],
      "rollback_evidence_required": [
        "workflow file and runner label evidence",
        "branch protection / CODEOWNERS redacted export or no-data attestation",
        "repository secret name parity or no-secret attestation",
        "agent / bounty runtime gate checklist if later approved"
      ],
      "rollback_triggers": [
        "agent / bounty execution surface is mistaken for runtime authorization",
        "runner owner or branch protection cannot be verified",
        "GitHub target or canonical source conflicts with local workflow evidence"
      ],
      "manual_recovery_outline": [
        "Keep repository in read-only governance until owner decision exists.",
        "Do not change workflow, runner, or source-control primary automatically.",
        "If execution scope is unclear, hold at owner response and runtime gate remains 0."
      ],
      "execution_authorized": false,
      "still_forbidden": [
        "auto_create_repo",
        "push_refs",
        "modify_workflow",
        "enable_runner",
        "move_secret_values",
        "switch_github_primary",
        "runtime_execute_agent_bounty"
      ]
    }
  ],
  "rollback_owner_handoff": {
    "status": "ready_not_dispatched",
    "package_ready": true,
    "handoff_completion_percent": 100,
    "repo_template_count": 7,
    "preflight_checks": [
      {
        "check_id": "preflight-latest-source-control-baseline",
        "title": "送件前確認 gitea/main、P1-2、P1-3、P1-4 與 S4.13 最新狀態",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      },
      {
        "check_id": "preflight-seven-in-scope-repos-only",
        "title": "只向 9 個 in-scope repos 收 rollback owner / fallback / trigger / validation 回覆",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      },
      {
        "check_id": "preflight-fallback-role-kept",
        "title": "回覆必須確認 Gitea 或現行來源仍保留 fallback 角色",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      },
      {
        "check_id": "preflight-validation-windows-bound",
        "title": "每個 repo 必須對應 pre-cutover、1h、24h 三個驗證窗口",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      },
      {
        "check_id": "preflight-redacted-evidence-only",
        "title": "只收 owner role/team、決策理由、脫敏 evidence ref 與 follow-up owner",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      },
      {
        "check_id": "preflight-no-cutover-or-rollback-command",
        "title": "primary switch、rollback execution、refs sync、workflow/secret 變更與 Gitea disable 全部拒收",
        "completion_state": "defined_not_dispatched",
        "current_status": "已定義，未送件"
      }
    ],
    "handoff_packet": {
      "request_id": "p1_5_primary_rollback_owner_handoff",
      "stage_id": "S4.4",
      "prerequisite_gates": [
        "S4.9 Gitea owner response gate",
        "P1-2 Gitea authenticated inventory request handoff",
        "P1-3 GitHub target owner response handoff",
        "P1-4 workflow / secret owner response handoff",
        "S4.13 owner response validation rollup"
      ],
      "requested_repo_templates": [
        "awoooi",
        "clawbot-v5",
        "wooo-aiops",
        "wooo-infra-config",
        "ewoooc",
        "bitan-pharmacy",
        "tsenyang-website"
      ],
      "recipient_role_or_team": "repo owner / release owner / fallback owner role only；不收個人 credential",
      "required_response_fields": [
        "owner_role_or_team",
        "decision",
        "decision_reason",
        "fallback_role_confirmation",
        "rollback_trigger_scope",
        "validation_window_owner",
        "redacted_evidence_refs",
        "followup_owner"
      ],
      "validation_window_refs": [
        "pre_cutover_freeze_review",
        "post_cutover_one_hour_observe",
        "post_cutover_twenty_four_hour_review"
      ],
      "allowed_evidence_refs": [
        "docs/security/source-control-primary-readiness-gate.snapshot.json",
        "docs/security/source-control-ref-truth-owner-response.snapshot.json",
        "docs/security/github-target-owner-decision-response.snapshot.json",
        "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json",
        "docs/security/source-control-owner-response-validation-rollup.snapshot.json"
      ],
      "forbidden_inputs": [
        "token value",
        "secret value",
        "private key",
        "runner registration token",
        "webhook secret",
        "repo write instruction",
        "refs sync or delete instruction",
        "GitHub primary switch request",
        "rollback execution request",
        "Gitea disable or archive request",
        "active scan or host maintenance request"
      ],
      "not_approval": true,
      "request_dispatch_authorized": false
    },
    "repo_owner_response_templates": [
      {
        "repo_key": "awoooi",
        "github_repo": "owenhytsai/awoooi",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "clawbot-v5",
        "github_repo": "owenhytsai/clawbot-v5",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "wooo-aiops",
        "github_repo": "owenhytsai/wooo-aiops",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "wooo-infra-config",
        "github_repo": "owenhytsai/wooo-infra-config",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "ewoooc",
        "github_repo": "owenhytsai/ewoooc",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "bitan-pharmacy",
        "github_repo": "owenhytsai/bitan-pharmacy",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      },
      {
        "repo_key": "tsenyang-website",
        "github_repo": "owenhytsai/tsenyang-website",
        "rollback_owner_status": "waiting_owner_response",
        "fallback_role_confirmation_required": true,
        "trigger_review_required": true,
        "validation_window_refs": [
          "pre_cutover_freeze_review",
          "post_cutover_one_hour_observe",
          "post_cutover_twenty_four_hour_review"
        ],
        "required_response_fields": [
          "owner_role_or_team",
          "decision",
          "decision_reason",
          "fallback_role_confirmation",
          "rollback_trigger_scope",
          "validation_window_owner",
          "redacted_evidence_refs",
          "followup_owner"
        ],
        "response_received": false,
        "response_accepted": false,
        "primary_ready": false,
        "execution_authorized": false
      }
    ],
    "post_handoff_invariants": [
      "request dispatch authorized 仍為 false，未送件前不得增加 request_sent_count。",
      "owner response received / accepted / rejected 全部維持 0。",
      "owner response 通過前不得把任何 repo 標記 primary_ready。",
      "dry-run completed count 與 active cutover count 維持 0。",
      "不得把 rollback owner handoff 當成 GitHub primary approval、rollback execution approval 或 Gitea disable approval。",
      "未來即使 owner response 通過，也只能更新 read-only rollback ADR、primary readiness wording、approval board 與 status rollup。"
    ]
  },
  "rollback_triggers": [
    "main/dev SHA 或 tag parity 與 owner-approved truth 不一致",
    "workflow、webhook、runner、deploy key、branch protection 或 repository secret name parity evidence 不完整",
    "GitHub hosted runner 使用量或 billing risk 超出 owner-approved 範圍",
    "deploy marker、release workflow 或 required status check 在 cutover 後失敗",
    "duplicate webhook 造成重複部署、重複通知或 approval queue 重複事件",
    "owner / visibility / canonical decision 被撤回或出現衝突",
    "post-cutover 1h 或 24h validation window 未通過"
  ],
  "validation_windows": [
    {
      "window_id": "pre_cutover_freeze_review",
      "title": "切換前 freeze review",
      "required_checks": [
        "確認 refs truth、workflow / secret export、owner / visibility / canonical、rollback owner 全部已批准",
        "確認沒有 unresolved HIGH risk blocker",
        "確認 Gitea fallback 保持可用"
      ],
      "failure_handling": "任何缺口都只回到 approval review，不執行 cutover。",
      "execution_authorized": false
    },
    {
      "window_id": "post_cutover_one_hour_observe",
      "title": "切換後 1 小時觀察窗口",
      "required_checks": [
        "deploy workflow / required checks 成功",
        "webhook 沒有重複事件",
        "runner 使用符合 owner-approved self-hosted / hosted policy",
        "核心服務健康與告警量未異常升高"
      ],
      "failure_handling": "只建立 rollback approval candidate；不得自動切回或自動改 webhook。",
      "execution_authorized": false
    },
    {
      "window_id": "post_cutover_twenty_four_hour_review",
      "title": "切換後 24 小時 review",
      "required_checks": [
        "refs、deploy、webhook、runner、secret name parity 沒有新增 drift",
        "AwoooP audit evidence 完整",
        "repo owner 確認可維持 GitHub primary 或要求 rollback review"
      ],
      "failure_handling": "若未通過，保留 Gitea fallback 並等待人工 rollback decision record。",
      "execution_authorized": false
    }
  ],
  "acceptance_rules": [
    "本 ADR 草案完成不代表任何 repo 可切 GitHub primary。",
    "每個 in-scope repo 必須有 owner-approved rollback plan、pre-cutover evidence、post-cutover validation window 與 rollback owner。",
    "任何 rollback 或 primary switch 都必須另有 runtime gate 與人工批准，不得由本 snapshot 自動觸發。",
    "Gitea fallback 不得在 24h review 完成前停用、刪除、封存或降級。",
    "任何 secret、token、cookie、private key、webhook secret 或 runner token 都不得保存。"
  ],
  "forbidden_actions": [
    "switch_github_primary",
    "execute_rollback",
    "create_github_repo",
    "change_repo_visibility",
    "sync_git_refs",
    "delete_git_refs",
    "force_push",
    "modify_webhook",
    "modify_workflow",
    "modify_branch_protection",
    "move_secret_values",
    "disable_gitea",
    "delete_or_archive_gitea_repo",
    "add_action_button"
  ]
}
