# CI/CD Evolution Design

**Status:** Draft
**Date:** 2026-04-20 (original draft) | 2026-04-23 (revised: integrate existing AI Code Blocker) | 2026-04-25 (revised: restore Phase 4/5 staging, fix Axiom 5 references, address Copilot-comment job interaction)
**Scope:** Branch protection, merge policy, and automated review for `main` on `pingcap-inc/MetaDrivenPlatform4AI`.
**Audience:** Platform engineers, CI/CD maintainers, reviewers of branch-protection changes.

---

## 1. Summary

Today `main` has essentially no enforced merge gate and almost no human review process. Correctness rests on Copilot + CI on the PR head, with post-hoc auto-revert as the safety net. This works — the team ships — but leaves a measurable base-drift race (2.7% of merges land untested against their actual base) and zero-human-review on 91.3% of PRs, which is fine until it isn't.

This RFC proposes the minimum change that closes the base-drift hole and adds a deliberate, size-gated deep-review signal, **without** requiring human approvals, **without** running the heavy review pipeline in CI, and **without** reintroducing contributor-UX pain:

1. **Enable GitHub merge queue.** Queue-mode serialisation means CI runs against the speculative merged commit; base-drift is closed by the mechanism itself.
2. **Enable "require conversation resolution" on `main`.** Soft norm-based gate; hooks the review agent without building a required status check.
3. **Evolve the existing AI Code Blocker into a comment-based review gate.** The repo already has a lightweight MiniMax-based review pipeline running on every PR via GitHub Actions. Remove its informational commit status posting (noise — not in the required checks list), switch to unresolved-comment blocking via conversation resolution. Future tiers (agent-based, full-environment) can layer on top without changing the gating mechanism.
4. **Reconcile the branch-protection drift** documented in the assessment before any of the above — the locked list, the live config, and the actual workflows must be consistent.

The posture is deliberately lax. Every knob is reversible via a single setting; nothing in this design should ever feel like it must be true forever. Tighten when the data says to, measured against the baseline established by the [assessment](../cicd-current-state-assessment.md).

---

## 2. Problem

Quoting the assessment (section 10):

- **G1 — No merged-state verification.** 23.3% of PRs merge stale; 2.7% of all merges touch a runtime file that an intervening PR also touched. The team already shipped auto-revert (`#957`, `#1000`) because this cost is real.
- **G2 — No human review culture.** 91.3% of PRs merge with zero human feedback. Copilot formal-reviewed 14.7% of PRs in the full window (40% in the most recent 200, where adoption ramped up). `github-actions` comments on the majority of PRs with test-result drops. Any-bot-feedback reaches 85.7% of PRs. That is the entire external-review surface today.
- **G3 — Branch-protection live/locked drift.** The gh-branch-protection SKILL locks four required checks on `main`; the live configuration requires zero. The SKILL references a workflow file that doesn't exist (`e2e-api-tests.yml` — the check is actually emitted by `ci.yml`). ~~One of the locked checks (`Integration Tests`) is disabled in the workflow and would block forever if re-enabled.~~ **Partially resolved:** PR #1593 (merged 2026-04-21) re-enabled `Integration Tests` with a path-filter gate. The remaining drift items are: (a) the erroneous `e2e-api-tests.yml` workflow reference in the SKILL, and (b) the live protection still requires zero checks vs the locked list's four.
- **G4 — No CI health telemetry.** The per-check first-attempt pass rate is unknown, which means queue-eviction risk cannot be quantified in advance.

The mirror of the problem is what **not** to do: the team has already tried "require branches up-to-date before merge" without a queue, and disabled it because constant rebases at 21 merges/day killed contributor velocity. Anything that reintroduces that failure mode is off the table.

---

## 3. Non-goals

This design explicitly does **not**:

- Require human approvals on PRs. The review-culture gap is real but orthogonal; reinstating mandatory approvals with no reviewer bench just blocks merges.
- Use GitHub Actions as the compute host for medium/heavy reviews. Per-minute billing ($0.008–0.032/min) makes GH Actions cost-prohibitive for 15–90 min agent workloads ($50–400/month). GH Actions is fine for the existing lightweight review (2–5 min), but future Tier 2/3 reviews would run on Lambda/Fargate where per-second vCPU+memory billing is 20–65× cheaper.
- Make the deep review a required status check. The review agent posts comments, not status checks. Comment-based blocking via `required_conversation_resolution` preserves the fail-open property: if the infrastructure is down, no blocking comment goes up, and PRs merge normally.
- Re-enable `strict=true` on required status checks (the "require branches up-to-date before merge" flag) outside the merge queue. That's the setting whose UX cost drove it to be disabled in the first place.
- Replace Copilot. Copilot's review coverage (14.7% formal reviews across the window, ~40% on the most recent 200 PRs) plus the broader `github-actions` comment flood means any-bot-feedback reaches 85.7% of PRs — Copilot is not the thing that's broken.
- Build a long-running service to host the deep review. The tiered model is event-driven (task-per-review with zero idle cost), not an always-on service. Always-on ECS/EC2 would waste $9–144/month on idle time at 5–29% utilization.

---

## 4. Proposal

Four components, plus the supporting infrastructure for the review agent. Each is independently valuable; each can be rolled back in isolation.

### 4.1 Enable GitHub merge queue on `main`

Add `merge_group:` triggers to the workflows that emit the currently-required (locked) checks. When a PR enters the queue, GitHub constructs a speculative merge commit — PR branch + current `main` + any PRs ahead in the queue — and runs the required workflows against that commit. If the batch passes, the PRs land; if it fails, GitHub bisects and only the offending PR is evicted.

**Why this closes G1.** The speculative merge commit is — by construction — the exact state that will be on `main` after merge. A check that passes on it is a check that ran against the actual merged code. This is not a policy; it is a property of the mechanism. The 2.7% base-drift window in the assessment measures PRs where the last CI run happened against a stale base; a merge queue makes that window 0 for queue-gated checks.

**Queue-eviction risk.** The pain of a merge queue is directly proportional to the flake rate of its required checks. The assessment flagged G4 (no CI health telemetry) as a prerequisite for sizing this pain. The rollout (section 6) accounts for this by requiring a measurement phase before broadening the queue's required checks beyond the existing locked list.

**Scope of checks added to queue.** Start narrow: only the checks already required today (once G3 drift is reconciled). Do not add new checks to the queue as part of this change. If deep review eventually becomes a required merge-queue gate, that is its own future decision with its own justification form.

### 4.2 Enable "require conversation resolution" in branch protection

Flip `required_conversation_resolution.enabled` to `true` on `main`. Any unresolved review comment blocks merge.

**What this gives us.** A native GitHub hook that a bot (or human) can use to block merges without creating a status check. Posting a review comment marks the PR unmergeable until somebody clicks "Resolve conversation."

**What this does not give us.** The gate is self-service. The PR author can click "Resolve" without addressing the comment. We are accepting this as a norm-based control, not a mechanical one. If the data later shows authors routinely resolve without addressing, we will revisit (see section 6 rollback triggers).

**Why this instead of a status check.** A status check from the review agent would block *every* PR unless the agent actively posts `success`. That couples main's merge path to the agent's availability. Conversation resolution stays optional: the agent contributes a block only when it actively chooses to, and nothing happens when the agent is silent.

### 4.3 Evolve the existing AI Code Blocker into a comment-based review gate

The repo already has a lightweight AI review pipeline: the **AI Code Blocker** (`.github/workflows/ai-code-blocker.yml`, `.github/scripts/ai_blocker.py`). It runs on every PR via GitHub Actions, calls the MiniMax API to review the diff against six verdict standards (defined in `.github/copilot-instructions.md`), parses Copilot review comments for critical violations, and posts both a commit status and a PR comment.

#### Current state assessment

| Aspect | Finding |
|---|---|
| **Coverage** | Runs on every PR (`pull_request: opened/synchronize/reopened`). 100% trigger rate on pull_request events. |
| **Review model** | MiniMax API (single model, not dual-model). |
| **Verdict standards** | Six rules: no `__c` fields, no ProfileId branching, no hardcoded defaults, no business enum literals, no tenant table names, no hardcoded field writability. |
| **Output** | Posts commit status ("AI Code Blocker": success/failure/error) AND PR comment (when blocking). |
| **Maturity** | ~20 stabilization commits (#1629–#1734). Retry logic, diff filtering, Copilot comment parsing. |
| **Effectiveness** | Recent blocking examples are actionable: caught a syntax error (PR #1794), flagged a hardcoded `__c` field (PR #1793). Both PRs merged anyway — the commit status is not in the required checks list. |
| **Problem** | The commit status posting is noise. It creates a visible but non-blocking green/red check that teaches contributors to ignore it. The actual value is in the PR comments. |

#### Changes in this rollout

1. **Remove commit status posting.** Delete the `post_commit_status()` calls (5 code paths in `ai_blocker.py` lines 926–962; definition at line 236). The "AI Code Blocker" commit status context disappears entirely. Also remove the `statuses: write` permission from the workflow. **Note:** the `ai-review-via-copilot-comments` job (lines 67–95 of `ai-code-blocker.yml`) also invokes `post_commit_status` via `--skip-review` mode and must be updated in the same change.
2. **Switch to conversation-resolution blocking.** Combined with §4.2, blocking findings become unresolved PR comments that prevent merge. Advisory findings become auto-resolved comments (informational only). This gives the AI review actual merge-blocking power without coupling it to status check availability.
3. **Retain MiniMax as the review model for now.** The dual-model approach (Claude + Codex, per the `/review` command's dual-model protocol) is a natural future evolution but not part of this rollout.

#### Severity taxonomy

Findings are classified into two categories that determine the gating behavior:

- **Blocking** (comment left unresolved — merge blocked until human triage): security vulnerabilities, correctness bugs, data loss risk, API contract violations (Axiom 1 — frontend/backend mismatch), verdict standard violations
- **Advisory** (auto-resolved, findings posted as informational comment): style, naming, performance suggestions, test coverage gaps, documentation

#### Fail-open property

If the AI Code Blocker workflow fails (GH Actions outage, MiniMax API down):
- No blocking comment goes up.
- The PR passes the existing gates (CI + whatever humans choose to do).
- The PR merges normally.

**Partial-execution edge case.** If the workflow starts and posts a blocking comment (unresolved) but then crashes before completing, the orphaned unresolved comment blocks the PR under `required_conversation_resolution`. This is accepted as a minor fail-closed risk: the PR author can self-resolve the orphaned comment to unblock. The `concurrency: cancel-in-progress: true` setting in the workflow means a re-triggered run (push a new commit) will replace the failed run, and the new run's comments supersede the orphaned one.

The review signal is *contributory, not mandatory*.

#### Copilot-comment job interaction

The `ai-code-blocker.yml` workflow has a second job (`ai-review-via-copilot-comments`) triggered by `pull_request_review_comment` when Copilot posts inline comments. Under conversation resolution, this creates a chain: Copilot posts an inline comment → triggers the AI Code Blocker's Copilot-parsing job → that job may post its own blocking comment → two resolution requirements from one Copilot action. To prevent this amplification, Phase 4 must scope the Copilot-comment job to status-posting removal only (no new blocking comments from the Copilot-parsing path). The Copilot-comment job's purpose is to aggregate Copilot findings into a single status; under the new model, Copilot's own inline comments are already individually subject to conversation resolution, so a separate AI Code Blocker comment on top would be redundant.

#### What the review agent does NOT do

- Does not post a status check (uses conversation-resolution gate only — this is the key change).
- Does not push code (no auto-fix, no rebase, nothing that modifies the PR branch).
- Does not participate in the merge queue's speculative testing.

#### Future evolution (not in this rollout)

The tiered escalation model remains the long-term direction:

| Tier | What it does | Compute | When |
|---|---|---|---|
| **1 — Lightweight** (exists today) | Read diff → MiniMax API → post findings | GH Actions runner | Now |
| **2 — Medium** (future) | Clone repo → agent loop (grep, read, AST, multi-turn reasoning) → post findings | Fargate Spot (1 vCPU, 2 GB) | When Tier 1 stabilizes under conversation resolution |
| **3 — Heavyweight** (future) | Boot full env → Playwright browser tests → screenshots → post findings | Fargate Spot (4 vCPU, 8 GB) | When Tier 2 validates the escalation model |

Escalation triggers (for future tiers): Tier 1 flags a blocking finding, PR is XL (>2000 LOC), PR touches mandated paths, or manual `deep-review` label. The Lambda dispatcher + Fargate infrastructure described in §4.5 is provisioned only when the team is ready to add Tier 2/3.

### 4.4 Reconcile branch-protection drift (prerequisite)

Before enabling the queue (4.1), the state documented in the assessment's Gap G3 must be resolved. Two remaining edits are required to `.agent/skills/gh-branch-protection/SKILL.md`, each following the Change-Justification Form process that the SKILL mandates:

1. **Fix the `Source workflow` column** for `E2E API Stable Scenes` — it is emitted by `ci.yml`, not `e2e-api-tests.yml`. This is an errata fix with no policy change.
2. ~~Remove `Integration Tests` from the locked list.~~ **Resolved by PR #1593** (merged 2026-04-21). The `if: false` guard was replaced with a `needs.changes.outputs.backend == 'true'` path-filter gate, the TiDB image was pinned by digest, and the wait timeout was bumped. The job is running and passing on backend-touching PRs. It remains in the locked list — no action needed.
3. **Apply the locked list to live protection.** The SKILL's Audit command currently returns `DRIFT`; the remediation is a single scoped PUT to `required_status_checks` per the SKILL's Write section, after item 1 is resolved.

None of this is in scope for *this* RFC to execute — but the RFC's rollout (§6) gates queue enablement on these being done, so they are called out here so reviewers can confirm the ordering.

### 4.5 Infrastructure (future — Tier 2/3 only)

The immediate rollout (Phases 0–4) uses the existing GitHub Actions infrastructure. No new AWS resources are needed.

When the team is ready to add Tier 2/3 escalation, the following AWS resources would be provisioned:

| Resource | Purpose | Cost |
|---|---|---|
| **Lambda function** (Python 3.12, 512 MB, 15-min timeout) | Dispatcher (routes to Tier 2/3 Fargate tasks) | Free tier |
| **API Gateway** (HTTP API) | Receives GitHub webhook events | Free tier (< 1M requests/mo) |
| **ECS Fargate task definitions** (×2: Tier 2 + Tier 3) | Medium and heavyweight review tasks. Spot capacity provider. | Per-task only (see §4.3) |
| **ECR repository** (×2 images) | Docker images: Tier 2 (agent toolchain), Tier 3 (agent + Go + Node + Playwright) | < $1/mo storage |
| **Secrets Manager** (×3 secrets) | Anthropic API key, OpenAI API key, GitHub bot token | ~$1.20/mo |
| **IAM roles** (×2) | Lambda exec (ecs:RunTask, secrets access), ECS task (secrets access) | Free |
| **CloudWatch** | Lambda + ECS task logs, error-rate alarms | < $1/mo |

**Total infrastructure overhead: ~$2–3/month** on top of the per-review compute costs. **Setup estimate:** ~2–4 hours of Terraform/CDK. This is deferred until Phase 4 data justifies the escalation model.

---

## 5. Explicitly rejected alternatives

Brief justifications; the exploration behind each is in the ~20-turn conversation that produced the assessment and this RFC.

- **Status-check-based hard gate from the review agent.** Would make the agent's availability load-bearing on every PR's mergeability. Rejected because (a) graceful degradation requires the merge path to function without the agent, (b) it recreates exactly the operational-burden problem that ruled out running deep review as a required CI check, and (c) conversation-resolution gives equivalent blocking power without coupling availability.
- **Laptop-based local poller.** The original design for §4.3. Rejected because (a) single point of failure — laptop off/asleep/crashed means zero review coverage, incompatible with the ≥90% LARGE/XL coverage target (§7), (b) API keys stored on a personal machine have no rotation or access audit trail, (c) the "graceful degradation" framing masked an operational reality: the primary big-PR author's laptop availability determined the review surface for the whole team.
- **GitHub Actions as compute host for medium/heavy reviews.** Considered and rejected for Tier 2/3. Per-minute billing ($0.008–0.032/min) makes 15–90 min agent workloads cost-prohibitive: $50–400/month for the same work that Fargate event-driven tasks handle at $1.55–41/month (20–65× cheaper). GH Actions is fine for Tier 1 (the existing AI Code Blocker runs in ~2–5 min), but not for long-running agent workloads.
- **Always-on ECS/EC2 service.** Running a 24/7 container to poll GitHub when actual utilization is 5–29% wastes $9–144/month on idle time. Event-driven tasks (spin up per review, pay only for active compute) eliminate idle cost entirely.
- **Single-tier (always heavyweight) review.** Running Playwright + full environment boot on every qualifying PR would cost $12–41/month to cover ~210 reviews, when ~90% of them need only a lightweight API-call review. The tiered approach costs $0.13–4.28/month by reserving heavyweight for the ~10% that need it.
- **AWS Lambda for medium/heavy reviews.** Lambda's hard 15-minute timeout makes it unviable for medium (15–45 min) and heavyweight (30–90 min) reviews. Step Functions chaining would work around the limit but adds $25–50/month in orchestration cost and significant complexity for marginal savings over Fargate.
- **Require branches up-to-date, no queue.** Already tried; disabled because constant rebasing at 21 merges/day destroyed contributor throughput. Merge queue is the same invariant with much better UX.
- **Required human approvals.** The assessment shows there is no bench of reviewers — 5.5% of PRs get a human review at all, and Copilot plus the author effectively *is* the review for most PRs. Requiring approvals without a bench just blocks merges. Revisit if / when the review agent and any downstream investment grow the review-culture bench.
- **Add the review agent's finding as a required status check only when the check is present.** GitHub does not support conditional-required checks (a required check whose presence depends on PR properties). Workarounds exist (emit `success` proactively for PRs that don't qualify) but they re-couple the merge path to the agent's availability.

---

## 6. Rollout plan

Every phase is reversible via a single setting. Rollback cost is minutes, not days.

**Phase 0 — Land this design doc + the assessment.** No system changes. Establishes the baseline and the direction so subsequent phases have a traceable justification. This doc + `docs/cicd-current-state-assessment.md` land as a single PR. The assessment's raw data stays in the author's local working copy (`local_docs/cicd-current-state-assessment/data/`, locally-excluded) — the assessment's §11 documents the rerun recipe for future snapshots.

**Phase 1 — Reconcile the branch-protection drift (G3).** Two remaining edits per §4.4 (the third — re-enabling `Integration Tests` — was resolved by PR #1593), each through the gh-branch-protection SKILL's Change-Justification Form process. After this phase the locked list, the workflows, and the live config are consistent. The merge queue is still off; nothing observable changes for contributors except that required checks, when flipped back on, will match what actually runs.

**Phase 2 — Measure CI first-attempt pass rate for 2 weeks (G4).** Run a lightweight `check-runs` scraper against the last ~500 PRs' head SHAs and compute per-check flake rate. If any required check flakes >3% of first attempts, that check becomes a separate workstream before it enters the queue — queue-eviction pain scales directly with flake rate. (Industry guidance from GitHub and Shopify merge-queue deployments puts the pain threshold at 1–3%; we use 3% as the upper bound.) This phase gates 3.

**Phase 3 — Enable merge queue on `main` with the current required checks only.** Add `merge_group:` triggers to `ci.yml`, enable the queue in repo settings, route required contexts through the queue. No new checks added. Contributors' UX change: "Merge" button becomes "Merge when ready" and the PR joins a queue; typical added latency ~ one CI window. **Pre-merge verification required:** confirm that the merge queue's synthetic commit shape does not break the auto-revert trigger in `#957`/`#1000` (the trigger may key on squash-merge commit message patterns that differ from queue-merged commits).

**Phase 4 — Evolve AI Code Blocker (comment-mode switch).** Two changes ship together:

1. **Remove commit status posting from the AI Code Blocker.** Delete the `post_commit_status()` calls and `statuses: write` permission from both jobs (`ai-review-via-minimax` and `ai-review-via-copilot-comments`). The "AI Code Blocker" commit status context disappears. This is the removal of the status-only behaviour — it was noise (not in the required checks list, taught contributors to ignore it).
2. **Switch the AI Code Blocker to the severity taxonomy** (§4.3). Blocking findings → unresolved PR comment. Advisory findings → auto-resolved PR comment. The existing `--post-comment` flag already controls comment posting; the change is making all qualifying PRs get comments (not just blocked ones) and classifying findings into blocking vs advisory. The `ai-review-via-copilot-comments` job is scoped to status-removal only — it does not post new blocking comments, because Copilot's own inline comments are already individually subject to conversation resolution once Phase 5 enables it.

Observe for ~1 week: confirm the AI Code Blocker's comment volume and severity classification are stable before enabling conversation resolution. This avoids coupling an untested comment mode with a merge gate.

**Phase 5 — Enable "require conversation resolution" in branch protection.** Single setting flip. This makes unresolved AI Code Blocker comments actually prevent merge. **Note:** this also gates merge on any unresolved Copilot inline comments (~40% of recent PRs get Copilot formal reviews per assessment §6; the unresolved inline comment rate may be higher). This is accepted as an intended tightening — Copilot comments are generally actionable, and authors can self-resolve. If the self-resolve rate on Copilot comments exceeds 80% within 60 seconds, revisit whether Copilot's inline comments should be excluded from the resolution requirement.

### Rollback triggers (any one → revert the most recent phase and hold)

- **Queue-eviction rate > 5% of queue attempts.** Indicates flakes are paying the queue tax. Revert to phase 2 and treat the flaky check as a blocker.
- **Median PR open-to-merge latency > 90 min** (vs. baseline 43 min). Revert the queue; investigate whether a specific workflow is slow or whether queue contention is the issue.
- **Conversation-resolution abuse**: >25% of blocking comments from the AI Code Blocker get self-resolved by the PR author within 60 seconds. Means authors are bypassing reflexively; pause blocking mode and reassess whether a status check is needed after all.
- **Any Copilot + AI Code Blocker duplication > 50% of findings**: if the blocker is mostly re-saying what Copilot already said, we're not adding signal; cost exceeds value and the blocker should be scoped down or retired.

---

## 7. Success metrics

Re-run the assessment (recipe in the assessment's §11) ~60 days after phase 5 and compare. Targets:

| Metric | Baseline (2026-04-20) | Target after rollout |
|---|---|---|
| Base-drift merges with runtime overlap | **2.7%** (16 / 600) | **≤ 0.5%** — queue closes this mechanistically |
| PRs with Copilot formal review | 14.7% window, ~40% recent | **≥ 50%** sustained, Copilot unchanged |
| LARGE/XL PRs with any substantive external review (Copilot OR AI Code Blocker) | ~12–22% (humans only on big PRs) | **≥ 90%** — AI Code Blocker already reviews all PRs; conversation resolution makes findings actionable |
| Revert rate | ~1.0% visible (6/600); 1.0–1.8% including implied reverts | Same-or-better; no regression |
| Median PR open-to-merge | 43 min | **≤ 60 min** (queue overhead tolerable) |
| Queue-eviction rate | n/a | **< 5%** of queue attempts |
| Review agent false-positive rate (findings marked "not actionable" by author) | n/a | **< 25%** after 8 weeks |
| Review agent infra cost | n/a (GH Actions included) | **$0/month incremental** — Tier 1 runs on existing GH Actions runners; future Tier 2/3 infra < $10/month |

None of these are aspirational. All are measurable from re-running the same scripts, plus one new one for check-run pass rate (built in phase 2) and the AI Code Blocker's existing workflow logs (GitHub Actions run history + PR comment audit trail).

---

## 8. Open questions

Things this RFC does not commit to; each can be decided based on post-phase-5 data.

- **Model upgrade path.** The existing AI Code Blocker uses MiniMax. The `/review` command's dual-model protocol (Claude + Codex) is the natural upgrade path. When to upgrade: after conversation-resolution blocking stabilizes and the false-positive rate is measured. The severity taxonomy and gating mechanism are model-agnostic.
- **Tier 2/3 deployment timing.** When the Tier 1 review (existing AI Code Blocker under conversation resolution) stabilizes, the tiered escalation infrastructure (§4.5) can be provisioned. Decision criteria: Tier 1 false-positive rate < 25% sustained for 8 weeks, and at least 3 examples of PRs where Tier 1 missed a finding that deeper analysis would have caught.
- **Size thresholds for qualifying PRs.** The existing AI Code Blocker runs on all PRs. If this is too noisy under conversation-resolution blocking, add thresholds (e.g., `additions > 500` OR `changed_files > 10`).
- **Promoting the review agent to a required status check.** Explicitly out of scope. Conversation-resolution blocking is the gating mechanism. Revisit only if the self-resolve abuse rate makes it ineffective.
- **Deep review on merge-queue entry (`merge_group:` trigger).** The exact "run deep review on the exact merged state" semantics only exist at queue-entry time. If phase 4 surfaces that the agent's timing (on PR head, possibly stale) produces noise, there is a natural upgrade path: trigger the review from the `merge_group:` event. That is a future decision; not proposed here.

---

## 9. References

- [CI/CD Current-State Assessment](../cicd-current-state-assessment.md) — the data-driven baseline this design is a response to. Its §11 documents how to reproduce the underlying dataset (the raw data is intentionally kept local, not committed).
- [`.agent/skills/gh-branch-protection/SKILL.md`](../../.agent/skills/gh-branch-protection/SKILL.md) — the locked-list contract and Change-Justification Form that phases 1 and 3 must follow.
- [`.github/workflows/ci.yml`](../../.github/workflows/ci.yml) — source of the currently-required check names.
- [`.github/workflows/ai-code-blocker.yml`](../../.github/workflows/ai-code-blocker.yml) — existing AI review pipeline evolved in Phase 4.
- [`.github/scripts/ai_blocker.py`](../../.github/scripts/ai_blocker.py) — review engine: MiniMax API, Copilot comment parsing, status posting (to be removed in Phase 4).
- [`.github/copilot-instructions.md`](../../.github/copilot-instructions.md) — six verdict standards that feed both Copilot and the AI Code Blocker.
- [`CLAUDE.md`](../../CLAUDE.md) — correctness-model axioms (1–4). The review agent's future model upgrade follows the `/review` command's dual-model protocol.
