Files
awoooi/docs/security/source-control-primary-rollback-adr.snapshot.json
Your Name 58e760fae2
All checks were successful
CD Pipeline / tests (push) Successful in 1m25s
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / build-and-deploy (push) Successful in 4m2s
CD Pipeline / post-deploy-checks (push) Successful in 1m48s
feat(security): 擴充 S4.10 target owner response
2026-06-11 20:30:41 +08:00

855 lines
33 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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/mainP1-2P1-3P1-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-cutover1h24h ",
"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 switchrollback executionrefs syncworkflow/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 approvalrollback execution approval Gitea disable approval",
"使 owner response read-only rollback ADRprimary readiness wordingapproval board status rollup"
]
},
"rollback_triggers": [
"main/dev SHA tag parity owner-approved truth ",
"workflowwebhookrunnerdeploy keybranch protection repository secret name parity evidence ",
"GitHub hosted runner 使 billing risk owner-approved ",
"deploy markerrelease 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 truthworkflow / secret exportowner / visibility / canonicalrollback 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": [
"refsdeploywebhookrunnersecret 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 planpre-cutover evidencepost-cutover validation window rollback owner",
" rollback primary switch runtime gate snapshot ",
"Gitea fallback 24h review ",
" secrettokencookieprivate keywebhook 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"
]
}