This is an automated email from the ASF dual-hosted git repository.

shuke987 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new cace2bb01f1 [improvement](workflow) Accept qualified local review 
receipts (#66959)
cace2bb01f1 is described below

commit cace2bb01f15ee6f8160eff17004052bb9aa18cc
Author: shuke <[email protected]>
AuthorDate: Mon Sep 7 10:58:38 2026 +0800

    [improvement](workflow) Accept qualified local review receipts (#66959)
    
    Problem Summary:
    The hosted code-review pipeline can run out of review tokens even when a
    committer has already completed the equivalent `doris-repo-review`
    workflow locally. Accept a strictly formatted `doris-repo-review/v1`
    PASS comment as an alternative source for the existing `code-review`
    commit status.
    
    The trusted default-branch workflow now:
    
    - accepts only comments authored by users with effective `write` or
    `admin` repository permission;
    - requires the receipt commit to equal the live PR head;
    - requires the reviewed base to equal the live base or be its ancestor
    by no more than 48 hours of commit history;
    - enforces the exact Opus 5, Fable 5, and GPT-5.6 Sol model allowlist at
    `xhigh`, `max`, or `ultra` effort;
    - requires `PASS`, convergence, one to three rounds, and zero
    Blocker/Major findings;
    - writes `code-review: success` only after every check passes.
    
    The 48-hour base rule is evaluated when the comment is created or
    edited. Runtime identity remains an auditable local declaration rather
    than cryptographic proof, so the existing write-permission boundary and
    later sampling remain part of the trust model.
---
 .github/scripts/resolve_code_review_status.py      | 123 +++++++++
 .github/scripts/test_resolve_code_review_status.py | 119 +++++++++
 .../scripts/test_validate_review_pass_comment.py   | 290 +++++++++++++++++++++
 .github/scripts/validate_review_pass_comment.py    | 235 +++++++++++++++++
 .github/workflows/code-review-aggregate-status.yml |  85 ++++++
 .github/workflows/code-review-runner.yml           |  40 ++-
 .github/workflows/code-review-sync-result.yml      | 252 +++++++++++++++---
 7 files changed, 1103 insertions(+), 41 deletions(-)

diff --git a/.github/scripts/resolve_code_review_status.py 
b/.github/scripts/resolve_code_review_status.py
new file mode 100644
index 00000000000..cc81807e34e
--- /dev/null
+++ b/.github/scripts/resolve_code_review_status.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+"""Resolve the SHA-wide code-review status from PR/base-specific sources."""
+
+from __future__ import annotations
+
+import argparse
+import json
+import re
+from dataclasses import dataclass
+from pathlib import Path
+
+
+SOURCE_CONTEXT_RE = re.compile(
+    
r"code-review/source/(?:automated|local|skip)/pr-(\d+)/base-([0-9a-fA-F]{40})"
+)
+SHA_RE = re.compile(r"[0-9a-fA-F]{40}")
+
+
+class ResolutionError(ValueError):
+    """The supplied GitHub API data cannot be resolved safely."""
+
+
+@dataclass(frozen=True)
+class Resolution:
+    state: str
+    description: str
+
+
+def resolve_status(
+    pulls: list[object], statuses: list[object], *, head_sha: str
+) -> Resolution:
+    if SHA_RE.fullmatch(head_sha) is None:
+        raise ResolutionError("head SHA is not a full SHA")
+
+    open_contexts: set[tuple[int, str]] = set()
+    for item in pulls:
+        if not isinstance(item, dict) or item.get("state") != "open":
+            continue
+        head = item.get("head")
+        base = item.get("base")
+        if not isinstance(head, dict) or not isinstance(base, dict):
+            raise ResolutionError("pull request is missing head or base 
information")
+        pull_head = head.get("sha")
+        base_sha = base.get("sha")
+        number = item.get("number")
+        if not isinstance(pull_head, str) or not isinstance(base_sha, str):
+            raise ResolutionError("pull request head or base SHA is invalid")
+        if pull_head.casefold() != head_sha.casefold():
+            continue
+        if not isinstance(number, int) or SHA_RE.fullmatch(base_sha) is None:
+            raise ResolutionError("pull request number or base SHA is invalid")
+        open_contexts.add((number, base_sha.casefold()))
+
+    if not open_contexts:
+        return Resolution(
+            "pending", f"No open pull request currently uses {head_sha[:12]}."
+        )
+
+    latest_by_context: dict[str, dict[str, object]] = {}
+    for item in statuses:
+        if not isinstance(item, dict):
+            raise ResolutionError("commit status entry is invalid")
+        context = item.get("context")
+        status_id = item.get("id")
+        state = item.get("state")
+        if not isinstance(context, str) or not isinstance(status_id, int):
+            raise ResolutionError("commit status context or id is invalid")
+        if not isinstance(state, str):
+            raise ResolutionError("commit status state is invalid")
+        previous = latest_by_context.get(context)
+        if previous is None or status_id > int(previous["id"]):
+            latest_by_context[context] = item
+
+    approved_contexts: set[tuple[int, str]] = set()
+    for context, item in latest_by_context.items():
+        match = SOURCE_CONTEXT_RE.fullmatch(context)
+        if match is not None and item["state"] == "success":
+            approved_contexts.add((int(match.group(1)), 
match.group(2).casefold()))
+
+    missing = sorted(open_contexts - approved_contexts)
+    if missing:
+        number, base_sha = missing[0]
+        remaining = len(missing) - 1
+        suffix = f" (+{remaining} more)" if remaining else ""
+        return Resolution(
+            "pending",
+            f"Awaiting code review for PR #{number} at 
{base_sha[:12]}{suffix}.",
+        )
+
+    count = len(open_contexts)
+    noun = "context" if count == 1 else "contexts"
+    return Resolution(
+        "success",
+        f"Code review passed for {count} open PR {noun} on {head_sha[:12]}.",
+    )
+
+
+def load_list(path: Path, name: str) -> list[object]:
+    value = json.loads(path.read_text(encoding="utf-8"))
+    if not isinstance(value, list):
+        raise ResolutionError(f"{name} JSON must be an array")
+    return value
+
+
+def main() -> int:
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--pulls-file", type=Path, required=True)
+    parser.add_argument("--statuses-file", type=Path, required=True)
+    parser.add_argument("--head-sha", required=True)
+    args = parser.parse_args()
+
+    resolution = resolve_status(
+        load_list(args.pulls_file, "pulls"),
+        load_list(args.statuses_file, "statuses"),
+        head_sha=args.head_sha,
+    )
+    print(f"state={resolution.state}")
+    print(f"description={resolution.description}")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/.github/scripts/test_resolve_code_review_status.py 
b/.github/scripts/test_resolve_code_review_status.py
new file mode 100644
index 00000000000..113e7cca1bf
--- /dev/null
+++ b/.github/scripts/test_resolve_code_review_status.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+import unittest
+
+from resolve_code_review_status import ResolutionError, resolve_status
+
+
+HEAD_SHA = "a" * 40
+OTHER_HEAD_SHA = "d" * 40
+BASE_SHA = "b" * 40
+OTHER_BASE_SHA = "c" * 40
+
+
+def pull(number: int, *, head: str = HEAD_SHA, base: str = BASE_SHA, state: 
str = "open") -> dict:
+    return {
+        "number": number,
+        "state": state,
+        "head": {"sha": head},
+        "base": {"sha": base},
+    }
+
+
+def status(
+    status_id: int,
+    *,
+    source: str = "local",
+    pr_number: int = 123,
+    base: str = BASE_SHA,
+    state: str = "success",
+) -> dict:
+    return {
+        "id": status_id,
+        "state": state,
+        "context": f"code-review/source/{source}/pr-{pr_number}/base-{base}",
+    }
+
+
+class ResolveCodeReviewStatusTest(unittest.TestCase):
+    def test_accepts_one_matching_source(self) -> None:
+        result = resolve_status([pull(123)], [status(1)], head_sha=HEAD_SHA)
+        self.assertEqual("success", result.state)
+
+    def test_requires_every_open_pr_with_the_same_head(self) -> None:
+        pulls = [pull(123), pull(124, base=OTHER_BASE_SHA)]
+        statuses = [status(1, pr_number=123)]
+        result = resolve_status(pulls, statuses, head_sha=HEAD_SHA)
+        self.assertEqual("pending", result.state)
+        self.assertIn("PR #124", result.description)
+
+    def test_accepts_different_sources_for_shared_head(self) -> None:
+        pulls = [pull(123), pull(124, base=OTHER_BASE_SHA)]
+        statuses = [
+            status(1, pr_number=123),
+            status(2, source="automated", pr_number=124, base=OTHER_BASE_SHA),
+        ]
+        result = resolve_status(pulls, statuses, head_sha=HEAD_SHA)
+        self.assertEqual("success", result.state)
+        self.assertIn("2 open PR contexts", result.description)
+
+    def test_shared_head_recovers_after_another_pr_moves(self) -> None:
+        statuses = [status(1, pr_number=123)]
+        before = resolve_status(
+            [pull(123), pull(124, base=OTHER_BASE_SHA)],
+            statuses,
+            head_sha=HEAD_SHA,
+        )
+        after = resolve_status(
+            [pull(123), pull(124, head=OTHER_HEAD_SHA, base=OTHER_BASE_SHA)],
+            statuses,
+            head_sha=HEAD_SHA,
+        )
+        self.assertEqual("pending", before.state)
+        self.assertEqual("success", after.state)
+
+    def test_does_not_reuse_a_source_after_base_changes(self) -> None:
+        result = resolve_status(
+            [pull(123, base=OTHER_BASE_SHA)], [status(1)], head_sha=HEAD_SHA
+        )
+        self.assertEqual("pending", result.state)
+
+    def test_ignores_closed_prs_and_prs_for_other_heads(self) -> None:
+        pulls = [
+            pull(123),
+            pull(124, state="closed"),
+            pull(125, head=OTHER_HEAD_SHA),
+        ]
+        result = resolve_status(pulls, [status(1)], head_sha=HEAD_SHA)
+        self.assertEqual("success", result.state)
+
+    def test_latest_state_wins_within_one_source_context(self) -> None:
+        statuses = [status(1), status(2, state="pending")]
+        result = resolve_status([pull(123)], statuses, head_sha=HEAD_SHA)
+        self.assertEqual("pending", result.state)
+
+    def test_another_success_source_can_satisfy_the_context(self) -> None:
+        statuses = [
+            status(1),
+            status(2, state="pending"),
+            status(3, source="skip"),
+        ]
+        result = resolve_status([pull(123)], statuses, head_sha=HEAD_SHA)
+        self.assertEqual("success", result.state)
+
+    def test_ignores_unscoped_legacy_code_review_success(self) -> None:
+        statuses = [{"id": 1, "state": "success", "context": "code-review"}]
+        result = resolve_status([pull(123)], statuses, head_sha=HEAD_SHA)
+        self.assertEqual("pending", result.state)
+
+    def test_returns_pending_without_an_open_pr(self) -> None:
+        result = resolve_status([], [], head_sha=HEAD_SHA)
+        self.assertEqual("pending", result.state)
+
+    def test_rejects_malformed_api_data(self) -> None:
+        with self.assertRaisesRegex(ResolutionError, "base SHA"):
+            resolve_status([pull(123, base="short")], [], head_sha=HEAD_SHA)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/.github/scripts/test_validate_review_pass_comment.py 
b/.github/scripts/test_validate_review_pass_comment.py
new file mode 100644
index 00000000000..6a6c6f54cb4
--- /dev/null
+++ b/.github/scripts/test_validate_review_pass_comment.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+import tempfile
+import unittest
+from pathlib import Path
+
+from validate_review_pass_comment import ValidationError, validate_comment
+
+
+HEAD_SHA = "a" * 40
+BASE_SHA = "b" * 40
+LIVE_BASE_SHA = "c" * 40
+VALIDATOR = Path(__file__).with_name("validate_review_pass_comment.py")
+
+
+def make_comment(**overrides: str) -> str:
+    fields = {
+        "schema": "doris-repo-review/v1",
+        "status": "PASS",
+        "pr": "apache/doris#123",
+        "commit": HEAD_SHA,
+        "base": BASE_SHA,
+        "reviewed_at": "2026-08-18T12:01+00:00",
+        "reviewer": "doris-committer",
+        "model": "gpt-5.6-sol",
+        "effort": "xhigh",
+        "findings": "{blocker: 0, major: 0, minor: 1, nit: 2}",
+        "rounds": "2",
+        "converged": "true",
+    }
+    fields.update(overrides)
+    yaml_body = "\n".join(f"{key}: {value}" for key, value in fields.items())
+    return f"""<!-- doris-repo-review:v1:begin -->
+### Local pipeline review — ✅ PASS
+
+```yaml
+{yaml_body}
+```
+
+**Notes for maintainers**
+
+_None._
+<!-- doris-repo-review:v1:end -->
+"""
+
+
+def validate(comment: str, **overrides: object) -> dict[str, object]:
+    arguments = {
+        "repository": "apache/doris",
+        "pr_number": 123,
+        "head_sha": HEAD_SHA,
+        "live_base_sha": LIVE_BASE_SHA,
+        "base_compare_status": "ahead",
+        "reviewed_base_committed_at": "2026-08-17T12:00:00Z",
+        "live_base_committed_at": "2026-08-19T11:59:00Z",
+        "comment_author": "doris-committer",
+        "comment_author_permission": "write",
+    }
+    arguments.update(overrides)
+    return validate_comment(
+        comment,
+        **arguments,
+    )
+
+
+class ValidateReviewPassCommentTest(unittest.TestCase):
+    def test_accepts_allowed_model_effort_combinations(self) -> None:
+        combinations = (
+            ("claude-opus-5", "xhigh"),
+            ("claude-opus-5", "max"),
+            ("claude-opus-5[1m]", "xhigh"),
+            ("claude-opus-5[1m]", "max"),
+            ("claude-fable-5", "xhigh"),
+            ("claude-fable-5", "max"),
+            ("claude-fable-5[1m]", "xhigh"),
+            ("claude-fable-5[1m]", "max"),
+            ("gpt-5.6-sol", "xhigh"),
+            ("gpt-5.6-sol", "max"),
+            ("gpt-5.6-sol", "ultra"),
+        )
+        for model, effort in combinations:
+            with self.subTest(model=model, effort=effort):
+                fields = validate(make_comment(model=model, effort=effort))
+                self.assertEqual(model, fields["model"])
+
+    def test_rejects_ultra_for_claude_models(self) -> None:
+        for model in (
+            "claude-opus-5",
+            "claude-opus-5[1m]",
+            "claude-fable-5",
+            "claude-fable-5[1m]",
+        ):
+            with self.subTest(model=model):
+                with self.assertRaisesRegex(ValidationError, "is not allowed 
for model"):
+                    validate(make_comment(model=model, effort="ultra"))
+
+    def test_rejects_effort_below_xhigh(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "is not allowed for 
model"):
+            validate(make_comment(effort="high"))
+
+    def test_rejects_unlisted_model(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "model is not allowed"):
+            validate(make_comment(model="gpt-5.6"))
+
+    def test_rejects_a_different_head(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "current PR head"):
+            validate(make_comment(commit="c" * 40))
+
+    def test_reviewed_at_does_not_expire_the_comment(self) -> None:
+        fields = validate(make_comment(reviewed_at="2020-01-01T00:00+00:00"))
+        self.assertEqual("2020-01-01T00:00+00:00", fields["reviewed_at"])
+
+    def test_accepts_the_current_base_regardless_of_commit_age(self) -> None:
+        fields = validate(
+            make_comment(base=LIVE_BASE_SHA),
+            base_compare_status="identical",
+            reviewed_base_committed_at=None,
+            live_base_committed_at=None,
+        )
+        self.assertEqual(LIVE_BASE_SHA, fields["base"])
+
+    def test_accepts_a_base_exactly_48_hours_behind(self) -> None:
+        fields = validate(
+            make_comment(),
+            reviewed_base_committed_at="2026-08-17T12:00:00Z",
+            live_base_committed_at="2026-08-19T12:00:00Z",
+        )
+        self.assertEqual(BASE_SHA, fields["base"])
+
+    def test_rejects_a_base_more_than_48_hours_behind(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "more than 48 hours 
behind"):
+            validate(
+                make_comment(),
+                reviewed_base_committed_at="2026-08-17T11:59:59Z",
+                live_base_committed_at="2026-08-19T12:00:00Z",
+            )
+
+    def test_rejects_a_diverged_base(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "not an ancestor"):
+            validate(make_comment(), base_compare_status="diverged")
+
+    def test_rejects_inconsistent_equal_base_comparison(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "compare status 
identical"):
+            validate(make_comment(base=LIVE_BASE_SHA), 
base_compare_status="ahead")
+
+    def test_rejects_base_commit_times_in_reverse_order(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "after the current base"):
+            validate(
+                make_comment(),
+                reviewed_base_committed_at="2026-08-19T12:01:00Z",
+                live_base_committed_at="2026-08-19T12:00:00Z",
+            )
+
+    def test_rejects_missing_base_commit_times(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "commit time is 
required"):
+            validate(make_comment(), reviewed_base_committed_at=None)
+
+    def test_rejects_a_different_reviewer(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "comment author"):
+            validate(make_comment(reviewer="someone-else"))
+
+    def test_accepts_admin_permission(self) -> None:
+        fields = validate(make_comment(), comment_author_permission="admin")
+        self.assertEqual("doris-committer", fields["reviewer"])
+
+    def test_rejects_non_write_permissions(self) -> None:
+        for permission in ("read", "triage", "none", ""):
+            with self.subTest(permission=permission):
+                with self.assertRaisesRegex(ValidationError, "write 
permission"):
+                    validate(make_comment(), 
comment_author_permission=permission)
+
+    def test_rejects_a_different_pr(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "different pull request"):
+            validate(make_comment(pr="apache/doris#124"))
+
+    def test_rejects_blocker_or_major_findings(self) -> None:
+        for findings in (
+            "{blocker: 1, major: 0, minor: 0, nit: 0}",
+            "{blocker: 0, major: 1, minor: 0, nit: 0}",
+        ):
+            with self.subTest(findings=findings):
+                with self.assertRaisesRegex(ValidationError, "must both be 
zero"):
+                    validate(make_comment(findings=findings))
+
+    def test_rejects_a_non_converged_review(self) -> None:
+        with self.assertRaisesRegex(ValidationError, "did not converge"):
+            validate(make_comment(converged="false"))
+
+    def test_rejects_rounds_outside_the_pipeline_limit(self) -> None:
+        for rounds in ("0", "4"):
+            with self.subTest(rounds=rounds):
+                with self.assertRaisesRegex(ValidationError, "between 1 and 
3"):
+                    validate(make_comment(rounds=rounds))
+
+    def test_rejects_duplicate_markers(self) -> None:
+        comment = make_comment() + make_comment()
+        with self.assertRaisesRegex(ValidationError, "exactly one v1 marker 
pair"):
+            validate(comment)
+
+    def test_rejects_reversed_markers(self) -> None:
+        comment = make_comment()
+        marked_body = comment.split("<!-- doris-repo-review:v1:begin -->", 
1)[1].split(
+            "<!-- doris-repo-review:v1:end -->", 1
+        )[0]
+        reversed_comment = (
+            "<!-- doris-repo-review:v1:end -->"
+            + marked_body
+            + "<!-- doris-repo-review:v1:begin -->"
+        )
+        with self.assertRaisesRegex(ValidationError, "out of order"):
+            validate(reversed_comment)
+
+    def test_extract_base_cli(self) -> None:
+        with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as 
comment_file:
+            comment_file.write(make_comment())
+            comment_file.flush()
+            result = subprocess.run(
+                [
+                    sys.executable,
+                    str(VALIDATOR),
+                    "extract-base",
+                    "--comment-file",
+                    comment_file.name,
+                ],
+                check=True,
+                capture_output=True,
+                text=True,
+            )
+        self.assertEqual(BASE_SHA, result.stdout.strip())
+
+    def test_extract_base_cli_rejects_a_non_sha(self) -> None:
+        with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as 
comment_file:
+            comment_file.write(make_comment(base="not-a-sha"))
+            comment_file.flush()
+            result = subprocess.run(
+                [
+                    sys.executable,
+                    str(VALIDATOR),
+                    "extract-base",
+                    "--comment-file",
+                    comment_file.name,
+                ],
+                check=False,
+                capture_output=True,
+                text=True,
+            )
+        self.assertEqual(1, result.returncode)
+        self.assertIn("base is not a full SHA", result.stderr)
+
+    def test_validate_cli_accepts_write_permission(self) -> None:
+        with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as 
comment_file:
+            comment_file.write(make_comment())
+            comment_file.flush()
+            result = subprocess.run(
+                [
+                    sys.executable,
+                    str(VALIDATOR),
+                    "validate",
+                    "--comment-file",
+                    comment_file.name,
+                    "--repository",
+                    "apache/doris",
+                    "--pr-number",
+                    "123",
+                    "--head-sha",
+                    HEAD_SHA,
+                    "--live-base-sha",
+                    LIVE_BASE_SHA,
+                    "--base-compare-status",
+                    "ahead",
+                    "--reviewed-base-committed-at",
+                    "2026-08-17T12:00:00Z",
+                    "--live-base-committed-at",
+                    "2026-08-19T11:59:00Z",
+                    "--comment-author",
+                    "doris-committer",
+                    "--comment-author-permission",
+                    "write",
+                ],
+                check=True,
+                capture_output=True,
+                text=True,
+            )
+        self.assertIn("VALID: local pipeline review passed", result.stdout)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/.github/scripts/validate_review_pass_comment.py 
b/.github/scripts/validate_review_pass_comment.py
new file mode 100644
index 00000000000..5f33a8b5e95
--- /dev/null
+++ b/.github/scripts/validate_review_pass_comment.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python3
+"""Validate a doris-repo-review PASS comment for the current PR head."""
+
+from __future__ import annotations
+
+import argparse
+import datetime as dt
+import re
+import sys
+from pathlib import Path
+
+
+BEGIN_MARKER = "<!-- doris-repo-review:v1:begin -->"
+END_MARKER = "<!-- doris-repo-review:v1:end -->"
+SCHEMA = "doris-repo-review/v1"
+MAX_BASE_LAG = dt.timedelta(hours=48)
+
+ALLOWED_EFFORTS_BY_MODEL = {
+    "claude-opus-5": frozenset({"xhigh", "max"}),
+    "claude-opus-5[1m]": frozenset({"xhigh", "max"}),
+    "claude-fable-5": frozenset({"xhigh", "max"}),
+    "claude-fable-5[1m]": frozenset({"xhigh", "max"}),
+    "gpt-5.6-sol": frozenset({"xhigh", "max", "ultra"}),
+}
+ALLOWED_AUTHOR_PERMISSIONS = frozenset({"write", "admin"})
+EXPECTED_FIELDS = (
+    "schema",
+    "status",
+    "pr",
+    "commit",
+    "base",
+    "reviewed_at",
+    "reviewer",
+    "model",
+    "effort",
+    "findings",
+    "rounds",
+    "converged",
+)
+FINDINGS_RE = re.compile(
+    r"\{blocker: (\d+), major: (\d+), minor: (\d+), nit: (\d+)\}"
+)
+SHA_RE = re.compile(r"[0-9a-fA-F]{40}")
+
+
+class ValidationError(ValueError):
+    """The comment is not eligible to satisfy the code-review check."""
+
+
+def parse_comment(comment: str) -> dict[str, object]:
+    if comment.count(BEGIN_MARKER) != 1 or comment.count(END_MARKER) != 1:
+        raise ValidationError("expected exactly one v1 marker pair")
+    if comment.index(BEGIN_MARKER) > comment.index(END_MARKER):
+        raise ValidationError("v1 markers are out of order")
+
+    marked_body = comment.split(BEGIN_MARKER, 1)[1].split(END_MARKER, 1)[0]
+    yaml_blocks = re.findall(r"```yaml\n(.*?)\n```", marked_body, 
flags=re.DOTALL)
+    if len(yaml_blocks) != 1:
+        raise ValidationError("expected exactly one fenced yaml block")
+
+    fields: dict[str, object] = {}
+    field_order: list[str] = []
+    for line in yaml_blocks[0].splitlines():
+        if ":" not in line:
+            raise ValidationError(f"malformed yaml field: {line!r}")
+        key, value = line.split(":", 1)
+        key = key.strip()
+        value = value.strip()
+        if key in fields:
+            raise ValidationError(f"duplicate field: {key}")
+        field_order.append(key)
+        fields[key] = value
+
+    if tuple(field_order) != EXPECTED_FIELDS:
+        raise ValidationError("comment fields do not match the v1 schema")
+
+    findings_match = FINDINGS_RE.fullmatch(str(fields["findings"]))
+    if findings_match is None:
+        raise ValidationError("findings must use the v1 inline-map format")
+    fields["findings"] = tuple(int(value) for value in findings_match.groups())
+
+    try:
+        fields["rounds"] = int(str(fields["rounds"]))
+    except ValueError as exc:
+        raise ValidationError("rounds must be an integer") from exc
+
+    return fields
+
+
+def validate_comment(
+    comment: str,
+    *,
+    repository: str,
+    pr_number: int,
+    head_sha: str,
+    live_base_sha: str,
+    base_compare_status: str,
+    reviewed_base_committed_at: str | None,
+    live_base_committed_at: str | None,
+    comment_author: str,
+    comment_author_permission: str,
+) -> dict[str, object]:
+    fields = parse_comment(comment)
+
+    if fields["schema"] != SCHEMA:
+        raise ValidationError(f"unsupported schema: {fields['schema']}")
+    if fields["status"] != "PASS":
+        raise ValidationError("status is not PASS")
+    if str(fields["pr"]).casefold() != f"{repository}#{pr_number}".casefold():
+        raise ValidationError("comment targets a different pull request")
+
+    reviewed_commit = str(fields["commit"])
+    require_full_sha("commit", reviewed_commit)
+    if reviewed_commit.casefold() != head_sha.casefold():
+        raise ValidationError("reviewed commit does not match the current PR 
head")
+    reviewed_base_sha = str(fields["base"])
+    require_full_sha("base", reviewed_base_sha)
+    require_full_sha("live base", live_base_sha)
+
+    same_base = reviewed_base_sha.casefold() == live_base_sha.casefold()
+    if same_base:
+        if base_compare_status != "identical":
+            raise ValidationError("equal base SHAs must have compare status 
identical")
+    else:
+        if base_compare_status != "ahead":
+            raise ValidationError("reviewed base is not an ancestor of the 
current PR base")
+        reviewed_base_time = parse_timestamp(
+            "reviewed base commit time", reviewed_base_committed_at
+        )
+        live_base_time = parse_timestamp("current base commit time", 
live_base_committed_at)
+        base_lag = live_base_time.astimezone(dt.timezone.utc) - 
reviewed_base_time.astimezone(
+            dt.timezone.utc
+        )
+        if base_lag < dt.timedelta(0):
+            raise ValidationError("reviewed base commit time is after the 
current base commit time")
+        if base_lag > MAX_BASE_LAG:
+            raise ValidationError("reviewed base is more than 48 hours behind 
the current PR base")
+
+    if str(fields["reviewer"]).casefold() != comment_author.casefold():
+        raise ValidationError("reviewer does not match the GitHub comment 
author")
+    if comment_author_permission not in ALLOWED_AUTHOR_PERMISSIONS:
+        raise ValidationError("comment author does not have write permission")
+    allowed_efforts = ALLOWED_EFFORTS_BY_MODEL.get(str(fields["model"]))
+    if allowed_efforts is None:
+        raise ValidationError(f"model is not allowed: {fields['model']}")
+    if fields["effort"] not in allowed_efforts:
+        raise ValidationError(
+            f"effort {fields['effort']} is not allowed for model 
{fields['model']}"
+        )
+
+    blocker, major, _minor, _nit = fields["findings"]
+    if blocker != 0 or major != 0:
+        raise ValidationError("Blocker and Major findings must both be zero")
+    if fields["converged"] != "true":
+        raise ValidationError("review did not converge")
+    if not 1 <= int(fields["rounds"]) <= 3:
+        raise ValidationError("rounds must be between 1 and 3")
+
+    parse_timestamp("reviewed_at", str(fields["reviewed_at"]))
+
+    return fields
+
+
+def parse_timestamp(name: str, value: str | None) -> dt.datetime:
+    if value is None:
+        raise ValidationError(f"{name} is required")
+    try:
+        timestamp = dt.datetime.fromisoformat(value)
+    except ValueError as exc:
+        raise ValidationError(f"{name} is not a valid ISO-8601 timestamp") 
from exc
+    if timestamp.tzinfo is None or timestamp.utcoffset() is None:
+        raise ValidationError(f"{name} must include a timezone offset")
+    return timestamp
+
+
+def require_full_sha(name: str, value: str) -> None:
+    if SHA_RE.fullmatch(value) is None:
+        raise ValidationError(f"{name} is not a full SHA")
+
+
+def main() -> int:
+    parser = argparse.ArgumentParser()
+    subparsers = parser.add_subparsers(dest="command", required=True)
+
+    extract_parser = subparsers.add_parser("extract-base")
+    extract_parser.add_argument("--comment-file", type=Path, required=True)
+
+    validate_parser = subparsers.add_parser("validate")
+    validate_parser.add_argument("--comment-file", type=Path, required=True)
+    validate_parser.add_argument("--repository", required=True)
+    validate_parser.add_argument("--pr-number", type=int, required=True)
+    validate_parser.add_argument("--head-sha", required=True)
+    validate_parser.add_argument("--live-base-sha", required=True)
+    validate_parser.add_argument("--base-compare-status", required=True)
+    validate_parser.add_argument("--reviewed-base-committed-at")
+    validate_parser.add_argument("--live-base-committed-at")
+    validate_parser.add_argument("--comment-author", required=True)
+    validate_parser.add_argument("--comment-author-permission", required=True)
+    args = parser.parse_args()
+
+    try:
+        comment = args.comment_file.read_text(encoding="utf-8")
+        if args.command == "extract-base":
+            fields = parse_comment(comment)
+            if fields["schema"] != SCHEMA:
+                raise ValidationError(f"unsupported schema: 
{fields['schema']}")
+            reviewed_base_sha = str(fields["base"])
+            require_full_sha("base", reviewed_base_sha)
+            print(reviewed_base_sha)
+            return 0
+        fields = validate_comment(
+            comment,
+            repository=args.repository,
+            pr_number=args.pr_number,
+            head_sha=args.head_sha,
+            live_base_sha=args.live_base_sha,
+            base_compare_status=args.base_compare_status,
+            reviewed_base_committed_at=args.reviewed_base_committed_at,
+            live_base_committed_at=args.live_base_committed_at,
+            comment_author=args.comment_author,
+            comment_author_permission=args.comment_author_permission,
+        )
+    except (OSError, ValidationError, ValueError) as exc:
+        print(f"INVALID: {exc}", file=sys.stderr)
+        return 1
+
+    print(
+        "VALID: local pipeline review passed "
+        f"with {fields['model']} at effort {fields['effort']} for 
{fields['commit']}"
+    )
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/.github/workflows/code-review-aggregate-status.yml 
b/.github/workflows/code-review-aggregate-status.yml
new file mode 100644
index 00000000000..89812d76e31
--- /dev/null
+++ b/.github/workflows/code-review-aggregate-status.yml
@@ -0,0 +1,85 @@
+name: Aggregate Code Review Status
+
+on:
+  workflow_call:
+    inputs:
+      head_sha:
+        description: Commit whose PR/base-specific review sources should be 
aggregated.
+        required: true
+        type: string
+
+permissions: {}
+
+jobs:
+  aggregate:
+    runs-on: ubuntu-latest
+    concurrency:
+      group: code-review-status-${{ inputs.head_sha }}
+      cancel-in-progress: false
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write
+    steps:
+      - name: Mark aggregate status as pending
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_SHA: ${{ inputs.head_sha }}
+          REPO: ${{ github.repository }}
+        run: |
+          gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
+            -X POST \
+            -f state='pending' \
+            -f context='code-review' \
+            -f description="Recalculating code review for ${HEAD_SHA:0:12}." \
+            -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
+
+      - name: Checkout trusted status resolver
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.repository.default_branch }}
+          persist-credentials: false
+          sparse-checkout: .github/scripts/resolve_code_review_status.py
+          sparse-checkout-cone-mode: false
+
+      - name: Resolve review status across open PR contexts
+        id: resolution
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_SHA: ${{ inputs.head_sha }}
+          REPO: ${{ github.repository }}
+        run: |
+          pull_pages="$RUNNER_TEMP/code-review-pull-pages.json"
+          pulls="$RUNNER_TEMP/code-review-pulls.json"
+          status_pages="$RUNNER_TEMP/code-review-status-pages.json"
+          statuses="$RUNNER_TEMP/code-review-statuses.json"
+
+          gh api --paginate --slurp \
+            -H 'Accept: application/vnd.github+json' \
+            "repos/${REPO}/pulls?state=open&per_page=100" > "$pull_pages"
+          jq '[.[][]]' "$pull_pages" > "$pulls"
+
+          gh api --paginate --slurp \
+            -H 'Accept: application/vnd.github+json' \
+            "repos/${REPO}/commits/${HEAD_SHA}/statuses?per_page=100" > 
"$status_pages"
+          jq '[.[][]]' "$status_pages" > "$statuses"
+
+          python3 .github/scripts/resolve_code_review_status.py \
+            --pulls-file "$pulls" \
+            --statuses-file "$statuses" \
+            --head-sha "$HEAD_SHA" >> "$GITHUB_OUTPUT"
+
+      - name: Publish aggregate code-review status
+        env:
+          DESCRIPTION: ${{ steps.resolution.outputs.description }}
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_SHA: ${{ inputs.head_sha }}
+          REPO: ${{ github.repository }}
+          STATE: ${{ steps.resolution.outputs.state }}
+        run: |
+          gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
+            -X POST \
+            -f state="$STATE" \
+            -f context='code-review' \
+            -f description="$DESCRIPTION" \
+            -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
diff --git a/.github/workflows/code-review-runner.yml 
b/.github/workflows/code-review-runner.yml
index 6a0ed2e1b9a..4e8cbbdfb9c 100644
--- a/.github/workflows/code-review-runner.yml
+++ b/.github/workflows/code-review-runner.yml
@@ -55,6 +55,11 @@ permissions:
 jobs:
   code-review:
     runs-on: ubuntu-latest
+    outputs:
+      base_sha: ${{ steps.review_inputs.outputs.base_sha }}
+      head_sha: ${{ steps.review_inputs.outputs.head_sha }}
+      manage_status: ${{ steps.review_inputs.outputs.manage_status }}
+      pr_number: ${{ steps.review_inputs.outputs.pr_number }}
     # Pre-finalization steps can use 183 minutes and auth sync can use 8 more,
     # leaving 12 minutes for runner setup and post-job cleanup.
     timeout-minutes: 203
@@ -136,15 +141,25 @@ jobs:
         if: ${{ steps.review_inputs.outputs.manage_status == 'true' }}
         timeout-minutes: 2
         env:
+          BASE_SHA: ${{ steps.review_inputs.outputs.base_sha }}
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           HEAD_SHA: ${{ steps.review_inputs.outputs.head_sha }}
+          PR_NUMBER: ${{ steps.review_inputs.outputs.pr_number }}
           REPO: ${{ github.repository }}
         run: |
           gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
             -X POST \
             -f state='pending' \
             -f context='code-review' \
-            -f description="Automated review is running for ${HEAD_SHA}." \
+            -f description="Automated review is running for PR #${PR_NUMBER}." 
\
+            -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
+
+          
source_context="code-review/source/automated/pr-${PR_NUMBER}/base-${BASE_SHA}"
+          gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
+            -X POST \
+            -f state='pending' \
+            -f context="$source_context" \
+            -f description="Automated review is running for PR #${PR_NUMBER} 
at ${BASE_SHA:0:12}." \
             -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
 
       - name: Checkout repository
@@ -859,27 +874,30 @@ jobs:
           }}
         timeout-minutes: 2
         env:
+          BASE_SHA: ${{ steps.review_inputs.outputs.base_sha }}
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           HEAD_SHA: ${{ steps.review_inputs.outputs.head_sha }}
           JOB_STATUS: ${{ job.status }}
+          PR_NUMBER: ${{ steps.review_inputs.outputs.pr_number }}
           REPO: ${{ github.repository }}
           REVIEW_CONTEXT_OUTCOME: ${{ steps.review_context.outcome }}
           REVIEW_OUTCOME: ${{ steps.review.outcome }}
         run: |
           state="pending"
-          summary="Trigger /review to start automated review for ${HEAD_SHA}."
+          summary="Automated review did not pass for PR #${PR_NUMBER} at 
${BASE_SHA:0:12}."
 
           if [ "$JOB_STATUS" = "success" ] && \
              [ "$REVIEW_CONTEXT_OUTCOME" = "success" ] && \
              [ "$REVIEW_OUTCOME" = "success" ]; then
             state="success"
-            summary="Automated review was triggered for ${HEAD_SHA}."
+            summary="Automated review passed for PR #${PR_NUMBER} at 
${BASE_SHA:0:12}."
           fi
 
+          
source_context="code-review/source/automated/pr-${PR_NUMBER}/base-${BASE_SHA}"
           gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
             -X POST \
             -f state="${state}" \
-            -f context='code-review' \
+            -f context="$source_context" \
             -f description="${summary}" \
             -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
 
@@ -1012,3 +1030,17 @@ jobs:
           OSS_AK: ${{ secrets.OSS_AK }}
           OSS_SK: ${{ secrets.OSS_SK }}
           OSS_ENDPOINT: oss-cn-hongkong.aliyuncs.com
+
+  aggregate-status:
+    needs: code-review
+    if: >-
+      always() &&
+      needs.code-review.outputs.manage_status == 'true' &&
+      needs.code-review.outputs.head_sha != ''
+    uses: ./.github/workflows/code-review-aggregate-status.yml
+    with:
+      head_sha: ${{ needs.code-review.outputs.head_sha }}
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write
diff --git a/.github/workflows/code-review-sync-result.yml 
b/.github/workflows/code-review-sync-result.yml
index ab84a4ab9c0..a45a9b06041 100644
--- a/.github/workflows/code-review-sync-result.yml
+++ b/.github/workflows/code-review-sync-result.yml
@@ -2,18 +2,183 @@ name: Code Review
 
 on:
   pull_request_target:
-    types: [opened, synchronize, reopened, ready_for_review]
+    types: [opened, synchronize, reopened, ready_for_review, edited, closed]
   issue_comment:
-    types: [created, edited]
+    types: [created]
 
 permissions:
+  contents: read
   pull-requests: read
   statuses: write
 
 jobs:
+  accept-skill-review:
+    name: Accept local skill review PASS
+    runs-on: ubuntu-latest
+    outputs:
+      accepted: ${{ steps.validation.outputs.valid }}
+      head_sha: ${{ steps.validation.outputs.head_sha }}
+    if: >
+      github.event_name == 'issue_comment' &&
+      github.event.issue.pull_request != null &&
+      contains(github.event.comment.body, '<!-- doris-repo-review:v1:begin 
-->')
+    steps:
+      # A local PASS is a creation-time credential. Later edits, deletion, or
+      # permission changes do not revoke it; edited events are intentionally 
ignored.
+      - name: Authorize review comment creator
+        id: authorization
+        env:
+          COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
+          EVENT_SENDER: ${{ github.event.sender.login }}
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          REPO: ${{ github.repository }}
+        run: |
+          if [ "$COMMENT_AUTHOR" != "$EVENT_SENDER" ]; then
+            echo "Review comment ignored: creator and event sender differ."
+            echo "authorized=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+
+          if ! permission_info="$(gh api 
"repos/${REPO}/collaborators/${COMMENT_AUTHOR}/permission")"; then
+            echo "Review comment ignored: cannot verify ${COMMENT_AUTHOR}'s 
repository permission."
+            echo "authorized=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+          if ! comment_author_permission="$(jq -er '.permission | strings' 
<<<"$permission_info")"; then
+            echo "Review comment ignored: cannot read ${COMMENT_AUTHOR}'s 
repository permission."
+            echo "authorized=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+          if [[ "$comment_author_permission" != "write" && 
"$comment_author_permission" != "admin" ]]; then
+            echo "Review comment ignored: ${COMMENT_AUTHOR} does not have 
write permission."
+            echo "authorized=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+
+          echo "authorized=true" >> "$GITHUB_OUTPUT"
+          echo "permission=$comment_author_permission" >> "$GITHUB_OUTPUT"
+
+      - name: Checkout trusted validation script
+        if: steps.authorization.outputs.authorized == 'true'
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.repository.default_branch }}
+          persist-credentials: false
+          sparse-checkout: .github/scripts/validate_review_pass_comment.py
+          sparse-checkout-cone-mode: false
+
+      - name: Validate local review comment
+        if: steps.authorization.outputs.authorized == 'true'
+        id: validation
+        env:
+          COMMENT_AUTHOR_PERMISSION: ${{ 
steps.authorization.outputs.permission }}
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          REPO: ${{ github.repository }}
+          PR_NUMBER: ${{ github.event.issue.number }}
+          COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
+        run: |
+          comment_file="$RUNNER_TEMP/doris-repo-review-comment.md"
+          jq -r '.comment.body' "$GITHUB_EVENT_PATH" > "$comment_file"
+
+          pr_info="$(gh api "repos/${REPO}/pulls/${PR_NUMBER}")"
+          head_sha="$(jq -r '.head.sha' <<<"$pr_info")"
+          live_base_sha="$(jq -r '.base.sha' <<<"$pr_info")"
+          pr_state="$(jq -r '.state' <<<"$pr_info")"
+          if [ "$pr_state" != "open" ]; then
+            echo "Review comment ignored: pull request is ${pr_state}."
+            echo "valid=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+
+          if ! reviewed_base_sha="$(python3 
.github/scripts/validate_review_pass_comment.py \
+              extract-base --comment-file "$comment_file")"; then
+            echo "Review comment ignored: cannot read its reviewed base."
+            echo "valid=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+          if ! base_compare="$(gh api \
+              
"repos/${REPO}/compare/${reviewed_base_sha}...${live_base_sha}")"; then
+            echo "Review comment ignored: cannot compare its base with the 
current PR base."
+            echo "valid=false" >> "$GITHUB_OUTPUT"
+            exit 0
+          fi
+          base_compare_status="$(jq -r '.status' <<<"$base_compare")"
+          if [ "$reviewed_base_sha" = "$live_base_sha" ]; then
+            reviewed_base_committed_at=""
+            live_base_committed_at=""
+          else
+            if ! reviewed_base_committed_at="$(gh api \
+                "repos/${REPO}/commits/${reviewed_base_sha}" --jq 
'.commit.committer.date')" || \
+               ! live_base_committed_at="$(gh api \
+                "repos/${REPO}/commits/${live_base_sha}" --jq 
'.commit.committer.date')"; then
+              echo "Review comment ignored: cannot resolve base commit times."
+              echo "valid=false" >> "$GITHUB_OUTPUT"
+              exit 0
+            fi
+          fi
+
+          if validation_output="$(python3 
.github/scripts/validate_review_pass_comment.py validate \
+              --comment-file "$comment_file" \
+              --repository "$REPO" \
+              --pr-number "$PR_NUMBER" \
+              --head-sha "$head_sha" \
+              --live-base-sha "$live_base_sha" \
+              --base-compare-status "$base_compare_status" \
+              --reviewed-base-committed-at "$reviewed_base_committed_at" \
+              --live-base-committed-at "$live_base_committed_at" \
+              --comment-author "$COMMENT_AUTHOR" \
+              --comment-author-permission "$COMMENT_AUTHOR_PERMISSION" 2>&1)"; 
then
+            echo "$validation_output"
+            echo "valid=true" >> "$GITHUB_OUTPUT"
+            echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"
+            echo "base_sha=$live_base_sha" >> "$GITHUB_OUTPUT"
+          else
+            echo "$validation_output"
+            echo "valid=false" >> "$GITHUB_OUTPUT"
+          fi
+
+      - name: Record local review source
+        if: steps.validation.outputs.valid == 'true'
+        env:
+          BASE_SHA: ${{ steps.validation.outputs.base_sha }}
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          REPO: ${{ github.repository }}
+          HEAD_SHA: ${{ steps.validation.outputs.head_sha }}
+          COMMENT_URL: ${{ github.event.comment.html_url }}
+          PR_NUMBER: ${{ github.event.issue.number }}
+        run: |
+          
source_context="code-review/source/local/pr-${PR_NUMBER}/base-${BASE_SHA}"
+          gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
+            -X POST \
+            -f state='pending' \
+            -f context='code-review' \
+            -f description="Recalculating code review for PR #${PR_NUMBER}." \
+            -f target_url="$COMMENT_URL"
+
+          gh api "repos/${REPO}/statuses/${HEAD_SHA}" \
+            -X POST \
+            -f state='success' \
+            -f context="$source_context" \
+            -f description="Local review passed for PR #${PR_NUMBER} at 
${BASE_SHA:0:12}." \
+            -f target_url="$COMMENT_URL"
+
+  aggregate-after-skill-review:
+    needs: accept-skill-review
+    if: needs.accept-skill-review.outputs.accepted == 'true'
+    uses: ./.github/workflows/code-review-aggregate-status.yml
+    with:
+      head_sha: ${{ needs.accept-skill-review.outputs.head_sha }}
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write
+
   skip-on-comment:
     name: Skip review via skip buildall comment
     runs-on: ubuntu-latest
+    outputs:
+      accepted: ${{ steps.skip.outputs.accepted }}
+      head_sha: ${{ steps.skip.outputs.head_sha }}
     if: >
       github.event_name == 'issue_comment' &&
       github.event.issue.pull_request != null &&
@@ -21,6 +186,7 @@ jobs:
       contains(github.event.comment.body, 'skip buildall')
     steps:
       - name: Check user permission and mark review as success
+        id: skip
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           REPO: ${{ github.repository }}
@@ -29,6 +195,7 @@ jobs:
         run: |
           PR_INFO=$(gh api repos/${REPO}/pulls/${PR_NUMBER})
           HEAD_SHA=$(echo "${PR_INFO}" | jq -r '.head.sha')
+          BASE_SHA=$(echo "${PR_INFO}" | jq -r '.base.sha')
           TARGET_BRANCH=$(echo "${PR_INFO}" | jq -r '.base.ref')
 
           ALLOWED=false
@@ -48,51 +215,62 @@ jobs:
 
           if [[ "${ALLOWED}" != 'true' ]]; then
               echo "COMMENT_USER_ID ${COMMENT_USER_ID} is not allowed to skip 
code review."
+              echo "accepted=false" >> "$GITHUB_OUTPUT"
               exit 0
           fi
 
           echo "COMMENT_USER_ID ${COMMENT_USER_ID} is allowed to skip code 
review for ${TARGET_BRANCH}."
+          
source_context="code-review/source/skip/pr-${PR_NUMBER}/base-${BASE_SHA}"
           gh api repos/${REPO}/statuses/${HEAD_SHA} \
             -X POST \
-            -f state="success" \
+            -f state="pending" \
             -f context='code-review' \
-            -f description="Code review skipped via 'skip buildall' comment." \
+            -f description="Recalculating code review for PR #${PR_NUMBER}." \
             -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
 
+          gh api repos/${REPO}/statuses/${HEAD_SHA} \
+            -X POST \
+            -f state="success" \
+            -f context="$source_context" \
+            -f description="Code review skipped for PR #${PR_NUMBER} at 
${BASE_SHA:0:12}." \
+            -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
+
+          echo "accepted=true" >> "$GITHUB_OUTPUT"
+          echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
+
+  aggregate-after-skip:
+    needs: skip-on-comment
+    if: needs.skip-on-comment.outputs.accepted == 'true'
+    uses: ./.github/workflows/code-review-aggregate-status.yml
+    with:
+      head_sha: ${{ needs.skip-on-comment.outputs.head_sha }}
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write
+
   sync-status:
     name: Sync review status
-    runs-on: ubuntu-latest
-    timeout-minutes: 120
     if: github.event_name == 'pull_request_target'
-    steps:
-      - name: Check automated review decision for current PR head
-        env:
-          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          REPO: ${{ github.repository }}
-          PR_NUMBER: ${{ github.event.pull_request.number }}
-          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
-        run: |
-          STATUSES=$(gh api --paginate 
repos/${REPO}/commits/${HEAD_SHA}/status)
-          review_state=$(printf '%s' "$STATUSES" | jq -r '
-            ([ .statuses[]
-              | select(.context == "code-review")
-            ]
-            | sort_by(.created_at)
-            | last
-            | .state) // ""
-          ')
-
-          state="pending"
-          summary="Trigger /review to start automated review for ${HEAD_SHA}."
-
-          if [ "$review_state" = "success" ]; then
-            state="success"
-            summary="Automated review was triggered for ${HEAD_SHA}."
-          fi
+    uses: ./.github/workflows/code-review-aggregate-status.yml
+    with:
+      head_sha: ${{ github.event.pull_request.head.sha }}
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write
 
-          gh api repos/${REPO}/statuses/${HEAD_SHA} \
-            -X POST \
-            -f state="${state}" \
-            -f context='code-review' \
-            -f description="${summary}" \
-            -f target_url="${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}"
+  sync-previous-head-status:
+    name: Sync previous review status
+    if: >
+      github.event_name == 'pull_request_target' &&
+      github.event.action == 'synchronize' &&
+      github.event.before != '' &&
+      github.event.before != github.event.pull_request.head.sha
+    uses: ./.github/workflows/code-review-aggregate-status.yml
+    with:
+      head_sha: ${{ github.event.before }}
+    permissions:
+      contents: read
+      pull-requests: read
+      statuses: write


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to