From a3f4c83a72afbe1cf7676bb8e733de2d1d87be81 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 21:17:20 +0900 Subject: [PATCH 001/138] ci: materialize focused review-agent mention router --- ...aterialize-review-agent-mention-router.yml | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 .github/workflows/materialize-review-agent-mention-router.yml diff --git a/.github/workflows/materialize-review-agent-mention-router.yml b/.github/workflows/materialize-review-agent-mention-router.yml new file mode 100644 index 000000000..2edb8cde9 --- /dev/null +++ b/.github/workflows/materialize-review-agent-mention-router.yml @@ -0,0 +1,226 @@ +name: Materialize focused review-agent mention router + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/materialize-review-agent-mention-router.yml + +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + materialize: + if: >- + github.repository == 'ContextualWisdomLab/.github' + && github.ref == 'refs/heads/feat/review-agent-mention-router-main' + runs-on: ubuntu-24.04 + timeout-minutes: 45 + permissions: + contents: write + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact current-main branch + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Import immutable focused source + env: + SOURCE_SHA: 337f42601c214036fa4d4a55b7a29b710f4a4d2b + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + git cat-file -e "${SOURCE_SHA}^{commit}" + git checkout "$SOURCE_SHA" -- \ + .github/workflows/agent-mention-router.yml \ + docs/automation/review-agent-comment-invocation.md \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + + cat >.github/workflows/agent-mention-router-quality-ci.yml <<'YAML' + name: Agent Mention Router Quality CI + + on: + pull_request: + branches: [main] + paths: + - ".github/workflows/agent-mention-router.yml" + - ".github/workflows/agent-mention-router-quality-ci.yml" + - "scripts/ci/agent_mention_router.py" + - "scripts/ci/agent_mention_sweep.py" + - "tests/test_agent_mention_*.py" + - "requirements-opencode-review-ci-hashes.txt" + push: + branches: [main] + paths: + - ".github/workflows/agent-mention-router.yml" + - ".github/workflows/agent-mention-router-quality-ci.yml" + - "scripts/ci/agent_mention_router.py" + - "scripts/ci/agent_mention_sweep.py" + - "tests/test_agent_mention_*.py" + - "requirements-opencode-review-ci-hashes.txt" + + concurrency: + group: agent-mention-router-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + permissions: + contents: read + + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + + jobs: + quality: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout exact head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + - name: Install exact hash-locked tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + - name: Run complete focused branch coverage + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + source = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + git diff --check + YAML + + python3 - <<'PY' + from pathlib import Path + + changelog = Path("CHANGELOG.md") + source = changelog.read_text(encoding="utf-8") + entry = ( + "- Add a trusted pull-request comment router for `@cwl-noema-review` " + "and review-only `@opencode-agent` dispatches, with organization sweep, " + "exact-head receipts, repository allowlisting, and a permanent 100% " + "statement/branch/docstring quality gate.\n" + ) + marker = "## [Unreleased]\n" + if marker not in source: + raise SystemExit("CHANGELOG is missing the Unreleased section") + if entry not in source: + changelog.write_text( + source.replace(marker, marker + "\n" + entry, 1), + encoding="utf-8", + ) + PY + rm .github/workflows/materialize-review-agent-mention-router.yml + git diff --check + + - name: Install exact hash-locked tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Verify focused production contract + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + source = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + git diff --check + + - name: Publish focused implementation and remove materializer + env: + EXPECTED_HEAD: ${{ github.sha }} + HEAD_BRANCH: ${{ github.ref_name }} + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + remote_head="$(git ls-remote origin "refs/heads/${HEAD_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add --all + git diff --cached --quiet && { echo "No focused implementation generated" >&2; exit 1; } + git commit -m "feat(automation): route trusted review-agent mentions" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.https://github.com/.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${HEAD_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${HEAD_BRANCH}" From 0cdc975e7b98e271ad7c2e52519384ac9ed4d73d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:00:37 +0900 Subject: [PATCH 002/138] chore(automation): remove transient mention-router materializer --- ...aterialize-review-agent-mention-router.yml | 226 ------------------ 1 file changed, 226 deletions(-) delete mode 100644 .github/workflows/materialize-review-agent-mention-router.yml diff --git a/.github/workflows/materialize-review-agent-mention-router.yml b/.github/workflows/materialize-review-agent-mention-router.yml deleted file mode 100644 index 2edb8cde9..000000000 --- a/.github/workflows/materialize-review-agent-mention-router.yml +++ /dev/null @@ -1,226 +0,0 @@ -name: Materialize focused review-agent mention router - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/materialize-review-agent-mention-router.yml - -permissions: - contents: read - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - materialize: - if: >- - github.repository == 'ContextualWisdomLab/.github' - && github.ref == 'refs/heads/feat/review-agent-mention-router-main' - runs-on: ubuntu-24.04 - timeout-minutes: 45 - permissions: - contents: write - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact current-main branch - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Import immutable focused source - env: - SOURCE_SHA: 337f42601c214036fa4d4a55b7a29b710f4a4d2b - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - git cat-file -e "${SOURCE_SHA}^{commit}" - git checkout "$SOURCE_SHA" -- \ - .github/workflows/agent-mention-router.yml \ - docs/automation/review-agent-comment-invocation.md \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py - - cat >.github/workflows/agent-mention-router-quality-ci.yml <<'YAML' - name: Agent Mention Router Quality CI - - on: - pull_request: - branches: [main] - paths: - - ".github/workflows/agent-mention-router.yml" - - ".github/workflows/agent-mention-router-quality-ci.yml" - - "scripts/ci/agent_mention_router.py" - - "scripts/ci/agent_mention_sweep.py" - - "tests/test_agent_mention_*.py" - - "requirements-opencode-review-ci-hashes.txt" - push: - branches: [main] - paths: - - ".github/workflows/agent-mention-router.yml" - - ".github/workflows/agent-mention-router-quality-ci.yml" - - "scripts/ci/agent_mention_router.py" - - "scripts/ci/agent_mention_sweep.py" - - "tests/test_agent_mention_*.py" - - "requirements-opencode-review-ci-hashes.txt" - - concurrency: - group: agent-mention-router-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - - permissions: - contents: read - - env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - - jobs: - quality: - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - name: Checkout exact head - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - name: Install exact hash-locked tooling - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - name: Run complete focused branch coverage - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - source = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py - git diff --check - YAML - - python3 - <<'PY' - from pathlib import Path - - changelog = Path("CHANGELOG.md") - source = changelog.read_text(encoding="utf-8") - entry = ( - "- Add a trusted pull-request comment router for `@cwl-noema-review` " - "and review-only `@opencode-agent` dispatches, with organization sweep, " - "exact-head receipts, repository allowlisting, and a permanent 100% " - "statement/branch/docstring quality gate.\n" - ) - marker = "## [Unreleased]\n" - if marker not in source: - raise SystemExit("CHANGELOG is missing the Unreleased section") - if entry not in source: - changelog.write_text( - source.replace(marker, marker + "\n" + entry, 1), - encoding="utf-8", - ) - PY - rm .github/workflows/materialize-review-agent-mention-router.yml - git diff --check - - - name: Install exact hash-locked tooling - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Verify focused production contract - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - source = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py - git diff --check - - - name: Publish focused implementation and remove materializer - env: - EXPECTED_HEAD: ${{ github.sha }} - HEAD_BRANCH: ${{ github.ref_name }} - PUSH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - remote_head="$(git ls-remote origin "refs/heads/${HEAD_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add --all - git diff --cached --quiet && { echo "No focused implementation generated" >&2; exit 1; } - git commit -m "feat(automation): route trusted review-agent mentions" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.https://github.com/.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${HEAD_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${HEAD_BRANCH}" From e8adc56a43723e494567da69b8f8025064b9af90 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:03:03 +0900 Subject: [PATCH 003/138] test(automation): preserve trusted mention-router contracts --- tests/test_agent_mention_router.py | 345 +++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 tests/test_agent_mention_router.py diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py new file mode 100644 index 000000000..673054a0d --- /dev/null +++ b/tests/test_agent_mention_router.py @@ -0,0 +1,345 @@ +"""Tests for trusted PR comment agent mention routing.""" + +from __future__ import annotations + +import importlib.util +import json +import sys +from pathlib import Path +from types import ModuleType, SimpleNamespace + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + +def load_module() -> ModuleType: + """Load the router module from its script path.""" + + module_name = "agent_mention_router" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def receipt(comment_id: int, *, trusted: bool = True) -> dict: + """Build one trusted or attacker-controlled receipt-looking comment.""" + + return { + "body": f"", + "user": { + "login": "github-actions[bot]" if trusted else "attacker", + "type": "Bot" if trusted else "User", + }, + } + + +def event( + body: str, + *, + association: str = "MEMBER", + user_type: str = "User", +) -> dict: + """Build a representative enriched issue-comment event.""" + + return { + "repository": {"full_name": "ContextualWisdomLab/example"}, + "issue": { + "number": 17, + "pull_request": {"url": "https://api.github.test/pr/17"}, + }, + "comment": { + "id": 91, + "body": body, + "author_association": association, + "user": {"login": "maintainer", "type": user_type}, + }, + "pull_request": { + "state": "open", + "head": {"sha": "a" * 40}, + "base": {"ref": "develop"}, + }, + } + + +class FakeClient: + """Capture JSON API calls for deterministic dispatch assertions.""" + + def __init__(self) -> None: + """Initialize an empty call ledger.""" + + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Record one request and return no response body.""" + + self.calls.append((list(args), input_payload)) + return None + + +def test_exact_mentions_and_parse_event() -> None: + """Both exact mentions are recognized with immutable PR metadata.""" + + module = load_module() + request = module.parse_event( + event("please @cwl-noema-review and @opencode-agent") + ) + assert request is not None + assert request.agents == ("cwl-noema-review", "opencode-agent") + assert request.pull_request_head_sha == "a" * 40 + assert request.pull_request_base_branch == "develop" + assert module.exact_mentions("@opencode-agent-evil @cwl-noema-review2") == () + + +@pytest.mark.parametrize( + "payload", + [ + event("no agent here"), + event("@opencode-agent", association="CONTRIBUTOR"), + event("@opencode-agent", user_type="Bot"), + {**event("@opencode-agent"), "issue": {"number": 17}}, + { + **event("@opencode-agent"), + "pull_request": { + **event("@opencode-agent")["pull_request"], + "state": "closed", + }, + }, + { + **event("@opencode-agent"), + "conversation_comments": [receipt(91)], + }, + ], +) +def test_parse_event_ignores_untrusted_irrelevant_or_processed_comments( + payload: dict, +) -> None: + """Untrusted, irrelevant, non-PR, and acknowledged comments are ignored.""" + + assert load_module().parse_event(payload) is None + + +def test_untrusted_receipt_marker_cannot_suppress_invocation() -> None: + """A user-authored marker does not acknowledge a trusted invocation.""" + + payload = event("@opencode-agent") + payload["conversation_comments"] = [receipt(91, trusted=False)] + assert load_module().parse_event(payload) is not None + + +@pytest.mark.parametrize( + ("path", "value", "message"), + [ + (("repository", "full_name"), "outside/example", "limited"), + (("issue", "number"), 0, "number"), + (("comment", "id"), 0, "comment id"), + (("pull_request", "head", "sha"), "bad", "head SHA"), + (("pull_request", "base", "ref"), "-bad", "base branch"), + (("comment", "user", "login"), "", "actor"), + ], +) +def test_parse_event_rejects_malformed_trusted_requests( + path: tuple[str, ...], + value: object, + message: str, +) -> None: + """Malformed trusted invocation metadata fails closed.""" + + payload = event("@opencode-agent") + target = payload + for key in path[:-1]: + target = target[key] + target[path[-1]] = value + with pytest.raises(ValueError, match=message): + load_module().parse_event(payload) + + +def test_receipt_and_allowlist_helpers() -> None: + """Receipt extraction and exact repository allowlists are deterministic.""" + + module = load_module() + assert module.receipt_marker(91) == "" + with pytest.raises(ValueError, match="positive"): + module.receipt_marker(0) + comments = [ + receipt(91), + { + "body": "x y", + "user": {"login": "github-actions[bot]", "type": "Bot"}, + }, + receipt(93, trusted=False), + {"body": None, "user": {"login": "github-actions[bot]", "type": "Bot"}}, + ] + assert module.processed_comment_ids(comments) == frozenset({91, 92}) + assert module.parse_repository_allowlist( + "ContextualWisdomLab/example, ContextualWisdomLab/.github," + ) == frozenset( + {"ContextualWisdomLab/example", "ContextualWisdomLab/.github"} + ) + with pytest.raises(ValueError, match="invalid repository"): + module.parse_repository_allowlist("outside/example") + + +def test_eligible_agents_and_payloads() -> None: + """Eligibility and event bodies preserve the bounded review contract.""" + + module = load_module() + request = module.parse_event(event("@cwl-noema-review @opencode-agent")) + assert request is not None + assert module.eligible_agents( + request, + opencode_allowlist=frozenset({request.repository}), + ) == (("cwl-noema-review", "opencode-agent"), ()) + assert module.eligible_agents( + request, + opencode_allowlist=frozenset(), + ) == (("cwl-noema-review",), ("opencode-agent",)) + noema = module.noema_payload(request) + assert noema["event_type"] == "noema-review" + assert noema["client_payload"]["pr_head_sha"] == "a" * 40 + opencode = module.opencode_payload(request) + assert opencode["event_type"] == "merge-scheduler" + assert opencode["client_payload"]["base_branch"] == "develop" + assert opencode["client_payload"]["merge_mode"] == "disabled" + assert opencode["client_payload"]["enable_auto_merge"] is False + assert opencode["client_payload"]["update_branches"] is False + + +def test_dispatch_uses_central_events_and_acknowledges() -> None: + """Both agents dispatch centrally with bounded review-only OpenCode options.""" + + module = load_module() + request = module.parse_event(event("@cwl-noema-review @opencode-agent")) + assert request is not None + target = FakeClient() + central = FakeClient() + result = module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset({request.repository}), + ) + assert result == ("@cwl-noema-review", "@opencode-agent") + assert [payload["event_type"] for _, payload in central.calls] == [ + "noema-review", + "merge-scheduler", + ] + assert all( + args[0] == "repos/ContextualWisdomLab/.github/dispatches" + for args, _ in central.calls + ) + assert target.calls[0][1] == {"content": "eyes"} + assert "cwl-agent-mention-receipt:91" in target.calls[1][1]["body"] + + +def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( + capsys, +) -> None: + """OpenCode fails closed outside its allowlist while dry-run is mutation-free.""" + + module = load_module() + request = module.parse_event(event("@opencode-agent")) + assert request is not None + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + ) == () + assert central.calls == [] + assert "Rejected @opencode-agent" in target.calls[-1][1]["body"] + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + dry_run=True, + ) == () + assert target.calls == central.calls == [] + output = capsys.readouterr().out + assert "DRY-RUN agent mention" in output + assert "reject=opencode-agent" in output + + +def test_dispatch_noema_only_covers_non_opencode_path() -> None: + """A Noema-only request bypasses the OpenCode allowlist branch.""" + + module = load_module() + request = module.parse_event(event("@cwl-noema-review")) + assert request is not None + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + ) == ("@cwl-noema-review",) + assert central.calls[0][1]["event_type"] == "noema-review" + + +def test_github_client_validates_token_and_decodes_json(monkeypatch) -> None: + """The token-bound client never places credentials in command arguments.""" + + module = load_module() + with pytest.raises(ValueError, match="token"): + module.GitHubClient("") + calls = [] + + def fake_run(command, **kwargs): + calls.append((command, kwargs)) + return SimpleNamespace(stdout='{"ok": true}\n') + + monkeypatch.setattr(module.subprocess, "run", fake_run) + client = module.GitHubClient("secret-token") + assert client.request(["repos/x/y"], input_payload={"a": 1}) == {"ok": True} + command, kwargs = calls[0] + assert command == ["gh", "api", "repos/x/y", "--input", "-"] + assert "secret-token" not in command + assert kwargs["env"]["GH_TOKEN"] == "secret-token" + assert kwargs["input"] == '{"a": 1}' + monkeypatch.setattr( + module.subprocess, + "run", + lambda *args, **kwargs: SimpleNamespace(stdout=" "), + ) + assert client.request(["repos/x/y"]) is None + + +def test_load_event_and_main_paths(tmp_path: Path, monkeypatch, capsys) -> None: + """CLI rejects malformed JSON, ignores irrelevant events, and dispatches input.""" + + module = load_module() + array_path = tmp_path / "array.json" + array_path.write_text(json.dumps(["bad"]), encoding="utf-8") + with pytest.raises(ValueError, match="JSON object"): + module.load_event(str(array_path)) + ignored_path = tmp_path / "ignored.json" + ignored_path.write_text(json.dumps(event("nothing")), encoding="utf-8") + assert module.main(["--event-path", str(ignored_path)]) == 0 + assert "nothing to dispatch" in capsys.readouterr().out + with pytest.raises(SystemExit): + module.main([]) + valid_path = tmp_path / "valid.json" + valid_path.write_text(json.dumps(event("@opencode-agent")), encoding="utf-8") + captured = [] + monkeypatch.setenv("GH_TOKEN", "token") + monkeypatch.setenv( + "OPENCODE_REPOSITORY_DISPATCH_TARGETS", + "ContextualWisdomLab/example", + ) + monkeypatch.setattr( + module, + "dispatch_request", + lambda request, **kwargs: captured.append((request, kwargs)) or (), + ) + assert module.main(["--event-path", str(valid_path), "--dry-run"]) == 0 + assert captured[0][1]["dry_run"] is True From 39afd62dc601bc97fd71902086555c4afd1ffc8e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:04:04 +0900 Subject: [PATCH 004/138] test(automation): preserve organization mention sweep contracts --- tests/test_agent_mention_sweep.py | 408 ++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 tests/test_agent_mention_sweep.py diff --git a/tests/test_agent_mention_sweep.py b/tests/test_agent_mention_sweep.py new file mode 100644 index 000000000..b64257e7a --- /dev/null +++ b/tests/test_agent_mention_sweep.py @@ -0,0 +1,408 @@ +"""Tests for organization-wide pull-request comment mention sweeping.""" + +from __future__ import annotations + +import importlib +import sys +from datetime import datetime, timezone +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +SCRIPTS = ROOT / "scripts" / "ci" +sys.path.insert(0, str(SCRIPTS)) + + +class FakeClient: + """Endpoint-keyed fake GitHub client for sweep tests.""" + + def __init__(self, responses=None) -> None: + """Initialize response mapping and request ledger.""" + + self.responses = responses or {} + self.calls = [] + + def request(self, args, *, input_payload=None): + """Return the response registered for the first API argument.""" + + self.calls.append((list(args), input_payload)) + return self.responses.get(args[0]) + + +def comment( + comment_id: int, + body: str, + *, + association: str = "MEMBER", + user_type: str = "User", + login: str = "maintainer", +) -> dict: + """Build one issue-comment API object.""" + + return { + "id": comment_id, + "body": body, + "author_association": association, + "user": {"login": login, "type": user_type}, + } + + +def repository( + name: str = "example", + *, + owner: str = "ContextualWisdomLab", + archived: bool = False, + disabled: bool = False, +) -> dict: + """Build one repository API object.""" + + return { + "full_name": f"{owner}/{name}", + "owner": {"login": owner}, + "archived": archived, + "disabled": disabled, + } + + +def candidate(number: int = 7) -> dict: + """Build one normalized pull-request candidate.""" + + return { + "number": number, + "repository": "ContextualWisdomLab/example", + "pull_request": { + "url": ( + "https://api.github.com/repos/ContextualWisdomLab/example/" + f"pulls/{number}" + ) + }, + } + + +def pull_list_item(number: int = 7, updated_at: str = "2026-08-05T11:00:00Z") -> dict: + """Build one pull-list API item.""" + + return {"number": number, "updated_at": updated_at} + + +def live_pull(state: str = "open") -> dict: + """Build live pull-request metadata consumed by the router.""" + + return { + "state": state, + "head": {"sha": "b" * 40}, + "base": {"ref": "main"}, + } + + +def module(): + """Reload the sweep module for isolated monkeypatching.""" + + return importlib.reload(importlib.import_module("agent_mention_sweep")) + + +def test_timestamp_cutoff_and_page_validation() -> None: + """Timestamps, lookback bounds, and pagination fail closed.""" + + sweep = module() + now = datetime(2026, 8, 5, 12, 0, tzinfo=timezone.utc) + assert sweep.parse_timestamp("2026-08-05T11:00:00Z") == datetime( + 2026, + 8, + 5, + 11, + 0, + tzinfo=timezone.utc, + ) + for invalid in ("bad", "2026-08-05T11:00:00"): + with pytest.raises(ValueError, match="timestamp"): + sweep.parse_timestamp(invalid) + assert sweep.cutoff_timestamp(24, now=now) == "2026-08-04T12:00:00Z" + for hours in (0, 721): + with pytest.raises(ValueError, match="lookback"): + sweep.cutoff_timestamp(hours, now=now) + with pytest.raises(ValueError, match="timezone-aware"): + sweep.cutoff_timestamp(1, now=datetime(2026, 8, 5)) + assert sweep.flatten_pages([[{"a": 1}], [{"b": 2}]]) == [ + {"a": 1}, + {"b": 2}, + ] + assert sweep.flatten_pages( + [{"items": [{"a": 1}]}], collection_key="items" + ) == [{"a": 1}] + with pytest.raises(ValueError, match="empty"): + sweep.flatten_pages(None) + with pytest.raises(ValueError, match="page is not an object"): + sweep.flatten_pages([[]], collection_key="items") + with pytest.raises(ValueError, match="not a list"): + sweep.flatten_pages({"items": {}}, collection_key="items") + with pytest.raises(ValueError, match="non-object"): + sweep.flatten_pages([[1]]) + + +def test_accessible_repository_sources_filter_and_validate() -> None: + """PAT and installation-token repository inventories are both supported.""" + + sweep = module() + organization_response = [[ + repository(), + repository("archived", archived=True), + repository("disabled", disabled=True), + repository("outside", owner="outside"), + ]] + organization_client = FakeClient( + {"orgs/ContextualWisdomLab/repos": organization_response} + ) + assert sweep.list_accessible_repositories( + organization_client, + organization="ContextualWisdomLab", + repository_source="organization", + ) == ["ContextualWisdomLab/example"] + installation_client = FakeClient( + {"installation/repositories": [ + {"repositories": [repository(), repository("second")]} + ]} + ) + assert sweep.list_accessible_repositories( + installation_client, + organization="ContextualWisdomLab", + repository_source="installation", + ) == ["ContextualWisdomLab/example", "ContextualWisdomLab/second"] + with pytest.raises(ValueError, match="organization"): + sweep.list_accessible_repositories( + organization_client, + organization="bad/name", + repository_source="organization", + ) + with pytest.raises(ValueError, match="repository source"): + sweep.list_accessible_repositories( + organization_client, + organization="ContextualWisdomLab", + repository_source="bad", + ) + invalid_client = FakeClient( + {"orgs/ContextualWisdomLab/repos": [[ + {**repository(), "full_name": "bad/name"} + ]]} + ) + with pytest.raises(ValueError, match="full_name"): + sweep.list_accessible_repositories( + invalid_client, + organization="ContextualWisdomLab", + repository_source="organization", + ) + + +def test_recent_pull_request_filtering() -> None: + """Only open accessible PRs updated at or after the cutoff are yielded.""" + + sweep = module() + client = FakeClient( + { + "orgs/ContextualWisdomLab/repos": [[repository()]], + "repos/ContextualWisdomLab/example/pulls": [[ + pull_list_item(7, "2026-08-05T11:00:00Z"), + pull_list_item(8, "2026-08-04T11:59:59Z"), + ]], + } + ) + assert list(sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-04T12:00:00Z", + )) == [candidate()] + bad_number_client = FakeClient( + { + "orgs/ContextualWisdomLab/repos": [[repository()]], + "repos/ContextualWisdomLab/example/pulls": [[ + {"number": 0, "updated_at": "2026-08-05T11:00:00Z"} + ]], + } + ) + with pytest.raises(ValueError, match="pull request number"): + list(sweep.list_recent_pull_requests( + bad_number_client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-04T12:00:00Z", + )) + + +def test_build_requests_skips_trusted_receipts_and_closed_pull_requests() -> None: + """Only unacknowledged trusted comments on a live PR become requests.""" + + sweep = module() + comments_endpoint = "repos/ContextualWisdomLab/example/issues/7/comments" + pull_endpoint = "repos/ContextualWisdomLab/example/pulls/7" + comments = [ + comment(10, "@opencode-agent"), + comment( + 11, + "", + user_type="Bot", + login="github-actions[bot]", + ), + comment(12, "@cwl-noema-review"), + comment(13, "@opencode-agent", association="CONTRIBUTOR"), + ] + client = FakeClient({comments_endpoint: [comments], pull_endpoint: live_pull()}) + requests = sweep.build_requests_for_pull_request( + client, issue=candidate(), since="2026-08-04T00:00:00Z" + ) + assert [request.comment_id for request in requests] == [12] + assert requests[0].agents == ("cwl-noema-review",) + closed = FakeClient( + {comments_endpoint: [comments], pull_endpoint: live_pull("closed")} + ) + assert sweep.build_requests_for_pull_request( + closed, issue=candidate(), since="2026-08-04T00:00:00Z" + ) == () + with pytest.raises(ValueError, match="repository"): + sweep.build_requests_for_pull_request( + client, issue={**candidate(), "repository": "bad/name"}, since="x" + ) + with pytest.raises(ValueError, match="number"): + sweep.build_requests_for_pull_request( + client, issue={**candidate(), "number": 0}, since="x" + ) + + +def mention_request(number: int, comment_id: int, agent: str): + """Build one validated router request for orchestration tests.""" + + router = importlib.import_module("agent_mention_router") + return router.MentionRequest( + "ContextualWisdomLab/example", + number, + "a" * 40, + "main", + comment_id, + "maintainer", + (agent,), + ) + + +def test_sweep_dispatches_with_limit_and_reports_empty(monkeypatch, capsys) -> None: + """The sweep dispatches deterministically and respects its mutation budget.""" + + sweep = module() + request_a = mention_request(7, 10, "opencode-agent") + request_b = mention_request(8, 11, "cwl-noema-review") + monkeypatch.setattr( + sweep, "list_recent_pull_requests", lambda *args, **kwargs: iter([candidate()]) + ) + monkeypatch.setattr( + sweep, + "build_requests_for_pull_request", + lambda *args, **kwargs: (request_a, request_b), + ) + dispatched = [] + monkeypatch.setattr( + sweep, + "dispatch_request", + lambda request, **kwargs: dispatched.append(request.comment_id) or (), + ) + assert sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=1, + opencode_allowlist=frozenset({"ContextualWisdomLab/example"}), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) == 1 + assert dispatched == [10] + assert "reached dispatch limit" in capsys.readouterr().out + monkeypatch.setattr( + sweep, "list_recent_pull_requests", lambda *args, **kwargs: iter(()) + ) + assert sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="installation", + lookback_hours=24, + max_dispatches=2, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) == 0 + assert "0 dispatch" in capsys.readouterr().out + for value in (0, 101): + with pytest.raises(ValueError, match="max dispatches"): + sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=value, + opencode_allowlist=frozenset(), + ) + + +def test_sweep_continues_across_empty_results_and_completes( + monkeypatch, capsys +) -> None: + """Empty candidate results do not stop later PR processing.""" + + sweep = module() + request = mention_request(8, 12, "cwl-noema-review") + monkeypatch.setattr( + sweep, + "list_recent_pull_requests", + lambda *args, **kwargs: iter([candidate(), candidate(8)]), + ) + monkeypatch.setattr( + sweep, + "build_requests_for_pull_request", + lambda *args, issue, **kwargs: () if issue["number"] == 7 else (request,), + ) + dispatched = [] + monkeypatch.setattr( + sweep, + "dispatch_request", + lambda request, **kwargs: dispatched.append(request.comment_id) or (), + ) + assert sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=2, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) == 1 + assert dispatched == [12] + assert "completed with 1 dispatch" in capsys.readouterr().out + + +def test_main_constructs_clients_and_forwards_options(monkeypatch) -> None: + """CLI reads credentials, parses allowlist, and forwards bounded options.""" + + sweep = module() + captured = [] + monkeypatch.setenv("TARGET_REPOSITORY_TOKEN", "target") + monkeypatch.setenv("AGENT_DISPATCH_TOKEN", "dispatch") + monkeypatch.setenv( + "OPENCODE_REPOSITORY_DISPATCH_TARGETS", "ContextualWisdomLab/example" + ) + monkeypatch.setattr(sweep, "sweep", lambda **kwargs: captured.append(kwargs) or 0) + assert sweep.main([ + "--organization", + "ContextualWisdomLab", + "--repository-source", + "installation", + "--lookback-hours", + "48", + "--max-dispatches", + "3", + "--dry-run", + ]) == 0 + assert captured[0]["repository_source"] == "installation" + assert captured[0]["lookback_hours"] == 48 + assert captured[0]["max_dispatches"] == 3 + assert captured[0]["dry_run"] is True From 57a6b9b3b35683804c92baf12a419c308ba0fbba Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:04:22 +0900 Subject: [PATCH 005/138] test(automation): preserve least-privilege mention workflow contract --- tests/test_agent_mention_workflow_contract.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_agent_mention_workflow_contract.py diff --git a/tests/test_agent_mention_workflow_contract.py b/tests/test_agent_mention_workflow_contract.py new file mode 100644 index 000000000..dbdcd2334 --- /dev/null +++ b/tests/test_agent_mention_workflow_contract.py @@ -0,0 +1,41 @@ +"""Static least-privilege and trigger contract for agent mention automation.""" + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" + + +def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> None: + """The router is central-only, organization-wide, and least-privileged.""" + + text = WORKFLOW.read_text(encoding="utf-8") + header, jobs = text.split("\njobs:\n", 1) + assert "issue_comment:" in header + assert 'cron: "*/5 * * * *"' in header + assert "workflow_dispatch:" in header + assert "permissions:\n contents: read" in header + assert "contents: write" not in header + + local, sweep = jobs.split("\n sweep-organization-agent-mentions:\n", 1) + assert "route-local-agent-mention:" in local + assert "github.repository == 'ContextualWisdomLab/.github'" in local + assert ( + "permissions:\n" + " contents: write\n" + " issues: write\n" + " pull-requests: read" + ) in local + assert "ref: ${{ github.event.repository.default_branch }}" in local + assert "TARGET_REPOSITORY_TOKEN: ${{ github.token }}" in local + assert "conversation_comments" in local + + assert "permissions:\n contents: write\n id-token: write" in sweep + assert "github.repository == 'ContextualWisdomLab/.github'" in sweep + assert "github.event_name == 'schedule'" in sweep + assert "github.event_name == 'workflow_dispatch'" in sweep + assert "secrets.PR_REVIEW_MERGE_TOKEN" in sweep + assert "secrets.OPENCODE_APPROVE_TOKEN" in sweep + assert "TARGET_REPOSITORY_SOURCE" in sweep + assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep + assert "agent_mention_sweep.py" in sweep From 6c5038c0a7afbcc5252a464748975e4c9a70e326 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:05:20 +0900 Subject: [PATCH 006/138] feat(automation): add trusted review-agent mention router --- scripts/ci/agent_mention_router.py | 342 +++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 scripts/ci/agent_mention_router.py diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py new file mode 100644 index 000000000..d3a8518d9 --- /dev/null +++ b/scripts/ci/agent_mention_router.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 +"""Route trusted pull-request comment mentions to CWL review agents.""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import subprocess +from dataclasses import dataclass +from typing import Any, Sequence + +CENTRAL_AUTOMATION_REPOSITORY = "ContextualWisdomLab/.github" +TRUSTED_ASSOCIATIONS = frozenset({"OWNER", "MEMBER", "COLLABORATOR"}) +MENTION_PATTERNS = { + "cwl-noema-review": re.compile( + r"(?") + + +@dataclass(frozen=True) +class MentionRequest: + """Validated agent-mention request extracted from one issue comment event.""" + + repository: str + pull_request_number: int + pull_request_head_sha: str + pull_request_base_branch: str + comment_id: int + actor: str + agents: tuple[str, ...] + + +class GitHubClient: + """Small token-bound wrapper around ``gh api`` for JSON requests.""" + + def __init__(self, token: str) -> None: + """Initialize a client with one non-empty GitHub credential.""" + + if not token: + raise ValueError("GitHub token is required") + self._token = token + + def request( + self, + args: Sequence[str], + *, + input_payload: dict[str, Any] | None = None, + ) -> Any: + """Execute ``gh api`` and decode its optional JSON response.""" + + command = ["gh", "api", *args] + if input_payload is not None: + command.extend(["--input", "-"]) + environment = os.environ.copy() + environment["GH_TOKEN"] = self._token + completed = subprocess.run( + command, + input=None if input_payload is None else json.dumps(input_payload), + text=True, + capture_output=True, + check=True, + env=environment, + ) + output = completed.stdout.strip() + return None if not output else json.loads(output) + + +def exact_mentions(body: str) -> tuple[str, ...]: + """Return supported exact agent mentions in deterministic order.""" + + return tuple( + name for name, pattern in MENTION_PATTERNS.items() if pattern.search(body) + ) + + +def receipt_marker(comment_id: int) -> str: + """Return the hidden idempotency marker for one invocation comment.""" + + if comment_id < 1: + raise ValueError("comment id must be positive") + return f"" + + +def processed_comment_ids(comments: Sequence[dict[str, Any]]) -> frozenset[int]: + """Extract receipt IDs authored by the trusted GitHub Actions bot only.""" + + processed: set[int] = set() + for comment in comments: + user = comment.get("user") or {} + if ( + str(user.get("login") or "").casefold() + != "github-actions[bot]" + or str(user.get("type") or "").casefold() != "bot" + ): + continue + body = str(comment.get("body") or "") + processed.update(int(match) for match in RECEIPT_RE.findall(body)) + return frozenset(processed) + + +def parse_event(event: dict[str, Any]) -> MentionRequest | None: + """Return a validated mention request, or ``None`` for an ignored event.""" + + issue = event.get("issue") or {} + comment = event.get("comment") or {} + repository = event.get("repository") or {} + pull_request = event.get("pull_request") or {} + if not issue.get("pull_request"): + return None + if pull_request.get("state") != "open": + return None + if str(comment.get("user", {}).get("type", "")).casefold() == "bot": + return None + if str(comment.get("author_association", "")).upper() not in TRUSTED_ASSOCIATIONS: + return None + agents = exact_mentions(str(comment.get("body") or "")) + if not agents: + return None + + repository_name = str(repository.get("full_name") or "").strip() + actor = str(comment.get("user", {}).get("login") or "").strip() + head_sha = str(pull_request.get("head", {}).get("sha") or "").strip() + base_branch = str(pull_request.get("base", {}).get("ref") or "").strip() + number = issue.get("number") + comment_id = comment.get("id") + if not REPOSITORY_RE.fullmatch(repository_name): + raise ValueError( + "agent mentions are limited to ContextualWisdomLab repositories" + ) + if not isinstance(number, int) or number < 1: + raise ValueError("pull request number is missing or invalid") + if not isinstance(comment_id, int) or comment_id < 1: + raise ValueError("comment id is missing or invalid") + if comment_id in processed_comment_ids(event.get("conversation_comments") or ()): + return None + if not HEAD_SHA_RE.fullmatch(head_sha): + raise ValueError("pull request head SHA is missing or invalid") + if not BASE_BRANCH_RE.fullmatch(base_branch): + raise ValueError("pull request base branch is missing or invalid") + if not actor: + raise ValueError("comment actor is missing") + return MentionRequest( + repository_name, + number, + head_sha.lower(), + base_branch, + comment_id, + actor, + agents, + ) + + +def parse_repository_allowlist(raw_value: str) -> frozenset[str]: + """Parse and validate a comma-separated exact repository allowlist.""" + + repositories = frozenset( + part.strip() for part in raw_value.split(",") if part.strip() + ) + invalid = sorted( + repository + for repository in repositories + if not REPOSITORY_RE.fullmatch(repository) + ) + if invalid: + raise ValueError(f"invalid repository allowlist entries: {', '.join(invalid)}") + return repositories + + +def eligible_agents( + request: MentionRequest, + *, + opencode_allowlist: frozenset[str], +) -> tuple[tuple[str, ...], tuple[str, ...]]: + """Partition requested agents into dispatchable and rejected handles.""" + + dispatchable: list[str] = [] + rejected: list[str] = [] + if "cwl-noema-review" in request.agents: + dispatchable.append("cwl-noema-review") + if "opencode-agent" in request.agents: + if request.repository in opencode_allowlist: + dispatchable.append("opencode-agent") + else: + rejected.append("opencode-agent") + return tuple(dispatchable), tuple(rejected) + + +def noema_payload(request: MentionRequest) -> dict[str, Any]: + """Return the central Noema repository-dispatch request body.""" + + return { + "event_type": "noema-review", + "client_payload": { + "target_repository": request.repository, + "pr_number": request.pull_request_number, + "pr_head_sha": request.pull_request_head_sha, + "requested_by": request.actor, + "source_comment_id": request.comment_id, + }, + } + + +def opencode_payload(request: MentionRequest) -> dict[str, Any]: + """Return the review-only central OpenCode scheduler dispatch body.""" + + return { + "event_type": "merge-scheduler", + "client_payload": { + "target_repository": request.repository, + "pr_number": request.pull_request_number, + "pr_head_sha": request.pull_request_head_sha, + "base_branch": request.pull_request_base_branch, + "trigger_reviews": True, + "review_dispatch_limit": "1", + "enable_auto_merge": False, + "update_branches": False, + "merge_mode": "disabled", + "requested_agent": "opencode-agent", + "requested_by": request.actor, + "source_comment_id": request.comment_id, + }, + } + + +def dispatch_request( + request: MentionRequest, + *, + target_client: GitHubClient, + dispatch_client: GitHubClient, + opencode_allowlist: frozenset[str], + dry_run: bool = False, +) -> tuple[str, ...]: + """Dispatch requested agents and acknowledge the invocation on its PR.""" + + dispatchable, rejected = eligible_agents( + request, + opencode_allowlist=opencode_allowlist, + ) + handles = tuple(f"@{agent}" for agent in dispatchable) + if dry_run: + print( + "DRY-RUN agent mention " + f"repo={request.repository} pr={request.pull_request_number} " + f"head={request.pull_request_head_sha} " + f"dispatch={','.join(dispatchable) or 'none'} " + f"reject={','.join(rejected) or 'none'}" + ) + return handles + dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" + if "cwl-noema-review" in dispatchable: + dispatch_client.request( + [dispatch_endpoint, "-X", "POST"], + input_payload=noema_payload(request), + ) + if "opencode-agent" in dispatchable: + dispatch_client.request( + [dispatch_endpoint, "-X", "POST"], + input_payload=opencode_payload(request), + ) + target_api = f"repos/{request.repository}" + target_client.request( + [f"{target_api}/issues/comments/{request.comment_id}/reactions", "-X", "POST"], + input_payload={"content": "eyes"}, + ) + status_parts: list[str] = [] + if handles: + status_parts.append(f"Queued {' and '.join(handles)}") + if rejected: + rejected_handles = " and ".join(f"@{agent}" for agent in rejected) + status_parts.append( + f"Rejected {rejected_handles}: repository is absent from " + "OPENCODE_REPOSITORY_DISPATCH_TARGETS" + ) + acknowledgement = ( + f"{receipt_marker(request.comment_id)}\n" + f"{' ; '.join(status_parts)} for PR #{request.pull_request_number} at head " + f"`{request.pull_request_head_sha}`. Existing review workflows remain " + "authoritative for the final verdict and failure evidence." + ) + target_client.request( + [f"{target_api}/issues/{request.pull_request_number}/comments", "-X", "POST"], + input_payload={"body": acknowledgement}, + ) + return handles + + +def load_event(path: str) -> dict[str, Any]: + """Load and validate a GitHub event JSON document.""" + + with open(path, encoding="utf-8") as handle: + value = json.load(handle) + if not isinstance(value, dict): + raise ValueError("GitHub event payload must be a JSON object") + return value + + +def main(argv: Sequence[str] | None = None) -> int: + """Run the mention router for one enriched GitHub issue-comment event.""" + + parser = argparse.ArgumentParser() + parser.add_argument("--event-path", default=os.environ.get("GITHUB_EVENT_PATH", "")) + parser.add_argument("--dry-run", action="store_true") + args = parser.parse_args(argv) + if not args.event_path: + parser.error("--event-path or GITHUB_EVENT_PATH is required") + request = parse_event(load_event(args.event_path)) + if request is None: + print("No trusted pull-request agent mention found; nothing to dispatch.") + return 0 + target_token = os.environ.get("TARGET_REPOSITORY_TOKEN") or os.environ.get( + "GH_TOKEN", "" + ) + dispatch_token = os.environ.get("AGENT_DISPATCH_TOKEN") or os.environ.get( + "GH_TOKEN", "" + ) + allowlist = parse_repository_allowlist( + os.environ.get("OPENCODE_REPOSITORY_DISPATCH_TARGETS", "") + ) + dispatch_request( + request, + target_client=GitHubClient(target_token), + dispatch_client=GitHubClient(dispatch_token), + opencode_allowlist=allowlist, + dry_run=args.dry_run, + ) + return 0 + + +if __name__ == "__main__": # pragma: no cover + raise SystemExit(main()) From fab2bf9a02b36818f2e3cc7948386c87aa9eb49f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:06:11 +0900 Subject: [PATCH 007/138] feat(automation): add bounded organization mention sweep --- scripts/ci/agent_mention_sweep.py | 312 ++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 scripts/ci/agent_mention_sweep.py diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py new file mode 100644 index 000000000..181d2d62f --- /dev/null +++ b/scripts/ci/agent_mention_sweep.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python3 +"""Sweep recent CWL pull-request comments for trusted review-agent mentions.""" + +from __future__ import annotations + +import argparse +import os +import re +from datetime import datetime, timedelta, timezone +from typing import Any, Iterator, Sequence + +from agent_mention_router import ( + GitHubClient, + MentionRequest, + dispatch_request, + parse_event, + parse_repository_allowlist, + processed_comment_ids, +) + +ORG_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+$") +REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") +REPOSITORY_SOURCES = frozenset({"organization", "installation"}) + + +def parse_timestamp(value: str) -> datetime: + """Parse one GitHub ISO-8601 timestamp into timezone-aware UTC.""" + + try: + parsed = datetime.fromisoformat(value.replace("Z", "+00:00")) + except (AttributeError, ValueError) as exc: + raise ValueError("invalid GitHub timestamp") from exc + if parsed.tzinfo is None: + raise ValueError("GitHub timestamp must be timezone-aware") + return parsed.astimezone(timezone.utc) + + +def cutoff_timestamp(lookback_hours: int, *, now: datetime | None = None) -> str: + """Return an ISO-8601 UTC cutoff for the bounded comment lookback window.""" + + if lookback_hours < 1 or lookback_hours > 24 * 30: + raise ValueError("lookback hours must be between 1 and 720") + current = now or datetime.now(timezone.utc) + if current.tzinfo is None: + raise ValueError("current time must be timezone-aware") + cutoff = current.astimezone(timezone.utc) - timedelta(hours=lookback_hours) + return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") + + +def flatten_pages(value: Any, *, collection_key: str | None = None) -> list[dict[str, Any]]: + """Flatten ``gh api --paginate --slurp`` output into object records.""" + + if value is None: + raise ValueError("paginated GitHub response is empty") + pages = value if isinstance(value, list) else [value] + records: list[dict[str, Any]] = [] + for page in pages: + if collection_key and not isinstance(page, dict): + raise ValueError("paginated GitHub response page is not an object") + collection = page.get(collection_key, []) if collection_key else page + if not isinstance(collection, list): + raise ValueError("paginated GitHub response is not a list") + if not all(isinstance(record, dict) for record in collection): + raise ValueError("paginated GitHub response contains a non-object record") + records.extend(collection) + return records + + +def list_accessible_repositories( + client: GitHubClient, + *, + organization: str, + repository_source: str, +) -> list[str]: + """List active organization repositories visible to the selected token type.""" + + if not ORG_NAME_RE.fullmatch(organization): + raise ValueError("invalid organization name") + if repository_source not in REPOSITORY_SOURCES: + raise ValueError("repository source must be organization or installation") + if repository_source == "installation": + response = client.request( + [ + "installation/repositories", + "-X", + "GET", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + repositories = flatten_pages(response, collection_key="repositories") + else: + response = client.request( + [ + f"orgs/{organization}/repos", + "-X", + "GET", + "-f", + "type=all", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + repositories = flatten_pages(response) + names: list[str] = [] + for repository in repositories: + full_name = str(repository.get("full_name") or "") + owner = str(repository.get("owner", {}).get("login") or "") + if owner.casefold() != organization.casefold(): + continue + if repository.get("archived") or repository.get("disabled"): + continue + if not REPOSITORY_RE.fullmatch(full_name): + raise ValueError("GitHub returned an invalid repository full_name") + names.append(full_name) + return sorted(set(names)) + + +def list_recent_pull_requests( + client: GitHubClient, + *, + organization: str, + repository_source: str, + since: str, +) -> Iterator[dict[str, Any]]: + """Yield recent open pull requests and stop when the caller stops consuming.""" + + cutoff = parse_timestamp(since) + for repository in list_accessible_repositories( + client, + organization=organization, + repository_source=repository_source, + ): + response = client.request( + [ + f"repos/{repository}/pulls", + "-X", + "GET", + "-f", + "state=open", + "-f", + "sort=updated", + "-f", + "direction=desc", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + for pull_request in flatten_pages(response): + if parse_timestamp(str(pull_request.get("updated_at") or "")) < cutoff: + continue + number = pull_request.get("number") + if not isinstance(number, int) or number < 1: + raise ValueError("GitHub returned an invalid pull request number") + yield { + "number": number, + "repository": repository, + "pull_request": { + "url": f"https://api.github.com/repos/{repository}/pulls/{number}" + }, + } + + +def list_recent_comments( + client: GitHubClient, + *, + repository: str, + pull_request_number: int, + since: str, +) -> list[dict[str, Any]]: + """List recent issue comments for one pull request.""" + + response = client.request( + [ + f"repos/{repository}/issues/{pull_request_number}/comments", + "-X", + "GET", + "-f", + f"since={since}", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + return flatten_pages(response) + + +def build_requests_for_pull_request( + client: GitHubClient, + *, + issue: dict[str, Any], + since: str, +) -> tuple[MentionRequest, ...]: + """Build unacknowledged trusted mention requests for one live pull request.""" + + repository = str(issue.get("repository") or "") + if not REPOSITORY_RE.fullmatch(repository): + raise ValueError("pull request candidate has an invalid repository") + number = issue.get("number") + if not isinstance(number, int) or number < 1: + raise ValueError("pull request candidate has an invalid number") + comments = list_recent_comments( + client, + repository=repository, + pull_request_number=number, + since=since, + ) + processed = processed_comment_ids(comments) + live_pull = client.request([f"repos/{repository}/pulls/{number}"]) + if not isinstance(live_pull, dict) or live_pull.get("state") != "open": + return () + requests: list[MentionRequest] = [] + for comment in comments: + comment_id = comment.get("id") + if isinstance(comment_id, int) and comment_id in processed: + continue + event = { + "repository": {"full_name": repository}, + "issue": {"number": number, "pull_request": issue.get("pull_request")}, + "comment": comment, + "pull_request": live_pull, + "conversation_comments": comments, + } + request = parse_event(event) + if request is not None: + requests.append(request) + return tuple(requests) + + +def sweep( + *, + target_client: GitHubClient, + dispatch_client: GitHubClient, + organization: str, + repository_source: str, + lookback_hours: int, + max_dispatches: int, + opencode_allowlist: frozenset[str], + dry_run: bool = False, + now: datetime | None = None, +) -> int: + """Dispatch up to ``max_dispatches`` unacknowledged organization mentions.""" + + if max_dispatches < 1 or max_dispatches > 100: + raise ValueError("max dispatches must be between 1 and 100") + since = cutoff_timestamp(lookback_hours, now=now) + dispatched = 0 + for issue in list_recent_pull_requests( + target_client, + organization=organization, + repository_source=repository_source, + since=since, + ): + for request in build_requests_for_pull_request( + target_client, + issue=issue, + since=since, + ): + dispatch_request( + request, + target_client=target_client, + dispatch_client=dispatch_client, + opencode_allowlist=opencode_allowlist, + dry_run=dry_run, + ) + dispatched += 1 + if dispatched >= max_dispatches: + print(f"Agent mention sweep reached dispatch limit {max_dispatches}.") + return dispatched + print(f"Agent mention sweep completed with {dispatched} dispatch(es).") + return dispatched + + +def main(argv: Sequence[str] | None = None) -> int: + """Run the scheduled organization mention sweep.""" + + parser = argparse.ArgumentParser() + parser.add_argument("--organization", default="ContextualWisdomLab") + parser.add_argument( + "--repository-source", + choices=sorted(REPOSITORY_SOURCES), + default="organization", + ) + parser.add_argument("--lookback-hours", type=int, default=168) + parser.add_argument("--max-dispatches", type=int, default=20) + parser.add_argument("--dry-run", action="store_true") + args = parser.parse_args(argv) + allowlist = parse_repository_allowlist( + os.environ.get("OPENCODE_REPOSITORY_DISPATCH_TARGETS", "") + ) + sweep( + target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), + dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), + organization=args.organization, + repository_source=args.repository_source, + lookback_hours=args.lookback_hours, + max_dispatches=args.max_dispatches, + opencode_allowlist=allowlist, + dry_run=args.dry_run, + ) + return 0 + + +if __name__ == "__main__": # pragma: no cover + raise SystemExit(main()) From 1867cc8ad18913824aba776852edfe91e299f64f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:06:42 +0900 Subject: [PATCH 008/138] test(automation): pin mention-router runner and checkout source --- tests/test_agent_mention_workflow_contract.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_agent_mention_workflow_contract.py b/tests/test_agent_mention_workflow_contract.py index dbdcd2334..6cd46c930 100644 --- a/tests/test_agent_mention_workflow_contract.py +++ b/tests/test_agent_mention_workflow_contract.py @@ -4,6 +4,7 @@ ROOT = Path(__file__).resolve().parents[1] WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" +CHECKOUT_PIN = "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1" def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> None: @@ -16,6 +17,10 @@ def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> assert "workflow_dispatch:" in header assert "permissions:\n contents: read" in header assert "contents: write" not in header + assert text.count("runs-on: ubuntu-24.04") == 2 + assert text.count(CHECKOUT_PIN) == 2 + assert "ubuntu-latest" not in text + assert "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" not in text local, sweep = jobs.split("\n sweep-organization-agent-mentions:\n", 1) assert "route-local-agent-mention:" in local From 8cd9be3b91f94b440340ed413cd779ae53eebd52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:08:46 +0900 Subject: [PATCH 009/138] feat(automation): add trusted review-agent mention workflow --- .github/workflows/agent-mention-router.yml | 187 +++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 .github/workflows/agent-mention-router.yml diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml new file mode 100644 index 000000000..0a18342a8 --- /dev/null +++ b/.github/workflows/agent-mention-router.yml @@ -0,0 +1,187 @@ +name: Review Agent Mention Router + +on: + issue_comment: + types: [created] + schedule: + - cron: "*/5 * * * *" + workflow_dispatch: + +concurrency: + group: review-agent-mention-router-${{ github.repository }} + cancel-in-progress: false + +# Organization required-workflow rules do not propagate issue_comment events +# into sibling repositories. Keep the workflow default read-only; each bounded +# job declares only the writes it actually needs. +permissions: + contents: read + +jobs: + route-local-agent-mention: + if: >- + github.repository == 'ContextualWisdomLab/.github' + && github.event_name == 'issue_comment' + && github.event.issue.pull_request + && github.event.comment.user.type != 'Bot' + && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) + && ( + contains(github.event.comment.body, '@cwl-noema-review') + || contains(github.event.comment.body, '@opencode-agent') + ) + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + contents: write + issues: write + pull-requests: read + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + GH_TOKEN: ${{ github.token }} + TARGET_REPOSITORY_TOKEN: ${{ github.token }} + AGENT_DISPATCH_TOKEN: ${{ github.token }} + OPENCODE_REPOSITORY_DISPATCH_TARGETS: ${{ vars.OPENCODE_REPOSITORY_DISPATCH_TARGETS }} + steps: + - name: Check out trusted default-branch router + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.repository.default_branch }} + persist-credentials: false + + - name: Resolve immutable pull-request head and prior receipts + env: + REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.issue.number }} + SOURCE_EVENT_PATH: ${{ github.event_path }} + run: | + set -euo pipefail + pr_json="$(gh api "repos/${REPOSITORY}/pulls/${PR_NUMBER}")" + comments_json="$( + gh api --paginate --slurp \ + "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" \ + | jq -c 'add // []' + )" + jq \ + --argjson pull_request "$pr_json" \ + --argjson conversation_comments "$comments_json" \ + '. + { + pull_request: $pull_request, + conversation_comments: $conversation_comments + }' \ + "$SOURCE_EVENT_PATH" >"${RUNNER_TEMP}/agent-mention-event.json" + + - name: Route trusted local agent mention + run: >- + python3 scripts/ci/agent_mention_router.py + --event-path "${RUNNER_TEMP}/agent-mention-event.json" + + sweep-organization-agent-mentions: + if: >- + github.repository == 'ContextualWisdomLab/.github' + && ( + github.event_name == 'schedule' + || github.event_name == 'workflow_dispatch' + ) + runs-on: ubuntu-24.04 + timeout-minutes: 15 + permissions: + contents: write + id-token: write + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + OPENCODE_REPOSITORY_DISPATCH_TARGETS: ${{ vars.OPENCODE_REPOSITORY_DISPATCH_TARGETS }} + LOOKBACK_HOURS: ${{ vars.AGENT_MENTION_LOOKBACK_HOURS || '168' }} + MAX_DISPATCHES: ${{ vars.AGENT_MENTION_MAX_DISPATCHES || '20' }} + DRY_RUN: "false" + steps: + - name: Exchange OpenCode app token for sibling-repository comments + id: sweep_app_token + env: + OIDC_AUDIENCE: opencode-github-action + OPENCODE_API_BASE_URL: https://api.opencode.ai + USER_TOKEN_CONFIGURED: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '' }} + run: | + set -euo pipefail + mark_unavailable() { + echo "available=false" >>"$GITHUB_OUTPUT" + } + if [ "$USER_TOKEN_CONFIGURED" = "true" ]; then + echo "A configured cross-repository user token takes precedence." + mark_unavailable + exit 0 + fi + if [ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || [ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]; then + echo "OpenCode app token exchange unavailable: OIDC request environment is missing." + mark_unavailable + exit 0 + fi + request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}" + separator="&" + case "$request_url" in + *\?*) ;; + *) separator="?" ;; + esac + if ! oidc_response="$( + curl -fsS \ + -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ + "${request_url}${separator}audience=${OIDC_AUDIENCE}" + )"; then + echo "OpenCode app token exchange unavailable: OIDC token request did not complete." + mark_unavailable + exit 0 + fi + oidc_token="$(jq -r '.value // empty' <<<"$oidc_response")" + if [ -z "$oidc_token" ]; then + echo "OpenCode app token exchange unavailable: OIDC token response was empty." + mark_unavailable + exit 0 + fi + if ! token_response="$( + curl -fsS \ + -X POST \ + -H "Authorization: Bearer ${oidc_token}" \ + "${OPENCODE_API_BASE_URL}/exchange_github_app_token" + )"; then + echo "OpenCode app token exchange unavailable: app token request did not complete." + mark_unavailable + exit 0 + fi + app_token="$(jq -r '.token // empty' <<<"$token_response")" + if [ -z "$app_token" ]; then + echo "OpenCode app token exchange unavailable: app token response was empty." + mark_unavailable + exit 0 + fi + echo "::add-mask::$app_token" + { + echo "available=true" + echo "token=$app_token" + } >>"$GITHUB_OUTPUT" + + - name: Check out trusted central router + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.repository.default_branch }} + persist-credentials: false + + - name: Sweep recent organization PR comments + env: + TARGET_REPOSITORY_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.sweep_app_token.outputs.token }} + TARGET_REPOSITORY_SOURCE: ${{ (secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '') && 'organization' || steps.sweep_app_token.outputs.available == 'true' && 'installation' || '' }} + AGENT_DISPATCH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [ -z "${TARGET_REPOSITORY_TOKEN:-}" ] || [ -z "${TARGET_REPOSITORY_SOURCE:-}" ]; then + echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." + exit 1 + fi + args=( + --organization ContextualWisdomLab + --repository-source "$TARGET_REPOSITORY_SOURCE" + --lookback-hours "$LOOKBACK_HOURS" + --max-dispatches "$MAX_DISPATCHES" + ) + if [ "$DRY_RUN" = "true" ]; then + args+=(--dry-run) + fi + python3 scripts/ci/agent_mention_sweep.py "${args[@]}" From 7e53010cff2f25736bb9923888f197b7875e7ae5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:09:18 +0900 Subject: [PATCH 010/138] ci(automation): enforce mention-router quality gates --- .../agent-mention-router-quality-ci.yml | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/workflows/agent-mention-router-quality-ci.yml diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml new file mode 100644 index 000000000..f9a6792f2 --- /dev/null +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -0,0 +1,86 @@ +name: Agent Mention Router Quality CI + +on: + pull_request: + branches: [main] + paths: + - ".github/workflows/agent-mention-router.yml" + - ".github/workflows/agent-mention-router-quality-ci.yml" + - "scripts/ci/agent_mention_router.py" + - "scripts/ci/agent_mention_sweep.py" + - "tests/test_agent_mention_*.py" + - "requirements-opencode-review-ci-hashes.txt" + push: + branches: [main] + paths: + - ".github/workflows/agent-mention-router.yml" + - ".github/workflows/agent-mention-router-quality-ci.yml" + - "scripts/ci/agent_mention_router.py" + - "scripts/ci/agent_mention_sweep.py" + - "tests/test_agent_mention_*.py" + - "requirements-opencode-review-ci-hashes.txt" + +concurrency: + group: agent-mention-router-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + quality: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout exact head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + - name: Install exact hash-locked tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + - name: Run complete focused branch coverage + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + source = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py + git diff --check From f6aaa6eb71157a7775d02c4c66b272540a29000e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:09:53 +0900 Subject: [PATCH 011/138] docs(automation): document review-agent mention routing --- .../review-agent-comment-invocation.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/automation/review-agent-comment-invocation.md diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md new file mode 100644 index 000000000..6480a327c --- /dev/null +++ b/docs/automation/review-agent-comment-invocation.md @@ -0,0 +1,61 @@ +# Review-agent comment invocation + +Updated: 2026-08-05 + +## Purpose + +Trusted ContextualWisdomLab maintainers can invoke the existing review planes from a pull-request conversation: + +- `@cwl-noema-review` requests the independent Noema review. +- `@opencode-agent` requests a bounded current-head OpenCode review only; the invocation itself disables branch updates, automatic merge, and direct merge. + +The router never checks out or executes pull-request-controlled code. It reads live PR metadata, binds the request to the current head SHA and base branch, and dispatches the already deployed central workflows in `ContextualWisdomLab/.github`. + +## Architecture + +GitHub organization ruleset workflows support `pull_request`, `pull_request_target`, and `merge_group`, but not `issue_comment`. Separately, an `issue_comment` workflow runs only when that workflow file exists on the commented repository's default branch. Therefore, a workflow stored only in the central `.github` repository cannot directly receive comments created in sibling repositories. + +The implementation uses two bounded paths: + +1. **Local fast path.** Comments on `ContextualWisdomLab/.github` trigger `issue_comment` immediately. +2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and dispatches unacknowledged requests. A hidden receipt keyed by source comment ID prevents normal repeated sweeps or local workflow reruns from redispatching the same invocation. + +A user or fine-grained token enumerates organization repositories. When the OpenCode GitHub App installation token is the available credential, the sweep instead uses GitHub's installation-repositories endpoint, which returns only repositories accessible to that installation. This avoids depending on an organization-issues endpoint whose documented fine-grained token support is user-token-oriented. + +This preserves the central MSA boundary without copying privileged workflow code into every product repository. + +## Trust and permission boundary + +- Accepted comment associations: `OWNER`, `MEMBER`, and `COLLABORATOR`. +- Bot comments, ordinary contributors, issue comments outside PRs, closed PRs, malformed metadata, already acknowledged comments, and lookalike handles fail closed. +- The workflow default token is read-only. +- The local job receives job-scoped `contents: write`, `issues: write`, and `pull-requests: read`. +- The organization sweep uses the established cross-repository credential chain for reading and acknowledging target comments, while the central repository's own token dispatches the central workflows. +- OpenCode dispatch is restricted to the exact `OPENCODE_REPOSITORY_DISPATCH_TARGETS` allowlist. +- An invocation cannot merge: `enable_auto_merge=false`, `update_branches=false`, and `merge_mode=disabled` are explicit in the dispatch payload. +- Every dispatch is bound to live PR number, current head SHA, and base branch metadata fetched from GitHub immediately before dispatch. +- Both jobs use the fixed `ubuntu-24.04` runner and an immutable `actions/checkout` v7.0.1 commit pin; checkout credentials are not persisted. + +## Operator controls + +- `AGENT_MENTION_LOOKBACK_HOURS`: default `168`, allowed range 1–720. +- `AGENT_MENTION_MAX_DISPATCHES`: default `20`, allowed range 1–100. +- Manual `workflow_dispatch` supports the same bounds and a dry-run mode. +- The sweep fails visibly when no cross-repository credential is available. +- `PR_REVIEW_MERGE_TOKEN` or `OPENCODE_APPROVE_TOKEN` takes precedence. Otherwise, the workflow exchanges its OIDC token for the existing OpenCode installation token and enumerates that installation's repositories. + +## Verification and rollback + +The permanent quality workflow runs the deterministic router, sweep, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. + +Rollback is deletion of the two mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. + +## References + +GitHub. (n.d.). *Available rules for rulesets*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets + +GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/enterprise-cloud@latest/actions/reference/workflows-and-actions/events-that-trigger-workflows + +GitHub. (n.d.). *REST API endpoints for GitHub App installations*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/apps/installations + +GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/issues/issues From 580909f4efc6ec6445241b33ad23d30b25408b78 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:10:20 +0900 Subject: [PATCH 012/138] docs(changelog): record trusted mention-router slice --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e601de81b..eaa4bab7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Semantic Versioning where the repository publishes a release. ### Added +- Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate. - Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence. ### Fixed From b0d2d115d7ada282f58289fb289858526862c20e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:11:38 +0900 Subject: [PATCH 013/138] docs(automation): define mention-router activation gate --- docs/automation/review-agent-comment-invocation.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index 6480a327c..dc72b9de0 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -48,6 +48,10 @@ This preserves the central MSA boundary without copying privileged workflow code The permanent quality workflow runs the deterministic router, sweep, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. +### Activation gate + +The router is inactive until its workflow and helper code are merged into the protected default branch. A materialization, predecessor, cancelled, queued, or stale-head run is not activation evidence. Production activation requires the exact final head to pass the permanent quality workflow, security and supply-chain checks, current-head automated review, an independent approval, unresolved-thread policy, and branch protection without bypass. + Rollback is deletion of the two mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. ## References @@ -58,4 +62,4 @@ GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 5 GitHub. (n.d.). *REST API endpoints for GitHub App installations*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/apps/installations -GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/issues/issues +GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/issues/issues \ No newline at end of file From b67b99e69184dc6c31ffc16f8cdcdbb2600fb4f5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:14:06 +0900 Subject: [PATCH 014/138] test(automation): isolate CLI environment contract --- tests/test_agent_mention_router.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 673054a0d..31190299e 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -326,6 +326,7 @@ def test_load_event_and_main_paths(tmp_path: Path, monkeypatch, capsys) -> None: ignored_path.write_text(json.dumps(event("nothing")), encoding="utf-8") assert module.main(["--event-path", str(ignored_path)]) == 0 assert "nothing to dispatch" in capsys.readouterr().out + monkeypatch.delenv("GITHUB_EVENT_PATH", raising=False) with pytest.raises(SystemExit): module.main([]) valid_path = tmp_path / "valid.json" From 95f5e54b3e7fa0ea9da9758379a30f8b4c85ebde Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:14:42 +0900 Subject: [PATCH 015/138] test(automation): require path-based coverage measurement --- tests/test_agent_mention_workflow_contract.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_agent_mention_workflow_contract.py b/tests/test_agent_mention_workflow_contract.py index 6cd46c930..cfcdc9c88 100644 --- a/tests/test_agent_mention_workflow_contract.py +++ b/tests/test_agent_mention_workflow_contract.py @@ -4,6 +4,9 @@ ROOT = Path(__file__).resolve().parents[1] WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" +QUALITY_WORKFLOW = ( + ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" +) CHECKOUT_PIN = "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1" @@ -44,3 +47,14 @@ def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> assert "TARGET_REPOSITORY_SOURCE" in sweep assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep assert "agent_mention_sweep.py" in sweep + + +def test_quality_workflow_measures_exact_files_without_module_name_warnings() -> None: + """Coverage includes the two script paths instead of treating paths as modules.""" + + text = QUALITY_WORKFLOW.read_text(encoding="utf-8") + coverage_config = text.split("[run]\n", 1)[1].split("[report]\n", 1)[0] + assert "include =" in coverage_config + assert "source =" not in coverage_config + assert "scripts/ci/agent_mention_router.py" in coverage_config + assert "scripts/ci/agent_mention_sweep.py" in coverage_config From cf4400f7f8fe673f1f89c467a6629bd92dcaae2c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 22:15:05 +0900 Subject: [PATCH 016/138] ci(automation): measure exact mention-router script paths --- .github/workflows/agent-mention-router-quality-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index f9a6792f2..6aafab9f2 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -60,7 +60,7 @@ jobs: cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' [run] branch = True - source = + include = scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py [report] From 588ea687206eeca2d8c090ebe613088243e258fb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:35:09 +0900 Subject: [PATCH 017/138] test(agent-router): require per-agent durable dispatch idempotency --- tests/test_agent_mention_idempotency.py | 313 ++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 tests/test_agent_mention_idempotency.py diff --git a/tests/test_agent_mention_idempotency.py b/tests/test_agent_mention_idempotency.py new file mode 100644 index 000000000..313936bc6 --- /dev/null +++ b/tests/test_agent_mention_idempotency.py @@ -0,0 +1,313 @@ +"""Regression tests for durable per-agent mention dispatch idempotency.""" + +from __future__ import annotations + +import importlib.util +import re +import sys +from pathlib import Path +from types import ModuleType + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + +def load_module() -> ModuleType: + """Load the router module from its script path for isolated tests.""" + + module_name = "agent_mention_router_idempotency" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def request(module: ModuleType): + """Build one request containing both supported review agents.""" + + return module.MentionRequest( + "ContextualWisdomLab/inkspan", + 65, + "a" * 40, + "main", + 12345, + "maintainer", + ("cwl-noema-review", "opencode-agent"), + ) + + +class RunAwareClient: + """Fake GitHub client with workflow-run inventory and fault injection.""" + + def __init__(self, *, runs=None, fail_event=None, fail_target_call=None) -> None: + """Initialize bounded responses and optional deterministic failures.""" + + self.runs = runs or {} + self.fail_event = fail_event + self.fail_target_call = fail_target_call + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Return workflow runs, record mutations, or raise at a selected boundary.""" + + call_number = len(self.calls) + 1 + self.calls.append((list(args), input_payload)) + endpoint = args[0] + if endpoint.endswith("/runs"): + return self.runs.get(endpoint, {"workflow_runs": []}) + if endpoint.endswith("/dispatches"): + event_type = (input_payload or {}).get("event_type") + if event_type == self.fail_event: + raise RuntimeError(f"failed {event_type}") + if self.fail_target_call == call_number: + raise RuntimeError(f"failed target call {call_number}") + return None + + +def workflow_run(module: ModuleType, mention_request, agent: str, run_id: int) -> dict: + """Build one durable central workflow-run record for an exact agent request.""" + + return { + "id": run_id, + "event": "repository_dispatch", + "status": "completed", + "conclusion": "failure", + "display_title": ( + "Required review " + f"{module.agent_invocation_marker(mention_request, agent)}" + ), + } + + +def run_inventory(module: ModuleType, mention_request, *agents: str) -> dict: + """Return endpoint-keyed workflow-run responses for selected agents.""" + + inventory = {} + for index, agent in enumerate(agents, start=1): + endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS[agent] + inventory[endpoint] = { + "workflow_runs": [workflow_run(module, mention_request, agent, index)] + } + return inventory + + +def dispatch_events(client: RunAwareClient) -> list[str]: + """Return repository-dispatch event types recorded by one fake client.""" + + return [ + payload["event_type"] + for args, payload in client.calls + if args[0].endswith("/dispatches") and payload is not None + ] + + +def test_invocation_key_binds_complete_request_identity() -> None: + """The opaque key changes with agent, head, PR, repository, or source comment.""" + + module = load_module() + original = request(module) + noema_key = module.agent_invocation_key(original, "cwl-noema-review") + opencode_key = module.agent_invocation_key(original, "opencode-agent") + assert re.fullmatch(r"[0-9a-f]{64}", noema_key) + assert noema_key != opencode_key + assert module.agent_invocation_marker(original, "cwl-noema-review") == ( + f"[cwl-agent-invocation:{noema_key}]" + ) + + changed_values = ( + module.MentionRequest( + "ContextualWisdomLab/naruon", + original.pull_request_number, + original.pull_request_head_sha, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), + module.MentionRequest( + original.repository, + original.pull_request_number + 1, + original.pull_request_head_sha, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), + module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), + module.MentionRequest( + original.repository, + original.pull_request_number, + original.pull_request_head_sha, + original.pull_request_base_branch, + original.comment_id + 1, + original.actor, + original.agents, + ), + ) + assert all( + module.agent_invocation_key(changed, "cwl-noema-review") != noema_key + for changed in changed_values + ) + with pytest.raises(ValueError, match="unsupported agent"): + module.agent_invocation_key(original, "unknown-agent") + + +def test_payloads_carry_exact_agent_invocation_identity() -> None: + """Both downstream entrypoints receive the same deterministic request identity.""" + + module = load_module() + mention_request = request(module) + noema = module.noema_payload(mention_request)["client_payload"] + opencode = module.opencode_payload(mention_request)["client_payload"] + + assert noema["requested_agent"] == "cwl-noema-review" + assert noema["agent_invocation_key"] == module.agent_invocation_key( + mention_request, "cwl-noema-review" + ) + assert opencode["requested_agent"] == "opencode-agent" + assert opencode["agent_invocation_key"] == module.agent_invocation_key( + mention_request, "opencode-agent" + ) + for payload in (noema, opencode): + assert payload["target_repository"] == mention_request.repository + assert payload["pr_number"] == mention_request.pull_request_number + assert payload["pr_head_sha"] == mention_request.pull_request_head_sha + assert payload["source_comment_id"] == mention_request.comment_id + + +def test_existing_workflow_runs_are_per_agent_durable_evidence() -> None: + """Queued, running, completed, or failed exact-key runs suppress only that agent.""" + + module = load_module() + mention_request = request(module) + client = RunAwareClient( + runs=run_inventory(module, mention_request, "cwl-noema-review") + ) + assert module.dispatched_agents(mention_request, client) == frozenset( + {"cwl-noema-review"} + ) + + forged = { + module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"]: { + "workflow_runs": [ + { + **workflow_run( + module, mention_request, "cwl-noema-review", 2 + ), + "display_title": "forged unrelated title", + } + ] + } + } + assert module.dispatched_agents( + mention_request, RunAwareClient(runs=forged) + ) == frozenset() + + malformed = RunAwareClient( + runs={ + module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"]: { + "workflow_runs": "not-a-list" + } + } + ) + with pytest.raises(ValueError, match="workflow-run"): + module.dispatched_agents(mention_request, malformed) + + +def test_partial_failure_retries_only_the_missing_agent() -> None: + """A later dispatch failure never repeats an already materialized agent run.""" + + module = load_module() + mention_request = request(module) + target = RunAwareClient() + first = RunAwareClient(fail_event="merge-scheduler") + + with pytest.raises(RuntimeError, match="merge-scheduler"): + module.dispatch_request( + mention_request, + target_client=target, + dispatch_client=first, + opencode_allowlist=frozenset({mention_request.repository}), + ) + assert dispatch_events(first) == ["noema-review", "merge-scheduler"] + + retry = RunAwareClient( + runs=run_inventory(module, mention_request, "cwl-noema-review") + ) + assert module.dispatch_request( + mention_request, + target_client=RunAwareClient(), + dispatch_client=retry, + opencode_allowlist=frozenset({mention_request.repository}), + ) == ("@opencode-agent",) + assert dispatch_events(retry) == ["merge-scheduler"] + + +def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: + """Target-repository UX failure is separate from durable dispatch evidence.""" + + module = load_module() + mention_request = request(module) + central = RunAwareClient() + failing_target = RunAwareClient(fail_target_call=1) + with pytest.raises(RuntimeError, match="target call"): + module.dispatch_request( + mention_request, + target_client=failing_target, + dispatch_client=central, + opencode_allowlist=frozenset({mention_request.repository}), + ) + assert dispatch_events(central) == ["noema-review", "merge-scheduler"] + + retry = RunAwareClient( + runs=run_inventory( + module, + mention_request, + "cwl-noema-review", + "opencode-agent", + ) + ) + retry_target = RunAwareClient(fail_target_call=1) + assert module.dispatch_request( + mention_request, + target_client=retry_target, + dispatch_client=retry, + opencode_allowlist=frozenset({mention_request.repository}), + ) == () + assert dispatch_events(retry) == [] + assert retry_target.calls == [] + + +def test_exact_run_inventory_accepts_paginated_slurp_shape() -> None: + """The bounded parser handles gh --paginate --slurp pages deterministically.""" + + module = load_module() + mention_request = request(module) + endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] + client = RunAwareClient( + runs={ + endpoint: [ + {"workflow_runs": []}, + { + "workflow_runs": [ + workflow_run(module, mention_request, "opencode-agent", 9) + ] + }, + ] + } + ) + assert module.dispatched_agents(mention_request, client) == frozenset( + {"opencode-agent"} + ) From ee1e33e4562872920bec08de197c8b8d17d7273a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:35:37 +0900 Subject: [PATCH 018/138] test(agent-router): require downstream exact-key idempotency --- ...st_agent_mention_downstream_idempotency.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/test_agent_mention_downstream_idempotency.py diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py new file mode 100644 index 000000000..24b5f4745 --- /dev/null +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -0,0 +1,53 @@ +"""Static contracts for downstream review-agent invocation idempotency.""" + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +ROUTER_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" +QUALITY_WORKFLOW = ( + ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" +) +NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "noema-review.yml" +OPENCODE_WORKFLOW = ( + ROOT / ".github" / "workflows" / "pr-review-merge-scheduler.yml" +) + + +def test_router_can_read_durable_central_workflow_runs() -> None: + """Both local routing and sibling sweeping receive actions read access.""" + + text = ROUTER_WORKFLOW.read_text(encoding="utf-8") + local, sweep = text.split("\n sweep-organization-agent-mentions:\n", 1) + assert "permissions:\n actions: read" in local + assert "permissions:\n actions: read" in sweep + assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in local + assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep + + +def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> None: + """Noema and OpenCode entrypoints serialize an exact agent invocation key.""" + + noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") + opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") + for text in (noema, opencode): + assert "github.event.client_payload.agent_invocation_key" in text + assert "cwl-agent-invocation:" in text + assert "source_comment_id" in text + assert "requested_agent" in noema + assert "requested_agent" in opencode + assert "cancel-in-progress: ${{ github.event_name != 'repository_dispatch' }}" in noema + assert "cancel-in-progress: ${{ github.event_name != 'repository_dispatch' }}" in opencode + + +def test_quality_gate_tracks_every_idempotency_surface() -> None: + """The permanent focused gate reruns for downstream workflow contract changes.""" + + text = QUALITY_WORKFLOW.read_text(encoding="utf-8") + for path in ( + '.github/workflows/noema-review.yml', + '.github/workflows/pr-review-merge-scheduler.yml', + 'tests/test_agent_mention_idempotency.py', + 'tests/test_agent_mention_downstream_idempotency.py', + ): + assert f' - "{path}"' in text + assert path in text.split("python -m coverage run -m pytest -q", 1)[1] From cb08d051f296d438815c3d658bcb2003f7bf7317 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:36:17 +0900 Subject: [PATCH 019/138] test(agent-router): separate workflow trigger and pytest contracts --- tests/test_agent_mention_downstream_idempotency.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index 24b5f4745..9489990c2 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -40,14 +40,19 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No def test_quality_gate_tracks_every_idempotency_surface() -> None: - """The permanent focused gate reruns for downstream workflow contract changes.""" + """The permanent focused gate reruns and executes all bounded contracts.""" text = QUALITY_WORKFLOW.read_text(encoding="utf-8") - for path in ( + for workflow_path in ( '.github/workflows/noema-review.yml', '.github/workflows/pr-review-merge-scheduler.yml', + ): + assert f' - "{workflow_path}"' in text + + test_command = text.split("python -m coverage run -m pytest -q", 1)[1] + for test_path in ( 'tests/test_agent_mention_idempotency.py', 'tests/test_agent_mention_downstream_idempotency.py', ): - assert f' - "{path}"' in text - assert path in text.split("python -m coverage run -m pytest -q", 1)[1] + assert f' - "{test_path}"' in text + assert test_path in test_command From 6008bacc467921c0fcb48c808fbbc02c3b4f4dfe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:36:52 +0900 Subject: [PATCH 020/138] test(agent-router): execute durable idempotency contracts --- .../agent-mention-router-quality-ci.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index 6aafab9f2..d9403b163 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -6,18 +6,26 @@ on: paths: - ".github/workflows/agent-mention-router.yml" - ".github/workflows/agent-mention-router-quality-ci.yml" + - ".github/workflows/noema-review.yml" + - ".github/workflows/pr-review-merge-scheduler.yml" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" + - "tests/test_agent_mention_idempotency.py" + - "tests/test_agent_mention_downstream_idempotency.py" - "requirements-opencode-review-ci-hashes.txt" push: branches: [main] paths: - ".github/workflows/agent-mention-router.yml" - ".github/workflows/agent-mention-router-quality-ci.yml" + - ".github/workflows/noema-review.yml" + - ".github/workflows/pr-review-merge-scheduler.yml" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" + - "tests/test_agent_mention_idempotency.py" + - "tests/test_agent_mention_downstream_idempotency.py" - "requirements-opencode-review-ci-hashes.txt" concurrency: @@ -72,7 +80,9 @@ jobs: python -m coverage run -m pytest -q \ tests/test_agent_mention_router.py \ tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py python -m coverage report --fail-under=100 python -m interrogate --fail-under=100 \ scripts/ci/agent_mention_router.py \ @@ -82,5 +92,7 @@ jobs: scripts/ci/agent_mention_sweep.py \ tests/test_agent_mention_router.py \ tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py git diff --check From d7c2335be0bbd59a185c649735d3f25cbdcac561 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:38:59 +0900 Subject: [PATCH 021/138] fix(agent-router): deduplicate exact per-agent dispatches --- scripts/ci/agent_mention_router.py | 153 +++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 8 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index d3a8518d9..20cef05dd 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -4,6 +4,7 @@ from __future__ import annotations import argparse +import hashlib import json import os import re @@ -23,10 +24,21 @@ re.IGNORECASE, ), } +AGENT_WORKFLOW_RUN_ENDPOINTS = { + "cwl-noema-review": ( + f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" + "noema-review.yml/runs" + ), + "opencode-agent": ( + f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" + "pr-review-merge-scheduler.yml/runs" + ), +} REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") HEAD_SHA_RE = re.compile(r"^[0-9a-fA-F]{40}$") BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$") RECEIPT_RE = re.compile(r"") +MAX_WORKFLOW_RUN_RECORDS = 10_000 @dataclass(frozen=True) @@ -86,7 +98,7 @@ def exact_mentions(body: str) -> tuple[str, ...]: def receipt_marker(comment_id: int) -> str: - """Return the hidden idempotency marker for one invocation comment.""" + """Return the hidden target-comment acknowledgement marker.""" if comment_id < 1: raise ValueError("comment id must be positive") @@ -94,7 +106,13 @@ def receipt_marker(comment_id: int) -> str: def processed_comment_ids(comments: Sequence[dict[str, Any]]) -> frozenset[int]: - """Extract receipt IDs authored by the trusted GitHub Actions bot only.""" + """Extract local receipts authored by the trusted GitHub Actions bot only. + + These target-repository comments are a local optimization and user-facing + acknowledgement. Central exact-key workflow-run records remain authoritative + for cross-repository dispatch idempotency because PAT and installation-token + identities can rotate and target-repository actors can be spoofed. + """ processed: set[int] = set() for comment in comments: @@ -197,15 +215,116 @@ def eligible_agents( return tuple(dispatchable), tuple(rejected) +def agent_invocation_key(request: MentionRequest, agent: str) -> str: + """Return a deterministic opaque key for one exact agent invocation. + + The key binds repository, pull request, exact head, base branch, requested + agent, source comment, and requesting actor. It contains no credential or + provider response and is safe to place in workflow run names. + """ + + if agent not in AGENT_WORKFLOW_RUN_ENDPOINTS: + raise ValueError(f"unsupported agent: {agent}") + canonical = json.dumps( + { + "actor": request.actor, + "agent": agent, + "base_branch": request.pull_request_base_branch, + "comment_id": request.comment_id, + "head_sha": request.pull_request_head_sha, + "pr_number": request.pull_request_number, + "repository": request.repository, + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + return hashlib.sha256(canonical).hexdigest() + + +def agent_invocation_marker(request: MentionRequest, agent: str) -> str: + """Return the exact workflow-run marker for one agent invocation.""" + + return f"[cwl-agent-invocation:{agent_invocation_key(request, agent)}]" + + +def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: + """Validate and flatten bounded ``gh --paginate --slurp`` workflow runs.""" + + pages = value if isinstance(value, list) else [value] + if not pages or not all(isinstance(page, dict) for page in pages): + raise ValueError("workflow-run response must contain object pages") + records: list[dict[str, Any]] = [] + for page in pages: + page_records = page.get("workflow_runs") + if not isinstance(page_records, list) or not all( + isinstance(record, dict) for record in page_records + ): + raise ValueError("workflow-run response contains invalid records") + records.extend(page_records) + if len(records) > MAX_WORKFLOW_RUN_RECORDS: + raise ValueError("workflow-run response exceeds the bounded record limit") + return tuple(records) + + +def dispatched_agents( + request: MentionRequest, + dispatch_client: GitHubClient, + agents: Sequence[str] | None = None, +) -> frozenset[str]: + """Return agents with a durable central run for this exact invocation. + + A run record proves GitHub accepted the repository dispatch even when its + conclusion is failure. Repeating a failed invocation requires a new trusted + source comment, which produces a different key and preserves auditable + at-most-once behavior for each request. + """ + + candidates = tuple(request.agents if agents is None else agents) + observed: set[str] = set() + for agent in candidates: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS.get(agent) + if endpoint is None: + raise ValueError(f"unsupported agent: {agent}") + response = dispatch_client.request( + [ + endpoint, + "-X", + "GET", + "-f", + "event=repository_dispatch", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + marker = agent_invocation_marker(request, agent) + for run in _workflow_run_records(response): + run_id = run.get("id") + if ( + isinstance(run_id, int) + and run_id > 0 + and run.get("event") == "repository_dispatch" + and marker in str(run.get("display_title") or "") + ): + observed.add(agent) + break + return frozenset(observed) + + def noema_payload(request: MentionRequest) -> dict[str, Any]: """Return the central Noema repository-dispatch request body.""" + agent = "cwl-noema-review" return { "event_type": "noema-review", "client_payload": { "target_repository": request.repository, "pr_number": request.pull_request_number, "pr_head_sha": request.pull_request_head_sha, + "requested_agent": agent, + "agent_invocation_key": agent_invocation_key(request, agent), "requested_by": request.actor, "source_comment_id": request.comment_id, }, @@ -215,6 +334,7 @@ def noema_payload(request: MentionRequest) -> dict[str, Any]: def opencode_payload(request: MentionRequest) -> dict[str, Any]: """Return the review-only central OpenCode scheduler dispatch body.""" + agent = "opencode-agent" return { "event_type": "merge-scheduler", "client_payload": { @@ -227,7 +347,8 @@ def opencode_payload(request: MentionRequest) -> dict[str, Any]: "enable_auto_merge": False, "update_branches": False, "merge_mode": "disabled", - "requested_agent": "opencode-agent", + "requested_agent": agent, + "agent_invocation_key": agent_invocation_key(request, agent), "requested_by": request.actor, "source_comment_id": request.comment_id, }, @@ -242,14 +363,14 @@ def dispatch_request( opencode_allowlist: frozenset[str], dry_run: bool = False, ) -> tuple[str, ...]: - """Dispatch requested agents and acknowledge the invocation on its PR.""" + """Dispatch only missing agents and acknowledge new work on the target PR.""" dispatchable, rejected = eligible_agents( request, opencode_allowlist=opencode_allowlist, ) - handles = tuple(f"@{agent}" for agent in dispatchable) if dry_run: + handles = tuple(f"@{agent}" for agent in dispatchable) print( "DRY-RUN agent mention " f"repo={request.repository} pr={request.pull_request_number} " @@ -258,17 +379,25 @@ def dispatch_request( f"reject={','.join(rejected) or 'none'}" ) return handles + + existing = dispatched_agents(request, dispatch_client, dispatchable) + missing = tuple(agent for agent in dispatchable if agent not in existing) + handles = tuple(f"@{agent}" for agent in missing) + if not missing and not rejected: + return () + dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" - if "cwl-noema-review" in dispatchable: + if "cwl-noema-review" in missing: dispatch_client.request( [dispatch_endpoint, "-X", "POST"], input_payload=noema_payload(request), ) - if "opencode-agent" in dispatchable: + if "opencode-agent" in missing: dispatch_client.request( [dispatch_endpoint, "-X", "POST"], input_payload=opencode_payload(request), ) + target_api = f"repos/{request.repository}" target_client.request( [f"{target_api}/issues/comments/{request.comment_id}/reactions", "-X", "POST"], @@ -277,6 +406,13 @@ def dispatch_request( status_parts: list[str] = [] if handles: status_parts.append(f"Queued {' and '.join(handles)}") + existing_handles = tuple( + f"@{agent}" for agent in dispatchable if agent in existing + ) + if existing_handles: + status_parts.append( + f"Already queued {' and '.join(existing_handles)} on this exact request" + ) if rejected: rejected_handles = " and ".join(f"@{agent}" for agent in rejected) status_parts.append( @@ -286,7 +422,8 @@ def dispatch_request( acknowledgement = ( f"{receipt_marker(request.comment_id)}\n" f"{' ; '.join(status_parts)} for PR #{request.pull_request_number} at head " - f"`{request.pull_request_head_sha}`. Existing review workflows remain " + f"`{request.pull_request_head_sha}`. Central exact-key workflow runs are " + "the durable dispatch ledger; existing review workflows remain " "authoritative for the final verdict and failure evidence." ) target_client.request( From 109a5fae712536e83fddeeb771c4f35af17509ab Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:45:12 +0900 Subject: [PATCH 022/138] fix(agent-router): accept empty workflow-run inventory --- scripts/ci/agent_mention_router.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 20cef05dd..bc9ea824f 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -251,6 +251,8 @@ def agent_invocation_marker(request: MentionRequest, agent: str) -> str: def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: """Validate and flatten bounded ``gh --paginate --slurp`` workflow runs.""" + if value is None: + return () pages = value if isinstance(value, list) else [value] if not pages or not all(isinstance(page, dict) for page in pages): raise ValueError("workflow-run response must contain object pages") From 9e11bb3a5ecc2f464230efa66d1fc47600780437 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:45:43 +0900 Subject: [PATCH 023/138] test(agent-router): model durable run inventory reads --- tests/test_agent_mention_router.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 31190299e..47fbe4468 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -75,12 +75,26 @@ def __init__(self) -> None: self.calls: list[tuple[list[str], dict | None]] = [] def request(self, args, *, input_payload=None): - """Record one request and return no response body.""" + """Record one request and return an empty run inventory for reads.""" self.calls.append((list(args), input_payload)) + if args[0].endswith("/runs"): + return {"workflow_runs": []} return None +def repository_dispatch_calls( + client: FakeClient, +) -> list[tuple[list[str], dict]]: + """Return only mutation calls that enqueue central repository dispatches.""" + + return [ + (args, payload) + for args, payload in client.calls + if args[0].endswith("/dispatches") and payload is not None + ] + + def test_exact_mentions_and_parse_event() -> None: """Both exact mentions are recognized with immutable PR metadata.""" @@ -224,13 +238,14 @@ def test_dispatch_uses_central_events_and_acknowledges() -> None: opencode_allowlist=frozenset({request.repository}), ) assert result == ("@cwl-noema-review", "@opencode-agent") - assert [payload["event_type"] for _, payload in central.calls] == [ + dispatches = repository_dispatch_calls(central) + assert [payload["event_type"] for _, payload in dispatches] == [ "noema-review", "merge-scheduler", ] assert all( args[0] == "repos/ContextualWisdomLab/.github/dispatches" - for args, _ in central.calls + for args, _ in dispatches ) assert target.calls[0][1] == {"content": "eyes"} assert "cwl-agent-mention-receipt:91" in target.calls[1][1]["body"] @@ -283,7 +298,9 @@ def test_dispatch_noema_only_covers_non_opencode_path() -> None: dispatch_client=central, opencode_allowlist=frozenset(), ) == ("@cwl-noema-review",) - assert central.calls[0][1]["event_type"] == "noema-review" + dispatches = repository_dispatch_calls(central) + assert len(dispatches) == 1 + assert dispatches[0][1]["event_type"] == "noema-review" def test_github_client_validates_token_and_decodes_json(monkeypatch) -> None: From 236fd71b289130fcd82c7280f70f088beebffadc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:46:00 +0900 Subject: [PATCH 024/138] fix(agent-router): grant durable workflow-run read access --- .github/workflows/agent-mention-router.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index 0a18342a8..d10ff03f9 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -32,6 +32,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: + actions: read contents: write issues: write pull-requests: read @@ -85,6 +86,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: + actions: read contents: write id-token: write env: From 78af2e0960bc5f0cd5d94f6d6152d3b29a6892f2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:47:35 +0900 Subject: [PATCH 025/138] test(agent-router): require durable dispatch wrappers --- ...st_agent_mention_downstream_idempotency.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index 9489990c2..b2aabd43d 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -7,9 +7,11 @@ QUALITY_WORKFLOW = ( ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" ) -NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "noema-review.yml" +NOEMA_WORKFLOW = ( + ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" +) OPENCODE_WORKFLOW = ( - ROOT / ".github" / "workflows" / "pr-review-merge-scheduler.yml" + ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" ) @@ -25,7 +27,7 @@ def test_router_can_read_durable_central_workflow_runs() -> None: def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> None: - """Noema and OpenCode entrypoints serialize an exact agent invocation key.""" + """Agent wrappers serialize and validate one exact invocation key.""" noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") @@ -33,10 +35,17 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No assert "github.event.client_payload.agent_invocation_key" in text assert "cwl-agent-invocation:" in text assert "source_comment_id" in text - assert "requested_agent" in noema - assert "requested_agent" in opencode - assert "cancel-in-progress: ${{ github.event_name != 'repository_dispatch' }}" in noema - assert "cancel-in-progress: ${{ github.event_name != 'repository_dispatch' }}" in opencode + assert "requested_agent" in text + assert "cancel-in-progress: false" in text + assert "^[0-9a-f]{64}$" in text + assert "^[1-9][0-9]*$" in text + assert "repos/${GITHUB_REPOSITORY}/dispatches" in text + assert "types: [agent-mention-noema]" in noema + assert 'event_type: "noema-review"' in noema + assert 'REQUESTED_AGENT: "cwl-noema-review"' in noema + assert "types: [agent-mention-opencode]" in opencode + assert 'event_type: "merge-scheduler"' in opencode + assert 'REQUESTED_AGENT: "opencode-agent"' in opencode def test_quality_gate_tracks_every_idempotency_surface() -> None: @@ -44,8 +53,8 @@ def test_quality_gate_tracks_every_idempotency_surface() -> None: text = QUALITY_WORKFLOW.read_text(encoding="utf-8") for workflow_path in ( - '.github/workflows/noema-review.yml', - '.github/workflows/pr-review-merge-scheduler.yml', + '.github/workflows/agent-mention-noema-dispatch.yml', + '.github/workflows/agent-mention-opencode-dispatch.yml', ): assert f' - "{workflow_path}"' in text From f0522c4f9e0a92b0ad4b525f40b87e07c9cab735 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:48:31 +0900 Subject: [PATCH 026/138] feat(agent-router): add durable Noema dispatch wrapper --- .../agent-mention-noema-dispatch.yml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 .github/workflows/agent-mention-noema-dispatch.yml diff --git a/.github/workflows/agent-mention-noema-dispatch.yml b/.github/workflows/agent-mention-noema-dispatch.yml new file mode 100644 index 000000000..95c84cfce --- /dev/null +++ b/.github/workflows/agent-mention-noema-dispatch.yml @@ -0,0 +1,96 @@ +name: Agent Mention Noema Dispatch +run-name: >- + Agent Mention Noema ${{ github.event.client_payload.target_repository }}#${{ + github.event.client_payload.pr_number }} [cwl-agent-invocation:${{ + github.event.client_payload.agent_invocation_key }}] + +on: + repository_dispatch: + types: [agent-mention-noema] + +concurrency: + group: agent-mention-noema-${{ github.event.client_payload.agent_invocation_key || github.run_id }} + cancel-in-progress: false + +permissions: + actions: read + contents: write + +jobs: + validate-and-forward: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + env: + GH_TOKEN: ${{ github.token }} + REQUESTED_AGENT: "cwl-noema-review" + PAYLOAD_AGENT: ${{ github.event.client_payload.requested_agent || '' }} + INVOCATION_KEY: ${{ github.event.client_payload.agent_invocation_key || '' }} + TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || '' }} + PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} + PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} + SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} + steps: + - name: Validate exact invocation and elect one durable leader + id: leader + run: | + set -euo pipefail + if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || + ! [[ "$INVOCATION_KEY" =~ ^[0-9a-f]{64}$ ]] || + ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || + ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]]; then + echo "::error::Rejected malformed or mismatched Noema agent invocation payload." + exit 1 + fi + + marker="[cwl-agent-invocation:${INVOCATION_KEY}]" + leader_id="$( + gh api --paginate --slurp \ + "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-noema-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ + | jq -r --arg marker "$marker" ' + [.[].workflow_runs[] + | select((.display_title // "") | contains($marker)) + | .id] + | min // empty + ' + )" + if [ -z "$leader_id" ]; then + echo "::error::Could not establish the durable Noema invocation leader." + exit 1 + fi + if [ "$leader_id" != "$GITHUB_RUN_ID" ]; then + echo "forward=false" >>"$GITHUB_OUTPUT" + echo "Duplicate exact-key invocation suppressed by durable workflow-run identity." + exit 0 + fi + echo "forward=true" >>"$GITHUB_OUTPUT" + + - name: Forward once to the authoritative Noema workflow + if: steps.leader.outputs.forward == 'true' + run: | + set -euo pipefail + jq -n \ + --arg target_repository "$TARGET_REPOSITORY" \ + --argjson pr_number "$PR_NUMBER" \ + --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg requested_agent "$REQUESTED_AGENT" \ + --arg agent_invocation_key "$INVOCATION_KEY" \ + --arg requested_by "$REQUESTED_BY" \ + --argjson source_comment_id "$SOURCE_COMMENT_ID" \ + '{ + event_type: "noema-review", + client_payload: { + target_repository: $target_repository, + pr_number: $pr_number, + pr_head_sha: $pr_head_sha, + requested_agent: $requested_agent, + agent_invocation_key: $agent_invocation_key, + requested_by: $requested_by, + source_comment_id: $source_comment_id + } + }' \ + | gh api "repos/${GITHUB_REPOSITORY}/dispatches" -X POST --input - From 88b59602df06a91cc87b6681172f8e1ba1e94652 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:49:09 +0900 Subject: [PATCH 027/138] feat(agent-router): add durable OpenCode dispatch wrapper --- .../agent-mention-opencode-dispatch.yml | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 .github/workflows/agent-mention-opencode-dispatch.yml diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml new file mode 100644 index 000000000..294998343 --- /dev/null +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -0,0 +1,115 @@ +name: Agent Mention OpenCode Dispatch +run-name: >- + Agent Mention OpenCode ${{ github.event.client_payload.target_repository }}#${{ + github.event.client_payload.pr_number }} [cwl-agent-invocation:${{ + github.event.client_payload.agent_invocation_key }}] + +on: + repository_dispatch: + types: [agent-mention-opencode] + +concurrency: + group: agent-mention-opencode-${{ github.event.client_payload.agent_invocation_key || github.run_id }} + cancel-in-progress: false + +permissions: + actions: read + contents: write + +jobs: + validate-and-forward: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + env: + GH_TOKEN: ${{ github.token }} + REQUESTED_AGENT: "opencode-agent" + PAYLOAD_AGENT: ${{ github.event.client_payload.requested_agent || '' }} + INVOCATION_KEY: ${{ github.event.client_payload.agent_invocation_key || '' }} + TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || '' }} + PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} + PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} + REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} + SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} + TRIGGER_REVIEWS: ${{ github.event.client_payload.trigger_reviews }} + REVIEW_DISPATCH_LIMIT: ${{ github.event.client_payload.review_dispatch_limit || '' }} + ENABLE_AUTO_MERGE: ${{ github.event.client_payload.enable_auto_merge }} + UPDATE_BRANCHES: ${{ github.event.client_payload.update_branches }} + MERGE_MODE: ${{ github.event.client_payload.merge_mode || '' }} + steps: + - name: Validate exact review-only invocation and elect one durable leader + id: leader + run: | + set -euo pipefail + if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || + ! [[ "$INVOCATION_KEY" =~ ^[0-9a-f]{64}$ ]] || + ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || + ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$BASE_BRANCH" =~ ^(?!-)[A-Za-z0-9._/-]+$ ]] || + ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]] || + [ "$TRIGGER_REVIEWS" != "true" ] || + [ "$REVIEW_DISPATCH_LIMIT" != "1" ] || + [ "$ENABLE_AUTO_MERGE" != "false" ] || + [ "$UPDATE_BRANCHES" != "false" ] || + [ "$MERGE_MODE" != "disabled" ]; then + echo "::error::Rejected malformed, mismatched, or mutation-capable OpenCode invocation payload." + exit 1 + fi + + marker="[cwl-agent-invocation:${INVOCATION_KEY}]" + leader_id="$( + gh api --paginate --slurp \ + "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-opencode-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ + | jq -r --arg marker "$marker" ' + [.[].workflow_runs[] + | select((.display_title // "") | contains($marker)) + | .id] + | min // empty + ' + )" + if [ -z "$leader_id" ]; then + echo "::error::Could not establish the durable OpenCode invocation leader." + exit 1 + fi + if [ "$leader_id" != "$GITHUB_RUN_ID" ]; then + echo "forward=false" >>"$GITHUB_OUTPUT" + echo "Duplicate exact-key invocation suppressed by durable workflow-run identity." + exit 0 + fi + echo "forward=true" >>"$GITHUB_OUTPUT" + + - name: Forward once to the authoritative review-only scheduler + if: steps.leader.outputs.forward == 'true' + run: | + set -euo pipefail + jq -n \ + --arg target_repository "$TARGET_REPOSITORY" \ + --argjson pr_number "$PR_NUMBER" \ + --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg base_branch "$BASE_BRANCH" \ + --arg requested_agent "$REQUESTED_AGENT" \ + --arg agent_invocation_key "$INVOCATION_KEY" \ + --arg requested_by "$REQUESTED_BY" \ + --argjson source_comment_id "$SOURCE_COMMENT_ID" \ + '{ + event_type: "merge-scheduler", + client_payload: { + target_repository: $target_repository, + pr_number: $pr_number, + pr_head_sha: $pr_head_sha, + base_branch: $base_branch, + trigger_reviews: true, + review_dispatch_limit: "1", + enable_auto_merge: false, + update_branches: false, + merge_mode: "disabled", + requested_agent: $requested_agent, + agent_invocation_key: $agent_invocation_key, + requested_by: $requested_by, + source_comment_id: $source_comment_id + } + }' \ + | gh api "repos/${GITHUB_REPOSITORY}/dispatches" -X POST --input - From d4caec695217d5803c7fa9aebad9d27f55d4991d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:51:11 +0900 Subject: [PATCH 028/138] feat(agent-router): route through durable dispatch wrappers --- scripts/ci/agent_mention_router.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index bc9ea824f..f1db4746f 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -27,11 +27,11 @@ AGENT_WORKFLOW_RUN_ENDPOINTS = { "cwl-noema-review": ( f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" - "noema-review.yml/runs" + "agent-mention-noema-dispatch.yml/runs" ), "opencode-agent": ( f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" - "pr-review-merge-scheduler.yml/runs" + "agent-mention-opencode-dispatch.yml/runs" ), } REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") @@ -316,11 +316,11 @@ def dispatched_agents( def noema_payload(request: MentionRequest) -> dict[str, Any]: - """Return the central Noema repository-dispatch request body.""" + """Return the durable Noema wrapper dispatch request body.""" agent = "cwl-noema-review" return { - "event_type": "noema-review", + "event_type": "agent-mention-noema", "client_payload": { "target_repository": request.repository, "pr_number": request.pull_request_number, @@ -334,11 +334,11 @@ def noema_payload(request: MentionRequest) -> dict[str, Any]: def opencode_payload(request: MentionRequest) -> dict[str, Any]: - """Return the review-only central OpenCode scheduler dispatch body.""" + """Return the durable review-only OpenCode wrapper dispatch body.""" agent = "opencode-agent" return { - "event_type": "merge-scheduler", + "event_type": "agent-mention-opencode", "client_payload": { "target_repository": request.repository, "pr_number": request.pull_request_number, From 68877ff7e47a5ff0a0bceb48666bb300b89c48f1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:52:37 +0900 Subject: [PATCH 029/138] test(agent-router): expect durable wrapper events --- tests/test_agent_mention_router.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 47fbe4468..3cc9fcbf4 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -213,10 +213,10 @@ def test_eligible_agents_and_payloads() -> None: opencode_allowlist=frozenset(), ) == (("cwl-noema-review",), ("opencode-agent",)) noema = module.noema_payload(request) - assert noema["event_type"] == "noema-review" + assert noema["event_type"] == "agent-mention-noema" assert noema["client_payload"]["pr_head_sha"] == "a" * 40 opencode = module.opencode_payload(request) - assert opencode["event_type"] == "merge-scheduler" + assert opencode["event_type"] == "agent-mention-opencode" assert opencode["client_payload"]["base_branch"] == "develop" assert opencode["client_payload"]["merge_mode"] == "disabled" assert opencode["client_payload"]["enable_auto_merge"] is False @@ -240,8 +240,8 @@ def test_dispatch_uses_central_events_and_acknowledges() -> None: assert result == ("@cwl-noema-review", "@opencode-agent") dispatches = repository_dispatch_calls(central) assert [payload["event_type"] for _, payload in dispatches] == [ - "noema-review", - "merge-scheduler", + "agent-mention-noema", + "agent-mention-opencode", ] assert all( args[0] == "repos/ContextualWisdomLab/.github/dispatches" @@ -300,7 +300,7 @@ def test_dispatch_noema_only_covers_non_opencode_path() -> None: ) == ("@cwl-noema-review",) dispatches = repository_dispatch_calls(central) assert len(dispatches) == 1 - assert dispatches[0][1]["event_type"] == "noema-review" + assert dispatches[0][1]["event_type"] == "agent-mention-noema" def test_github_client_validates_token_and_decodes_json(monkeypatch) -> None: From ec201dff654622232c3eac96aa1c9dfa5feeb12c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:53:31 +0900 Subject: [PATCH 030/138] test(agent-router): cover wrapper event idempotency --- tests/test_agent_mention_idempotency.py | 26 +++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/test_agent_mention_idempotency.py b/tests/test_agent_mention_idempotency.py index 313936bc6..21be1713a 100644 --- a/tests/test_agent_mention_idempotency.py +++ b/tests/test_agent_mention_idempotency.py @@ -165,12 +165,16 @@ def test_invocation_key_binds_complete_request_identity() -> None: def test_payloads_carry_exact_agent_invocation_identity() -> None: - """Both downstream entrypoints receive the same deterministic request identity.""" + """Both durable wrappers receive the same deterministic request identity.""" module = load_module() mention_request = request(module) - noema = module.noema_payload(mention_request)["client_payload"] - opencode = module.opencode_payload(mention_request)["client_payload"] + noema_body = module.noema_payload(mention_request) + opencode_body = module.opencode_payload(mention_request) + assert noema_body["event_type"] == "agent-mention-noema" + assert opencode_body["event_type"] == "agent-mention-opencode" + noema = noema_body["client_payload"] + opencode = opencode_body["client_payload"] assert noema["requested_agent"] == "cwl-noema-review" assert noema["agent_invocation_key"] == module.agent_invocation_key( @@ -232,16 +236,19 @@ def test_partial_failure_retries_only_the_missing_agent() -> None: module = load_module() mention_request = request(module) target = RunAwareClient() - first = RunAwareClient(fail_event="merge-scheduler") + first = RunAwareClient(fail_event="agent-mention-opencode") - with pytest.raises(RuntimeError, match="merge-scheduler"): + with pytest.raises(RuntimeError, match="agent-mention-opencode"): module.dispatch_request( mention_request, target_client=target, dispatch_client=first, opencode_allowlist=frozenset({mention_request.repository}), ) - assert dispatch_events(first) == ["noema-review", "merge-scheduler"] + assert dispatch_events(first) == [ + "agent-mention-noema", + "agent-mention-opencode", + ] retry = RunAwareClient( runs=run_inventory(module, mention_request, "cwl-noema-review") @@ -252,7 +259,7 @@ def test_partial_failure_retries_only_the_missing_agent() -> None: dispatch_client=retry, opencode_allowlist=frozenset({mention_request.repository}), ) == ("@opencode-agent",) - assert dispatch_events(retry) == ["merge-scheduler"] + assert dispatch_events(retry) == ["agent-mention-opencode"] def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: @@ -269,7 +276,10 @@ def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: dispatch_client=central, opencode_allowlist=frozenset({mention_request.repository}), ) - assert dispatch_events(central) == ["noema-review", "merge-scheduler"] + assert dispatch_events(central) == [ + "agent-mention-noema", + "agent-mention-opencode", + ] retry = RunAwareClient( runs=run_inventory( From c1171d74fc8b4d47acf8e5bc5c0013415f3ba03c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:55:40 +0900 Subject: [PATCH 031/138] test(agent-router): reject unsupported Bash lookahead --- tests/test_agent_mention_downstream_idempotency.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index b2aabd43d..f5849ecf4 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -46,6 +46,9 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No assert "types: [agent-mention-opencode]" in opencode assert 'event_type: "merge-scheduler"' in opencode assert 'REQUESTED_AGENT: "opencode-agent"' in opencode + assert "^(?!-)" not in opencode + assert '[[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' in opencode + assert '[[ "$BASE_BRANCH" == -* ]]' in opencode def test_quality_gate_tracks_every_idempotency_surface() -> None: From 316246c9ea61890d942fc1ff5714f0f1dc5275ed Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:56:46 +0900 Subject: [PATCH 032/138] fix(agent-router): use portable Bash base validation --- .github/workflows/agent-mention-opencode-dispatch.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml index 294998343..42f821c75 100644 --- a/.github/workflows/agent-mention-opencode-dispatch.yml +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -47,7 +47,8 @@ jobs: ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || - ! [[ "$BASE_BRANCH" =~ ^(?!-)[A-Za-z0-9._/-]+$ ]] || + ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || + [[ "$BASE_BRANCH" == -* ]] || ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]] || [ "$TRIGGER_REVIEWS" != "true" ] || From d69a7678ffa6a0cfa28b648243709c00c972aacb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:57:26 +0900 Subject: [PATCH 033/138] ci(agent-router): track durable dispatch wrappers --- .github/workflows/agent-mention-router-quality-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index d9403b163..837819ea4 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -6,8 +6,8 @@ on: paths: - ".github/workflows/agent-mention-router.yml" - ".github/workflows/agent-mention-router-quality-ci.yml" - - ".github/workflows/noema-review.yml" - - ".github/workflows/pr-review-merge-scheduler.yml" + - ".github/workflows/agent-mention-noema-dispatch.yml" + - ".github/workflows/agent-mention-opencode-dispatch.yml" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" @@ -19,8 +19,8 @@ on: paths: - ".github/workflows/agent-mention-router.yml" - ".github/workflows/agent-mention-router-quality-ci.yml" - - ".github/workflows/noema-review.yml" - - ".github/workflows/pr-review-merge-scheduler.yml" + - ".github/workflows/agent-mention-noema-dispatch.yml" + - ".github/workflows/agent-mention-opencode-dispatch.yml" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" From 7a5db21bb835a289e78fe79b2074ea579fbe23d6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 5 Aug 2026 23:58:58 +0900 Subject: [PATCH 034/138] test(agent-router): make central run ledger authoritative --- tests/test_agent_mention_receipt_authority.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/test_agent_mention_receipt_authority.py diff --git a/tests/test_agent_mention_receipt_authority.py b/tests/test_agent_mention_receipt_authority.py new file mode 100644 index 000000000..5e26f8868 --- /dev/null +++ b/tests/test_agent_mention_receipt_authority.py @@ -0,0 +1,60 @@ +"""Contracts that keep target-repository receipt comments non-authoritative.""" + +from __future__ import annotations + +import importlib +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +SCRIPTS = ROOT / "scripts" / "ci" +sys.path.insert(0, str(SCRIPTS)) + + +def test_receipt_looking_comments_never_suppress_a_trusted_request() -> None: + """Only durable central exact-key workflow runs may suppress redispatch.""" + + router = importlib.reload(importlib.import_module("agent_mention_router")) + event = { + "repository": {"full_name": "ContextualWisdomLab/inkspan"}, + "issue": {"number": 64, "pull_request": {"url": "https://example.test"}}, + "comment": { + "id": 101, + "body": "@opencode-agent", + "author_association": "MEMBER", + "user": {"login": "maintainer", "type": "User"}, + }, + "pull_request": { + "state": "open", + "head": {"sha": "a" * 40}, + "base": {"ref": "main"}, + }, + "conversation_comments": [ + { + "body": "", + "user": {"login": "github-actions[bot]", "type": "Bot"}, + }, + { + "body": "", + "user": {"login": "rotated-installation-bot", "type": "Bot"}, + }, + { + "body": "", + "user": {"login": "attacker", "type": "User"}, + }, + ], + } + + request = router.parse_event(event) + assert request is not None + assert request.comment_id == 101 + assert request.agents == ("opencode-agent",) + + +def test_sweep_does_not_use_target_receipts_as_dispatch_authority() -> None: + """The organization sweep delegates suppression to the central run ledger.""" + + source = (SCRIPTS / "agent_mention_sweep.py").read_text(encoding="utf-8") + + assert "processed_comment_ids" not in source + assert "comment_id in processed" not in source From 75df0cd4416c550e38f600666cdfeb868df6a450 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:01:35 +0900 Subject: [PATCH 035/138] ci(agent-router): execute receipt authority contract --- .github/workflows/agent-mention-router-quality-ci.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index 837819ea4..36a8d43a9 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -11,8 +11,6 @@ on: - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" - - "tests/test_agent_mention_idempotency.py" - - "tests/test_agent_mention_downstream_idempotency.py" - "requirements-opencode-review-ci-hashes.txt" push: branches: [main] @@ -24,8 +22,6 @@ on: - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" - - "tests/test_agent_mention_idempotency.py" - - "tests/test_agent_mention_downstream_idempotency.py" - "requirements-opencode-review-ci-hashes.txt" concurrency: @@ -82,7 +78,8 @@ jobs: tests/test_agent_mention_sweep.py \ tests/test_agent_mention_workflow_contract.py \ tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py python -m coverage report --fail-under=100 python -m interrogate --fail-under=100 \ scripts/ci/agent_mention_router.py \ @@ -94,5 +91,6 @@ jobs: tests/test_agent_mention_sweep.py \ tests/test_agent_mention_workflow_contract.py \ tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py git diff --check From d3afa233baca00511d76a46ae44bfbf4ee169b5d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:03:22 +0900 Subject: [PATCH 036/138] test(agent-router): make production paths receipt-independent --- tests/test_agent_mention_receipt_authority.py | 55 ++++--------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/tests/test_agent_mention_receipt_authority.py b/tests/test_agent_mention_receipt_authority.py index 5e26f8868..9280167b9 100644 --- a/tests/test_agent_mention_receipt_authority.py +++ b/tests/test_agent_mention_receipt_authority.py @@ -2,53 +2,21 @@ from __future__ import annotations -import importlib -import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SCRIPTS = ROOT / "scripts" / "ci" -sys.path.insert(0, str(SCRIPTS)) - - -def test_receipt_looking_comments_never_suppress_a_trusted_request() -> None: - """Only durable central exact-key workflow runs may suppress redispatch.""" - - router = importlib.reload(importlib.import_module("agent_mention_router")) - event = { - "repository": {"full_name": "ContextualWisdomLab/inkspan"}, - "issue": {"number": 64, "pull_request": {"url": "https://example.test"}}, - "comment": { - "id": 101, - "body": "@opencode-agent", - "author_association": "MEMBER", - "user": {"login": "maintainer", "type": "User"}, - }, - "pull_request": { - "state": "open", - "head": {"sha": "a" * 40}, - "base": {"ref": "main"}, - }, - "conversation_comments": [ - { - "body": "", - "user": {"login": "github-actions[bot]", "type": "Bot"}, - }, - { - "body": "", - "user": {"login": "rotated-installation-bot", "type": "Bot"}, - }, - { - "body": "", - "user": {"login": "attacker", "type": "User"}, - }, - ], - } - - request = router.parse_event(event) - assert request is not None - assert request.comment_id == 101 - assert request.agents == ("opencode-agent",) +ROUTER_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" + + +def test_local_router_does_not_load_target_receipts_as_dispatch_authority() -> None: + """The local path routes the source event without prior-comment receipts.""" + + workflow = ROUTER_WORKFLOW.read_text(encoding="utf-8") + local = workflow.split("\n sweep-organization-agent-mentions:\n", 1)[0] + + assert "conversation_comments" not in local + assert "/comments?per_page=100" not in local def test_sweep_does_not_use_target_receipts_as_dispatch_authority() -> None: @@ -58,3 +26,4 @@ def test_sweep_does_not_use_target_receipts_as_dispatch_authority() -> None: assert "processed_comment_ids" not in source assert "comment_id in processed" not in source + assert "/comments?per_page=100" not in source From f384e2ee07a64aede7bc40044198ea5a6c5a0312 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:04:20 +0900 Subject: [PATCH 037/138] fix(agent-router): remove local receipt authority --- .github/workflows/agent-mention-router.yml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index d10ff03f9..b57254852 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -49,7 +49,7 @@ jobs: ref: ${{ github.event.repository.default_branch }} persist-credentials: false - - name: Resolve immutable pull-request head and prior receipts + - name: Resolve immutable pull-request head env: REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.issue.number }} @@ -57,18 +57,9 @@ jobs: run: | set -euo pipefail pr_json="$(gh api "repos/${REPOSITORY}/pulls/${PR_NUMBER}")" - comments_json="$( - gh api --paginate --slurp \ - "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" \ - | jq -c 'add // []' - )" jq \ --argjson pull_request "$pr_json" \ - --argjson conversation_comments "$comments_json" \ - '. + { - pull_request: $pull_request, - conversation_comments: $conversation_comments - }' \ + '. + {pull_request: $pull_request}' \ "$SOURCE_EVENT_PATH" >"${RUNNER_TEMP}/agent-mention-event.json" - name: Route trusted local agent mention From 7689c3a9e8411c9ba37116ba895db46bb1168013 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:05:21 +0900 Subject: [PATCH 038/138] fix(agent-router): make sweep receipt-independent --- scripts/ci/agent_mention_sweep.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py index 181d2d62f..67cf79d3c 100644 --- a/scripts/ci/agent_mention_sweep.py +++ b/scripts/ci/agent_mention_sweep.py @@ -15,7 +15,6 @@ dispatch_request, parse_event, parse_repository_allowlist, - processed_comment_ids, ) ORG_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+$") @@ -198,7 +197,7 @@ def build_requests_for_pull_request( issue: dict[str, Any], since: str, ) -> tuple[MentionRequest, ...]: - """Build unacknowledged trusted mention requests for one live pull request.""" + """Build trusted mention requests for one live pull request.""" repository = str(issue.get("repository") or "") if not REPOSITORY_RE.fullmatch(repository): @@ -212,21 +211,16 @@ def build_requests_for_pull_request( pull_request_number=number, since=since, ) - processed = processed_comment_ids(comments) live_pull = client.request([f"repos/{repository}/pulls/{number}"]) if not isinstance(live_pull, dict) or live_pull.get("state") != "open": return () requests: list[MentionRequest] = [] for comment in comments: - comment_id = comment.get("id") - if isinstance(comment_id, int) and comment_id in processed: - continue event = { "repository": {"full_name": repository}, "issue": {"number": number, "pull_request": issue.get("pull_request")}, "comment": comment, "pull_request": live_pull, - "conversation_comments": comments, } request = parse_event(event) if request is not None: @@ -246,7 +240,7 @@ def sweep( dry_run: bool = False, now: datetime | None = None, ) -> int: - """Dispatch up to ``max_dispatches`` unacknowledged organization mentions.""" + """Dispatch up to ``max_dispatches`` recent organization mentions.""" if max_dispatches < 1 or max_dispatches > 100: raise ValueError("max dispatches must be between 1 and 100") From b86250d5201905d654e8c0d7baab55df1003d77b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:14:23 +0900 Subject: [PATCH 039/138] test: prevent no-op sweep requests from exhausting budget --- tests/test_agent_mention_sweep.py | 244 ++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 79 deletions(-) diff --git a/tests/test_agent_mention_sweep.py b/tests/test_agent_mention_sweep.py index b64257e7a..d3b9ffe0a 100644 --- a/tests/test_agent_mention_sweep.py +++ b/tests/test_agent_mention_sweep.py @@ -160,9 +160,11 @@ def test_accessible_repository_sources_filter_and_validate() -> None: repository_source="organization", ) == ["ContextualWisdomLab/example"] installation_client = FakeClient( - {"installation/repositories": [ - {"repositories": [repository(), repository("second")]} - ]} + { + "installation/repositories": [ + {"repositories": [repository(), repository("second")]} + ] + } ) assert sweep.list_accessible_repositories( installation_client, @@ -182,9 +184,11 @@ def test_accessible_repository_sources_filter_and_validate() -> None: repository_source="bad", ) invalid_client = FakeClient( - {"orgs/ContextualWisdomLab/repos": [[ - {**repository(), "full_name": "bad/name"} - ]]} + { + "orgs/ContextualWisdomLab/repos": [[ + {**repository(), "full_name": "bad/name"} + ]] + } ) with pytest.raises(ValueError, match="full_name"): sweep.list_accessible_repositories( @@ -207,12 +211,14 @@ def test_recent_pull_request_filtering() -> None: ]], } ) - assert list(sweep.list_recent_pull_requests( - client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-04T12:00:00Z", - )) == [candidate()] + assert list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-04T12:00:00Z", + ) + ) == [candidate()] bad_number_client = FakeClient( { "orgs/ContextualWisdomLab/repos": [[repository()]], @@ -222,16 +228,18 @@ def test_recent_pull_request_filtering() -> None: } ) with pytest.raises(ValueError, match="pull request number"): - list(sweep.list_recent_pull_requests( - bad_number_client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-04T12:00:00Z", - )) + list( + sweep.list_recent_pull_requests( + bad_number_client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-04T12:00:00Z", + ) + ) -def test_build_requests_skips_trusted_receipts_and_closed_pull_requests() -> None: - """Only unacknowledged trusted comments on a live PR become requests.""" +def test_build_requests_ignores_receipt_markers_and_skips_closed_pulls() -> None: + """Target comments are context only; trusted live mentions remain requests.""" sweep = module() comments_endpoint = "repos/ContextualWisdomLab/example/issues/7/comments" @@ -251,14 +259,20 @@ def test_build_requests_skips_trusted_receipts_and_closed_pull_requests() -> Non requests = sweep.build_requests_for_pull_request( client, issue=candidate(), since="2026-08-04T00:00:00Z" ) - assert [request.comment_id for request in requests] == [12] - assert requests[0].agents == ("cwl-noema-review",) + assert [request.comment_id for request in requests] == [10, 12] + assert [request.agents for request in requests] == [ + ("opencode-agent",), + ("cwl-noema-review",), + ] closed = FakeClient( {comments_endpoint: [comments], pull_endpoint: live_pull("closed")} ) - assert sweep.build_requests_for_pull_request( - closed, issue=candidate(), since="2026-08-04T00:00:00Z" - ) == () + assert ( + sweep.build_requests_for_pull_request( + closed, issue=candidate(), since="2026-08-04T00:00:00Z" + ) + == () + ) with pytest.raises(ValueError, match="repository"): sweep.build_requests_for_pull_request( client, issue={**candidate(), "repository": "bad/name"}, since="x" @@ -285,7 +299,7 @@ def mention_request(number: int, comment_id: int, agent: str): def test_sweep_dispatches_with_limit_and_reports_empty(monkeypatch, capsys) -> None: - """The sweep dispatches deterministically and respects its mutation budget.""" + """The sweep bounds source requests that actually queue new agent work.""" sweep = module() request_a = mention_request(7, 10, "opencode-agent") @@ -298,37 +312,46 @@ def test_sweep_dispatches_with_limit_and_reports_empty(monkeypatch, capsys) -> N "build_requests_for_pull_request", lambda *args, **kwargs: (request_a, request_b), ) - dispatched = [] - monkeypatch.setattr( - sweep, - "dispatch_request", - lambda request, **kwargs: dispatched.append(request.comment_id) or (), + dispatch_calls = [] + + def dispatch_new_work(request, **kwargs): + """Record one call and report its newly queued agent handle.""" + + dispatch_calls.append(request.comment_id) + return (f"@{request.agents[0]}",) + + monkeypatch.setattr(sweep, "dispatch_request", dispatch_new_work) + assert ( + sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=1, + opencode_allowlist=frozenset({"ContextualWisdomLab/example"}), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) + == 1 ) - assert sweep.sweep( - target_client=FakeClient(), - dispatch_client=FakeClient(), - organization="ContextualWisdomLab", - repository_source="organization", - lookback_hours=24, - max_dispatches=1, - opencode_allowlist=frozenset({"ContextualWisdomLab/example"}), - now=datetime(2026, 8, 5, tzinfo=timezone.utc), - ) == 1 - assert dispatched == [10] + assert dispatch_calls == [10] assert "reached dispatch limit" in capsys.readouterr().out monkeypatch.setattr( sweep, "list_recent_pull_requests", lambda *args, **kwargs: iter(()) ) - assert sweep.sweep( - target_client=FakeClient(), - dispatch_client=FakeClient(), - organization="ContextualWisdomLab", - repository_source="installation", - lookback_hours=24, - max_dispatches=2, - opencode_allowlist=frozenset(), - now=datetime(2026, 8, 5, tzinfo=timezone.utc), - ) == 0 + assert ( + sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="installation", + lookback_hours=24, + max_dispatches=2, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) + == 0 + ) assert "0 dispatch" in capsys.readouterr().out for value in (0, 101): with pytest.raises(ValueError, match="max dispatches"): @@ -343,6 +366,58 @@ def test_sweep_dispatches_with_limit_and_reports_empty(monkeypatch, capsys) -> N ) +def test_sweep_noops_do_not_starve_new_mentions_across_repeated_runs( + monkeypatch, +) -> None: + """Already-ledgered requests never consume the bounded new-work budget.""" + + sweep = module() + historical = tuple( + mention_request(7, comment_id, "opencode-agent") + for comment_id in range(100, 121) + ) + new_request = mention_request(7, 999, "opencode-agent") + requests = (*historical, new_request) + monkeypatch.setattr( + sweep, "list_recent_pull_requests", lambda *args, **kwargs: iter([candidate()]) + ) + monkeypatch.setattr( + sweep, + "build_requests_for_pull_request", + lambda *args, **kwargs: requests, + ) + ledgered_comment_ids = {request.comment_id for request in historical} + dispatch_calls = [] + + def dispatch_from_ledger(request, **kwargs): + """Return work only for a source request absent from the durable ledger.""" + + dispatch_calls.append(request.comment_id) + if request.comment_id in ledgered_comment_ids: + return () + ledgered_comment_ids.add(request.comment_id) + return ("@opencode-agent",) + + monkeypatch.setattr(sweep, "dispatch_request", dispatch_from_ledger) + sweep_kwargs = { + "target_client": FakeClient(), + "dispatch_client": FakeClient(), + "organization": "ContextualWisdomLab", + "repository_source": "organization", + "lookback_hours": 168, + "max_dispatches": 1, + "opencode_allowlist": frozenset({"ContextualWisdomLab/example"}), + "now": datetime(2026, 8, 5, tzinfo=timezone.utc), + } + + assert sweep.sweep(**sweep_kwargs) == 1 + assert dispatch_calls == [request.comment_id for request in requests] + dispatch_calls.clear() + + assert sweep.sweep(**sweep_kwargs) == 0 + assert dispatch_calls == [request.comment_id for request in requests] + + def test_sweep_continues_across_empty_results_and_completes( monkeypatch, capsys ) -> None: @@ -360,23 +435,29 @@ def test_sweep_continues_across_empty_results_and_completes( "build_requests_for_pull_request", lambda *args, issue, **kwargs: () if issue["number"] == 7 else (request,), ) - dispatched = [] - monkeypatch.setattr( - sweep, - "dispatch_request", - lambda request, **kwargs: dispatched.append(request.comment_id) or (), + dispatch_calls = [] + + def dispatch_new_work(request, **kwargs): + """Record and report the one newly queued review agent.""" + + dispatch_calls.append(request.comment_id) + return ("@cwl-noema-review",) + + monkeypatch.setattr(sweep, "dispatch_request", dispatch_new_work) + assert ( + sweep.sweep( + target_client=FakeClient(), + dispatch_client=FakeClient(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=2, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 5, tzinfo=timezone.utc), + ) + == 1 ) - assert sweep.sweep( - target_client=FakeClient(), - dispatch_client=FakeClient(), - organization="ContextualWisdomLab", - repository_source="organization", - lookback_hours=24, - max_dispatches=2, - opencode_allowlist=frozenset(), - now=datetime(2026, 8, 5, tzinfo=timezone.utc), - ) == 1 - assert dispatched == [12] + assert dispatch_calls == [12] assert "completed with 1 dispatch" in capsys.readouterr().out @@ -391,17 +472,22 @@ def test_main_constructs_clients_and_forwards_options(monkeypatch) -> None: "OPENCODE_REPOSITORY_DISPATCH_TARGETS", "ContextualWisdomLab/example" ) monkeypatch.setattr(sweep, "sweep", lambda **kwargs: captured.append(kwargs) or 0) - assert sweep.main([ - "--organization", - "ContextualWisdomLab", - "--repository-source", - "installation", - "--lookback-hours", - "48", - "--max-dispatches", - "3", - "--dry-run", - ]) == 0 + assert ( + sweep.main( + [ + "--organization", + "ContextualWisdomLab", + "--repository-source", + "installation", + "--lookback-hours", + "48", + "--max-dispatches", + "3", + "--dry-run", + ] + ) + == 0 + ) assert captured[0]["repository_source"] == "installation" assert captured[0]["lookback_hours"] == 48 assert captured[0]["max_dispatches"] == 3 From 22e4c18a41eb45b677a4571f083a3275fdfbbcc1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:14:44 +0900 Subject: [PATCH 040/138] test: assert job permissions independently --- tests/test_agent_mention_workflow_contract.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/test_agent_mention_workflow_contract.py b/tests/test_agent_mention_workflow_contract.py index cfcdc9c88..409f194e5 100644 --- a/tests/test_agent_mention_workflow_contract.py +++ b/tests/test_agent_mention_workflow_contract.py @@ -28,17 +28,19 @@ def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> local, sweep = jobs.split("\n sweep-organization-agent-mentions:\n", 1) assert "route-local-agent-mention:" in local assert "github.repository == 'ContextualWisdomLab/.github'" in local - assert ( - "permissions:\n" - " contents: write\n" - " issues: write\n" - " pull-requests: read" - ) in local + for permission in ( + "actions: read", + "contents: write", + "issues: write", + "pull-requests: read", + ): + assert f" {permission}" in local assert "ref: ${{ github.event.repository.default_branch }}" in local assert "TARGET_REPOSITORY_TOKEN: ${{ github.token }}" in local - assert "conversation_comments" in local + assert "conversation_comments" not in local - assert "permissions:\n contents: write\n id-token: write" in sweep + for permission in ("actions: read", "contents: write", "id-token: write"): + assert f" {permission}" in sweep assert "github.repository == 'ContextualWisdomLab/.github'" in sweep assert "github.event_name == 'schedule'" in sweep assert "github.event_name == 'workflow_dispatch'" in sweep From 1fd0119c999dbf954c6e402c4e40f71e07b5db6c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:15:08 +0900 Subject: [PATCH 041/138] test: accept wildcard quality-gate path coverage --- tests/test_agent_mention_downstream_idempotency.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index f5849ecf4..f5eb00e68 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -56,15 +56,17 @@ def test_quality_gate_tracks_every_idempotency_surface() -> None: text = QUALITY_WORKFLOW.read_text(encoding="utf-8") for workflow_path in ( - '.github/workflows/agent-mention-noema-dispatch.yml', - '.github/workflows/agent-mention-opencode-dispatch.yml', + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", ): assert f' - "{workflow_path}"' in text + assert ' - "tests/test_agent_mention_*.py"' in text test_command = text.split("python -m coverage run -m pytest -q", 1)[1] + compile_command = text.split("python -m compileall -q", 1)[1] for test_path in ( - 'tests/test_agent_mention_idempotency.py', - 'tests/test_agent_mention_downstream_idempotency.py', + "tests/test_agent_mention_idempotency.py", + "tests/test_agent_mention_downstream_idempotency.py", ): - assert f' - "{test_path}"' in text assert test_path in test_command + assert test_path in compile_command From 90568424a6405934d9701a4a01a72d2fcb9bcde6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:16:04 +0900 Subject: [PATCH 042/138] fix: preserve sweep capacity for newly queued work --- scripts/ci/agent_mention_sweep.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py index 67cf79d3c..ae1ee0b4d 100644 --- a/scripts/ci/agent_mention_sweep.py +++ b/scripts/ci/agent_mention_sweep.py @@ -240,7 +240,7 @@ def sweep( dry_run: bool = False, now: datetime | None = None, ) -> int: - """Dispatch up to ``max_dispatches`` recent organization mentions.""" + """Bound source requests that actually queue at least one new agent.""" if max_dispatches < 1 or max_dispatches > 100: raise ValueError("max dispatches must be between 1 and 100") @@ -257,13 +257,15 @@ def sweep( issue=issue, since=since, ): - dispatch_request( + queued_agents = dispatch_request( request, target_client=target_client, dispatch_client=dispatch_client, opencode_allowlist=opencode_allowlist, dry_run=dry_run, ) + if not queued_agents: + continue dispatched += 1 if dispatched >= max_dispatches: print(f"Agent mention sweep reached dispatch limit {max_dispatches}.") From 94277180dc512a26540d7e3b8dcd0836de44721f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:18:19 +0900 Subject: [PATCH 043/138] test: cover durable run-ledger failure boundaries --- tests/test_agent_mention_idempotency.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_agent_mention_idempotency.py b/tests/test_agent_mention_idempotency.py index 21be1713a..2cd19a8ed 100644 --- a/tests/test_agent_mention_idempotency.py +++ b/tests/test_agent_mention_idempotency.py @@ -230,6 +230,29 @@ def test_existing_workflow_runs_are_per_agent_durable_evidence() -> None: module.dispatched_agents(mention_request, malformed) +def test_workflow_run_inventory_edge_cases_fail_closed(monkeypatch) -> None: + """Empty, malformed, oversized, and unsupported run queries fail safely.""" + + module = load_module() + mention_request = request(module) + + assert module._workflow_run_records(None) == () + for malformed in ([], ["not-an-object"]): + with pytest.raises(ValueError, match="object pages"): + module._workflow_run_records(malformed) + + monkeypatch.setattr(module, "MAX_WORKFLOW_RUN_RECORDS", 0) + with pytest.raises(ValueError, match="bounded record limit"): + module._workflow_run_records({"workflow_runs": [{}]}) + + with pytest.raises(ValueError, match="unsupported agent"): + module.dispatched_agents( + mention_request, + RunAwareClient(), + agents=("unknown-agent",), + ) + + def test_partial_failure_retries_only_the_missing_agent() -> None: """A later dispatch failure never repeats an already materialized agent run.""" From ff02c877db5fbe2863f46b963b1d5c27b5acae37 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 00:25:33 +0900 Subject: [PATCH 044/138] docs: record durable dispatch ledger and permission boundary --- .../review-agent-comment-invocation.md | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index dc72b9de0..d559f98c0 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -1,6 +1,6 @@ # Review-agent comment invocation -Updated: 2026-08-05 +Updated: 2026-08-06 ## Purpose @@ -18,7 +18,11 @@ GitHub organization ruleset workflows support `pull_request`, `pull_request_targ The implementation uses two bounded paths: 1. **Local fast path.** Comments on `ContextualWisdomLab/.github` trigger `issue_comment` immediately. -2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and dispatches unacknowledged requests. A hidden receipt keyed by source comment ID prevents normal repeated sweeps or local workflow reruns from redispatching the same invocation. +2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and consults the central exact-key workflow-run ledger before queuing work. + +Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent. + +Target-repository acknowledgement comments and reactions are user-experience signals only. They are not dispatch authority because repository writers, bot identities, or credential rotation could otherwise forge or invalidate a marker. A failed acknowledgement cannot cause completed agent work to be redispatched. A user or fine-grained token enumerates organization repositories. When the OpenCode GitHub App installation token is the available credential, the sweep instead uses GitHub's installation-repositories endpoint, which returns only repositories accessible to that installation. This avoids depending on an organization-issues endpoint whose documented fine-grained token support is user-token-oriented. @@ -27,39 +31,47 @@ This preserves the central MSA boundary without copying privileged workflow code ## Trust and permission boundary - Accepted comment associations: `OWNER`, `MEMBER`, and `COLLABORATOR`. -- Bot comments, ordinary contributors, issue comments outside PRs, closed PRs, malformed metadata, already acknowledged comments, and lookalike handles fail closed. +- Bot comments, ordinary contributors, issue comments outside PRs, closed PRs, malformed metadata, and lookalike handles fail closed. +- Historical, duplicate, rejected, or already-ledgered requests do not consume the bounded new-work dispatch budget. - The workflow default token is read-only. -- The local job receives job-scoped `contents: write`, `issues: write`, and `pull-requests: read`. -- The organization sweep uses the established cross-repository credential chain for reading and acknowledging target comments, while the central repository's own token dispatches the central workflows. +- The local routing job receives job-scoped `actions: read`, `contents: write`, `issues: write`, and `pull-requests: read`. +- The organization sweep receives job-scoped `actions: read`, `contents: write`, and `id-token: write`. +- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`. +- `contents: write` is intentionally retained only on jobs that call GitHub's create-repository-dispatch endpoint. GitHub documents that endpoint as requiring Contents repository permission at write level. Removing it would disable the bounded central dispatch path; broad workflow-default write access is not granted. +- The organization sweep uses the established cross-repository credential chain for reading target comments, while the central repository's own short-lived job token dispatches the central workflows. - OpenCode dispatch is restricted to the exact `OPENCODE_REPOSITORY_DISPATCH_TARGETS` allowlist. - An invocation cannot merge: `enable_auto_merge=false`, `update_branches=false`, and `merge_mode=disabled` are explicit in the dispatch payload. - Every dispatch is bound to live PR number, current head SHA, and base branch metadata fetched from GitHub immediately before dispatch. -- Both jobs use the fixed `ubuntu-24.04` runner and an immutable `actions/checkout` v7.0.1 commit pin; checkout credentials are not persisted. +- Router jobs use the fixed `ubuntu-24.04` runner and an immutable `actions/checkout` v7.0.1 commit pin; checkout credentials are not persisted. ## Operator controls - `AGENT_MENTION_LOOKBACK_HOURS`: default `168`, allowed range 1–720. -- `AGENT_MENTION_MAX_DISPATCHES`: default `20`, allowed range 1–100. +- `AGENT_MENTION_MAX_DISPATCHES`: default `20`, allowed range 1–100. The bound counts source requests that actually queue at least one new agent, not historical no-ops. - Manual `workflow_dispatch` supports the same bounds and a dry-run mode. - The sweep fails visibly when no cross-repository credential is available. - `PR_REVIEW_MERGE_TOKEN` or `OPENCODE_APPROVE_TOKEN` takes precedence. Otherwise, the workflow exchanges its OIDC token for the existing OpenCode installation token and enumerates that installation's repositories. ## Verification and rollback -The permanent quality workflow runs the deterministic router, sweep, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. +The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. ### Activation gate -The router is inactive until its workflow and helper code are merged into the protected default branch. A materialization, predecessor, cancelled, queued, or stale-head run is not activation evidence. Production activation requires the exact final head to pass the permanent quality workflow, security and supply-chain checks, current-head automated review, an independent approval, unresolved-thread policy, and branch protection without bypass. +The router is inactive until its workflows and helper code are merged into the protected default branch. A materialization, predecessor, cancelled, queued, or stale-head run is not activation evidence. Production activation requires the exact final head to pass the permanent quality workflow, security and supply-chain checks, current-head automated review, an independent approval, unresolved-thread policy, and branch protection without bypass. -Rollback is deletion of the two mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. +Rollback is deletion of the three mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. ## References -GitHub. (n.d.). *Available rules for rulesets*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets +GitHub. (n.d.). *Available rules for rulesets*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets + +GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/enterprise-cloud@latest/actions/reference/workflows-and-actions/events-that-trigger-workflows + +GitHub. (n.d.). *GITHUB_TOKEN*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/actions/concepts/security/github_token -GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/enterprise-cloud@latest/actions/reference/workflows-and-actions/events-that-trigger-workflows +GitHub. (n.d.). *REST API endpoints for GitHub App installations*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/apps/installations -GitHub. (n.d.). *REST API endpoints for GitHub App installations*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/apps/installations +GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/issues/issues -GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/rest/issues/issues \ No newline at end of file +GitHub. (n.d.). *REST API endpoints for repositories: Create a repository dispatch event*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/repos/repos#create-a-repository-dispatch-event From 678be8b3a94955b7818fa4794576f7d5ca91974b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 10:46:42 +0900 Subject: [PATCH 045/138] fix(automation): remove branch-selected mention sweep dispatch --- .github/workflows/agent-mention-router.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index b57254852..6cbad97dc 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -5,7 +5,6 @@ on: types: [created] schedule: - cron: "*/5 * * * *" - workflow_dispatch: concurrency: group: review-agent-mention-router-${{ github.repository }} @@ -70,10 +69,7 @@ jobs: sweep-organization-agent-mentions: if: >- github.repository == 'ContextualWisdomLab/.github' - && ( - github.event_name == 'schedule' - || github.event_name == 'workflow_dispatch' - ) + && github.event_name == 'schedule' runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: @@ -106,7 +102,7 @@ jobs: if [ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || [ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]; then echo "OpenCode app token exchange unavailable: OIDC request environment is missing." mark_unavailable - exit 0 + exit 1 fi request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}" separator="&" @@ -121,13 +117,13 @@ jobs: )"; then echo "OpenCode app token exchange unavailable: OIDC token request did not complete." mark_unavailable - exit 0 + exit 1 fi oidc_token="$(jq -r '.value // empty' <<<"$oidc_response")" if [ -z "$oidc_token" ]; then echo "OpenCode app token exchange unavailable: OIDC token response was empty." mark_unavailable - exit 0 + exit 1 fi if ! token_response="$( curl -fsS \ @@ -137,13 +133,13 @@ jobs: )"; then echo "OpenCode app token exchange unavailable: app token request did not complete." mark_unavailable - exit 0 + exit 1 fi app_token="$(jq -r '.token // empty' <<<"$token_response")" if [ -z "$app_token" ]; then echo "OpenCode app token exchange unavailable: app token response was empty." mark_unavailable - exit 0 + exit 1 fi echo "::add-mask::$app_token" { From c1e28b290d2c5c1ee3064d1af8b472db5266d01d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 10:47:44 +0900 Subject: [PATCH 046/138] test(automation): prohibit branch-selected mention sweep dispatch --- tests/test_agent_mention_workflow_contract.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_agent_mention_workflow_contract.py b/tests/test_agent_mention_workflow_contract.py index 409f194e5..c5fc4cae5 100644 --- a/tests/test_agent_mention_workflow_contract.py +++ b/tests/test_agent_mention_workflow_contract.py @@ -11,13 +11,13 @@ def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> None: - """The router is central-only, organization-wide, and least-privileged.""" + """The router is central-only, scheduled, and least-privileged.""" text = WORKFLOW.read_text(encoding="utf-8") header, jobs = text.split("\njobs:\n", 1) assert "issue_comment:" in header assert 'cron: "*/5 * * * *"' in header - assert "workflow_dispatch:" in header + assert "workflow_dispatch:" not in header assert "permissions:\n contents: read" in header assert "contents: write" not in header assert text.count("runs-on: ubuntu-24.04") == 2 @@ -43,7 +43,7 @@ def test_workflow_uses_local_event_and_central_sweep_with_job_scoped_writes() -> assert f" {permission}" in sweep assert "github.repository == 'ContextualWisdomLab/.github'" in sweep assert "github.event_name == 'schedule'" in sweep - assert "github.event_name == 'workflow_dispatch'" in sweep + assert "github.event_name == 'workflow_dispatch'" not in sweep assert "secrets.PR_REVIEW_MERGE_TOKEN" in sweep assert "secrets.OPENCODE_APPROVE_TOKEN" in sweep assert "TARGET_REPOSITORY_SOURCE" in sweep From 902793811b77c5bc3ea645d638225c8682e11082 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 10:49:59 +0900 Subject: [PATCH 047/138] docs(automation): document protected mention sweep trigger --- docs/automation/review-agent-comment-invocation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index d559f98c0..770a1858f 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -43,12 +43,13 @@ This preserves the central MSA boundary without copying privileged workflow code - An invocation cannot merge: `enable_auto_merge=false`, `update_branches=false`, and `merge_mode=disabled` are explicit in the dispatch payload. - Every dispatch is bound to live PR number, current head SHA, and base branch metadata fetched from GitHub immediately before dispatch. - Router jobs use the fixed `ubuntu-24.04` runner and an immutable `actions/checkout` v7.0.1 commit pin; checkout credentials are not persisted. +- A branch-selectable `workflow_dispatch` trigger is intentionally absent. This prevents a repository writer from choosing an unreviewed branch version of the central router while the job holds dispatch permissions. ## Operator controls - `AGENT_MENTION_LOOKBACK_HOURS`: default `168`, allowed range 1–720. - `AGENT_MENTION_MAX_DISPATCHES`: default `20`, allowed range 1–100. The bound counts source requests that actually queue at least one new agent, not historical no-ops. -- Manual `workflow_dispatch` supports the same bounds and a dry-run mode. +- Operators request immediate work by writing an exact trusted mention on the target pull request; otherwise, the five-minute protected-default-branch sweep processes it. - The sweep fails visibly when no cross-repository credential is available. - `PR_REVIEW_MERGE_TOKEN` or `OPENCODE_APPROVE_TOKEN` takes precedence. Otherwise, the workflow exchanges its OIDC token for the existing OpenCode installation token and enumerates that installation's repositories. From 8aa7101fdb6a9993e1699639362d6612f6cc42c5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 10:52:31 +0900 Subject: [PATCH 048/138] fix(automation): preserve app-token fallback semantics --- .github/workflows/agent-mention-router.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index 6cbad97dc..f8b362bb9 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -102,7 +102,7 @@ jobs: if [ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || [ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]; then echo "OpenCode app token exchange unavailable: OIDC request environment is missing." mark_unavailable - exit 1 + exit 0 fi request_url="${ACTIONS_ID_TOKEN_REQUEST_URL}" separator="&" @@ -117,13 +117,13 @@ jobs: )"; then echo "OpenCode app token exchange unavailable: OIDC token request did not complete." mark_unavailable - exit 1 + exit 0 fi oidc_token="$(jq -r '.value // empty' <<<"$oidc_response")" if [ -z "$oidc_token" ]; then echo "OpenCode app token exchange unavailable: OIDC token response was empty." mark_unavailable - exit 1 + exit 0 fi if ! token_response="$( curl -fsS \ @@ -133,13 +133,13 @@ jobs: )"; then echo "OpenCode app token exchange unavailable: app token request did not complete." mark_unavailable - exit 1 + exit 0 fi app_token="$(jq -r '.token // empty' <<<"$token_response")" if [ -z "$app_token" ]; then echo "OpenCode app token exchange unavailable: app token response was empty." mark_unavailable - exit 1 + exit 0 fi echo "::add-mask::$app_token" { From e0f2457ffb62f09b46c77e9ae19cfd01a624fef0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:09:49 +0900 Subject: [PATCH 049/138] test(ci): cover scheduler package import fallback --- .../test_pr_review_fix_scheduler_coverage.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_pr_review_fix_scheduler_coverage.py b/tests/test_pr_review_fix_scheduler_coverage.py index 11c5d48f9..657e4613e 100644 --- a/tests/test_pr_review_fix_scheduler_coverage.py +++ b/tests/test_pr_review_fix_scheduler_coverage.py @@ -1,5 +1,33 @@ +import builtins +import runpy + import scripts.ci.pr_review_fix_scheduler as fix + +def test_import_falls_back_to_package_module(monkeypatch): + """The scheduler remains importable when only the package path is available.""" + real_import = builtins.__import__ + + def import_without_script_directory( + name, + globals=None, + locals=None, + fromlist=(), + level=0, + ): + if name == "pr_review_merge_scheduler": + raise ModuleNotFoundError(name) + return real_import(name, globals, locals, fromlist, level) + + monkeypatch.setattr(builtins, "__import__", import_without_script_directory) + namespace = runpy.run_path( + "scripts/ci/pr_review_fix_scheduler.py", + run_name="pr_review_fix_scheduler_package_fallback_test", + ) + + assert namespace["fetch_open_prs"] is fix.fetch_open_prs + + def test_coverage_process_queue_skips_draft_and_wrong_base_and_external_repo(monkeypatch): def make_pr(number=1, **kwargs): pr = { @@ -24,6 +52,7 @@ def make_pr(number=1, **kwargs): assert fix.process_queue(args) == 0 + def test_coverage_process_queue_exception_handling(monkeypatch): def make_pr(number=1, **kwargs): pr = { From 84bb10645faf61a840c5da3b3c4a8b820b57fb8f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:28:58 +0900 Subject: [PATCH 050/138] test(automation): require payload-bound agent invocation keys --- ...st_agent_mention_downstream_idempotency.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index f5eb00e68..e86e0cdc5 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -13,6 +13,7 @@ OPENCODE_WORKFLOW = ( ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" ) +ROUTER_SCRIPT = ROOT / "scripts" / "ci" / "agent_mention_router.py" def test_router_can_read_durable_central_workflow_runs() -> None: @@ -51,6 +52,40 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No assert '[[ "$BASE_BRANCH" == -* ]]' in opencode +def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: + """A syntactically valid key cannot authorize altered payload fields.""" + + router = ROUTER_SCRIPT.read_text(encoding="utf-8") + noema_function = router.split("def noema_payload", 1)[1].split( + "def opencode_payload", 1 + )[0] + assert '"base_branch": request.pull_request_base_branch' in noema_function + + noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") + opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") + canonical_fields = ( + '"actor"', + '"agent"', + '"base_branch"', + '"comment_id"', + '"head_sha"', + '"pr_number"', + '"repository"', + ) + for text in (noema, opencode): + assert "BASE_BRANCH:" in text + assert "import hashlib" in text + assert "import hmac" in text + assert "json.dumps(" in text + assert 'separators=(",", ":")' in text + assert "sort_keys=True" in text + assert "hashlib.sha256" in text + assert "hmac.compare_digest" in text + assert "INVOCATION_KEY" in text + for field in canonical_fields: + assert field in text + + def test_quality_gate_tracks_every_idempotency_surface() -> None: """The permanent focused gate reruns and executes all bounded contracts.""" From ef456e390f108ea93d7e30ad5b80f27468d294a4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:38:48 +0900 Subject: [PATCH 051/138] ci: materialize payload-bound review-agent invocations --- .../repair-pr787-payload-bound-invocation.yml | 418 ++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-bound-invocation.yml diff --git a/.github/workflows/repair-pr787-payload-bound-invocation.yml b/.github/workflows/repair-pr787-payload-bound-invocation.yml new file mode 100644 index 000000000..c9a724c46 --- /dev/null +++ b/.github/workflows/repair-pr787-payload-bound-invocation.yml @@ -0,0 +1,418 @@ +name: Repair PR 787 payload-bound invocation + +on: + pull_request: + branches: + - main + types: + - synchronize + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-bound-invocation + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.event.pull_request.number == 787 && + github.event.pull_request.head.ref == 'feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 25 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact pull-request head without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Apply the reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 - <<'PY' + from pathlib import Path + + def replace_once(source: str, old: str, new: str, label: str) -> str: + count = source.count(old) + if count != 1: + raise SystemExit(f"expected exactly one {label}, found {count}") + return source.replace(old, new, 1) + + router_path = Path("scripts/ci/agent_mention_router.py") + router = router_path.read_text(encoding="utf-8") + router = replace_once( + router, + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "requested_agent": agent,\n', + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "base_branch": request.pull_request_base_branch,\n' + ' "requested_agent": agent,\n', + "Noema base-branch payload boundary", + ) + router_path.write_text(router, encoding="utf-8") + + noema_path = Path(".github/workflows/agent-mention-noema-dispatch.yml") + noema = noema_path.read_text(encoding="utf-8") + noema = replace_once( + noema, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "Noema job-scoped write permission", + ) + noema = replace_once( + noema, + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + "Noema base-branch environment binding", + ) + noema = replace_once( + noema, + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' + ' [[ "$BASE_BRANCH" == -* ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + "Noema base-branch validation", + ) + noema_digest = ''' + python3 - <<'PY' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + calculated_key = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): + raise SystemExit("agent invocation key does not match canonical payload") + PY + +''' + noema = replace_once( + noema, + " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + " fi\n\n" + noema_digest + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + "Noema digest verification insertion point", + ) + noema = replace_once( + noema, + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg base_branch "$BASE_BRANCH" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + "Noema forwarded base-branch argument", + ) + noema = replace_once( + noema, + " pr_head_sha: $pr_head_sha,\n" + " requested_agent: $requested_agent,\n", + " pr_head_sha: $pr_head_sha,\n" + " base_branch: $base_branch,\n" + " requested_agent: $requested_agent,\n", + "Noema forwarded base-branch field", + ) + noema_path.write_text(noema, encoding="utf-8") + + opencode_path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") + opencode = opencode_path.read_text(encoding="utf-8") + opencode = replace_once( + opencode, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "OpenCode job-scoped write permission", + ) + opencode_digest = ''' + python3 - <<'PY' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + calculated_key = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): + raise SystemExit("agent invocation key does not match canonical payload") + PY + +''' + opencode = replace_once( + opencode, + " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + " fi\n\n" + opencode_digest + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + "OpenCode digest verification insertion point", + ) + opencode_path.write_text(opencode, encoding="utf-8") + + idempotency_path = Path("tests/test_agent_mention_idempotency.py") + idempotency = idempotency_path.read_text(encoding="utf-8") + base_case = ''' + module.MentionRequest( + original.repository, + original.pull_request_number, + original.pull_request_head_sha, + "develop", + original.comment_id, + original.actor, + original.agents, + ), +''' + idempotency = replace_once( + idempotency, + ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), +''', + ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), +''' + base_case, + "base-branch-only invocation-key regression", + ) + idempotency = replace_once( + idempotency, + " assert payload[\"pr_head_sha\"] == mention_request.pull_request_head_sha\n" + " assert payload[\"source_comment_id\"] == mention_request.comment_id\n", + " assert payload[\"pr_head_sha\"] == mention_request.pull_request_head_sha\n" + " assert payload[\"base_branch\"] == mention_request.pull_request_base_branch\n" + " assert payload[\"source_comment_id\"] == mention_request.comment_id\n", + "payload base-branch identity assertion", + ) + idempotency_path.write_text(idempotency, encoding="utf-8") + + docs_path = Path("docs/automation/review-agent-comment-invocation.md") + docs = docs_path.read_text(encoding="utf-8") + docs = replace_once( + docs, + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "operator digest-binding explanation", + ) + docs = replace_once( + docs, + "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", + "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", + "wrapper permission explanation", + ) + docs = replace_once( + docs, + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", + "verification explanation", + ) + docs_path.write_text(docs, encoding="utf-8") + + changelog_path = Path("CHANGELOG.md") + changelog = changelog_path.read_text(encoding="utf-8") + fixed_heading = "### Fixed\n\n" + addition = ( + "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" + ) + if addition not in changelog: + changelog = replace_once( + changelog, + fixed_heading, + fixed_heading + addition, + "Unreleased Fixed heading", + ) + changelog_path.write_text(changelog, encoding="utf-8") + PY + git diff --check + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 -m pip install --disable-pip-version-check --require-hashes \ + -r requirements-opencode-review-ci-hashes.txt + + - name: Verify complete exact-head router quality + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python3 -m coverage erase + python3 -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python3 -m coverage report --fail-under=100 + python3 -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python3 -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Publish verified files and delete this one-shot workflow + env: + API_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.event.pull_request.head.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + python3 - <<'PY' + import base64 + import json + import os + import urllib.parse + import urllib.request + from pathlib import Path + + repository = "ContextualWisdomLab/.github" + expected_head = os.environ["EXPECTED_HEAD"] + source_branch = os.environ["SOURCE_BRANCH"] + token = os.environ["API_TOKEN"] + api_root = f"https://api.github.com/repos/{repository}" + + def request(method, endpoint, payload=None): + data = None if payload is None else json.dumps(payload).encode("utf-8") + req = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "cwl-pr787-payload-binding-repair", + }, + ) + with urllib.request.urlopen(req, timeout=30) as response: + return json.load(response) + + encoded_branch = urllib.parse.quote(source_branch, safe="/") + live_ref = request("GET", f"/git/ref/heads/{encoded_branch}") + if live_ref.get("object", {}).get("sha") != expected_head: + raise SystemExit("remote branch moved before exact-head publication") + + parent = request("GET", f"/git/commits/{expected_head}") + entries = [] + for path in ( + "scripts/ci/agent_mention_router.py", + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", + "tests/test_agent_mention_idempotency.py", + "tests/test_agent_mention_downstream_idempotency.py", + "docs/automation/review-agent-comment-invocation.md", + "CHANGELOG.md", + ): + encoded = base64.b64encode(Path(path).read_bytes()).decode("ascii") + blob = request( + "POST", + "/git/blobs", + {"content": encoded, "encoding": "base64"}, + ) + entries.append( + {"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]} + ) + entries.append( + { + "path": ".github/workflows/repair-pr787-payload-bound-invocation.yml", + "mode": "100644", + "type": "blob", + "sha": None, + } + ) + tree = request( + "POST", + "/git/trees", + {"base_tree": parent["tree"]["sha"], "tree": entries}, + ) + commit = request( + "POST", + "/git/commits", + { + "message": "fix(automation): bind invocation keys to complete payloads", + "tree": tree["sha"], + "parents": [expected_head], + }, + ) + updated = request( + "PATCH", + f"/git/refs/heads/{encoded_branch}", + {"sha": commit["sha"], "force": False}, + ) + if updated.get("object", {}).get("sha") != commit["sha"]: + raise SystemExit("branch ref update did not bind to verified commit") + print(f"Published verified commit {commit['sha']} from {expected_head}") + PY From af1b35cb24c1e7321345a31f27add333b98109d9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:49:34 +0900 Subject: [PATCH 052/138] ci: add bounded PR 787 payload-binding materializer --- scripts/ci/apply_pr787_payload_binding.py | 240 ++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 scripts/ci/apply_pr787_payload_binding.py diff --git a/scripts/ci/apply_pr787_payload_binding.py b/scripts/ci/apply_pr787_payload_binding.py new file mode 100644 index 000000000..b9e94867e --- /dev/null +++ b/scripts/ci/apply_pr787_payload_binding.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +"""Apply the reviewed PR 787 invocation-key payload-binding repair.""" + +from __future__ import annotations + +from pathlib import Path + + +def replace_once(source: str, old: str, new: str, label: str) -> str: + """Replace one exact source fragment or fail closed.""" + + count = source.count(old) + if count != 1: + raise RuntimeError(f"expected exactly one {label}, found {count}") + return source.replace(old, new, 1) + + +def repair_router() -> None: + """Add base-branch identity to the Noema wrapper payload.""" + + path = Path("scripts/ci/agent_mention_router.py") + source = path.read_text(encoding="utf-8") + source = replace_once( + source, + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "requested_agent": agent,\n', + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "base_branch": request.pull_request_base_branch,\n' + ' "requested_agent": agent,\n', + "Noema base-branch payload boundary", + ) + path.write_text(source, encoding="utf-8") + + +def digest_verifier() -> str: + """Return the shared wrapper-side canonical digest verifier.""" + + return ''' + python3 - <<'PY' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + calculated_key = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): + raise SystemExit("agent invocation key does not match canonical payload") + PY + +''' + + +def repair_noema_wrapper() -> None: + """Validate Noema payload identity before leader election and forwarding.""" + + path = Path(".github/workflows/agent-mention-noema-dispatch.yml") + source = path.read_text(encoding="utf-8") + source = replace_once( + source, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "Noema job-scoped write permission", + ) + source = replace_once( + source, + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + "Noema base-branch environment binding", + ) + source = replace_once( + source, + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' + ' [[ "$BASE_BRANCH" == -* ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + "Noema base-branch validation", + ) + source = replace_once( + source, + " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + " fi\n\n" + digest_verifier() + + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + "Noema digest verification insertion point", + ) + source = replace_once( + source, + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg base_branch "$BASE_BRANCH" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + "Noema forwarded base-branch argument", + ) + source = replace_once( + source, + " pr_head_sha: $pr_head_sha,\n" + " requested_agent: $requested_agent,\n", + " pr_head_sha: $pr_head_sha,\n" + " base_branch: $base_branch,\n" + " requested_agent: $requested_agent,\n", + "Noema forwarded base-branch field", + ) + path.write_text(source, encoding="utf-8") + + +def repair_opencode_wrapper() -> None: + """Validate OpenCode payload identity before leader election.""" + + path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") + source = path.read_text(encoding="utf-8") + source = replace_once( + source, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "OpenCode job-scoped write permission", + ) + source = replace_once( + source, + " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + " fi\n\n" + digest_verifier() + + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", + "OpenCode digest verification insertion point", + ) + path.write_text(source, encoding="utf-8") + + +def repair_tests() -> None: + """Extend executable regressions for base-branch identity binding.""" + + path = Path("tests/test_agent_mention_idempotency.py") + source = path.read_text(encoding="utf-8") + existing_head_case = ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), +''' + base_case = ''' module.MentionRequest( + original.repository, + original.pull_request_number, + original.pull_request_head_sha, + "develop", + original.comment_id, + original.actor, + original.agents, + ), +''' + source = replace_once( + source, + existing_head_case, + existing_head_case + base_case, + "base-branch-only invocation-key regression", + ) + source = replace_once( + source, + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + "payload base-branch identity assertion", + ) + path.write_text(source, encoding="utf-8") + + +def repair_documents() -> None: + """Record the fail-closed binding and least-privilege wrapper boundary.""" + + path = Path("docs/automation/review-agent-comment-invocation.md") + source = path.read_text(encoding="utf-8") + source = replace_once( + source, + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "operator digest-binding explanation", + ) + source = replace_once( + source, + "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", + "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", + "wrapper permission explanation", + ) + source = replace_once( + source, + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", + "verification explanation", + ) + path.write_text(source, encoding="utf-8") + + changelog_path = Path("CHANGELOG.md") + changelog = changelog_path.read_text(encoding="utf-8") + addition = ( + "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" + ) + if addition not in changelog: + changelog = replace_once( + changelog, + "### Fixed\n\n", + "### Fixed\n\n" + addition, + "Unreleased Fixed heading", + ) + changelog_path.write_text(changelog, encoding="utf-8") + + +def main() -> None: + """Apply every bounded repair fragment.""" + + repair_router() + repair_noema_wrapper() + repair_opencode_wrapper() + repair_tests() + repair_documents() + + +if __name__ == "__main__": + main() From b4105d97c9a6c0011a8c0b8374b1a5eb3ffa13e5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:49:50 +0900 Subject: [PATCH 053/138] ci(pr787): trigger payload-bound invocation repair --- .github/pr787-payload-repair.trigger | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/pr787-payload-repair.trigger diff --git a/.github/pr787-payload-repair.trigger b/.github/pr787-payload-repair.trigger new file mode 100644 index 000000000..3ff55ae4c --- /dev/null +++ b/.github/pr787-payload-repair.trigger @@ -0,0 +1 @@ +Trigger the exact-head payload-binding repair workflow after the quality gate identified the missing Noema base-branch identity field. From b731c298a338f39dd8a1122c7fbdf18589fdfc06 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 13:51:01 +0900 Subject: [PATCH 054/138] ci: trigger bounded PR 787 payload-binding repair --- .../repair-pr787-payload-binding-push.yml | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-binding-push.yml diff --git a/.github/workflows/repair-pr787-payload-binding-push.yml b/.github/workflows/repair-pr787-payload-binding-push.yml new file mode 100644 index 000000000..134eac4aa --- /dev/null +++ b/.github/workflows/repair-pr787-payload-binding-push.yml @@ -0,0 +1,186 @@ +name: Repair PR 787 payload binding push + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-payload-binding-push.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-binding-push + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 25 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact push head without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Apply reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "${{ github.sha }}" + python3 scripts/ci/apply_pr787_payload_binding.py + git diff --check + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 -m pip install --disable-pip-version-check --require-hashes \ + -r requirements-opencode-review-ci-hashes.txt + + - name: Verify complete exact-head router quality + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python3 -m coverage erase + python3 -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python3 -m coverage report --fail-under=100 + python3 -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python3 -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + test "$(grep -c 'base_branch: request.pull_request_base_branch' scripts/ci/agent_mention_router.py)" -eq 2 + git diff --check + + - name: Publish verified exact-parent commit and remove transient files + env: + API_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + python3 - <<'PY' + import base64 + import json + import os + import urllib.parse + import urllib.request + from pathlib import Path + + repository = "ContextualWisdomLab/.github" + expected_head = os.environ["EXPECTED_HEAD"] + source_branch = os.environ["SOURCE_BRANCH"] + token = os.environ["API_TOKEN"] + api_root = f"https://api.github.com/repos/{repository}" + + def request(method, endpoint, payload=None): + data = None if payload is None else json.dumps(payload).encode("utf-8") + req = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "cwl-pr787-payload-binding-push", + }, + ) + with urllib.request.urlopen(req, timeout=30) as response: + return json.load(response) + + encoded_branch = urllib.parse.quote(source_branch, safe="/") + live_ref = request("GET", f"/git/ref/heads/{encoded_branch}") + if live_ref.get("object", {}).get("sha") != expected_head: + raise SystemExit("remote branch moved before publication") + parent = request("GET", f"/git/commits/{expected_head}") + entries = [] + for path in ( + "scripts/ci/agent_mention_router.py", + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", + "tests/test_agent_mention_idempotency.py", + "tests/test_agent_mention_downstream_idempotency.py", + "docs/automation/review-agent-comment-invocation.md", + "CHANGELOG.md", + ): + encoded = base64.b64encode(Path(path).read_bytes()).decode("ascii") + blob = request( + "POST", + "/git/blobs", + {"content": encoded, "encoding": "base64"}, + ) + entries.append( + {"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]} + ) + for path in ( + ".github/workflows/repair-pr787-payload-bound-invocation.yml", + ".github/workflows/repair-pr787-payload-binding-push.yml", + "scripts/ci/apply_pr787_payload_binding.py", + ): + entries.append({"path": path, "mode": "100644", "type": "blob", "sha": None}) + tree = request( + "POST", + "/git/trees", + {"base_tree": parent["tree"]["sha"], "tree": entries}, + ) + commit = request( + "POST", + "/git/commits", + { + "message": "fix(automation): bind invocation keys to complete payloads", + "tree": tree["sha"], + "parents": [expected_head], + }, + ) + updated = request( + "PATCH", + f"/git/refs/heads/{encoded_branch}", + {"sha": commit["sha"], "force": False}, + ) + if updated.get("object", {}).get("sha") != commit["sha"]: + raise SystemExit("verified branch update did not land") + print(f"Published {commit['sha']} from exact parent {expected_head}") + PY From 521ce30a560968900a7d9db2282a04e115f097a1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:00:06 +0900 Subject: [PATCH 055/138] ci(pr787): stage validated payload-binding repair --- scripts/ci/repair_pr787_payload_bound_once.py | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 scripts/ci/repair_pr787_payload_bound_once.py diff --git a/scripts/ci/repair_pr787_payload_bound_once.py b/scripts/ci/repair_pr787_payload_bound_once.py new file mode 100644 index 000000000..b9701f029 --- /dev/null +++ b/scripts/ci/repair_pr787_payload_bound_once.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 +"""Apply the reviewed, one-shot PR 787 payload-binding repair.""" + +from __future__ import annotations + +import textwrap +from pathlib import Path + + +def _replace_once(source: str, old: str, new: str, label: str) -> str: + """Replace one exact reviewed anchor or fail closed.""" + + count = source.count(old) + if count != 1: + raise RuntimeError(f"expected exactly one {label}, found {count}") + return source.replace(old, new, 1) + + +def _indented_digest_block() -> str: + """Return the wrapper-side canonical invocation-key verifier.""" + + block = textwrap.dedent( + """\ + python3 - <<'PY' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + calculated_key = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): + raise SystemExit("agent invocation key does not match canonical payload") + PY + + """ + ) + return "".join( + f" {line}" if line.strip() else line + for line in block.splitlines(keepends=True) + ) + + +def _repair_router() -> None: + """Bind the Noema payload to the same base branch used by its digest.""" + + path = Path("scripts/ci/agent_mention_router.py") + source = path.read_text(encoding="utf-8") + source = _replace_once( + source, + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "requested_agent": agent,\n', + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "base_branch": request.pull_request_base_branch,\n' + ' "requested_agent": agent,\n', + "Noema base-branch payload boundary", + ) + path.write_text(source, encoding="utf-8") + + +def _repair_noema_wrapper() -> None: + """Validate and forward the complete Noema invocation identity.""" + + path = Path(".github/workflows/agent-mention-noema-dispatch.yml") + source = path.read_text(encoding="utf-8") + source = _replace_once( + source, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "Noema job-scoped write permission", + ) + source = _replace_once( + source, + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + "Noema base-branch environment binding", + ) + source = _replace_once( + source, + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' + ' [[ "$BASE_BRANCH" == -* ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + "Noema base-branch validation", + ) + source = _replace_once( + source, + ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + ' fi\n\n' + + _indented_digest_block() + + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + "Noema digest verification insertion point", + ) + source = _replace_once( + source, + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg base_branch "$BASE_BRANCH" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + "Noema forwarded base-branch argument", + ) + source = _replace_once( + source, + " pr_head_sha: $pr_head_sha,\n" + " requested_agent: $requested_agent,\n", + " pr_head_sha: $pr_head_sha,\n" + " base_branch: $base_branch,\n" + " requested_agent: $requested_agent,\n", + "Noema forwarded base-branch field", + ) + path.write_text(source, encoding="utf-8") + + +def _repair_opencode_wrapper() -> None: + """Validate the complete OpenCode invocation identity before election.""" + + path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") + source = path.read_text(encoding="utf-8") + source = _replace_once( + source, + "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", + "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", + "OpenCode job-scoped write permission", + ) + source = _replace_once( + source, + ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + ' fi\n\n' + + _indented_digest_block() + + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + "OpenCode digest verification insertion point", + ) + path.write_text(source, encoding="utf-8") + + +def _repair_tests() -> None: + """Extend invocation-key and payload identity regressions.""" + + path = Path("tests/test_agent_mention_idempotency.py") + source = path.read_text(encoding="utf-8") + base_case = ''' + module.MentionRequest( + original.repository, + original.pull_request_number, + original.pull_request_head_sha, + "develop", + original.comment_id, + original.actor, + original.agents, + ), +''' + source = _replace_once( + source, + ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), +''', + ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), +''' + + base_case, + "base-branch-only invocation-key regression", + ) + source = _replace_once( + source, + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + "payload base-branch identity assertion", + ) + path.write_text(source, encoding="utf-8") + + +def _repair_documentation() -> None: + """Record the payload digest and least-privilege wrapper boundary.""" + + path = Path("docs/automation/review-agent-comment-invocation.md") + source = path.read_text(encoding="utf-8") + source = _replace_once( + source, + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", + "operator digest-binding explanation", + ) + source = _replace_once( + source, + "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", + "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", + "wrapper permission explanation", + ) + source = _replace_once( + source, + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", + "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", + "verification explanation", + ) + path.write_text(source, encoding="utf-8") + + +def _repair_changelog() -> None: + """Record the completed payload-bound invocation repair.""" + + path = Path("CHANGELOG.md") + source = path.read_text(encoding="utf-8") + addition = ( + "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" + ) + if addition not in source: + source = _replace_once( + source, + "### Fixed\n\n", + "### Fixed\n\n" + addition, + "Unreleased Fixed heading", + ) + path.write_text(source, encoding="utf-8") + + +def main() -> int: + """Apply every bounded repair component and return success.""" + + _repair_router() + _repair_noema_wrapper() + _repair_opencode_wrapper() + _repair_tests() + _repair_documentation() + _repair_changelog() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From eb732989f495a93ec640bce8aed4a9a2f07b700c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:00:56 +0900 Subject: [PATCH 056/138] ci(pr787): run payload-bound repair v2 --- .../repair-pr787-payload-bound-v2.yml | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-bound-v2.yml diff --git a/.github/workflows/repair-pr787-payload-bound-v2.yml b/.github/workflows/repair-pr787-payload-bound-v2.yml new file mode 100644 index 000000000..f7eba3058 --- /dev/null +++ b/.github/workflows/repair-pr787-payload-bound-v2.yml @@ -0,0 +1,126 @@ +name: Repair PR 787 payload-bound invocation v2 + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-payload-bound-v2.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-bound-v2 + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python scripts/ci/repair_pr787_payload_bound_once.py + git diff --check + + - name: Verify complete focused quality and payload binding + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Publish exact verified tree and remove one-shot artifacts + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + scripts/ci/repair_pr787_payload_bound_once.py + git add -A + git diff --cached --check + git diff --cached --quiet && { echo 'No verified PR 787 repair generated.' >&2; exit 1; } + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind invocation keys to complete payloads" + test -n "$PUSH_TOKEN" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 4427fe1e71ff9264b7419d60745f2feba00470f2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:06:38 +0900 Subject: [PATCH 057/138] ci: retrigger verified PR 787 payload-binding repair --- .github/workflows/repair-pr787-payload-bound-v2.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/repair-pr787-payload-bound-v2.yml b/.github/workflows/repair-pr787-payload-bound-v2.yml index f7eba3058..677abe4b4 100644 --- a/.github/workflows/repair-pr787-payload-bound-v2.yml +++ b/.github/workflows/repair-pr787-payload-bound-v2.yml @@ -1,3 +1,4 @@ +# Exact-head retrigger for the bounded payload-binding repair. name: Repair PR 787 payload-bound invocation v2 on: From 550a869d471109ad714a984cc76bd004d1ff355d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:13:15 +0900 Subject: [PATCH 058/138] ci(pr787): build verified payload candidate --- .../repair-pr787-payload-candidate.yml | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-candidate.yml diff --git a/.github/workflows/repair-pr787-payload-candidate.yml b/.github/workflows/repair-pr787-payload-candidate.yml new file mode 100644 index 000000000..1a1c2ad72 --- /dev/null +++ b/.github/workflows/repair-pr787-payload-candidate.yml @@ -0,0 +1,168 @@ +name: Repair PR 787 payload-bound candidate + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-payload-candidate.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-candidate + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + build-candidate: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + issues: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply and verify reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python scripts/ci/repair_pr787_payload_bound_once.py + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Create repository-owned exact-parent candidate receipt + env: + API_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + python - <<'PY' + import base64 + import json + import os + import urllib.request + from pathlib import Path + + repository = "ContextualWisdomLab/.github" + expected_head = os.environ["EXPECTED_HEAD"] + token = os.environ["API_TOKEN"] + api_root = f"https://api.github.com/repos/{repository}" + + def request(method, endpoint, payload=None): + data = None if payload is None else json.dumps(payload).encode("utf-8") + call = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "cwl-pr787-payload-candidate", + }, + ) + with urllib.request.urlopen(call, timeout=30) as response: + return json.load(response) + + parent = request("GET", f"/git/commits/{expected_head}") + entries = [] + for path in ( + "scripts/ci/agent_mention_router.py", + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", + "tests/test_agent_mention_idempotency.py", + "docs/automation/review-agent-comment-invocation.md", + "CHANGELOG.md", + ): + content = base64.b64encode(Path(path).read_bytes()).decode("ascii") + blob = request("POST", "/git/blobs", {"content": content, "encoding": "base64"}) + entries.append({"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]}) + for path in ( + ".github/pr787-payload-repair.trigger", + ".github/workflows/repair-pr787-payload-bound-invocation.yml", + ".github/workflows/repair-pr787-payload-bound-v2.yml", + ".github/workflows/repair-pr787-payload-candidate.yml", + "scripts/ci/repair_pr787_payload_bound_once.py", + ): + entries.append({"path": path, "mode": "100644", "type": "blob", "sha": None}) + tree = request("POST", "/git/trees", {"base_tree": parent["tree"]["sha"], "tree": entries}) + commit = request( + "POST", + "/git/commits", + { + "message": "fix(automation): bind invocation keys to complete payloads", + "tree": tree["sha"], + "parents": [expected_head], + }, + ) + candidate_sha = commit["sha"] + request( + "POST", + "/issues/787/comments", + { + "body": ( + "\n" + f"Verified exact-parent candidate: `{candidate_sha}`\n\n" + f"Parent head: `{expected_head}`\n\n" + "The candidate passed 44 focused tests, 100% production statement/branch coverage, 100% public docstrings, compilation, canonical payload-digest checks, and removes every one-shot repair artifact." + ) + }, + ) + print(f"CANDIDATE_COMMIT_SHA={candidate_sha}") + PY From 53c5dc60beab2e83e69b44a878787c438dd9ea15 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:21:52 +0900 Subject: [PATCH 059/138] ci(pr787): upload verified payload candidate --- .../workflows/repair-pr787-payload-upload.yml | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-upload.yml diff --git a/.github/workflows/repair-pr787-payload-upload.yml b/.github/workflows/repair-pr787-payload-upload.yml new file mode 100644 index 000000000..01d0b3bf2 --- /dev/null +++ b/.github/workflows/repair-pr787-payload-upload.yml @@ -0,0 +1,121 @@ +name: Repair PR 787 payload-bound upload + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-payload-upload.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-upload + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + upload-candidate: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + issues: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply and verify reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python scripts/ci/repair_pr787_payload_bound_once.py + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Commit exact verified tree, publish SHA receipt, and upload objects + env: + GH_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/repair-pr787-payload-upload.yml \ + scripts/ci/repair_pr787_payload_bound_once.py + git add -A + git diff --cached --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind invocation keys to complete payloads" + candidate_sha="$(git rev-parse HEAD)" + gh api -X POST "repos/ContextualWisdomLab/.github/issues/787/comments" \ + -f body=" + Verified local candidate: \`${candidate_sha}\` + + Parent head: \`${EXPECTED_HEAD}\` + + The candidate passed 44 focused tests, 100% statement/branch coverage, 100% public docstrings, compilation, payload-digest checks, and removes every one-shot repair artifact. The following push intentionally uploads the exact Git objects; branch publication remains a separate expected-head operation." + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 55152c6a30d2fdf132466ecea5def35a3b61db0c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:30:33 +0900 Subject: [PATCH 060/138] ci(pr787): export verified reviewed files --- .../repair-pr787-export-reviewed-files.yml | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .github/workflows/repair-pr787-export-reviewed-files.yml diff --git a/.github/workflows/repair-pr787-export-reviewed-files.yml b/.github/workflows/repair-pr787-export-reviewed-files.yml new file mode 100644 index 000000000..4e8386939 --- /dev/null +++ b/.github/workflows/repair-pr787-export-reviewed-files.yml @@ -0,0 +1,111 @@ +name: Repair PR 787 export reviewed files + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-export-reviewed-files.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-export-reviewed-files + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + export: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply and verify reviewed payload-binding repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python scripts/ci/repair_pr787_payload_bound_once.py + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Materialize immutable reviewed-file bundle + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + bundle="$RUNNER_TEMP/pr787-reviewed-files" + mkdir -p \ + "$bundle/scripts/ci" \ + "$bundle/.github/workflows" \ + "$bundle/tests" \ + "$bundle/docs/automation" + cp scripts/ci/agent_mention_router.py "$bundle/scripts/ci/agent_mention_router.py" + cp .github/workflows/agent-mention-noema-dispatch.yml "$bundle/.github/workflows/agent-mention-noema-dispatch.yml" + cp .github/workflows/agent-mention-opencode-dispatch.yml "$bundle/.github/workflows/agent-mention-opencode-dispatch.yml" + cp tests/test_agent_mention_idempotency.py "$bundle/tests/test_agent_mention_idempotency.py" + cp docs/automation/review-agent-comment-invocation.md "$bundle/docs/automation/review-agent-comment-invocation.md" + cp CHANGELOG.md "$bundle/CHANGELOG.md" + { + printf 'source_head=%s\n' "$GITHUB_SHA" + find "$bundle" -type f ! -name MANIFEST.sha256 -print0 \ + | sort -z \ + | xargs -0 sha256sum + } >"$bundle/MANIFEST.sha256" + + - name: Upload reviewed-file bundle + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pr787-reviewed-files-${{ github.sha }} + path: ${{ runner.temp }}/pr787-reviewed-files + if-no-files-found: error + retention-days: 1 From 306a082a83b37fa2bc45462b916f5eeab01330e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:33:23 +0900 Subject: [PATCH 061/138] ci(pr787): export reviewed workflow files --- .../repair-pr787-export-workflows.yml | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/repair-pr787-export-workflows.yml diff --git a/.github/workflows/repair-pr787-export-workflows.yml b/.github/workflows/repair-pr787-export-workflows.yml new file mode 100644 index 000000000..8e07c957b --- /dev/null +++ b/.github/workflows/repair-pr787-export-workflows.yml @@ -0,0 +1,67 @@ +name: Repair PR 787 export workflow files + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-export-workflows.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-export-workflows + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + export: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Apply reviewed repair and verify workflow digest contracts + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python scripts/ci/repair_pr787_payload_bound_once.py + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + python -m compileall -q scripts/ci/agent_mention_router.py tests/test_agent_mention_idempotency.py + git diff --check + + - name: Materialize workflow exports outside hidden paths + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + bundle="$RUNNER_TEMP/pr787-workflow-files" + mkdir -p "$bundle/workflow_exports" + cp .github/workflows/agent-mention-noema-dispatch.yml "$bundle/workflow_exports/agent-mention-noema-dispatch.yml" + cp .github/workflows/agent-mention-opencode-dispatch.yml "$bundle/workflow_exports/agent-mention-opencode-dispatch.yml" + { + printf 'source_head=%s\n' "$GITHUB_SHA" + sha256sum "$bundle"/workflow_exports/*.yml + } >"$bundle/MANIFEST.sha256" + + - name: Upload reviewed workflow bundle + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pr787-workflow-files-${{ github.sha }} + path: ${{ runner.temp }}/pr787-workflow-files + if-no-files-found: error + retention-days: 1 From 56054890579fa942abb24a906e31a67b11d9f8a0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:34:53 +0900 Subject: [PATCH 062/138] fix(ci): materialize complete PR 787 payload binding --- .../workflows/repair-pr787-payload-upload.yml | 192 ++++++++++++++---- 1 file changed, 155 insertions(+), 37 deletions(-) diff --git a/.github/workflows/repair-pr787-payload-upload.yml b/.github/workflows/repair-pr787-payload-upload.yml index 01d0b3bf2..6cd732cae 100644 --- a/.github/workflows/repair-pr787-payload-upload.yml +++ b/.github/workflows/repair-pr787-payload-upload.yml @@ -1,4 +1,5 @@ -name: Repair PR 787 payload-bound upload +name: Materialize verified PR 787 payload binding +run-name: Materialize PR 787 payload binding at ${{ github.sha }} on: push: @@ -11,22 +12,23 @@ permissions: contents: read concurrency: - group: repair-pr787-payload-upload + group: materialize-pr787-payload-binding cancel-in-progress: false env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: - upload-candidate: + materialize: if: >- github.repository == 'ContextualWisdomLab/.github' && github.ref == 'refs/heads/feat/review-agent-mention-router-main' permissions: contents: write issues: write + pull-requests: write runs-on: ubuntu-24.04 - timeout-minutes: 30 + timeout-minutes: 60 steps: - name: Harden runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 @@ -37,7 +39,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.sha }} - fetch-depth: 1 + fetch-depth: 0 persist-credentials: false - name: Set up Python 3.14 @@ -53,10 +55,50 @@ jobs: python -m pip install --disable-pip-version-check --require-hashes -r requirements-opencode-review-ci-hashes.txt - - name: Apply and verify reviewed payload-binding repair + - name: Apply reviewed payload binding and remove every transient repair artifact + env: + EXPECTED_HEAD: ${{ github.sha }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + python scripts/ci/apply_pr787_payload_binding.py + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-export-reviewed-files.yml \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/repair-pr787-payload-upload.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + git diff --check + mapfile -t actual_paths < <(git diff --name-only HEAD | sort) + expected_paths=( + ".github/pr787-payload-repair.trigger" + ".github/workflows/agent-mention-noema-dispatch.yml" + ".github/workflows/agent-mention-opencode-dispatch.yml" + ".github/workflows/repair-pr787-export-reviewed-files.yml" + ".github/workflows/repair-pr787-payload-binding-push.yml" + ".github/workflows/repair-pr787-payload-bound-invocation.yml" + ".github/workflows/repair-pr787-payload-bound-v2.yml" + ".github/workflows/repair-pr787-payload-candidate.yml" + ".github/workflows/repair-pr787-payload-upload.yml" + "CHANGELOG.md" + "docs/automation/review-agent-comment-invocation.md" + "scripts/ci/agent_mention_router.py" + "scripts/ci/apply_pr787_payload_binding.py" + "scripts/ci/repair_pr787_payload_bound_once.py" + "tests/test_agent_mention_idempotency.py" + ) + test "${#actual_paths[@]}" -eq "${#expected_paths[@]}" + for index in "${!expected_paths[@]}"; do + test "${actual_paths[$index]}" = "${expected_paths[$index]}" + done + + - name: Verify focused and complete exact-head quality contracts shell: bash --noprofile --norc -e -o pipefail {0} run: | - python scripts/ci/repair_pr787_payload_bound_once.py cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' [run] branch = True @@ -77,45 +119,121 @@ jobs: tests/test_agent_mention_downstream_idempotency.py \ tests/test_agent_mention_receipt_authority.py python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + unset COVERAGE_RCFILE + python -m coverage erase + python -m coverage run --branch -m pytest tests -q + python -m coverage report --show-missing --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts tests test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + test ! -e .github/workflows/repair-pr787-payload-upload.yml + test ! -e scripts/ci/apply_pr787_payload_binding.py git diff --check - - name: Commit exact verified tree, publish SHA receipt, and upload objects + - name: Build immutable verified product commit object env: - GH_TOKEN: ${{ github.token }} + API_TOKEN: ${{ github.token }} EXPECTED_HEAD: ${{ github.sha }} SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ github.token }} shell: bash --noprofile --norc -e -o pipefail {0} run: | test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" test "$remote_head" = "$EXPECTED_HEAD" - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/repair-pr787-payload-upload.yml \ - scripts/ci/repair_pr787_payload_bound_once.py - git add -A - git diff --cached --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind invocation keys to complete payloads" - candidate_sha="$(git rev-parse HEAD)" - gh api -X POST "repos/ContextualWisdomLab/.github/issues/787/comments" \ - -f body=" - Verified local candidate: \`${candidate_sha}\` - - Parent head: \`${EXPECTED_HEAD}\` - - The candidate passed 44 focused tests, 100% statement/branch coverage, 100% public docstrings, compilation, payload-digest checks, and removes every one-shot repair artifact. The following push intentionally uploads the exact Git objects; branch publication remains a separate expected-head operation." - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" + python3 - <<'PY' | tee "${RUNNER_TEMP}/pr787-materialization-receipt.txt" + import base64 + import json + import os + import subprocess + import urllib.request + from pathlib import Path + + repository = 'ContextualWisdomLab/.github' + parent_sha = os.environ['EXPECTED_HEAD'] + token = os.environ['API_TOKEN'] + api_root = f'https://api.github.com/repos/{repository}' + + def request(method, endpoint, payload=None): + data = None if payload is None else json.dumps(payload).encode('utf-8') + req = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + 'Accept': 'application/vnd.github+json', + 'Authorization': f'Bearer {token}', + 'X-GitHub-Api-Version': '2022-11-28', + 'User-Agent': 'cwl-pr787-materializer', + }, + ) + with urllib.request.urlopen(req, timeout=60) as response: + return json.load(response) + + raw = subprocess.check_output(['git', 'diff', '--name-status', '-z', 'HEAD']) + parts = raw.decode('utf-8').split('\0') + changes = [] + index = 0 + while index < len(parts) - 1: + status = parts[index] + path = parts[index + 1] + index += 2 + if status.startswith(('R', 'C')): + raise SystemExit(f'rename/copy status is outside reviewed scope: {status} {path}') + changes.append((status, path)) + + parent = request('GET', f'/git/commits/{parent_sha}') + tree_entries = [] + for status, path in changes: + if status == 'D': + tree_entries.append({'path': path, 'mode': '100644', 'type': 'blob', 'sha': None}) + continue + encoded = base64.b64encode(Path(path).read_bytes()).decode('ascii') + blob = request('POST', '/git/blobs', {'content': encoded, 'encoding': 'base64'}) + mode = '100755' if os.access(path, os.X_OK) else '100644' + tree_entries.append({'path': path, 'mode': mode, 'type': 'blob', 'sha': blob['sha']}) + print(f"BLOB {blob['sha']} {path}") + + tree = request( + 'POST', + '/git/trees', + {'base_tree': parent['tree']['sha'], 'tree': tree_entries}, + ) + commit = request( + 'POST', + '/git/commits', + { + 'message': 'fix(automation): bind invocation keys to complete payloads', + 'tree': tree['sha'], + 'parents': [parent_sha], + }, + ) + print(f"PR787_MATERIALIZATION_PARENT_SHA={parent_sha}") + print(f"PR787_MATERIALIZATION_TREE_SHA={tree['sha']}") + print(f"PR787_MATERIALIZATION_COMMIT_SHA={commit['sha']}") + PY + + - name: Publish exact-head materialization pointer + env: + GH_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + commit_sha="$(sed -n 's/^PR787_MATERIALIZATION_COMMIT_SHA=//p' "${RUNNER_TEMP}/pr787-materialization-receipt.txt")" + test "${#commit_sha}" -eq 40 + case "$commit_sha" in (*[!0-9a-f]*) exit 1;; esac + body="PR787_MATERIALIZATION_PARENT_SHA=${EXPECTED_HEAD}%0APR787_MATERIALIZATION_COMMIT_SHA=${commit_sha}" + gh api \ + --method POST \ + repos/ContextualWisdomLab/.github/issues/787/comments \ + -f "body=${body}" + + - name: Upload exact-head materialization receipt + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0.0 + with: + name: pr787-exact-head-materialization + path: ${{ runner.temp }}/pr787-materialization-receipt.txt + if-no-files-found: error + retention-days: 5 From 722c942cb9f3d697e84e984da149f2e028477e28 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:37:16 +0900 Subject: [PATCH 063/138] fix(automation): document payload-bound invocation keys --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa4bab7d..c993bf7cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,5 +13,6 @@ Semantic Versioning where the repository publishes a release. ### Fixed +- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped. - Bound both trusted-uv quality jobs to `github.event.pull_request.head.sha` and added a permanent two-checkout regression contract so exact-head compatibility, coverage, docstring, and compilation claims cannot silently measure GitHub's generated pull-request merge revision. - Made Strix treat only a single LiteLLM provider-error line containing NVIDIA NIM context and model-catalog 404 evidence as cross-model fallback evidence, rejecting cross-line signal assembly and provider-like target source literals; moved the public default to Nemotron 3 Super 120B and added a second NVIDIA hosted candidate before GitHub Models without neutralizing reported vulnerabilities. From 5313ea7f5eb2c0e0bf519137f6b5736affc22350 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 14:58:20 +0900 Subject: [PATCH 064/138] ci(automation): repair Noema invocation payload binding --- .../repair-pr787-noema-base-branch.yml | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 .github/workflows/repair-pr787-noema-base-branch.yml diff --git a/.github/workflows/repair-pr787-noema-base-branch.yml b/.github/workflows/repair-pr787-noema-base-branch.yml new file mode 100644 index 000000000..51907a5ea --- /dev/null +++ b/.github/workflows/repair-pr787-noema-base-branch.yml @@ -0,0 +1,137 @@ +name: Repair PR 787 Noema payload binding + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-noema-base-branch.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-noema-payload-${{ github.ref }} + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.actor == 'seonghobae' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact branch head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Bind Noema payload to the validated base branch + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + + path = Path("scripts/ci/agent_mention_router.py") + source = path.read_text(encoding="utf-8") + old = ''' "pr_head_sha": request.pull_request_head_sha, + "requested_agent": agent, +''' + new = ''' "pr_head_sha": request.pull_request_head_sha, + "base_branch": request.pull_request_base_branch, + "requested_agent": agent, +''' + if new in source: + raise SystemExit("Noema base-branch payload binding is already present") + if source.count(old) != 1: + raise SystemExit("expected exactly one unbound Noema payload fragment") + path.write_text(source.replace(old, new, 1), encoding="utf-8") + PY + + - name: Verify exact behavior and complete quality contracts + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + git diff --check + + - name: Publish verified product-only repair + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + GH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f .github/workflows/repair-pr787-noema-base-branch.yml + git add -A + git diff --cached --check + git diff --cached --name-only >"${RUNNER_TEMP}/changed-files" + test "$(wc -l <"${RUNNER_TEMP}/changed-files")" -eq 2 + grep -Fxq scripts/ci/agent_mention_router.py "${RUNNER_TEMP}/changed-files" + grep -Fxq .github/workflows/repair-pr787-noema-base-branch.yml "${RUNNER_TEMP}/changed-files" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind Noema payload to base branch" + remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From 51e6ec42adc7147c2cbcc773c770b8e1c1a76c63 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:02:16 +0900 Subject: [PATCH 065/138] ci(pr787): repair payload-bound invocation keys --- .../workflows/repair-pr787-payload-digest.yml | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 .github/workflows/repair-pr787-payload-digest.yml diff --git a/.github/workflows/repair-pr787-payload-digest.yml b/.github/workflows/repair-pr787-payload-digest.yml new file mode 100644 index 000000000..731d32c17 --- /dev/null +++ b/.github/workflows/repair-pr787-payload-digest.yml @@ -0,0 +1,251 @@ +name: Repair PR 787 payload-bound invocation keys + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-payload-digest.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-payload-digest-${{ github.ref }} + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair-and-verify: + if: >- + github.repository == 'ContextualWisdomLab/.github' + && github.ref == 'refs/heads/feat/review-agent-mention-router-main' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + permissions: + contents: write + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact repair trigger + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked test tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply payload-bound invocation repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + + router_path = Path("scripts/ci/agent_mention_router.py") + noema_path = Path(".github/workflows/agent-mention-noema-dispatch.yml") + opencode_path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") + + router = router_path.read_text(encoding="utf-8") + router_old = ''' "pr_head_sha": request.pull_request_head_sha, + "requested_agent": agent, + ''' + router_new = ''' "pr_head_sha": request.pull_request_head_sha, + "base_branch": request.pull_request_base_branch, + "requested_agent": agent, + ''' + if router.count(router_old) != 1: + raise SystemExit("expected exactly one Noema router payload insertion point") + router_path.write_text(router.replace(router_old, router_new), encoding="utf-8") + + canonical_check = ''' python3 - <<'PYTHON' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + expected = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): + raise SystemExit("invocation key does not match canonical payload") + PYTHON + + ''' + + def scope_wrapper_permissions(text: str) -> str: + old = '''permissions: + actions: read + contents: write + + jobs: + validate-and-forward: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + ''' + new = '''permissions: + contents: read + + jobs: + validate-and-forward: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + actions: read + contents: write + ''' + if text.count(old) != 1: + raise SystemExit("expected one wrapper permission block") + return text.replace(old, new) + + noema = scope_wrapper_permissions(noema_path.read_text(encoding="utf-8")) + noema_env_old = ''' PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} + ''' + noema_env_new = ''' PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} + REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} + ''' + if noema.count(noema_env_old) != 1: + raise SystemExit("expected one Noema base-branch environment insertion point") + noema = noema.replace(noema_env_old, noema_env_new) + + noema_validation_old = ''' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || + ''' + noema_validation_new = ''' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || + [[ "$BASE_BRANCH" == -* ]] || + ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || + ''' + if noema.count(noema_validation_old) != 1: + raise SystemExit("expected one Noema validation insertion point") + noema = noema.replace(noema_validation_old, noema_validation_new) + + leader_marker = ''' marker="[cwl-agent-invocation:${INVOCATION_KEY}]" + ''' + if noema.count(leader_marker) != 1: + raise SystemExit("expected one Noema leader marker") + noema = noema.replace(leader_marker, canonical_check + leader_marker) + + noema_arg_old = ''' --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg requested_agent "$REQUESTED_AGENT" \ + ''' + noema_arg_new = ''' --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg base_branch "$BASE_BRANCH" \ + --arg requested_agent "$REQUESTED_AGENT" \ + ''' + if noema.count(noema_arg_old) != 1: + raise SystemExit("expected one Noema forwarding argument insertion point") + noema = noema.replace(noema_arg_old, noema_arg_new) + + noema_payload_old = ''' pr_head_sha: $pr_head_sha, + requested_agent: $requested_agent, + ''' + noema_payload_new = ''' pr_head_sha: $pr_head_sha, + base_branch: $base_branch, + requested_agent: $requested_agent, + ''' + if noema.count(noema_payload_old) != 1: + raise SystemExit("expected one Noema forwarding payload insertion point") + noema_path.write_text( + noema.replace(noema_payload_old, noema_payload_new), encoding="utf-8" + ) + + opencode = scope_wrapper_permissions(opencode_path.read_text(encoding="utf-8")) + if opencode.count(leader_marker) != 1: + raise SystemExit("expected one OpenCode leader marker") + opencode_path.write_text( + opencode.replace(leader_marker, canonical_check + leader_marker), + encoding="utf-8", + ) + + Path(".github/workflows/repair-pr787-payload-digest.yml").unlink() + PY + git diff --check + + - name: Verify complete focused behavior and quality + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + git diff --check + + - name: Publish verified repair + env: + EXPECTED_HEAD: ${{ github.sha }} + HEAD_BRANCH: ${{ github.ref_name }} + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + remote_head="$(git ls-remote origin "refs/heads/${HEAD_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add --all + git diff --cached --quiet && { echo "No repair generated" >&2; exit 1; } + git commit -m "fix(automation): bind agent invocation keys to payloads" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.https://github.com/.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${HEAD_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${HEAD_BRANCH}" From 7e8511412c834d7c7a833201bd996d4dd4329fd1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:09:15 +0900 Subject: [PATCH 066/138] ci(pr787): finalize payload-bound review dispatch --- .../repair-pr787-finalize-payload-binding.yml | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 .github/workflows/repair-pr787-finalize-payload-binding.yml diff --git a/.github/workflows/repair-pr787-finalize-payload-binding.yml b/.github/workflows/repair-pr787-finalize-payload-binding.yml new file mode 100644 index 000000000..03e22cd9e --- /dev/null +++ b/.github/workflows/repair-pr787-finalize-payload-binding.yml @@ -0,0 +1,179 @@ +name: Finalize PR 787 payload-bound review dispatch + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-finalize-payload-binding.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-finalize-payload-${{ github.ref }} + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair-and-publish: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact repair trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply the reviewed permanent payload binding + shell: bash --noprofile --norc -e -o pipefail {0} + run: python scripts/ci/apply_pr787_payload_binding.py + + - name: Remove all branch-only repair machinery + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-export-reviewed-files.yml \ + .github/workflows/repair-pr787-export-workflows.yml \ + .github/workflows/repair-pr787-finalize-payload-binding.yml \ + .github/workflows/repair-pr787-noema-base-branch.yml \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/repair-pr787-payload-digest.yml \ + .github/workflows/repair-pr787-payload-upload.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + + - name: Verify exact behavior, branch coverage, docstrings, and syntax + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + git diff --check + + - name: Enforce the final product-file boundary + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + import subprocess + + allowed_permanent = { + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", + "CHANGELOG.md", + "docs/automation/review-agent-comment-invocation.md", + "scripts/ci/agent_mention_router.py", + "tests/test_agent_mention_idempotency.py", + } + allowed_temporary_prefixes = ( + ".github/pr787-payload-repair.trigger", + ".github/workflows/repair-pr787-", + "scripts/ci/apply_pr787_payload_binding.py", + "scripts/ci/repair_pr787_payload_bound_once.py", + ) + changed = set( + subprocess.check_output( + ["git", "diff", "--name-only", "HEAD"], text=True + ).splitlines() + ) + unexpected = sorted( + path + for path in changed + if path not in allowed_permanent + and not path.startswith(allowed_temporary_prefixes) + ) + if unexpected: + raise SystemExit( + "unexpected PR 787 finalizer paths: " + ", ".join(unexpected) + ) + required = { + ".github/workflows/agent-mention-noema-dispatch.yml", + ".github/workflows/agent-mention-opencode-dispatch.yml", + "scripts/ci/agent_mention_router.py", + } + missing = sorted(required - changed) + if missing: + raise SystemExit( + "missing required payload-binding paths: " + ", ".join(missing) + ) + PY + + - name: Publish the verified exact-head repair + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo "No verified repair was produced." >&2; exit 1; } + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind review dispatch keys to payloads" + remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From 7fa3fa294f6f921741a8b4863abb09d79f943dd0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:14:18 +0900 Subject: [PATCH 067/138] chore(ci): remove PR 787 repair trigger --- .github/pr787-payload-repair.trigger | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/pr787-payload-repair.trigger diff --git a/.github/pr787-payload-repair.trigger b/.github/pr787-payload-repair.trigger deleted file mode 100644 index 3ff55ae4c..000000000 --- a/.github/pr787-payload-repair.trigger +++ /dev/null @@ -1 +0,0 @@ -Trigger the exact-head payload-binding repair workflow after the quality gate identified the missing Noema base-branch identity field. From 438dfc633b39076805d65508d8ad011ef8dbac22 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:14:53 +0900 Subject: [PATCH 068/138] chore(ci): remove PR 787 export repair workflow --- .../repair-pr787-export-reviewed-files.yml | 111 ------------------ 1 file changed, 111 deletions(-) delete mode 100644 .github/workflows/repair-pr787-export-reviewed-files.yml diff --git a/.github/workflows/repair-pr787-export-reviewed-files.yml b/.github/workflows/repair-pr787-export-reviewed-files.yml deleted file mode 100644 index 4e8386939..000000000 --- a/.github/workflows/repair-pr787-export-reviewed-files.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Repair PR 787 export reviewed files - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-export-reviewed-files.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-export-reviewed-files - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - export: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply and verify reviewed payload-binding repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python scripts/ci/repair_pr787_payload_bound_once.py - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Materialize immutable reviewed-file bundle - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - bundle="$RUNNER_TEMP/pr787-reviewed-files" - mkdir -p \ - "$bundle/scripts/ci" \ - "$bundle/.github/workflows" \ - "$bundle/tests" \ - "$bundle/docs/automation" - cp scripts/ci/agent_mention_router.py "$bundle/scripts/ci/agent_mention_router.py" - cp .github/workflows/agent-mention-noema-dispatch.yml "$bundle/.github/workflows/agent-mention-noema-dispatch.yml" - cp .github/workflows/agent-mention-opencode-dispatch.yml "$bundle/.github/workflows/agent-mention-opencode-dispatch.yml" - cp tests/test_agent_mention_idempotency.py "$bundle/tests/test_agent_mention_idempotency.py" - cp docs/automation/review-agent-comment-invocation.md "$bundle/docs/automation/review-agent-comment-invocation.md" - cp CHANGELOG.md "$bundle/CHANGELOG.md" - { - printf 'source_head=%s\n' "$GITHUB_SHA" - find "$bundle" -type f ! -name MANIFEST.sha256 -print0 \ - | sort -z \ - | xargs -0 sha256sum - } >"$bundle/MANIFEST.sha256" - - - name: Upload reviewed-file bundle - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: pr787-reviewed-files-${{ github.sha }} - path: ${{ runner.temp }}/pr787-reviewed-files - if-no-files-found: error - retention-days: 1 From 0c72ab27edc3bab21e5433644264bc704fc3dff0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:15:27 +0900 Subject: [PATCH 069/138] chore(ci): remove PR 787 workflow export helper --- .../repair-pr787-export-workflows.yml | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 .github/workflows/repair-pr787-export-workflows.yml diff --git a/.github/workflows/repair-pr787-export-workflows.yml b/.github/workflows/repair-pr787-export-workflows.yml deleted file mode 100644 index 8e07c957b..000000000 --- a/.github/workflows/repair-pr787-export-workflows.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Repair PR 787 export workflow files - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-export-workflows.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-export-workflows - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - export: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Apply reviewed repair and verify workflow digest contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python scripts/ci/repair_pr787_payload_bound_once.py - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - python -m compileall -q scripts/ci/agent_mention_router.py tests/test_agent_mention_idempotency.py - git diff --check - - - name: Materialize workflow exports outside hidden paths - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - bundle="$RUNNER_TEMP/pr787-workflow-files" - mkdir -p "$bundle/workflow_exports" - cp .github/workflows/agent-mention-noema-dispatch.yml "$bundle/workflow_exports/agent-mention-noema-dispatch.yml" - cp .github/workflows/agent-mention-opencode-dispatch.yml "$bundle/workflow_exports/agent-mention-opencode-dispatch.yml" - { - printf 'source_head=%s\n' "$GITHUB_SHA" - sha256sum "$bundle"/workflow_exports/*.yml - } >"$bundle/MANIFEST.sha256" - - - name: Upload reviewed workflow bundle - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: pr787-workflow-files-${{ github.sha }} - path: ${{ runner.temp }}/pr787-workflow-files - if-no-files-found: error - retention-days: 1 From 874ecf7c088e87a173dec84735662b40d5d5bf75 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:16:06 +0900 Subject: [PATCH 070/138] chore(ci): remove PR 787 finalizer workflow --- .../repair-pr787-finalize-payload-binding.yml | 179 ------------------ 1 file changed, 179 deletions(-) delete mode 100644 .github/workflows/repair-pr787-finalize-payload-binding.yml diff --git a/.github/workflows/repair-pr787-finalize-payload-binding.yml b/.github/workflows/repair-pr787-finalize-payload-binding.yml deleted file mode 100644 index 03e22cd9e..000000000 --- a/.github/workflows/repair-pr787-finalize-payload-binding.yml +++ /dev/null @@ -1,179 +0,0 @@ -name: Finalize PR 787 payload-bound review dispatch - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-finalize-payload-binding.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-finalize-payload-${{ github.ref }} - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair-and-publish: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact repair trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply the reviewed permanent payload binding - shell: bash --noprofile --norc -e -o pipefail {0} - run: python scripts/ci/apply_pr787_payload_binding.py - - - name: Remove all branch-only repair machinery - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-export-reviewed-files.yml \ - .github/workflows/repair-pr787-export-workflows.yml \ - .github/workflows/repair-pr787-finalize-payload-binding.yml \ - .github/workflows/repair-pr787-noema-base-branch.yml \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/repair-pr787-payload-digest.yml \ - .github/workflows/repair-pr787-payload-upload.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - - - name: Verify exact behavior, branch coverage, docstrings, and syntax - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check - - - name: Enforce the final product-file boundary - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - import subprocess - - allowed_permanent = { - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - "CHANGELOG.md", - "docs/automation/review-agent-comment-invocation.md", - "scripts/ci/agent_mention_router.py", - "tests/test_agent_mention_idempotency.py", - } - allowed_temporary_prefixes = ( - ".github/pr787-payload-repair.trigger", - ".github/workflows/repair-pr787-", - "scripts/ci/apply_pr787_payload_binding.py", - "scripts/ci/repair_pr787_payload_bound_once.py", - ) - changed = set( - subprocess.check_output( - ["git", "diff", "--name-only", "HEAD"], text=True - ).splitlines() - ) - unexpected = sorted( - path - for path in changed - if path not in allowed_permanent - and not path.startswith(allowed_temporary_prefixes) - ) - if unexpected: - raise SystemExit( - "unexpected PR 787 finalizer paths: " + ", ".join(unexpected) - ) - required = { - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - "scripts/ci/agent_mention_router.py", - } - missing = sorted(required - changed) - if missing: - raise SystemExit( - "missing required payload-binding paths: " + ", ".join(missing) - ) - PY - - - name: Publish the verified exact-head repair - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo "No verified repair was produced." >&2; exit 1; } - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind review dispatch keys to payloads" - remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From 97a14bc994dc8587cb34de0c44bf15eb7177bea7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:16:39 +0900 Subject: [PATCH 071/138] chore(ci): remove PR 787 Noema repair workflow --- .../repair-pr787-noema-base-branch.yml | 137 ------------------ 1 file changed, 137 deletions(-) delete mode 100644 .github/workflows/repair-pr787-noema-base-branch.yml diff --git a/.github/workflows/repair-pr787-noema-base-branch.yml b/.github/workflows/repair-pr787-noema-base-branch.yml deleted file mode 100644 index 51907a5ea..000000000 --- a/.github/workflows/repair-pr787-noema-base-branch.yml +++ /dev/null @@ -1,137 +0,0 @@ -name: Repair PR 787 Noema payload binding - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-noema-base-branch.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-noema-payload-${{ github.ref }} - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.actor == 'seonghobae' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact branch head - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Bind Noema payload to the validated base branch - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - - path = Path("scripts/ci/agent_mention_router.py") - source = path.read_text(encoding="utf-8") - old = ''' "pr_head_sha": request.pull_request_head_sha, - "requested_agent": agent, -''' - new = ''' "pr_head_sha": request.pull_request_head_sha, - "base_branch": request.pull_request_base_branch, - "requested_agent": agent, -''' - if new in source: - raise SystemExit("Noema base-branch payload binding is already present") - if source.count(old) != 1: - raise SystemExit("expected exactly one unbound Noema payload fragment") - path.write_text(source.replace(old, new, 1), encoding="utf-8") - PY - - - name: Verify exact behavior and complete quality contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check - - - name: Publish verified product-only repair - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - GH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f .github/workflows/repair-pr787-noema-base-branch.yml - git add -A - git diff --cached --check - git diff --cached --name-only >"${RUNNER_TEMP}/changed-files" - test "$(wc -l <"${RUNNER_TEMP}/changed-files")" -eq 2 - grep -Fxq scripts/ci/agent_mention_router.py "${RUNNER_TEMP}/changed-files" - grep -Fxq .github/workflows/repair-pr787-noema-base-branch.yml "${RUNNER_TEMP}/changed-files" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind Noema payload to base branch" - remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From d47359b934dbec324b312228bab75fd9a22f3055 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:17:15 +0900 Subject: [PATCH 072/138] chore(ci): remove PR 787 payload push workflow --- .../repair-pr787-payload-binding-push.yml | 186 ------------------ 1 file changed, 186 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-binding-push.yml diff --git a/.github/workflows/repair-pr787-payload-binding-push.yml b/.github/workflows/repair-pr787-payload-binding-push.yml deleted file mode 100644 index 134eac4aa..000000000 --- a/.github/workflows/repair-pr787-payload-binding-push.yml +++ /dev/null @@ -1,186 +0,0 @@ -name: Repair PR 787 payload binding push - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-payload-binding-push.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-payload-binding-push - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 25 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact push head without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Apply reviewed payload-binding repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "${{ github.sha }}" - python3 scripts/ci/apply_pr787_payload_binding.py - git diff --check - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python3 -m pip install --disable-pip-version-check --require-hashes \ - -r requirements-opencode-review-ci-hashes.txt - - - name: Verify complete exact-head router quality - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python3 -m coverage erase - python3 -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python3 -m coverage report --fail-under=100 - python3 -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python3 -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - test "$(grep -c 'base_branch: request.pull_request_base_branch' scripts/ci/agent_mention_router.py)" -eq 2 - git diff --check - - - name: Publish verified exact-parent commit and remove transient files - env: - API_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - python3 - <<'PY' - import base64 - import json - import os - import urllib.parse - import urllib.request - from pathlib import Path - - repository = "ContextualWisdomLab/.github" - expected_head = os.environ["EXPECTED_HEAD"] - source_branch = os.environ["SOURCE_BRANCH"] - token = os.environ["API_TOKEN"] - api_root = f"https://api.github.com/repos/{repository}" - - def request(method, endpoint, payload=None): - data = None if payload is None else json.dumps(payload).encode("utf-8") - req = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {token}", - "X-GitHub-Api-Version": "2022-11-28", - "User-Agent": "cwl-pr787-payload-binding-push", - }, - ) - with urllib.request.urlopen(req, timeout=30) as response: - return json.load(response) - - encoded_branch = urllib.parse.quote(source_branch, safe="/") - live_ref = request("GET", f"/git/ref/heads/{encoded_branch}") - if live_ref.get("object", {}).get("sha") != expected_head: - raise SystemExit("remote branch moved before publication") - parent = request("GET", f"/git/commits/{expected_head}") - entries = [] - for path in ( - "scripts/ci/agent_mention_router.py", - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - "tests/test_agent_mention_idempotency.py", - "tests/test_agent_mention_downstream_idempotency.py", - "docs/automation/review-agent-comment-invocation.md", - "CHANGELOG.md", - ): - encoded = base64.b64encode(Path(path).read_bytes()).decode("ascii") - blob = request( - "POST", - "/git/blobs", - {"content": encoded, "encoding": "base64"}, - ) - entries.append( - {"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]} - ) - for path in ( - ".github/workflows/repair-pr787-payload-bound-invocation.yml", - ".github/workflows/repair-pr787-payload-binding-push.yml", - "scripts/ci/apply_pr787_payload_binding.py", - ): - entries.append({"path": path, "mode": "100644", "type": "blob", "sha": None}) - tree = request( - "POST", - "/git/trees", - {"base_tree": parent["tree"]["sha"], "tree": entries}, - ) - commit = request( - "POST", - "/git/commits", - { - "message": "fix(automation): bind invocation keys to complete payloads", - "tree": tree["sha"], - "parents": [expected_head], - }, - ) - updated = request( - "PATCH", - f"/git/refs/heads/{encoded_branch}", - {"sha": commit["sha"], "force": False}, - ) - if updated.get("object", {}).get("sha") != commit["sha"]: - raise SystemExit("verified branch update did not land") - print(f"Published {commit['sha']} from exact parent {expected_head}") - PY From b8b5bb288e5d9a760b6707cea10f102138d10d59 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:17:56 +0900 Subject: [PATCH 073/138] chore(ci): remove PR 787 invocation repair workflow --- .../repair-pr787-payload-bound-invocation.yml | 418 ------------------ 1 file changed, 418 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-bound-invocation.yml diff --git a/.github/workflows/repair-pr787-payload-bound-invocation.yml b/.github/workflows/repair-pr787-payload-bound-invocation.yml deleted file mode 100644 index c9a724c46..000000000 --- a/.github/workflows/repair-pr787-payload-bound-invocation.yml +++ /dev/null @@ -1,418 +0,0 @@ -name: Repair PR 787 payload-bound invocation - -on: - pull_request: - branches: - - main - types: - - synchronize - -permissions: - contents: read - -concurrency: - group: repair-pr787-payload-bound-invocation - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.event.pull_request.number == 787 && - github.event.pull_request.head.ref == 'feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 25 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact pull-request head without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Apply the reviewed payload-binding repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python3 - <<'PY' - from pathlib import Path - - def replace_once(source: str, old: str, new: str, label: str) -> str: - count = source.count(old) - if count != 1: - raise SystemExit(f"expected exactly one {label}, found {count}") - return source.replace(old, new, 1) - - router_path = Path("scripts/ci/agent_mention_router.py") - router = router_path.read_text(encoding="utf-8") - router = replace_once( - router, - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "requested_agent": agent,\n', - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "base_branch": request.pull_request_base_branch,\n' - ' "requested_agent": agent,\n', - "Noema base-branch payload boundary", - ) - router_path.write_text(router, encoding="utf-8") - - noema_path = Path(".github/workflows/agent-mention-noema-dispatch.yml") - noema = noema_path.read_text(encoding="utf-8") - noema = replace_once( - noema, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "Noema job-scoped write permission", - ) - noema = replace_once( - noema, - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - "Noema base-branch environment binding", - ) - noema = replace_once( - noema, - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' - ' [[ "$BASE_BRANCH" == -* ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - "Noema base-branch validation", - ) - noema_digest = ''' - python3 - <<'PY' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - calculated_key = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): - raise SystemExit("agent invocation key does not match canonical payload") - PY - -''' - noema = replace_once( - noema, - " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - " fi\n\n" + noema_digest + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - "Noema digest verification insertion point", - ) - noema = replace_once( - noema, - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg base_branch "$BASE_BRANCH" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - "Noema forwarded base-branch argument", - ) - noema = replace_once( - noema, - " pr_head_sha: $pr_head_sha,\n" - " requested_agent: $requested_agent,\n", - " pr_head_sha: $pr_head_sha,\n" - " base_branch: $base_branch,\n" - " requested_agent: $requested_agent,\n", - "Noema forwarded base-branch field", - ) - noema_path.write_text(noema, encoding="utf-8") - - opencode_path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") - opencode = opencode_path.read_text(encoding="utf-8") - opencode = replace_once( - opencode, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "OpenCode job-scoped write permission", - ) - opencode_digest = ''' - python3 - <<'PY' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - calculated_key = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): - raise SystemExit("agent invocation key does not match canonical payload") - PY - -''' - opencode = replace_once( - opencode, - " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - " fi\n\n" + opencode_digest + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - "OpenCode digest verification insertion point", - ) - opencode_path.write_text(opencode, encoding="utf-8") - - idempotency_path = Path("tests/test_agent_mention_idempotency.py") - idempotency = idempotency_path.read_text(encoding="utf-8") - base_case = ''' - module.MentionRequest( - original.repository, - original.pull_request_number, - original.pull_request_head_sha, - "develop", - original.comment_id, - original.actor, - original.agents, - ), -''' - idempotency = replace_once( - idempotency, - ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), -''', - ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), -''' + base_case, - "base-branch-only invocation-key regression", - ) - idempotency = replace_once( - idempotency, - " assert payload[\"pr_head_sha\"] == mention_request.pull_request_head_sha\n" - " assert payload[\"source_comment_id\"] == mention_request.comment_id\n", - " assert payload[\"pr_head_sha\"] == mention_request.pull_request_head_sha\n" - " assert payload[\"base_branch\"] == mention_request.pull_request_base_branch\n" - " assert payload[\"source_comment_id\"] == mention_request.comment_id\n", - "payload base-branch identity assertion", - ) - idempotency_path.write_text(idempotency, encoding="utf-8") - - docs_path = Path("docs/automation/review-agent-comment-invocation.md") - docs = docs_path.read_text(encoding="utf-8") - docs = replace_once( - docs, - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "operator digest-binding explanation", - ) - docs = replace_once( - docs, - "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", - "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", - "wrapper permission explanation", - ) - docs = replace_once( - docs, - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", - "verification explanation", - ) - docs_path.write_text(docs, encoding="utf-8") - - changelog_path = Path("CHANGELOG.md") - changelog = changelog_path.read_text(encoding="utf-8") - fixed_heading = "### Fixed\n\n" - addition = ( - "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" - ) - if addition not in changelog: - changelog = replace_once( - changelog, - fixed_heading, - fixed_heading + addition, - "Unreleased Fixed heading", - ) - changelog_path.write_text(changelog, encoding="utf-8") - PY - git diff --check - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python3 -m pip install --disable-pip-version-check --require-hashes \ - -r requirements-opencode-review-ci-hashes.txt - - - name: Verify complete exact-head router quality - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python3 -m coverage erase - python3 -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python3 -m coverage report --fail-under=100 - python3 -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python3 -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Publish verified files and delete this one-shot workflow - env: - API_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.event.pull_request.head.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - python3 - <<'PY' - import base64 - import json - import os - import urllib.parse - import urllib.request - from pathlib import Path - - repository = "ContextualWisdomLab/.github" - expected_head = os.environ["EXPECTED_HEAD"] - source_branch = os.environ["SOURCE_BRANCH"] - token = os.environ["API_TOKEN"] - api_root = f"https://api.github.com/repos/{repository}" - - def request(method, endpoint, payload=None): - data = None if payload is None else json.dumps(payload).encode("utf-8") - req = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {token}", - "X-GitHub-Api-Version": "2022-11-28", - "User-Agent": "cwl-pr787-payload-binding-repair", - }, - ) - with urllib.request.urlopen(req, timeout=30) as response: - return json.load(response) - - encoded_branch = urllib.parse.quote(source_branch, safe="/") - live_ref = request("GET", f"/git/ref/heads/{encoded_branch}") - if live_ref.get("object", {}).get("sha") != expected_head: - raise SystemExit("remote branch moved before exact-head publication") - - parent = request("GET", f"/git/commits/{expected_head}") - entries = [] - for path in ( - "scripts/ci/agent_mention_router.py", - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - "tests/test_agent_mention_idempotency.py", - "tests/test_agent_mention_downstream_idempotency.py", - "docs/automation/review-agent-comment-invocation.md", - "CHANGELOG.md", - ): - encoded = base64.b64encode(Path(path).read_bytes()).decode("ascii") - blob = request( - "POST", - "/git/blobs", - {"content": encoded, "encoding": "base64"}, - ) - entries.append( - {"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]} - ) - entries.append( - { - "path": ".github/workflows/repair-pr787-payload-bound-invocation.yml", - "mode": "100644", - "type": "blob", - "sha": None, - } - ) - tree = request( - "POST", - "/git/trees", - {"base_tree": parent["tree"]["sha"], "tree": entries}, - ) - commit = request( - "POST", - "/git/commits", - { - "message": "fix(automation): bind invocation keys to complete payloads", - "tree": tree["sha"], - "parents": [expected_head], - }, - ) - updated = request( - "PATCH", - f"/git/refs/heads/{encoded_branch}", - {"sha": commit["sha"], "force": False}, - ) - if updated.get("object", {}).get("sha") != commit["sha"]: - raise SystemExit("branch ref update did not bind to verified commit") - print(f"Published verified commit {commit['sha']} from {expected_head}") - PY From ecb93aae607a4eea7375d86abf985ef110cff6ab Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:17:57 +0900 Subject: [PATCH 074/138] ci(pr787): run payload-binding product finalizer --- ...agent-mention-payload-binding-finalize.yml | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 .github/workflows/agent-mention-payload-binding-finalize.yml diff --git a/.github/workflows/agent-mention-payload-binding-finalize.yml b/.github/workflows/agent-mention-payload-binding-finalize.yml new file mode 100644 index 000000000..afa072227 --- /dev/null +++ b/.github/workflows/agent-mention-payload-binding-finalize.yml @@ -0,0 +1,166 @@ +name: Agent mention payload-binding finalizer + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/agent-mention-payload-binding-finalize.yml + +permissions: + contents: read + +concurrency: + group: pr787-payload-binding-finalizer + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact branch head without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply the reviewed permanent repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: python scripts/ci/apply_pr787_payload_binding.py + + - name: Remove every branch-only repair artifact + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/agent-mention-payload-binding-finalize.yml \ + .github/workflows/repair-pr787-export-reviewed-files.yml \ + .github/workflows/repair-pr787-export-workflows.yml \ + .github/workflows/repair-pr787-finalize-payload-binding.yml \ + .github/workflows/repair-pr787-noema-base-branch.yml \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/repair-pr787-payload-digest.yml \ + .github/workflows/repair-pr787-payload-upload.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + + - name: Verify complete behavior and quality contracts + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + git diff --check + + - name: Prove the permanent payload and credential boundary + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + + router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") + noema_start = router.index("def noema_payload") + opencode_start = router.index("def opencode_payload") + noema_block = router[noema_start:opencode_start] + assert '"base_branch": request.pull_request_base_branch' in noema_block + + for workflow_path in ( + Path(".github/workflows/agent-mention-noema-dispatch.yml"), + Path(".github/workflows/agent-mention-opencode-dispatch.yml"), + ): + workflow = workflow_path.read_text(encoding="utf-8") + assert "contents: read" in workflow + assert "hmac.compare_digest" in workflow + assert '"base_branch"' in workflow + assert '"source_comment_id"' in workflow + assert '"requested_by"' in workflow + + temporary = [ + path + for path in Path(".github/workflows").glob("repair-pr787-*") + if path.exists() + ] + assert not temporary, temporary + assert not Path("scripts/ci/apply_pr787_payload_binding.py").exists() + assert not Path("scripts/ci/repair_pr787_payload_bound_once.py").exists() + PY + + - name: Publish the verified product-only commit + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo "No verified product repair was produced." >&2; exit 1; } + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind review dispatch keys to payloads" + remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From a7b1bee0982fba439e5f790657a13d12a30737e7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:18:34 +0900 Subject: [PATCH 075/138] chore(ci): remove PR 787 v2 repair workflow --- .../repair-pr787-payload-bound-v2.yml | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-bound-v2.yml diff --git a/.github/workflows/repair-pr787-payload-bound-v2.yml b/.github/workflows/repair-pr787-payload-bound-v2.yml deleted file mode 100644 index 677abe4b4..000000000 --- a/.github/workflows/repair-pr787-payload-bound-v2.yml +++ /dev/null @@ -1,127 +0,0 @@ -# Exact-head retrigger for the bounded payload-binding repair. -name: Repair PR 787 payload-bound invocation v2 - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-payload-bound-v2.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-payload-bound-v2 - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply reviewed payload-binding repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python scripts/ci/repair_pr787_payload_bound_once.py - git diff --check - - - name: Verify complete focused quality and payload binding - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Publish exact verified tree and remove one-shot artifacts - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - scripts/ci/repair_pr787_payload_bound_once.py - git add -A - git diff --cached --check - git diff --cached --quiet && { echo 'No verified PR 787 repair generated.' >&2; exit 1; } - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind invocation keys to complete payloads" - test -n "$PUSH_TOKEN" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From f1024b3cac7641261f9ead79ca703aa93868984b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:19:08 +0900 Subject: [PATCH 076/138] chore(ci): remove PR 787 candidate repair workflow --- .../repair-pr787-payload-candidate.yml | 168 ------------------ 1 file changed, 168 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-candidate.yml diff --git a/.github/workflows/repair-pr787-payload-candidate.yml b/.github/workflows/repair-pr787-payload-candidate.yml deleted file mode 100644 index 1a1c2ad72..000000000 --- a/.github/workflows/repair-pr787-payload-candidate.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: Repair PR 787 payload-bound candidate - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-payload-candidate.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-payload-candidate - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - build-candidate: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - issues: write - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply and verify reviewed payload-binding repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python scripts/ci/repair_pr787_payload_bound_once.py - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Create repository-owned exact-parent candidate receipt - env: - API_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - python - <<'PY' - import base64 - import json - import os - import urllib.request - from pathlib import Path - - repository = "ContextualWisdomLab/.github" - expected_head = os.environ["EXPECTED_HEAD"] - token = os.environ["API_TOKEN"] - api_root = f"https://api.github.com/repos/{repository}" - - def request(method, endpoint, payload=None): - data = None if payload is None else json.dumps(payload).encode("utf-8") - call = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {token}", - "X-GitHub-Api-Version": "2022-11-28", - "User-Agent": "cwl-pr787-payload-candidate", - }, - ) - with urllib.request.urlopen(call, timeout=30) as response: - return json.load(response) - - parent = request("GET", f"/git/commits/{expected_head}") - entries = [] - for path in ( - "scripts/ci/agent_mention_router.py", - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - "tests/test_agent_mention_idempotency.py", - "docs/automation/review-agent-comment-invocation.md", - "CHANGELOG.md", - ): - content = base64.b64encode(Path(path).read_bytes()).decode("ascii") - blob = request("POST", "/git/blobs", {"content": content, "encoding": "base64"}) - entries.append({"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]}) - for path in ( - ".github/pr787-payload-repair.trigger", - ".github/workflows/repair-pr787-payload-bound-invocation.yml", - ".github/workflows/repair-pr787-payload-bound-v2.yml", - ".github/workflows/repair-pr787-payload-candidate.yml", - "scripts/ci/repair_pr787_payload_bound_once.py", - ): - entries.append({"path": path, "mode": "100644", "type": "blob", "sha": None}) - tree = request("POST", "/git/trees", {"base_tree": parent["tree"]["sha"], "tree": entries}) - commit = request( - "POST", - "/git/commits", - { - "message": "fix(automation): bind invocation keys to complete payloads", - "tree": tree["sha"], - "parents": [expected_head], - }, - ) - candidate_sha = commit["sha"] - request( - "POST", - "/issues/787/comments", - { - "body": ( - "\n" - f"Verified exact-parent candidate: `{candidate_sha}`\n\n" - f"Parent head: `{expected_head}`\n\n" - "The candidate passed 44 focused tests, 100% production statement/branch coverage, 100% public docstrings, compilation, canonical payload-digest checks, and removes every one-shot repair artifact." - ) - }, - ) - print(f"CANDIDATE_COMMIT_SHA={candidate_sha}") - PY From 2002f9bf91338dc8ddadd030d75713e08d1db856 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:19:47 +0900 Subject: [PATCH 077/138] chore(ci): remove PR 787 digest repair workflow --- .../workflows/repair-pr787-payload-digest.yml | 251 ------------------ 1 file changed, 251 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-digest.yml diff --git a/.github/workflows/repair-pr787-payload-digest.yml b/.github/workflows/repair-pr787-payload-digest.yml deleted file mode 100644 index 731d32c17..000000000 --- a/.github/workflows/repair-pr787-payload-digest.yml +++ /dev/null @@ -1,251 +0,0 @@ -name: Repair PR 787 payload-bound invocation keys - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-payload-digest.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-payload-digest-${{ github.ref }} - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair-and-verify: - if: >- - github.repository == 'ContextualWisdomLab/.github' - && github.ref == 'refs/heads/feat/review-agent-mention-router-main' - runs-on: ubuntu-24.04 - timeout-minutes: 30 - permissions: - contents: write - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact repair trigger - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked test tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply payload-bound invocation repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - - router_path = Path("scripts/ci/agent_mention_router.py") - noema_path = Path(".github/workflows/agent-mention-noema-dispatch.yml") - opencode_path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") - - router = router_path.read_text(encoding="utf-8") - router_old = ''' "pr_head_sha": request.pull_request_head_sha, - "requested_agent": agent, - ''' - router_new = ''' "pr_head_sha": request.pull_request_head_sha, - "base_branch": request.pull_request_base_branch, - "requested_agent": agent, - ''' - if router.count(router_old) != 1: - raise SystemExit("expected exactly one Noema router payload insertion point") - router_path.write_text(router.replace(router_old, router_new), encoding="utf-8") - - canonical_check = ''' python3 - <<'PYTHON' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - expected = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): - raise SystemExit("invocation key does not match canonical payload") - PYTHON - - ''' - - def scope_wrapper_permissions(text: str) -> str: - old = '''permissions: - actions: read - contents: write - - jobs: - validate-and-forward: - if: github.repository == 'ContextualWisdomLab/.github' - runs-on: ubuntu-24.04 - timeout-minutes: 5 - ''' - new = '''permissions: - contents: read - - jobs: - validate-and-forward: - if: github.repository == 'ContextualWisdomLab/.github' - runs-on: ubuntu-24.04 - timeout-minutes: 5 - permissions: - actions: read - contents: write - ''' - if text.count(old) != 1: - raise SystemExit("expected one wrapper permission block") - return text.replace(old, new) - - noema = scope_wrapper_permissions(noema_path.read_text(encoding="utf-8")) - noema_env_old = ''' PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} - REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} - ''' - noema_env_new = ''' PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} - BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} - REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} - ''' - if noema.count(noema_env_old) != 1: - raise SystemExit("expected one Noema base-branch environment insertion point") - noema = noema.replace(noema_env_old, noema_env_new) - - noema_validation_old = ''' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || - ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || - ''' - noema_validation_new = ''' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || - ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || - [[ "$BASE_BRANCH" == -* ]] || - ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || - ''' - if noema.count(noema_validation_old) != 1: - raise SystemExit("expected one Noema validation insertion point") - noema = noema.replace(noema_validation_old, noema_validation_new) - - leader_marker = ''' marker="[cwl-agent-invocation:${INVOCATION_KEY}]" - ''' - if noema.count(leader_marker) != 1: - raise SystemExit("expected one Noema leader marker") - noema = noema.replace(leader_marker, canonical_check + leader_marker) - - noema_arg_old = ''' --arg pr_head_sha "$PR_HEAD_SHA" \ - --arg requested_agent "$REQUESTED_AGENT" \ - ''' - noema_arg_new = ''' --arg pr_head_sha "$PR_HEAD_SHA" \ - --arg base_branch "$BASE_BRANCH" \ - --arg requested_agent "$REQUESTED_AGENT" \ - ''' - if noema.count(noema_arg_old) != 1: - raise SystemExit("expected one Noema forwarding argument insertion point") - noema = noema.replace(noema_arg_old, noema_arg_new) - - noema_payload_old = ''' pr_head_sha: $pr_head_sha, - requested_agent: $requested_agent, - ''' - noema_payload_new = ''' pr_head_sha: $pr_head_sha, - base_branch: $base_branch, - requested_agent: $requested_agent, - ''' - if noema.count(noema_payload_old) != 1: - raise SystemExit("expected one Noema forwarding payload insertion point") - noema_path.write_text( - noema.replace(noema_payload_old, noema_payload_new), encoding="utf-8" - ) - - opencode = scope_wrapper_permissions(opencode_path.read_text(encoding="utf-8")) - if opencode.count(leader_marker) != 1: - raise SystemExit("expected one OpenCode leader marker") - opencode_path.write_text( - opencode.replace(leader_marker, canonical_check + leader_marker), - encoding="utf-8", - ) - - Path(".github/workflows/repair-pr787-payload-digest.yml").unlink() - PY - git diff --check - - - name: Verify complete focused behavior and quality - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check - - - name: Publish verified repair - env: - EXPECTED_HEAD: ${{ github.sha }} - HEAD_BRANCH: ${{ github.ref_name }} - PUSH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - remote_head="$(git ls-remote origin "refs/heads/${HEAD_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add --all - git diff --cached --quiet && { echo "No repair generated" >&2; exit 1; } - git commit -m "fix(automation): bind agent invocation keys to payloads" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.https://github.com/.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${HEAD_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${HEAD_BRANCH}" From 660cef37537dda8deda485684657ad29c82c8cf7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:20:29 +0900 Subject: [PATCH 078/138] chore(ci): remove PR 787 payload upload workflow --- .../workflows/repair-pr787-payload-upload.yml | 239 ------------------ 1 file changed, 239 deletions(-) delete mode 100644 .github/workflows/repair-pr787-payload-upload.yml diff --git a/.github/workflows/repair-pr787-payload-upload.yml b/.github/workflows/repair-pr787-payload-upload.yml deleted file mode 100644 index 6cd732cae..000000000 --- a/.github/workflows/repair-pr787-payload-upload.yml +++ /dev/null @@ -1,239 +0,0 @@ -name: Materialize verified PR 787 payload binding -run-name: Materialize PR 787 payload binding at ${{ github.sha }} - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-payload-upload.yml - -permissions: - contents: read - -concurrency: - group: materialize-pr787-payload-binding - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - materialize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - issues: write - pull-requests: write - runs-on: ubuntu-24.04 - timeout-minutes: 60 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply reviewed payload binding and remove every transient repair artifact - env: - EXPECTED_HEAD: ${{ github.sha }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - python scripts/ci/apply_pr787_payload_binding.py - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-export-reviewed-files.yml \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/repair-pr787-payload-upload.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - git diff --check - mapfile -t actual_paths < <(git diff --name-only HEAD | sort) - expected_paths=( - ".github/pr787-payload-repair.trigger" - ".github/workflows/agent-mention-noema-dispatch.yml" - ".github/workflows/agent-mention-opencode-dispatch.yml" - ".github/workflows/repair-pr787-export-reviewed-files.yml" - ".github/workflows/repair-pr787-payload-binding-push.yml" - ".github/workflows/repair-pr787-payload-bound-invocation.yml" - ".github/workflows/repair-pr787-payload-bound-v2.yml" - ".github/workflows/repair-pr787-payload-candidate.yml" - ".github/workflows/repair-pr787-payload-upload.yml" - "CHANGELOG.md" - "docs/automation/review-agent-comment-invocation.md" - "scripts/ci/agent_mention_router.py" - "scripts/ci/apply_pr787_payload_binding.py" - "scripts/ci/repair_pr787_payload_bound_once.py" - "tests/test_agent_mention_idempotency.py" - ) - test "${#actual_paths[@]}" -eq "${#expected_paths[@]}" - for index in "${!expected_paths[@]}"; do - test "${actual_paths[$index]}" = "${expected_paths[$index]}" - done - - - name: Verify focused and complete exact-head quality contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - unset COVERAGE_RCFILE - python -m coverage erase - python -m coverage run --branch -m pytest tests -q - python -m coverage report --show-missing --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts tests - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - test ! -e .github/workflows/repair-pr787-payload-upload.yml - test ! -e scripts/ci/apply_pr787_payload_binding.py - git diff --check - - - name: Build immutable verified product commit object - env: - API_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - python3 - <<'PY' | tee "${RUNNER_TEMP}/pr787-materialization-receipt.txt" - import base64 - import json - import os - import subprocess - import urllib.request - from pathlib import Path - - repository = 'ContextualWisdomLab/.github' - parent_sha = os.environ['EXPECTED_HEAD'] - token = os.environ['API_TOKEN'] - api_root = f'https://api.github.com/repos/{repository}' - - def request(method, endpoint, payload=None): - data = None if payload is None else json.dumps(payload).encode('utf-8') - req = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - 'Accept': 'application/vnd.github+json', - 'Authorization': f'Bearer {token}', - 'X-GitHub-Api-Version': '2022-11-28', - 'User-Agent': 'cwl-pr787-materializer', - }, - ) - with urllib.request.urlopen(req, timeout=60) as response: - return json.load(response) - - raw = subprocess.check_output(['git', 'diff', '--name-status', '-z', 'HEAD']) - parts = raw.decode('utf-8').split('\0') - changes = [] - index = 0 - while index < len(parts) - 1: - status = parts[index] - path = parts[index + 1] - index += 2 - if status.startswith(('R', 'C')): - raise SystemExit(f'rename/copy status is outside reviewed scope: {status} {path}') - changes.append((status, path)) - - parent = request('GET', f'/git/commits/{parent_sha}') - tree_entries = [] - for status, path in changes: - if status == 'D': - tree_entries.append({'path': path, 'mode': '100644', 'type': 'blob', 'sha': None}) - continue - encoded = base64.b64encode(Path(path).read_bytes()).decode('ascii') - blob = request('POST', '/git/blobs', {'content': encoded, 'encoding': 'base64'}) - mode = '100755' if os.access(path, os.X_OK) else '100644' - tree_entries.append({'path': path, 'mode': mode, 'type': 'blob', 'sha': blob['sha']}) - print(f"BLOB {blob['sha']} {path}") - - tree = request( - 'POST', - '/git/trees', - {'base_tree': parent['tree']['sha'], 'tree': tree_entries}, - ) - commit = request( - 'POST', - '/git/commits', - { - 'message': 'fix(automation): bind invocation keys to complete payloads', - 'tree': tree['sha'], - 'parents': [parent_sha], - }, - ) - print(f"PR787_MATERIALIZATION_PARENT_SHA={parent_sha}") - print(f"PR787_MATERIALIZATION_TREE_SHA={tree['sha']}") - print(f"PR787_MATERIALIZATION_COMMIT_SHA={commit['sha']}") - PY - - - name: Publish exact-head materialization pointer - env: - GH_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - commit_sha="$(sed -n 's/^PR787_MATERIALIZATION_COMMIT_SHA=//p' "${RUNNER_TEMP}/pr787-materialization-receipt.txt")" - test "${#commit_sha}" -eq 40 - case "$commit_sha" in (*[!0-9a-f]*) exit 1;; esac - body="PR787_MATERIALIZATION_PARENT_SHA=${EXPECTED_HEAD}%0APR787_MATERIALIZATION_COMMIT_SHA=${commit_sha}" - gh api \ - --method POST \ - repos/ContextualWisdomLab/.github/issues/787/comments \ - -f "body=${body}" - - - name: Upload exact-head materialization receipt - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0.0 - with: - name: pr787-exact-head-materialization - path: ${{ runner.temp }}/pr787-materialization-receipt.txt - if-no-files-found: error - retention-days: 5 From 0c88eeeed026f3761e3d86a6eb55871f58f45d59 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:20:35 +0900 Subject: [PATCH 079/138] ci(pr787): retrigger payload-binding finalizer --- .github/workflows/agent-mention-payload-binding-finalize.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/agent-mention-payload-binding-finalize.yml b/.github/workflows/agent-mention-payload-binding-finalize.yml index afa072227..9646f46f1 100644 --- a/.github/workflows/agent-mention-payload-binding-finalize.yml +++ b/.github/workflows/agent-mention-payload-binding-finalize.yml @@ -1,3 +1,4 @@ +# Exact-head retrigger: 2026-08-06T06:20Z name: Agent mention payload-binding finalizer on: From c64b98b76da7f1c9dd004dcd794fff453ae69006 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:21:20 +0900 Subject: [PATCH 080/138] chore(ci): remove PR 787 patch helper --- scripts/ci/apply_pr787_payload_binding.py | 240 ---------------------- 1 file changed, 240 deletions(-) delete mode 100644 scripts/ci/apply_pr787_payload_binding.py diff --git a/scripts/ci/apply_pr787_payload_binding.py b/scripts/ci/apply_pr787_payload_binding.py deleted file mode 100644 index b9e94867e..000000000 --- a/scripts/ci/apply_pr787_payload_binding.py +++ /dev/null @@ -1,240 +0,0 @@ -#!/usr/bin/env python3 -"""Apply the reviewed PR 787 invocation-key payload-binding repair.""" - -from __future__ import annotations - -from pathlib import Path - - -def replace_once(source: str, old: str, new: str, label: str) -> str: - """Replace one exact source fragment or fail closed.""" - - count = source.count(old) - if count != 1: - raise RuntimeError(f"expected exactly one {label}, found {count}") - return source.replace(old, new, 1) - - -def repair_router() -> None: - """Add base-branch identity to the Noema wrapper payload.""" - - path = Path("scripts/ci/agent_mention_router.py") - source = path.read_text(encoding="utf-8") - source = replace_once( - source, - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "requested_agent": agent,\n', - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "base_branch": request.pull_request_base_branch,\n' - ' "requested_agent": agent,\n', - "Noema base-branch payload boundary", - ) - path.write_text(source, encoding="utf-8") - - -def digest_verifier() -> str: - """Return the shared wrapper-side canonical digest verifier.""" - - return ''' - python3 - <<'PY' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - calculated_key = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): - raise SystemExit("agent invocation key does not match canonical payload") - PY - -''' - - -def repair_noema_wrapper() -> None: - """Validate Noema payload identity before leader election and forwarding.""" - - path = Path(".github/workflows/agent-mention-noema-dispatch.yml") - source = path.read_text(encoding="utf-8") - source = replace_once( - source, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "Noema job-scoped write permission", - ) - source = replace_once( - source, - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - "Noema base-branch environment binding", - ) - source = replace_once( - source, - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' - ' [[ "$BASE_BRANCH" == -* ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - "Noema base-branch validation", - ) - source = replace_once( - source, - " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - " fi\n\n" + digest_verifier() - + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - "Noema digest verification insertion point", - ) - source = replace_once( - source, - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg base_branch "$BASE_BRANCH" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - "Noema forwarded base-branch argument", - ) - source = replace_once( - source, - " pr_head_sha: $pr_head_sha,\n" - " requested_agent: $requested_agent,\n", - " pr_head_sha: $pr_head_sha,\n" - " base_branch: $base_branch,\n" - " requested_agent: $requested_agent,\n", - "Noema forwarded base-branch field", - ) - path.write_text(source, encoding="utf-8") - - -def repair_opencode_wrapper() -> None: - """Validate OpenCode payload identity before leader election.""" - - path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") - source = path.read_text(encoding="utf-8") - source = replace_once( - source, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "OpenCode job-scoped write permission", - ) - source = replace_once( - source, - " fi\n\n marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - " fi\n\n" + digest_verifier() - + " marker=\"[cwl-agent-invocation:${INVOCATION_KEY}]\"\n", - "OpenCode digest verification insertion point", - ) - path.write_text(source, encoding="utf-8") - - -def repair_tests() -> None: - """Extend executable regressions for base-branch identity binding.""" - - path = Path("tests/test_agent_mention_idempotency.py") - source = path.read_text(encoding="utf-8") - existing_head_case = ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), -''' - base_case = ''' module.MentionRequest( - original.repository, - original.pull_request_number, - original.pull_request_head_sha, - "develop", - original.comment_id, - original.actor, - original.agents, - ), -''' - source = replace_once( - source, - existing_head_case, - existing_head_case + base_case, - "base-branch-only invocation-key regression", - ) - source = replace_once( - source, - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - ' assert payload["source_comment_id"] == mention_request.comment_id\n', - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' - ' assert payload["source_comment_id"] == mention_request.comment_id\n', - "payload base-branch identity assertion", - ) - path.write_text(source, encoding="utf-8") - - -def repair_documents() -> None: - """Record the fail-closed binding and least-privilege wrapper boundary.""" - - path = Path("docs/automation/review-agent-comment-invocation.md") - source = path.read_text(encoding="utf-8") - source = replace_once( - source, - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "operator digest-binding explanation", - ) - source = replace_once( - source, - "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", - "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", - "wrapper permission explanation", - ) - source = replace_once( - source, - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", - "verification explanation", - ) - path.write_text(source, encoding="utf-8") - - changelog_path = Path("CHANGELOG.md") - changelog = changelog_path.read_text(encoding="utf-8") - addition = ( - "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" - ) - if addition not in changelog: - changelog = replace_once( - changelog, - "### Fixed\n\n", - "### Fixed\n\n" + addition, - "Unreleased Fixed heading", - ) - changelog_path.write_text(changelog, encoding="utf-8") - - -def main() -> None: - """Apply every bounded repair fragment.""" - - repair_router() - repair_noema_wrapper() - repair_opencode_wrapper() - repair_tests() - repair_documents() - - -if __name__ == "__main__": - main() From adebafaa4be38db03ec77bf5b5cce0a076eced07 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:22:10 +0900 Subject: [PATCH 081/138] chore(ci): remove PR 787 one-shot repair helper --- scripts/ci/repair_pr787_payload_bound_once.py | 265 ------------------ 1 file changed, 265 deletions(-) delete mode 100644 scripts/ci/repair_pr787_payload_bound_once.py diff --git a/scripts/ci/repair_pr787_payload_bound_once.py b/scripts/ci/repair_pr787_payload_bound_once.py deleted file mode 100644 index b9701f029..000000000 --- a/scripts/ci/repair_pr787_payload_bound_once.py +++ /dev/null @@ -1,265 +0,0 @@ -#!/usr/bin/env python3 -"""Apply the reviewed, one-shot PR 787 payload-binding repair.""" - -from __future__ import annotations - -import textwrap -from pathlib import Path - - -def _replace_once(source: str, old: str, new: str, label: str) -> str: - """Replace one exact reviewed anchor or fail closed.""" - - count = source.count(old) - if count != 1: - raise RuntimeError(f"expected exactly one {label}, found {count}") - return source.replace(old, new, 1) - - -def _indented_digest_block() -> str: - """Return the wrapper-side canonical invocation-key verifier.""" - - block = textwrap.dedent( - """\ - python3 - <<'PY' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - calculated_key = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): - raise SystemExit("agent invocation key does not match canonical payload") - PY - - """ - ) - return "".join( - f" {line}" if line.strip() else line - for line in block.splitlines(keepends=True) - ) - - -def _repair_router() -> None: - """Bind the Noema payload to the same base branch used by its digest.""" - - path = Path("scripts/ci/agent_mention_router.py") - source = path.read_text(encoding="utf-8") - source = _replace_once( - source, - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "requested_agent": agent,\n', - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "base_branch": request.pull_request_base_branch,\n' - ' "requested_agent": agent,\n', - "Noema base-branch payload boundary", - ) - path.write_text(source, encoding="utf-8") - - -def _repair_noema_wrapper() -> None: - """Validate and forward the complete Noema invocation identity.""" - - path = Path(".github/workflows/agent-mention-noema-dispatch.yml") - source = path.read_text(encoding="utf-8") - source = _replace_once( - source, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "Noema job-scoped write permission", - ) - source = _replace_once( - source, - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - "Noema base-branch environment binding", - ) - source = _replace_once( - source, - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' - ' [[ "$BASE_BRANCH" == -* ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - "Noema base-branch validation", - ) - source = _replace_once( - source, - ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - ' fi\n\n' - + _indented_digest_block() - + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - "Noema digest verification insertion point", - ) - source = _replace_once( - source, - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg base_branch "$BASE_BRANCH" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - "Noema forwarded base-branch argument", - ) - source = _replace_once( - source, - " pr_head_sha: $pr_head_sha,\n" - " requested_agent: $requested_agent,\n", - " pr_head_sha: $pr_head_sha,\n" - " base_branch: $base_branch,\n" - " requested_agent: $requested_agent,\n", - "Noema forwarded base-branch field", - ) - path.write_text(source, encoding="utf-8") - - -def _repair_opencode_wrapper() -> None: - """Validate the complete OpenCode invocation identity before election.""" - - path = Path(".github/workflows/agent-mention-opencode-dispatch.yml") - source = path.read_text(encoding="utf-8") - source = _replace_once( - source, - "permissions:\n actions: read\n contents: write\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n", - "permissions:\n actions: read\n contents: read\n\njobs:\n validate-and-forward:\n if: github.repository == 'ContextualWisdomLab/.github'\n permissions:\n actions: read\n contents: write\n", - "OpenCode job-scoped write permission", - ) - source = _replace_once( - source, - ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - ' fi\n\n' - + _indented_digest_block() - + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - "OpenCode digest verification insertion point", - ) - path.write_text(source, encoding="utf-8") - - -def _repair_tests() -> None: - """Extend invocation-key and payload identity regressions.""" - - path = Path("tests/test_agent_mention_idempotency.py") - source = path.read_text(encoding="utf-8") - base_case = ''' - module.MentionRequest( - original.repository, - original.pull_request_number, - original.pull_request_head_sha, - "develop", - original.comment_id, - original.actor, - original.agents, - ), -''' - source = _replace_once( - source, - ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), -''', - ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), -''' - + base_case, - "base-branch-only invocation-key regression", - ) - source = _replace_once( - source, - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - ' assert payload["source_comment_id"] == mention_request.comment_id\n', - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' - ' assert payload["source_comment_id"] == mention_request.comment_id\n', - "payload base-branch identity assertion", - ) - path.write_text(source, encoding="utf-8") - - -def _repair_documentation() -> None: - """Record the payload digest and least-privilege wrapper boundary.""" - - path = Path("docs/automation/review-agent-comment-invocation.md") - source = path.read_text(encoding="utf-8") - source = _replace_once( - source, - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Agent-specific wrapper workflows reconstruct the same sorted compact JSON identity and compare its SHA-256 digest before the key can participate in their run title, non-cancelling concurrency group, or durable-leader election. A syntactically valid key paired with altered payload fields therefore fails closed. The earliest valid central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent.\n", - "operator digest-binding explanation", - ) - source = _replace_once( - source, - "- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`.\n", - "- The two agent-specific wrapper workflows keep workflow-default contents read-only; only their validated forwarding jobs receive `actions: read` and `contents: write`.\n", - "wrapper permission explanation", - ) - source = _replace_once( - source, - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors.\n", - "The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, payload-digest, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It includes valid-format mismatched-key and base-branch-only identity regressions, compiles the Python files, and checks the final diff for whitespace errors.\n", - "verification explanation", - ) - path.write_text(source, encoding="utf-8") - - -def _repair_changelog() -> None: - """Record the completed payload-bound invocation repair.""" - - path = Path("CHANGELOG.md") - source = path.read_text(encoding="utf-8") - addition = ( - "- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n" - ) - if addition not in source: - source = _replace_once( - source, - "### Fixed\n\n", - "### Fixed\n\n" + addition, - "Unreleased Fixed heading", - ) - path.write_text(source, encoding="utf-8") - - -def main() -> int: - """Apply every bounded repair component and return success.""" - - _repair_router() - _repair_noema_wrapper() - _repair_opencode_wrapper() - _repair_tests() - _repair_documentation() - _repair_changelog() - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) From f62dfb1c6c08ecc8538a3b5c62dad35cd8192de4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:23:13 +0900 Subject: [PATCH 082/138] chore(ci): remove PR 787 payload finalizer --- ...agent-mention-payload-binding-finalize.yml | 167 ------------------ 1 file changed, 167 deletions(-) delete mode 100644 .github/workflows/agent-mention-payload-binding-finalize.yml diff --git a/.github/workflows/agent-mention-payload-binding-finalize.yml b/.github/workflows/agent-mention-payload-binding-finalize.yml deleted file mode 100644 index 9646f46f1..000000000 --- a/.github/workflows/agent-mention-payload-binding-finalize.yml +++ /dev/null @@ -1,167 +0,0 @@ -# Exact-head retrigger: 2026-08-06T06:20Z -name: Agent mention payload-binding finalizer - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/agent-mention-payload-binding-finalize.yml - -permissions: - contents: read - -concurrency: - group: pr787-payload-binding-finalizer - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact branch head without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply the reviewed permanent repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: python scripts/ci/apply_pr787_payload_binding.py - - - name: Remove every branch-only repair artifact - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/agent-mention-payload-binding-finalize.yml \ - .github/workflows/repair-pr787-export-reviewed-files.yml \ - .github/workflows/repair-pr787-export-workflows.yml \ - .github/workflows/repair-pr787-finalize-payload-binding.yml \ - .github/workflows/repair-pr787-noema-base-branch.yml \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/repair-pr787-payload-digest.yml \ - .github/workflows/repair-pr787-payload-upload.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - - - name: Verify complete behavior and quality contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check - - - name: Prove the permanent payload and credential boundary - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - - router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") - noema_start = router.index("def noema_payload") - opencode_start = router.index("def opencode_payload") - noema_block = router[noema_start:opencode_start] - assert '"base_branch": request.pull_request_base_branch' in noema_block - - for workflow_path in ( - Path(".github/workflows/agent-mention-noema-dispatch.yml"), - Path(".github/workflows/agent-mention-opencode-dispatch.yml"), - ): - workflow = workflow_path.read_text(encoding="utf-8") - assert "contents: read" in workflow - assert "hmac.compare_digest" in workflow - assert '"base_branch"' in workflow - assert '"source_comment_id"' in workflow - assert '"requested_by"' in workflow - - temporary = [ - path - for path in Path(".github/workflows").glob("repair-pr787-*") - if path.exists() - ] - assert not temporary, temporary - assert not Path("scripts/ci/apply_pr787_payload_binding.py").exists() - assert not Path("scripts/ci/repair_pr787_payload_bound_once.py").exists() - PY - - - name: Publish the verified product-only commit - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo "No verified product repair was produced." >&2; exit 1; } - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind review dispatch keys to payloads" - remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From 3bef8adf0f00b668a431d5113fc3081a1780a652 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:25:07 +0900 Subject: [PATCH 083/138] fix(automation): verify payload-bound invocation keys --- .../agent-mention-noema-dispatch.yml | 36 +++++++++++++++++-- .../agent-mention-opencode-dispatch.yml | 31 ++++++++++++++-- .../review-agent-comment-invocation.md | 8 ++--- scripts/ci/agent_mention_router.py | 1 + ...st_agent_mention_downstream_idempotency.py | 20 +++++++++++ 5 files changed, 88 insertions(+), 8 deletions(-) diff --git a/.github/workflows/agent-mention-noema-dispatch.yml b/.github/workflows/agent-mention-noema-dispatch.yml index 95c84cfce..7c41e7cab 100644 --- a/.github/workflows/agent-mention-noema-dispatch.yml +++ b/.github/workflows/agent-mention-noema-dispatch.yml @@ -13,14 +13,16 @@ concurrency: cancel-in-progress: false permissions: - actions: read - contents: write + contents: read jobs: validate-and-forward: if: github.repository == 'ContextualWisdomLab/.github' runs-on: ubuntu-24.04 timeout-minutes: 5 + permissions: + actions: read + contents: write env: GH_TOKEN: ${{ github.token }} REQUESTED_AGENT: "cwl-noema-review" @@ -29,6 +31,7 @@ jobs: TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || '' }} PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} steps: @@ -41,12 +44,39 @@ jobs: ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || + [[ "$BASE_BRANCH" == -* ]] || ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]]; then echo "::error::Rejected malformed or mismatched Noema agent invocation payload." exit 1 fi + python3 - <<'PYTHON' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + expected = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): + raise SystemExit("invocation key does not match canonical payload") + PYTHON + marker="[cwl-agent-invocation:${INVOCATION_KEY}]" leader_id="$( gh api --paginate --slurp \ @@ -77,6 +107,7 @@ jobs: --arg target_repository "$TARGET_REPOSITORY" \ --argjson pr_number "$PR_NUMBER" \ --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg base_branch "$BASE_BRANCH" \ --arg requested_agent "$REQUESTED_AGENT" \ --arg agent_invocation_key "$INVOCATION_KEY" \ --arg requested_by "$REQUESTED_BY" \ @@ -87,6 +118,7 @@ jobs: target_repository: $target_repository, pr_number: $pr_number, pr_head_sha: $pr_head_sha, + base_branch: $base_branch, requested_agent: $requested_agent, agent_invocation_key: $agent_invocation_key, requested_by: $requested_by, diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml index 42f821c75..e2a964ca6 100644 --- a/.github/workflows/agent-mention-opencode-dispatch.yml +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -13,14 +13,16 @@ concurrency: cancel-in-progress: false permissions: - actions: read - contents: write + contents: read jobs: validate-and-forward: if: github.repository == 'ContextualWisdomLab/.github' runs-on: ubuntu-24.04 timeout-minutes: 5 + permissions: + actions: read + contents: write env: GH_TOKEN: ${{ github.token }} REQUESTED_AGENT: "opencode-agent" @@ -60,6 +62,31 @@ jobs: exit 1 fi + python3 - <<'PYTHON' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + expected = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): + raise SystemExit("invocation key does not match canonical payload") + PYTHON + marker="[cwl-agent-invocation:${INVOCATION_KEY}]" leader_id="$( gh api --paginate --slurp \ diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index 770a1858f..40173bc90 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -20,7 +20,7 @@ The implementation uses two bounded paths: 1. **Local fast path.** Comments on `ContextualWisdomLab/.github` trigger `issue_comment` immediately. 2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and consults the central exact-key workflow-run ledger before queuing work. -Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, requested agent, and source comment ID. Agent-specific wrapper workflows use that key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent. +Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Before durable-leader election, each agent-specific wrapper reconstructs the same canonical JSON from its validated payload, hashes it with SHA-256, and compares the result in constant time with the supplied key. Altering any bound field while retaining a syntactically valid key therefore fails closed. Wrapper workflows use the verified key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent. Target-repository acknowledgement comments and reactions are user-experience signals only. They are not dispatch authority because repository writers, bot identities, or credential rotation could otherwise forge or invalidate a marker. A failed acknowledgement cannot cause completed agent work to be redispatched. @@ -36,12 +36,12 @@ This preserves the central MSA boundary without copying privileged workflow code - The workflow default token is read-only. - The local routing job receives job-scoped `actions: read`, `contents: write`, `issues: write`, and `pull-requests: read`. - The organization sweep receives job-scoped `actions: read`, `contents: write`, and `id-token: write`. -- The two agent-specific wrapper workflows receive only `actions: read` and `contents: write`. +- The two agent-specific wrapper workflows receive only job-scoped `actions: read` and `contents: write`; their workflow defaults remain `contents: read`. - `contents: write` is intentionally retained only on jobs that call GitHub's create-repository-dispatch endpoint. GitHub documents that endpoint as requiring Contents repository permission at write level. Removing it would disable the bounded central dispatch path; broad workflow-default write access is not granted. - The organization sweep uses the established cross-repository credential chain for reading target comments, while the central repository's own short-lived job token dispatches the central workflows. - OpenCode dispatch is restricted to the exact `OPENCODE_REPOSITORY_DISPATCH_TARGETS` allowlist. - An invocation cannot merge: `enable_auto_merge=false`, `update_branches=false`, and `merge_mode=disabled` are explicit in the dispatch payload. -- Every dispatch is bound to live PR number, current head SHA, and base branch metadata fetched from GitHub immediately before dispatch. +- Every dispatch is bound to live PR number, current head SHA, base branch, source comment, requested agent, and requesting actor metadata fetched or validated immediately before dispatch. - Router jobs use the fixed `ubuntu-24.04` runner and an immutable `actions/checkout` v7.0.1 commit pin; checkout credentials are not persisted. - A branch-selectable `workflow_dispatch` trigger is intentionally absent. This prevents a repository writer from choosing an unreviewed branch version of the central router while the job holds dispatch permissions. @@ -55,7 +55,7 @@ This preserves the central MSA boundary without copying privileged workflow code ## Verification and rollback -The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. +The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. A permanent regression contract also rejects the transient PR-specific branch-writer workflows and repair helpers used during development, so they cannot ship with the control plane. ### Activation gate diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index f1db4746f..8a08df6f4 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -325,6 +325,7 @@ def noema_payload(request: MentionRequest) -> dict[str, Any]: "target_repository": request.repository, "pr_number": request.pull_request_number, "pr_head_sha": request.pull_request_head_sha, + "base_branch": request.pull_request_base_branch, "requested_agent": agent, "agent_invocation_key": agent_invocation_key(request, agent), "requested_by": request.actor, diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index e86e0cdc5..2235f5a5a 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -105,3 +105,23 @@ def test_quality_gate_tracks_every_idempotency_surface() -> None: ): assert test_path in test_command assert test_path in compile_command + + +def test_branch_contains_no_transient_pr787_repair_automation() -> None: + """One-shot branch writers and repair helpers must not ship with the router.""" + + transient_paths = ( + ".github/pr787-payload-repair.trigger", + ".github/workflows/repair-pr787-export-reviewed-files.yml", + ".github/workflows/repair-pr787-export-workflows.yml", + ".github/workflows/repair-pr787-noema-base-branch.yml", + ".github/workflows/repair-pr787-payload-binding-push.yml", + ".github/workflows/repair-pr787-payload-bound-invocation.yml", + ".github/workflows/repair-pr787-payload-bound-v2.yml", + ".github/workflows/repair-pr787-payload-candidate.yml", + ".github/workflows/repair-pr787-payload-digest.yml", + ".github/workflows/repair-pr787-payload-upload.yml", + "scripts/ci/apply_pr787_payload_binding.py", + "scripts/ci/repair_pr787_payload_bound_once.py", + ) + assert all(not (ROOT / relative_path).exists() for relative_path in transient_paths) From 85c50910f5b26552dc49a4b94e993366cf3d6d60 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:27:47 +0900 Subject: [PATCH 084/138] ci(pr787): reconcile Noema payload binding --- ...agent-mention-router-payload-reconcile.yml | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/agent-mention-router-payload-reconcile.yml diff --git a/.github/workflows/agent-mention-router-payload-reconcile.yml b/.github/workflows/agent-mention-router-payload-reconcile.yml new file mode 100644 index 000000000..c23241b5c --- /dev/null +++ b/.github/workflows/agent-mention-router-payload-reconcile.yml @@ -0,0 +1,127 @@ +name: Reconcile PR 787 Noema payload binding + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/agent-mention-router-payload-reconcile.yml + +permissions: + contents: read + +concurrency: + group: pr787-noema-payload-reconcile + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + reconcile: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact head without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install hash-locked tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply minimal reviewed production fix + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + + path = Path("scripts/ci/agent_mention_router.py") + source = path.read_text(encoding="utf-8") + old = ''' "pr_head_sha": request.pull_request_head_sha, + "requested_agent": agent, +''' + new = ''' "pr_head_sha": request.pull_request_head_sha, + "base_branch": request.pull_request_base_branch, + "requested_agent": agent, +''' + if source.count(old) != 1: + raise SystemExit("expected one unbound Noema payload") + path.write_text(source.replace(old, new, 1), encoding="utf-8") + PY + + - name: Verify focused and complete quality contracts + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci tests + git diff --check + + - name: Remove temporary workflow and publish exact repair + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f .github/workflows/agent-mention-router-payload-reconcile.yml + git add -A + git diff --cached --check + changed="$(git diff --cached --name-only)" + printf '%s\n' "$changed" + test "$(printf '%s\n' "$changed" | sed '/^$/d' | wc -l)" -eq 2 + printf '%s\n' "$changed" | grep -Fxq scripts/ci/agent_mention_router.py + printf '%s\n' "$changed" | grep -Fxq .github/workflows/agent-mention-router-payload-reconcile.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind Noema payload to base branch" + remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From 92c83f44c75cae42e90dc6984dc89c696b6c3db9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 15:28:33 +0900 Subject: [PATCH 085/138] chore(ci): remove PR 787 payload reconcile workflow --- ...agent-mention-router-payload-reconcile.yml | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 .github/workflows/agent-mention-router-payload-reconcile.yml diff --git a/.github/workflows/agent-mention-router-payload-reconcile.yml b/.github/workflows/agent-mention-router-payload-reconcile.yml deleted file mode 100644 index c23241b5c..000000000 --- a/.github/workflows/agent-mention-router-payload-reconcile.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: Reconcile PR 787 Noema payload binding - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/agent-mention-router-payload-reconcile.yml - -permissions: - contents: read - -concurrency: - group: pr787-noema-payload-reconcile - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - reconcile: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact head without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install hash-locked tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply minimal reviewed production fix - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - - path = Path("scripts/ci/agent_mention_router.py") - source = path.read_text(encoding="utf-8") - old = ''' "pr_head_sha": request.pull_request_head_sha, - "requested_agent": agent, -''' - new = ''' "pr_head_sha": request.pull_request_head_sha, - "base_branch": request.pull_request_base_branch, - "requested_agent": agent, -''' - if source.count(old) != 1: - raise SystemExit("expected one unbound Noema payload") - path.write_text(source.replace(old, new, 1), encoding="utf-8") - PY - - - name: Verify focused and complete quality contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci tests - git diff --check - - - name: Remove temporary workflow and publish exact repair - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f .github/workflows/agent-mention-router-payload-reconcile.yml - git add -A - git diff --cached --check - changed="$(git diff --cached --name-only)" - printf '%s\n' "$changed" - test "$(printf '%s\n' "$changed" | sed '/^$/d' | wc -l)" -eq 2 - printf '%s\n' "$changed" | grep -Fxq scripts/ci/agent_mention_router.py - printf '%s\n' "$changed" | grep -Fxq .github/workflows/agent-mention-router-payload-reconcile.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind Noema payload to base branch" - remote_url="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - "$remote_url" "HEAD:refs/heads/${SOURCE_BRANCH}" From b2bd9d4fd6f570f9bbbfa49f4beaeb67459e4d0e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 17:50:57 +0900 Subject: [PATCH 086/138] ci(pr787): finalize payload binding and remove repair artifacts --- .../finalize-pr787-payload-binding.yml | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 .github/workflows/finalize-pr787-payload-binding.yml diff --git a/.github/workflows/finalize-pr787-payload-binding.yml b/.github/workflows/finalize-pr787-payload-binding.yml new file mode 100644 index 000000000..73df35bc9 --- /dev/null +++ b/.github/workflows/finalize-pr787-payload-binding.yml @@ -0,0 +1,152 @@ +name: Finalize PR 787 payload binding + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/finalize-pr787-payload-binding.yml + +permissions: + contents: read + +concurrency: + group: finalize-pr787-payload-binding + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Verify or apply the bounded payload repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + run_focused() { + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + } + + if ! run_focused; then + test -f scripts/ci/repair_pr787_payload_bound_once.py + python scripts/ci/repair_pr787_payload_bound_once.py + run_focused + fi + + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + grep -F '"base_branch": request.pull_request_base_branch' scripts/ci/agent_mention_router.py + grep -F 'BASE_BRANCH: ${{ github.event.client_payload.base_branch || '\''\'' }}' .github/workflows/agent-mention-noema-dispatch.yml + git diff --check + + - name: Remove every one-shot repair artifact + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/finalize-pr787-payload-binding.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + git diff --check + + - name: Verify the durable final tree + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test ! -e .github/pr787-payload-repair.trigger + test ! -e .github/workflows/repair-pr787-payload-binding-push.yml + test ! -e .github/workflows/repair-pr787-payload-bound-invocation.yml + test ! -e .github/workflows/repair-pr787-payload-bound-v2.yml + test ! -e .github/workflows/repair-pr787-payload-candidate.yml + test ! -e .github/workflows/finalize-pr787-payload-binding.yml + test ! -e scripts/ci/apply_pr787_payload_binding.py + test ! -e scripts/ci/repair_pr787_payload_bound_once.py + python -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + git diff --check + + - name: Publish exact verified final tree + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo '::error::No final-tree change was produced.'; exit 1; } + git commit -m "fix(automation): bind invocation keys to complete payloads" + test -n "$PUSH_TOKEN" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 04d715f8c9548ae69ef324abfec24df0bea0cf89 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 18:01:08 +0900 Subject: [PATCH 087/138] ci: remove accidental placeholder issues --- .../repair-pr787-dummy-issue-cleanup.yml | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 .github/workflows/repair-pr787-dummy-issue-cleanup.yml diff --git a/.github/workflows/repair-pr787-dummy-issue-cleanup.yml b/.github/workflows/repair-pr787-dummy-issue-cleanup.yml new file mode 100644 index 000000000..30c8e89b3 --- /dev/null +++ b/.github/workflows/repair-pr787-dummy-issue-cleanup.yml @@ -0,0 +1,131 @@ +name: Remove accidental placeholder issues + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-dummy-issue-cleanup.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-dummy-issue-cleanup + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + cleanup: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + issues: write + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Close only exact accidental placeholder issues + env: + API_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 - <<'PY' + from __future__ import annotations + + import datetime as dt + import json + import os + import urllib.parse + import urllib.request + + repository = "ContextualWisdomLab/.github" + token = os.environ["API_TOKEN"] + api_root = f"https://api.github.com/repos/{repository}" + cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(hours=6) + + def request(method: str, endpoint: str, payload: dict[str, object] | None = None): + data = None if payload is None else json.dumps(payload).encode("utf-8") + call = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "cwl-placeholder-cleanup", + }, + ) + with urllib.request.urlopen(call, timeout=30) as response: + return json.load(response) + + query = urllib.parse.urlencode( + { + "state": "open", + "creator": "seonghobae", + "sort": "created", + "direction": "desc", + "per_page": "100", + } + ) + issues = request("GET", f"/issues?{query}") + closed: list[int] = [] + for issue in issues: + if "pull_request" in issue: + continue + created_at = dt.datetime.fromisoformat(issue["created_at"].replace("Z", "+00:00")) + if created_at < cutoff: + continue + if issue.get("title") != "dummy": + continue + if (issue.get("body") or "").strip() != "dummy": + continue + if issue.get("user", {}).get("login") != "seonghobae": + continue + number = int(issue["number"]) + request( + "PATCH", + f"/issues/{number}", + {"state": "closed", "state_reason": "not_planned"}, + ) + closed.append(number) + print(f"closed_exact_placeholder_issues={len(closed)}") + PY + + - name: Remove the one-shot cleanup workflow + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f .github/workflows/repair-pr787-dummy-issue-cleanup.yml + git add -A + git diff --cached --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "chore: remove placeholder cleanup workflow" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From fa718341faea04187db95506c9b2cb56079654fc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:01:36 +0000 Subject: [PATCH 088/138] chore: remove placeholder cleanup workflow --- .../repair-pr787-dummy-issue-cleanup.yml | 131 ------------------ 1 file changed, 131 deletions(-) delete mode 100644 .github/workflows/repair-pr787-dummy-issue-cleanup.yml diff --git a/.github/workflows/repair-pr787-dummy-issue-cleanup.yml b/.github/workflows/repair-pr787-dummy-issue-cleanup.yml deleted file mode 100644 index 30c8e89b3..000000000 --- a/.github/workflows/repair-pr787-dummy-issue-cleanup.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Remove accidental placeholder issues - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-dummy-issue-cleanup.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-dummy-issue-cleanup - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - cleanup: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - issues: write - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Close only exact accidental placeholder issues - env: - API_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python3 - <<'PY' - from __future__ import annotations - - import datetime as dt - import json - import os - import urllib.parse - import urllib.request - - repository = "ContextualWisdomLab/.github" - token = os.environ["API_TOKEN"] - api_root = f"https://api.github.com/repos/{repository}" - cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(hours=6) - - def request(method: str, endpoint: str, payload: dict[str, object] | None = None): - data = None if payload is None else json.dumps(payload).encode("utf-8") - call = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {token}", - "X-GitHub-Api-Version": "2022-11-28", - "User-Agent": "cwl-placeholder-cleanup", - }, - ) - with urllib.request.urlopen(call, timeout=30) as response: - return json.load(response) - - query = urllib.parse.urlencode( - { - "state": "open", - "creator": "seonghobae", - "sort": "created", - "direction": "desc", - "per_page": "100", - } - ) - issues = request("GET", f"/issues?{query}") - closed: list[int] = [] - for issue in issues: - if "pull_request" in issue: - continue - created_at = dt.datetime.fromisoformat(issue["created_at"].replace("Z", "+00:00")) - if created_at < cutoff: - continue - if issue.get("title") != "dummy": - continue - if (issue.get("body") or "").strip() != "dummy": - continue - if issue.get("user", {}).get("login") != "seonghobae": - continue - number = int(issue["number"]) - request( - "PATCH", - f"/issues/{number}", - {"state": "closed", "state_reason": "not_planned"}, - ) - closed.append(number) - print(f"closed_exact_placeholder_issues={len(closed)}") - PY - - - name: Remove the one-shot cleanup workflow - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f .github/workflows/repair-pr787-dummy-issue-cleanup.yml - git add -A - git diff --cached --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "chore: remove placeholder cleanup workflow" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 41e65989ac8e5eb6f4155f0da63dc61845ce7dd8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 18:08:43 +0900 Subject: [PATCH 089/138] ci(pr787): finalize repaired payload tree v2 --- .../finalize-pr787-payload-binding-v2.yml | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 .github/workflows/finalize-pr787-payload-binding-v2.yml diff --git a/.github/workflows/finalize-pr787-payload-binding-v2.yml b/.github/workflows/finalize-pr787-payload-binding-v2.yml new file mode 100644 index 000000000..91645b97c --- /dev/null +++ b/.github/workflows/finalize-pr787-payload-binding-v2.yml @@ -0,0 +1,181 @@ +name: Finalize PR 787 payload binding v2 + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/finalize-pr787-payload-binding-v2.yml + +permissions: + contents: read + +concurrency: + group: finalize-pr787-payload-binding-v2 + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.actor == 'seonghobae' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 40 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Materialize the reviewed payload-bound product tree if required + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + run_contracts() { + python -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + } + + if ! run_contracts; then + test -f scripts/ci/repair_pr787_payload_bound_once.py + python scripts/ci/repair_pr787_payload_bound_once.py + run_contracts + fi + + python - <<'PY' + from pathlib import Path + + router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") + noema = Path(".github/workflows/agent-mention-noema-dispatch.yml").read_text(encoding="utf-8") + opencode = Path(".github/workflows/agent-mention-opencode-dispatch.yml").read_text(encoding="utf-8") + required_router = ( + '"base_branch": request.pull_request_base_branch', + '"requested_by": request.actor', + '"source_comment_id": request.comment_id', + ) + if not all(marker in router for marker in required_router): + raise SystemExit("router payload is not bound to the complete invocation identity") + for name, workflow in (("Noema", noema), ("OpenCode", opencode)): + if workflow.count("hmac.compare_digest") != 1: + raise SystemExit(f"{name} wrapper must verify exactly one canonical digest") + if 'BASE_BRANCH:' not in workflow: + raise SystemExit(f"{name} wrapper does not bind the base branch") + PY + git diff --check + + - name: Remove every PR 787 one-shot writer and repair artifact + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/finalize-pr787-payload-binding.yml \ + .github/workflows/finalize-pr787-payload-binding-v2.yml \ + .github/workflows/repair-pr787-dummy-issue-cleanup.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + git diff --check + + - name: Verify complete focused quality on the durable final tree + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + python - <<'PY' + from pathlib import Path + + forbidden = ( + Path(".github/pr787-payload-repair.trigger"), + Path(".github/workflows/repair-pr787-payload-binding-push.yml"), + Path(".github/workflows/repair-pr787-payload-bound-invocation.yml"), + Path(".github/workflows/repair-pr787-payload-bound-v2.yml"), + Path(".github/workflows/repair-pr787-payload-candidate.yml"), + Path(".github/workflows/finalize-pr787-payload-binding.yml"), + Path(".github/workflows/finalize-pr787-payload-binding-v2.yml"), + Path(".github/workflows/repair-pr787-dummy-issue-cleanup.yml"), + Path("scripts/ci/apply_pr787_payload_binding.py"), + Path("scripts/ci/repair_pr787_payload_bound_once.py"), + ) + remaining = [str(path) for path in forbidden if path.exists()] + if remaining: + raise SystemExit(f"one-shot artifacts remain: {remaining}") + PY + git diff --check + + - name: Publish exact verified durable tree + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo '::error::No durable final-tree change was produced.'; exit 1; } + git commit -m "fix(automation): bind invocation keys to complete payloads" + test -n "$PUSH_TOKEN" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 1cf29e5e0b5a8bea85156e7b31ec10f0e1c9d2d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:09:21 +0000 Subject: [PATCH 090/138] fix(automation): bind invocation keys to complete payloads --- .../finalize-pr787-payload-binding-v2.yml | 181 ------------------ .../finalize-pr787-payload-binding.yml | 152 --------------- 2 files changed, 333 deletions(-) delete mode 100644 .github/workflows/finalize-pr787-payload-binding-v2.yml delete mode 100644 .github/workflows/finalize-pr787-payload-binding.yml diff --git a/.github/workflows/finalize-pr787-payload-binding-v2.yml b/.github/workflows/finalize-pr787-payload-binding-v2.yml deleted file mode 100644 index 91645b97c..000000000 --- a/.github/workflows/finalize-pr787-payload-binding-v2.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Finalize PR 787 payload binding v2 - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/finalize-pr787-payload-binding-v2.yml - -permissions: - contents: read - -concurrency: - group: finalize-pr787-payload-binding-v2 - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.actor == 'seonghobae' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 40 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Materialize the reviewed payload-bound product tree if required - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - run_contracts() { - python -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - } - - if ! run_contracts; then - test -f scripts/ci/repair_pr787_payload_bound_once.py - python scripts/ci/repair_pr787_payload_bound_once.py - run_contracts - fi - - python - <<'PY' - from pathlib import Path - - router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") - noema = Path(".github/workflows/agent-mention-noema-dispatch.yml").read_text(encoding="utf-8") - opencode = Path(".github/workflows/agent-mention-opencode-dispatch.yml").read_text(encoding="utf-8") - required_router = ( - '"base_branch": request.pull_request_base_branch', - '"requested_by": request.actor', - '"source_comment_id": request.comment_id', - ) - if not all(marker in router for marker in required_router): - raise SystemExit("router payload is not bound to the complete invocation identity") - for name, workflow in (("Noema", noema), ("OpenCode", opencode)): - if workflow.count("hmac.compare_digest") != 1: - raise SystemExit(f"{name} wrapper must verify exactly one canonical digest") - if 'BASE_BRANCH:' not in workflow: - raise SystemExit(f"{name} wrapper does not bind the base branch") - PY - git diff --check - - - name: Remove every PR 787 one-shot writer and repair artifact - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/finalize-pr787-payload-binding.yml \ - .github/workflows/finalize-pr787-payload-binding-v2.yml \ - .github/workflows/repair-pr787-dummy-issue-cleanup.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - git diff --check - - - name: Verify complete focused quality on the durable final tree - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests - python - <<'PY' - from pathlib import Path - - forbidden = ( - Path(".github/pr787-payload-repair.trigger"), - Path(".github/workflows/repair-pr787-payload-binding-push.yml"), - Path(".github/workflows/repair-pr787-payload-bound-invocation.yml"), - Path(".github/workflows/repair-pr787-payload-bound-v2.yml"), - Path(".github/workflows/repair-pr787-payload-candidate.yml"), - Path(".github/workflows/finalize-pr787-payload-binding.yml"), - Path(".github/workflows/finalize-pr787-payload-binding-v2.yml"), - Path(".github/workflows/repair-pr787-dummy-issue-cleanup.yml"), - Path("scripts/ci/apply_pr787_payload_binding.py"), - Path("scripts/ci/repair_pr787_payload_bound_once.py"), - ) - remaining = [str(path) for path in forbidden if path.exists()] - if remaining: - raise SystemExit(f"one-shot artifacts remain: {remaining}") - PY - git diff --check - - - name: Publish exact verified durable tree - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo '::error::No durable final-tree change was produced.'; exit 1; } - git commit -m "fix(automation): bind invocation keys to complete payloads" - test -n "$PUSH_TOKEN" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" diff --git a/.github/workflows/finalize-pr787-payload-binding.yml b/.github/workflows/finalize-pr787-payload-binding.yml deleted file mode 100644 index 73df35bc9..000000000 --- a/.github/workflows/finalize-pr787-payload-binding.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: Finalize PR 787 payload binding - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/finalize-pr787-payload-binding.yml - -permissions: - contents: read - -concurrency: - group: finalize-pr787-payload-binding - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Verify or apply the bounded payload repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - run_focused() { - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests - } - - if ! run_focused; then - test -f scripts/ci/repair_pr787_payload_bound_once.py - python scripts/ci/repair_pr787_payload_bound_once.py - run_focused - fi - - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - grep -F '"base_branch": request.pull_request_base_branch' scripts/ci/agent_mention_router.py - grep -F 'BASE_BRANCH: ${{ github.event.client_payload.base_branch || '\''\'' }}' .github/workflows/agent-mention-noema-dispatch.yml - git diff --check - - - name: Remove every one-shot repair artifact - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/finalize-pr787-payload-binding.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - git diff --check - - - name: Verify the durable final tree - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test ! -e .github/pr787-payload-repair.trigger - test ! -e .github/workflows/repair-pr787-payload-binding-push.yml - test ! -e .github/workflows/repair-pr787-payload-bound-invocation.yml - test ! -e .github/workflows/repair-pr787-payload-bound-v2.yml - test ! -e .github/workflows/repair-pr787-payload-candidate.yml - test ! -e .github/workflows/finalize-pr787-payload-binding.yml - test ! -e scripts/ci/apply_pr787_payload_binding.py - test ! -e scripts/ci/repair_pr787_payload_bound_once.py - python -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check - - - name: Publish exact verified final tree - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo '::error::No final-tree change was produced.'; exit 1; } - git commit -m "fix(automation): bind invocation keys to complete payloads" - test -n "$PUSH_TOKEN" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 712dc72fda43e64dc5316510d3fa209f990b95a4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 18:21:25 +0900 Subject: [PATCH 091/138] ci: clean exact accidental placeholder issues v2 --- ...eanup-accidental-placeholder-issues-v2.yml | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 .github/workflows/cleanup-accidental-placeholder-issues-v2.yml diff --git a/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml b/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml new file mode 100644 index 000000000..e885db0bf --- /dev/null +++ b/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml @@ -0,0 +1,147 @@ +name: Clean exact accidental placeholder issues v2 + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/cleanup-accidental-placeholder-issues-v2.yml + +permissions: + contents: read + +concurrency: + group: cleanup-accidental-placeholder-issues-v2 + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + cleanup: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.actor == 'seonghobae' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + issues: write + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Close only exact accidental placeholders and remove accidental assignee + env: + API_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 - <<'PY' + from __future__ import annotations + + import datetime as dt + import json + import os + import urllib.error + import urllib.parse + import urllib.request + + repository = "ContextualWisdomLab/.github" + token = os.environ["API_TOKEN"] + api_root = f"https://api.github.com/repos/{repository}" + cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(hours=24) + + def request(method: str, endpoint: str, payload: dict[str, object] | None = None): + data = None if payload is None else json.dumps(payload).encode("utf-8") + call = urllib.request.Request( + api_root + endpoint, + data=data, + method=method, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "cwl-exact-placeholder-cleanup-v2", + }, + ) + try: + with urllib.request.urlopen(call, timeout=30) as response: + raw = response.read() + return None if not raw else json.loads(raw) + except urllib.error.HTTPError as error: + if method == "DELETE" and error.code in {404, 422}: + return None + raise + + query = urllib.parse.urlencode( + { + "state": "open", + "creator": "seonghobae", + "sort": "created", + "direction": "desc", + "per_page": "100", + } + ) + issues = request("GET", f"/issues?{query}") or [] + closed: list[int] = [] + for issue in issues: + if "pull_request" in issue: + continue + created_at = dt.datetime.fromisoformat(issue["created_at"].replace("Z", "+00:00")) + if created_at < cutoff: + continue + if issue.get("title") != "dummy": + continue + if (issue.get("body") or "").strip() != "dummy": + continue + if issue.get("user", {}).get("login") != "seonghobae": + continue + number = int(issue["number"]) + request( + "PATCH", + f"/issues/{number}", + {"state": "closed", "state_reason": "not_planned"}, + ) + closed.append(number) + + request( + "DELETE", + "/issues/794/assignees", + {"assignees": ["coderabbitai"]}, + ) + print(f"closed_exact_placeholder_issues={len(closed)}") + PY + + - name: Remove the cleanup workflow and publish exact tree + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f .github/workflows/cleanup-accidental-placeholder-issues-v2.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo '::error::Cleanup workflow was not removed.'; exit 1; } + git commit -m "chore: remove exact placeholder cleanup workflow" + test -n "$PUSH_TOKEN" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From cb1733a3b210589967ea98b3df9ccc315ea60085 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 18:24:55 +0900 Subject: [PATCH 092/138] ci(pr787): finalize durable payload tree v3 --- .../finalize-pr787-payload-binding-v3.yml | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 .github/workflows/finalize-pr787-payload-binding-v3.yml diff --git a/.github/workflows/finalize-pr787-payload-binding-v3.yml b/.github/workflows/finalize-pr787-payload-binding-v3.yml new file mode 100644 index 000000000..173bc3b30 --- /dev/null +++ b/.github/workflows/finalize-pr787-payload-binding-v3.yml @@ -0,0 +1,186 @@ +name: Finalize PR 787 payload binding v3 + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/finalize-pr787-payload-binding-v3.yml + +permissions: + contents: read + +concurrency: + group: finalize-pr787-payload-binding-v3 + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.actor == 'seonghobae' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 40 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Materialize the reviewed payload-bound product tree if required + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + run_contracts() { + python -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + } + + if ! run_contracts; then + test -f scripts/ci/repair_pr787_payload_bound_once.py + python scripts/ci/repair_pr787_payload_bound_once.py + run_contracts + fi + + python - <<'PY' + from pathlib import Path + + router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") + noema = Path(".github/workflows/agent-mention-noema-dispatch.yml").read_text(encoding="utf-8") + opencode = Path(".github/workflows/agent-mention-opencode-dispatch.yml").read_text(encoding="utf-8") + required_router = ( + '"base_branch": request.pull_request_base_branch', + '"requested_by": request.actor', + '"source_comment_id": request.comment_id', + ) + if not all(marker in router for marker in required_router): + raise SystemExit("router payload is not bound to the complete invocation identity") + for name, workflow in (("Noema", noema), ("OpenCode", opencode)): + if workflow.count("hmac.compare_digest") != 1: + raise SystemExit(f"{name} wrapper must verify exactly one canonical digest") + for marker in ("BASE_BRANCH:", "REQUESTED_BY:", "SOURCE_COMMENT_ID:"): + if marker not in workflow: + raise SystemExit(f"{name} wrapper is missing {marker}") + PY + git diff --check + + - name: Remove every PR 787 one-shot writer and repair artifact + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm -f \ + .github/pr787-payload-repair.trigger \ + .github/workflows/repair-pr787-payload-binding-push.yml \ + .github/workflows/repair-pr787-payload-bound-invocation.yml \ + .github/workflows/repair-pr787-payload-bound-v2.yml \ + .github/workflows/repair-pr787-payload-candidate.yml \ + .github/workflows/finalize-pr787-payload-binding.yml \ + .github/workflows/finalize-pr787-payload-binding-v2.yml \ + .github/workflows/finalize-pr787-payload-binding-v3.yml \ + .github/workflows/repair-pr787-dummy-issue-cleanup.yml \ + .github/workflows/cleanup-accidental-placeholder-issues-v2.yml \ + scripts/ci/apply_pr787_payload_binding.py \ + scripts/ci/repair_pr787_payload_bound_once.py + git diff --check + + - name: Verify complete focused quality on the durable final tree + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests + python - <<'PY' + from pathlib import Path + + forbidden = ( + Path(".github/pr787-payload-repair.trigger"), + Path(".github/workflows/repair-pr787-payload-binding-push.yml"), + Path(".github/workflows/repair-pr787-payload-bound-invocation.yml"), + Path(".github/workflows/repair-pr787-payload-bound-v2.yml"), + Path(".github/workflows/repair-pr787-payload-candidate.yml"), + Path(".github/workflows/finalize-pr787-payload-binding.yml"), + Path(".github/workflows/finalize-pr787-payload-binding-v2.yml"), + Path(".github/workflows/finalize-pr787-payload-binding-v3.yml"), + Path(".github/workflows/repair-pr787-dummy-issue-cleanup.yml"), + Path(".github/workflows/cleanup-accidental-placeholder-issues-v2.yml"), + Path("scripts/ci/apply_pr787_payload_binding.py"), + Path("scripts/ci/repair_pr787_payload_bound_once.py"), + ) + remaining = [str(path) for path in forbidden if path.exists()] + if remaining: + raise SystemExit(f"one-shot artifacts remain: {remaining}") + PY + git diff --check + + - name: Publish exact verified durable tree + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git diff --cached --quiet && { echo '::error::No durable final-tree change was produced.'; exit 1; } + git commit -m "fix(automation): bind invocation keys to complete payloads" + test -n "$PUSH_TOKEN" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 0cec3e0f6714737acca79cb7e686f6994565af00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:25:27 +0000 Subject: [PATCH 093/138] fix(automation): bind invocation keys to complete payloads --- ...eanup-accidental-placeholder-issues-v2.yml | 147 -------------- .../finalize-pr787-payload-binding-v3.yml | 186 ------------------ 2 files changed, 333 deletions(-) delete mode 100644 .github/workflows/cleanup-accidental-placeholder-issues-v2.yml delete mode 100644 .github/workflows/finalize-pr787-payload-binding-v3.yml diff --git a/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml b/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml deleted file mode 100644 index e885db0bf..000000000 --- a/.github/workflows/cleanup-accidental-placeholder-issues-v2.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: Clean exact accidental placeholder issues v2 - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/cleanup-accidental-placeholder-issues-v2.yml - -permissions: - contents: read - -concurrency: - group: cleanup-accidental-placeholder-issues-v2 - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - cleanup: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.actor == 'seonghobae' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - issues: write - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Close only exact accidental placeholders and remove accidental assignee - env: - API_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python3 - <<'PY' - from __future__ import annotations - - import datetime as dt - import json - import os - import urllib.error - import urllib.parse - import urllib.request - - repository = "ContextualWisdomLab/.github" - token = os.environ["API_TOKEN"] - api_root = f"https://api.github.com/repos/{repository}" - cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(hours=24) - - def request(method: str, endpoint: str, payload: dict[str, object] | None = None): - data = None if payload is None else json.dumps(payload).encode("utf-8") - call = urllib.request.Request( - api_root + endpoint, - data=data, - method=method, - headers={ - "Accept": "application/vnd.github+json", - "Authorization": f"Bearer {token}", - "X-GitHub-Api-Version": "2022-11-28", - "User-Agent": "cwl-exact-placeholder-cleanup-v2", - }, - ) - try: - with urllib.request.urlopen(call, timeout=30) as response: - raw = response.read() - return None if not raw else json.loads(raw) - except urllib.error.HTTPError as error: - if method == "DELETE" and error.code in {404, 422}: - return None - raise - - query = urllib.parse.urlencode( - { - "state": "open", - "creator": "seonghobae", - "sort": "created", - "direction": "desc", - "per_page": "100", - } - ) - issues = request("GET", f"/issues?{query}") or [] - closed: list[int] = [] - for issue in issues: - if "pull_request" in issue: - continue - created_at = dt.datetime.fromisoformat(issue["created_at"].replace("Z", "+00:00")) - if created_at < cutoff: - continue - if issue.get("title") != "dummy": - continue - if (issue.get("body") or "").strip() != "dummy": - continue - if issue.get("user", {}).get("login") != "seonghobae": - continue - number = int(issue["number"]) - request( - "PATCH", - f"/issues/{number}", - {"state": "closed", "state_reason": "not_planned"}, - ) - closed.append(number) - - request( - "DELETE", - "/issues/794/assignees", - {"assignees": ["coderabbitai"]}, - ) - print(f"closed_exact_placeholder_issues={len(closed)}") - PY - - - name: Remove the cleanup workflow and publish exact tree - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f .github/workflows/cleanup-accidental-placeholder-issues-v2.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo '::error::Cleanup workflow was not removed.'; exit 1; } - git commit -m "chore: remove exact placeholder cleanup workflow" - test -n "$PUSH_TOKEN" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" diff --git a/.github/workflows/finalize-pr787-payload-binding-v3.yml b/.github/workflows/finalize-pr787-payload-binding-v3.yml deleted file mode 100644 index 173bc3b30..000000000 --- a/.github/workflows/finalize-pr787-payload-binding-v3.yml +++ /dev/null @@ -1,186 +0,0 @@ -name: Finalize PR 787 payload binding v3 - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/finalize-pr787-payload-binding-v3.yml - -permissions: - contents: read - -concurrency: - group: finalize-pr787-payload-binding-v3 - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.actor == 'seonghobae' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 40 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Materialize the reviewed payload-bound product tree if required - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - run_contracts() { - python -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - } - - if ! run_contracts; then - test -f scripts/ci/repair_pr787_payload_bound_once.py - python scripts/ci/repair_pr787_payload_bound_once.py - run_contracts - fi - - python - <<'PY' - from pathlib import Path - - router = Path("scripts/ci/agent_mention_router.py").read_text(encoding="utf-8") - noema = Path(".github/workflows/agent-mention-noema-dispatch.yml").read_text(encoding="utf-8") - opencode = Path(".github/workflows/agent-mention-opencode-dispatch.yml").read_text(encoding="utf-8") - required_router = ( - '"base_branch": request.pull_request_base_branch', - '"requested_by": request.actor', - '"source_comment_id": request.comment_id', - ) - if not all(marker in router for marker in required_router): - raise SystemExit("router payload is not bound to the complete invocation identity") - for name, workflow in (("Noema", noema), ("OpenCode", opencode)): - if workflow.count("hmac.compare_digest") != 1: - raise SystemExit(f"{name} wrapper must verify exactly one canonical digest") - for marker in ("BASE_BRANCH:", "REQUESTED_BY:", "SOURCE_COMMENT_ID:"): - if marker not in workflow: - raise SystemExit(f"{name} wrapper is missing {marker}") - PY - git diff --check - - - name: Remove every PR 787 one-shot writer and repair artifact - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm -f \ - .github/pr787-payload-repair.trigger \ - .github/workflows/repair-pr787-payload-binding-push.yml \ - .github/workflows/repair-pr787-payload-bound-invocation.yml \ - .github/workflows/repair-pr787-payload-bound-v2.yml \ - .github/workflows/repair-pr787-payload-candidate.yml \ - .github/workflows/finalize-pr787-payload-binding.yml \ - .github/workflows/finalize-pr787-payload-binding-v2.yml \ - .github/workflows/finalize-pr787-payload-binding-v3.yml \ - .github/workflows/repair-pr787-dummy-issue-cleanup.yml \ - .github/workflows/cleanup-accidental-placeholder-issues-v2.yml \ - scripts/ci/apply_pr787_payload_binding.py \ - scripts/ci/repair_pr787_payload_bound_once.py - git diff --check - - - name: Verify complete focused quality on the durable final tree - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci/agent_mention_router.py scripts/ci/agent_mention_sweep.py tests - python - <<'PY' - from pathlib import Path - - forbidden = ( - Path(".github/pr787-payload-repair.trigger"), - Path(".github/workflows/repair-pr787-payload-binding-push.yml"), - Path(".github/workflows/repair-pr787-payload-bound-invocation.yml"), - Path(".github/workflows/repair-pr787-payload-bound-v2.yml"), - Path(".github/workflows/repair-pr787-payload-candidate.yml"), - Path(".github/workflows/finalize-pr787-payload-binding.yml"), - Path(".github/workflows/finalize-pr787-payload-binding-v2.yml"), - Path(".github/workflows/finalize-pr787-payload-binding-v3.yml"), - Path(".github/workflows/repair-pr787-dummy-issue-cleanup.yml"), - Path(".github/workflows/cleanup-accidental-placeholder-issues-v2.yml"), - Path("scripts/ci/apply_pr787_payload_binding.py"), - Path("scripts/ci/repair_pr787_payload_bound_once.py"), - ) - remaining = [str(path) for path in forbidden if path.exists()] - if remaining: - raise SystemExit(f"one-shot artifacts remain: {remaining}") - PY - git diff --check - - - name: Publish exact verified durable tree - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git diff --cached --quiet && { echo '::error::No durable final-tree change was produced.'; exit 1; } - git commit -m "fix(automation): bind invocation keys to complete payloads" - test -n "$PUSH_TOKEN" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 6e85bd6feace74e53cbb6007c72a83e29e91cc3e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:18:20 +0900 Subject: [PATCH 094/138] test(automation): prove rejected mentions are mutation-free --- ...est_agent_mention_rejection_idempotency.py | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/test_agent_mention_rejection_idempotency.py diff --git a/tests/test_agent_mention_rejection_idempotency.py b/tests/test_agent_mention_rejection_idempotency.py new file mode 100644 index 000000000..843454f3d --- /dev/null +++ b/tests/test_agent_mention_rejection_idempotency.py @@ -0,0 +1,66 @@ +"""Regression coverage for rejection-only agent mentions.""" + +from __future__ import annotations + +import importlib.util +import sys +from pathlib import Path +from types import ModuleType + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + +def load_module() -> ModuleType: + """Load the router module from its script path.""" + + module_name = "agent_mention_router_rejection_idempotency" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +class FakeClient: + """Capture bounded GitHub API calls for one router invocation.""" + + def __init__(self) -> None: + """Initialize an empty request ledger.""" + + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Record a request and return an empty workflow-run inventory.""" + + self.calls.append((list(args), input_payload)) + if args[0].endswith("/runs"): + return {"workflow_runs": []} + return None + + +def test_rejected_only_request_is_mutation_free() -> None: + """A disallowed OpenCode mention never creates repeatable target mutations.""" + + module = load_module() + request = module.MentionRequest( + "ContextualWisdomLab/example", + 17, + "a" * 40, + "main", + 91, + "maintainer", + ("opencode-agent",), + ) + target = FakeClient() + central = FakeClient() + + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + ) == () + assert target.calls == [] + assert central.calls == [] From 3ea8586b7c281c1f1682fb2f36014510b3cd7b02 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:19:58 +0900 Subject: [PATCH 095/138] ci(automation): execute complete exact-range quality gate --- .../agent-mention-router-quality-ci.yml | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index 36a8d43a9..658c6beca 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -8,9 +8,12 @@ on: - ".github/workflows/agent-mention-router-quality-ci.yml" - ".github/workflows/agent-mention-noema-dispatch.yml" - ".github/workflows/agent-mention-opencode-dispatch.yml" + - "docs/automation/review-agent-comment-invocation.md" + - "scripts/ci/agent_mention_invocation.py" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" + - "tests/test_pr_review_fix_scheduler_coverage.py" - "requirements-opencode-review-ci-hashes.txt" push: branches: [main] @@ -19,9 +22,12 @@ on: - ".github/workflows/agent-mention-router-quality-ci.yml" - ".github/workflows/agent-mention-noema-dispatch.yml" - ".github/workflows/agent-mention-opencode-dispatch.yml" + - "docs/automation/review-agent-comment-invocation.md" + - "scripts/ci/agent_mention_invocation.py" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" + - "tests/test_pr_review_fix_scheduler_coverage.py" - "requirements-opencode-review-ci-hashes.txt" concurrency: @@ -43,11 +49,39 @@ jobs: uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - - name: Checkout exact head + - name: Checkout exact head with comparison history uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 persist-credentials: false + - name: Determine exact changed range + env: + PR_BASE_SHA: ${{ github.event.pull_request.base.sha || '' }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || '' }} + PUSH_BEFORE_SHA: ${{ github.event.before || '' }} + PUSH_HEAD_SHA: ${{ github.sha }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then + base_sha="$PR_BASE_SHA" + head_sha="$PR_HEAD_SHA" + diff_range="${base_sha}...${head_sha}" + else + base_sha="$PUSH_BEFORE_SHA" + head_sha="$PUSH_HEAD_SHA" + if [[ "$base_sha" =~ ^0+$ ]]; then + base_sha="$(git rev-parse "${head_sha}^")" + fi + diff_range="${base_sha}..${head_sha}" + fi + git cat-file -e "${base_sha}^{commit}" + git cat-file -e "${head_sha}^{commit}" + { + echo "CHANGE_BASE_SHA=$base_sha" + echo "CHANGE_HEAD_SHA=$head_sha" + echo "CHANGE_DIFF_RANGE=$diff_range" + } >>"$GITHUB_ENV" - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -58,7 +92,7 @@ jobs: run: >- python -m pip install --disable-pip-version-check --require-hashes -r requirements-opencode-review-ci-hashes.txt - - name: Run complete focused branch coverage + - name: Run complete repository suite and bounded branch coverage shell: bash --noprofile --norc -e -o pipefail {0} run: | cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' @@ -73,24 +107,10 @@ jobs: EOF export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py + python -m coverage run -m pytest -q python -m coverage report --fail-under=100 python -m interrogate --fail-under=100 \ scripts/ci/agent_mention_router.py \ scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - git diff --check + python -m compileall -q scripts/ci tests + git diff --check "$CHANGE_DIFF_RANGE" From 26c859aaf2c0949e4c805fbf90b1834c01a0279c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:31:08 +0900 Subject: [PATCH 096/138] chore(automation): stage deterministic PR 787 review repairs --- scripts/ci/finalize_pr787_review_findings.py | 1632 ++++++++++++++++++ 1 file changed, 1632 insertions(+) create mode 100644 scripts/ci/finalize_pr787_review_findings.py diff --git a/scripts/ci/finalize_pr787_review_findings.py b/scripts/ci/finalize_pr787_review_findings.py new file mode 100644 index 000000000..b443f55a4 --- /dev/null +++ b/scripts/ci/finalize_pr787_review_findings.py @@ -0,0 +1,1632 @@ +#!/usr/bin/env python3 +"""Apply the final deterministic review-finding repairs for PR 787.""" + +from __future__ import annotations + +from pathlib import Path +from textwrap import dedent + +ROOT = Path(__file__).resolve().parents[2] + + +def read(path: str) -> str: + """Read one repository file as UTF-8 text.""" + + return (ROOT / path).read_text(encoding="utf-8") + + +def write(path: str, content: str) -> None: + """Write one repository file as normalized UTF-8 text.""" + + target = ROOT / path + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(content.rstrip() + "\n", encoding="utf-8") + + +def replace_once(path: str, old: str, new: str) -> None: + """Replace exactly one literal block and fail on an unexpected source tree.""" + + content = read(path) + count = content.count(old) + if count != 1: + raise RuntimeError(f"{path}: expected one replacement target, found {count}") + write(path, content.replace(old, new, 1)) + + +def replace_between(path: str, start: str, end: str, replacement: str) -> None: + """Replace one section delimited by stable function markers.""" + + content = read(path) + start_index = content.index(start) + end_index = content.index(end, start_index) + write(path, content[:start_index] + replacement.rstrip() + "\n\n" + content[end_index + 1 :]) + + +def update_router() -> None: + """Harden validation, diagnostics, durable-run lookup, and rejection idempotency.""" + + path = "scripts/ci/agent_mention_router.py" + replace_once( + path, + "import subprocess\nfrom dataclasses import dataclass\nfrom typing import Any, Sequence\n", + "import subprocess\nfrom dataclasses import dataclass\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Sequence\n", + ) + replace_once( + path, + 'BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$")\nRECEIPT_RE = re.compile(r"")\nMAX_WORKFLOW_RUN_RECORDS = 10_000\n', + 'BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$")\nACTOR_RE = re.compile(r"^[A-Za-z0-9-]+$")\nRECEIPT_RE = re.compile(r"")\nINVOCATION_MARKER_RE = re.compile(r"\\[cwl-agent-invocation:[0-9a-f]{64}\\]")\nMAX_WORKFLOW_RUN_RECORDS = 10_000\nWORKFLOW_RUN_LOOKBACK_HOURS = 24 * 30\n', + ) + replace_once( + path, + dedent( + ''' + completed = subprocess.run( + command, + input=None if input_payload is None else json.dumps(input_payload), + text=True, + capture_output=True, + check=True, + env=environment, + ) + output = completed.stdout.strip() + return None if not output else json.loads(output) + ''' + ).strip(), + dedent( + ''' + completed = subprocess.run( + command, + input=None if input_payload is None else json.dumps(input_payload), + text=True, + capture_output=True, + check=False, + env=environment, + ) + return_code = int(getattr(completed, "returncode", 0)) + if return_code: + diagnostic = " ".join( + str(getattr(completed, "stderr", "") or "").split() + ) + if not diagnostic: + diagnostic = "no stderr output" + raise RuntimeError( + f"gh api failed with exit code {return_code}: {diagnostic[:2000]}" + ) + output = completed.stdout.strip() + return None if not output else json.loads(output) + ''' + ).strip(), + ) + replace_once( + path, + ' if not actor:\n raise ValueError("comment actor is missing")\n', + ' if not ACTOR_RE.fullmatch(actor):\n raise ValueError("comment actor is missing or invalid")\n', + ) + replace_once( + path, + " if request.repository in opencode_allowlist:\n", + " normalized_allowlist = {entry.casefold() for entry in opencode_allowlist}\n if request.repository.casefold() in normalized_allowlist:\n", + ) + replace_once( + path, + "def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]:\n", + dedent( + ''' + def workflow_run_cutoff( + *, + now: datetime | None = None, + lookback_hours: int = WORKFLOW_RUN_LOOKBACK_HOURS, + ) -> str: + """Return the UTC lower bound for durable wrapper-run lookup.""" + + current = now or datetime.now(timezone.utc) + if current.tzinfo is None: + raise ValueError("workflow-run cutoff time must be timezone-aware") + cutoff = current.astimezone(timezone.utc) - timedelta(hours=lookback_hours) + return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") + + + def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: + ''' + ).strip() + "\n", + ) + replace_between( + path, + "def dispatched_agents(\n", + "\ndef noema_payload(\n", + dedent( + ''' + def dispatched_agents( + request: MentionRequest, + dispatch_client: GitHubClient, + agents: Sequence[str] | None = None, + *, + workflow_run_since: str | None = None, + run_marker_cache: dict[str, set[str]] | None = None, + ) -> frozenset[str]: + """Return agents with a durable central run for this exact invocation. + + Workflow inventories are bounded by the same maximum 30-day window as + the scheduled source-comment sweep. A caller-owned marker cache avoids + repeating the same agent workflow query for every candidate in one run. + """ + + candidates = tuple(request.agents if agents is None else agents) + observed: set[str] = set() + cutoff = workflow_run_since or workflow_run_cutoff() + marker_cache = run_marker_cache if run_marker_cache is not None else {} + for agent in candidates: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS.get(agent) + if endpoint is None: + raise ValueError(f"unsupported agent: {agent}") + if endpoint not in marker_cache: + response = dispatch_client.request( + [ + endpoint, + "-X", + "GET", + "-f", + "event=repository_dispatch", + "-f", + f"created=>={cutoff}", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + markers: set[str] = set() + for run in _workflow_run_records(response): + run_id = run.get("id") + if ( + isinstance(run_id, int) + and run_id > 0 + and run.get("event") == "repository_dispatch" + ): + markers.update( + INVOCATION_MARKER_RE.findall( + str(run.get("display_title") or "") + ) + ) + marker_cache[endpoint] = markers + if agent_invocation_marker(request, agent) in marker_cache[endpoint]: + observed.add(agent) + return frozenset(observed) + ''' + ).strip(), + ) + replace_between( + path, + "def dispatch_request(\n", + "\ndef load_event(\n", + dedent( + ''' + def dispatch_request( + request: MentionRequest, + *, + target_client: GitHubClient, + dispatch_client: GitHubClient, + opencode_allowlist: frozenset[str], + dry_run: bool = False, + workflow_run_since: str | None = None, + run_marker_cache: dict[str, set[str]] | None = None, + ) -> tuple[str, ...]: + """Dispatch missing agents and acknowledge only newly queued work.""" + + dispatchable, rejected = eligible_agents( + request, + opencode_allowlist=opencode_allowlist, + ) + if dry_run: + handles = tuple(f"@{agent}" for agent in dispatchable) + print( + "DRY-RUN agent mention " + f"repo={request.repository} pr={request.pull_request_number} " + f"head={request.pull_request_head_sha} " + f"dispatch={','.join(dispatchable) or 'none'} " + f"reject={','.join(rejected) or 'none'}" + ) + return handles + + existing = dispatched_agents( + request, + dispatch_client, + dispatchable, + workflow_run_since=workflow_run_since, + run_marker_cache=run_marker_cache, + ) + missing = tuple(agent for agent in dispatchable if agent not in existing) + handles = tuple(f"@{agent}" for agent in missing) + if not missing: + if rejected: + print( + "Rejected agent mention without target mutation " + f"repo={request.repository} pr={request.pull_request_number} " + f"comment={request.comment_id} " + f"agents={','.join(rejected)}" + ) + return () + + dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" + if "cwl-noema-review" in missing: + dispatch_client.request( + [dispatch_endpoint, "-X", "POST"], + input_payload=noema_payload(request), + ) + if run_marker_cache is not None: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] + run_marker_cache.setdefault(endpoint, set()).add( + agent_invocation_marker(request, "cwl-noema-review") + ) + if "opencode-agent" in missing: + dispatch_client.request( + [dispatch_endpoint, "-X", "POST"], + input_payload=opencode_payload(request), + ) + if run_marker_cache is not None: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] + run_marker_cache.setdefault(endpoint, set()).add( + agent_invocation_marker(request, "opencode-agent") + ) + + target_api = f"repos/{request.repository}" + target_client.request( + [ + f"{target_api}/issues/comments/{request.comment_id}/reactions", + "-X", + "POST", + ], + input_payload={"content": "eyes"}, + ) + status_parts: list[str] = [] + if handles: + status_parts.append(f"Queued {' and '.join(handles)}") + existing_handles = tuple( + f"@{agent}" for agent in dispatchable if agent in existing + ) + if existing_handles: + status_parts.append( + f"Already queued {' and '.join(existing_handles)} on this exact request" + ) + if rejected: + rejected_handles = " and ".join(f"@{agent}" for agent in rejected) + status_parts.append( + f"Rejected {rejected_handles}: repository is absent from " + "OPENCODE_REPOSITORY_DISPATCH_TARGETS" + ) + acknowledgement = ( + f"{receipt_marker(request.comment_id)}\n" + f"{' ; '.join(status_parts)} for PR #{request.pull_request_number} at head " + f"`{request.pull_request_head_sha}`. Central exact-key workflow runs are " + "the durable dispatch ledger; existing review workflows remain " + "authoritative for the final verdict and failure evidence." + ) + target_client.request( + [ + f"{target_api}/issues/{request.pull_request_number}/comments", + "-X", + "POST", + ], + input_payload={"body": acknowledgement}, + ) + return handles + ''' + ).strip(), + ) + + +def update_sweep() -> None: + """Make repository traversal lazy and isolate per-repository/candidate failures.""" + + path = "scripts/ci/agent_mention_sweep.py" + replace_once( + path, + "import re\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Iterator, Sequence\n", + "import re\nfrom dataclasses import dataclass\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Callable, Iterator, Sequence\n", + ) + replace_once( + path, + 'REPOSITORY_SOURCES = frozenset({"organization", "installation"})\n', + dedent( + ''' + REPOSITORY_SOURCES = frozenset({"organization", "installation"}) + + + @dataclass + class SweepMetrics: + """Mutable operational counters returned to the CLI boundary.""" + + failures: int = 0 + ''' + ).strip() + "\n", + ) + replace_once( + path, + dedent( + ''' + pages = value if isinstance(value, list) else [value] + records: list[dict[str, Any]] = [] + ''' + ).strip(), + dedent( + ''' + if ( + collection_key is None + and isinstance(value, list) + and all(isinstance(record, dict) for record in value) + ): + return list(value) + pages = value if isinstance(value, list) else [value] + records: list[dict[str, Any]] = [] + ''' + ).strip(), + ) + replace_between( + path, + "def list_recent_pull_requests(\n", + "\ndef list_recent_comments(\n", + dedent( + ''' + def list_recent_pull_requests( + client: GitHubClient, + *, + organization: str, + repository_source: str, + since: str, + on_error: Callable[[str, Exception], None] | None = None, + ) -> Iterator[dict[str, Any]]: + """Yield recent open pull requests with lazy cutoff-aware pagination.""" + + cutoff = parse_timestamp(since) + repositories = list_accessible_repositories( + client, + organization=organization, + repository_source=repository_source, + ) + for repository in repositories: + try: + page = 1 + while True: + response = client.request( + [ + f"repos/{repository}/pulls", + "-X", + "GET", + "-f", + "state=open", + "-f", + "sort=updated", + "-f", + "direction=desc", + "-f", + "per_page=100", + "-f", + f"page={page}", + ] + ) + pull_requests = flatten_pages(response) + if not pull_requests: + break + reached_cutoff = False + for pull_request in pull_requests: + if ( + parse_timestamp( + str(pull_request.get("updated_at") or "") + ) + < cutoff + ): + reached_cutoff = True + break + number = pull_request.get("number") + if not isinstance(number, int) or number < 1: + raise ValueError( + "GitHub returned an invalid pull request number" + ) + yield { + "number": number, + "repository": repository, + "pull_request": { + "url": ( + "https://api.github.com/repos/" + f"{repository}/pulls/{number}" + ) + }, + } + if reached_cutoff or len(pull_requests) < 100: + break + page += 1 + except Exception as exc: + if on_error is None: + raise + on_error(repository, exc) + ''' + ).strip(), + ) + replace_between( + path, + "def sweep(\n", + "\ndef main(\n", + dedent( + ''' + def sweep( + *, + target_client: GitHubClient, + dispatch_client: GitHubClient, + organization: str, + repository_source: str, + lookback_hours: int, + max_dispatches: int, + opencode_allowlist: frozenset[str], + dry_run: bool = False, + now: datetime | None = None, + metrics: SweepMetrics | None = None, + ) -> int: + """Queue bounded new work while isolating candidate-local failures.""" + + if max_dispatches < 1 or max_dispatches > 100: + raise ValueError("max dispatches must be between 1 and 100") + since = cutoff_timestamp(lookback_hours, now=now) + counters = metrics if metrics is not None else SweepMetrics() + run_marker_cache: dict[str, set[str]] = {} + dispatched = 0 + + def record_failure(scope: str, error: Exception) -> None: + """Record one isolated error and preserve the remaining sweep.""" + + counters.failures += 1 + message = " ".join(str(error).split()) or error.__class__.__name__ + print(f"::warning::Agent mention sweep skipped {scope}: {message[:1000]}") + + for issue in list_recent_pull_requests( + target_client, + organization=organization, + repository_source=repository_source, + since=since, + on_error=record_failure, + ): + issue_scope = f"{issue.get('repository')}#{issue.get('number')}" + try: + requests = build_requests_for_pull_request( + target_client, + issue=issue, + since=since, + ) + except Exception as exc: + record_failure(issue_scope, exc) + continue + for request in requests: + request_scope = f"{issue_scope}/comment-{request.comment_id}" + try: + queued_agents = dispatch_request( + request, + target_client=target_client, + dispatch_client=dispatch_client, + opencode_allowlist=opencode_allowlist, + dry_run=dry_run, + workflow_run_since=since, + run_marker_cache=run_marker_cache, + ) + except Exception as exc: + record_failure(request_scope, exc) + continue + if not queued_agents: + continue + dispatched += 1 + if dispatched >= max_dispatches: + print( + "Agent mention sweep reached dispatch limit " + f"{max_dispatches}; isolated failures={counters.failures}." + ) + return dispatched + print( + "Agent mention sweep completed with " + f"{dispatched} dispatch(es) and {counters.failures} isolated failure(s)." + ) + return dispatched + ''' + ).strip(), + ) + replace_once( + path, + dedent( + ''' + sweep( + target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), + dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), + organization=args.organization, + repository_source=args.repository_source, + lookback_hours=args.lookback_hours, + max_dispatches=args.max_dispatches, + opencode_allowlist=allowlist, + dry_run=args.dry_run, + ) + return 0 + ''' + ).strip(), + dedent( + ''' + metrics = SweepMetrics() + sweep( + target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), + dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), + organization=args.organization, + repository_source=args.repository_source, + lookback_hours=args.lookback_hours, + max_dispatches=args.max_dispatches, + opencode_allowlist=allowlist, + dry_run=args.dry_run, + metrics=metrics, + ) + return 1 if metrics.failures else 0 + ''' + ).strip(), + ) + + +def wrapper_workflow(agent: str) -> str: + """Return one complete resilient agent-wrapper workflow.""" + + if agent == "noema": + display = "Noema" + requested_agent = "cwl-noema-review" + workflow_file = "agent-mention-noema-dispatch.yml" + source_event = "agent-mention-noema" + target_event = "noema-review" + extra_env = "" + extra_validation = "" + forwarded_controls = "" + target_label = "authoritative Noema workflow" + else: + display = "OpenCode" + requested_agent = "opencode-agent" + workflow_file = "agent-mention-opencode-dispatch.yml" + source_event = "agent-mention-opencode" + target_event = "merge-scheduler" + extra_env = dedent( + ''' + TRIGGER_REVIEWS: ${{ github.event.client_payload.trigger_reviews }} + REVIEW_DISPATCH_LIMIT: ${{ github.event.client_payload.review_dispatch_limit || '' }} + ENABLE_AUTO_MERGE: ${{ github.event.client_payload.enable_auto_merge }} + UPDATE_BRANCHES: ${{ github.event.client_payload.update_branches }} + MERGE_MODE: ${{ github.event.client_payload.merge_mode || '' }} + ''' + ) + extra_validation = dedent( + ''' + [ "$TRIGGER_REVIEWS" != "true" ] || + [ "$REVIEW_DISPATCH_LIMIT" != "1" ] || + [ "$ENABLE_AUTO_MERGE" != "false" ] || + [ "$UPDATE_BRANCHES" != "false" ] || + [ "$MERGE_MODE" != "disabled" ] || + ''' + ) + forwarded_controls = dedent( + ''' + trigger_reviews: true, + review_dispatch_limit: "1", + enable_auto_merge: false, + update_branches: false, + merge_mode: "disabled", + ''' + ) + target_label = "authoritative review-only scheduler" + + return dedent( + f''' + name: Agent Mention {display} Dispatch + run-name: >- + Agent Mention {display} ${{{{ github.event.client_payload.target_repository }}}}#${{{{ + github.event.client_payload.pr_number }}}} [cwl-agent-invocation:${{{{ + github.event.client_payload.agent_invocation_key }}}}] + + on: + repository_dispatch: + types: [{source_event}] + + concurrency: + group: agent-mention-{agent}-${{{{ github.event.client_payload.agent_invocation_key || github.run_id }}}} + cancel-in-progress: false + queue: max + + permissions: + contents: read + + jobs: + validate-and-forward: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + actions: read + contents: write + env: + GH_TOKEN: ${{{{ github.token }}}} + REQUESTED_AGENT: "{requested_agent}" + PAYLOAD_AGENT: ${{{{ github.event.client_payload.requested_agent || '' }}}} + INVOCATION_KEY: ${{{{ github.event.client_payload.agent_invocation_key || '' }}}} + TARGET_REPOSITORY: ${{{{ github.event.client_payload.target_repository || '' }}}} + PR_NUMBER: ${{{{ github.event.client_payload.pr_number || '' }}}} + PR_HEAD_SHA: ${{{{ github.event.client_payload.pr_head_sha || '' }}}} + BASE_BRANCH: ${{{{ github.event.client_payload.base_branch || '' }}}} + REQUESTED_BY: ${{{{ github.event.client_payload.requested_by || '' }}}} + SOURCE_COMMENT_ID: ${{{{ github.event.client_payload.source_comment_id || '' }}}} + {extra_env.rstrip()} + steps: + - name: Validate exact invocation and elect one durable leader + id: leader + run: | + set -euo pipefail + if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || + ! [[ "$INVOCATION_KEY" =~ ^[0-9a-f]{{64}}$ ]] || + ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || + ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{{40}}$ ]] || + ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || + [[ "$BASE_BRANCH" == -* ]] || + ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || + {extra_validation.rstrip()} + ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]]; then + echo "::error::Rejected malformed or mismatched {display} agent invocation payload." + exit 1 + fi + + python3 - <<'PYTHON' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + {{ + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }}, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + expected = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): + raise SystemExit("invocation key does not match canonical payload") + PYTHON + + marker="[cwl-agent-invocation:${{INVOCATION_KEY}}]" + matching_run_ids() {{ + gh api --paginate --slurp \\ + "repos/${{GITHUB_REPOSITORY}}/actions/workflows/{workflow_file}/runs?event=repository_dispatch&per_page=100" \\ + | jq -r --arg marker "$marker" ' + [.[].workflow_runs[] + | select((.display_title // "") | contains($marker)) + | .id] + | unique + | sort + | .[] + ' + }} + + for attempt in 1 2 3; do + run_ids="$(matching_run_ids)" + lower_id="$( + awk -v current="$GITHUB_RUN_ID" '$1 < current {{ print $1; exit }}' \\ + <<<"$run_ids" + )" + if [ -n "$lower_id" ]; then + echo "forward=false" >>"$GITHUB_OUTPUT" + echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." + exit 0 + fi + if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then + echo "forward=true" >>"$GITHUB_OUTPUT" + exit 0 + fi + if [ "$attempt" -lt 3 ]; then + sleep "$((attempt * 2))" + fi + done + + echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." + echo "forward=true" >>"$GITHUB_OUTPUT" + + - name: Forward once to the {target_label} + if: steps.leader.outputs.forward == 'true' + run: | + set -euo pipefail + jq -n \\ + --arg target_repository "$TARGET_REPOSITORY" \\ + --argjson pr_number "$PR_NUMBER" \\ + --arg pr_head_sha "$PR_HEAD_SHA" \\ + --arg base_branch "$BASE_BRANCH" \\ + --arg requested_agent "$REQUESTED_AGENT" \\ + --arg agent_invocation_key "$INVOCATION_KEY" \\ + --arg requested_by "$REQUESTED_BY" \\ + --argjson source_comment_id "$SOURCE_COMMENT_ID" \\ + '{{ + event_type: "{target_event}", + client_payload: {{ + target_repository: $target_repository, + pr_number: $pr_number, + pr_head_sha: $pr_head_sha, + base_branch: $base_branch, + {forwarded_controls.rstrip()} + requested_agent: $requested_agent, + agent_invocation_key: $agent_invocation_key, + requested_by: $requested_by, + source_comment_id: $source_comment_id + }} + }}' \\ + | gh api "repos/${{GITHUB_REPOSITORY}}/dispatches" -X POST --input - + ''' + ) + + +def update_workflows() -> None: + """Harden wrapper election and keep exchanged credentials out of step outputs.""" + + write( + ".github/workflows/agent-mention-noema-dispatch.yml", + wrapper_workflow("noema"), + ) + write( + ".github/workflows/agent-mention-opencode-dispatch.yml", + wrapper_workflow("opencode"), + ) + path = ".github/workflows/agent-mention-router.yml" + content = read(path) + content = content.replace( + "curl -fsS \\\n -H \"Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}\"", + "curl -fsS --connect-timeout 10 --max-time 30 \\\n -H \"Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}\"", + ) + content = content.replace( + "curl -fsS \\\n -X POST \\\n -H \"Authorization: Bearer ${oidc_token}\"", + "curl -fsS --connect-timeout 10 --max-time 30 \\\n -X POST \\\n -H \"Authorization: Bearer ${oidc_token}\"", + ) + old_output = dedent( + ''' + { + echo "available=true" + echo "token=$app_token" + } >>"$GITHUB_OUTPUT" + ''' + ).strip() + new_output = dedent( + ''' + echo "available=true" >>"$GITHUB_OUTPUT" + echo "SWEEP_APP_TOKEN=$app_token" >>"$GITHUB_ENV" + ''' + ).strip() + if old_output not in content: + raise RuntimeError("agent-mention-router.yml: token output block changed") + content = content.replace(old_output, new_output, 1) + old_step = dedent( + ''' + - name: Sweep recent organization PR comments + env: + TARGET_REPOSITORY_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.sweep_app_token.outputs.token }} + TARGET_REPOSITORY_SOURCE: ${{ (secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '') && 'organization' || steps.sweep_app_token.outputs.available == 'true' && 'installation' || '' }} + AGENT_DISPATCH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [ -z "${TARGET_REPOSITORY_TOKEN:-}" ] || [ -z "${TARGET_REPOSITORY_SOURCE:-}" ]; then + echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." + exit 1 + fi + args=( + --organization ContextualWisdomLab + --repository-source "$TARGET_REPOSITORY_SOURCE" + --lookback-hours "$LOOKBACK_HOURS" + --max-dispatches "$MAX_DISPATCHES" + ) + if [ "$DRY_RUN" = "true" ]; then + args+=(--dry-run) + fi + python3 scripts/ci/agent_mention_sweep.py "${args[@]}" + ''' + ).strip() + new_step = dedent( + ''' + - name: Sweep recent organization PR comments + env: + PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} + AGENT_DISPATCH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [ -n "$PR_REVIEW_MERGE_TOKEN" ]; then + TARGET_REPOSITORY_TOKEN="$PR_REVIEW_MERGE_TOKEN" + TARGET_REPOSITORY_SOURCE="organization" + elif [ -n "$OPENCODE_APPROVE_TOKEN" ]; then + TARGET_REPOSITORY_TOKEN="$OPENCODE_APPROVE_TOKEN" + TARGET_REPOSITORY_SOURCE="organization" + else + TARGET_REPOSITORY_TOKEN="${SWEEP_APP_TOKEN:-}" + TARGET_REPOSITORY_SOURCE="${TARGET_REPOSITORY_TOKEN:+installation}" + fi + export TARGET_REPOSITORY_TOKEN + if [ -z "$TARGET_REPOSITORY_TOKEN" ] || [ -z "$TARGET_REPOSITORY_SOURCE" ]; then + echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." + exit 1 + fi + args=( + --organization ContextualWisdomLab + --repository-source "$TARGET_REPOSITORY_SOURCE" + --lookback-hours "$LOOKBACK_HOURS" + --max-dispatches "$MAX_DISPATCHES" + ) + if [ "$DRY_RUN" = "true" ]; then + args+=(--dry-run) + fi + python3 scripts/ci/agent_mention_sweep.py "${args[@]}" + ''' + ).strip() + if old_step not in content: + raise RuntimeError("agent-mention-router.yml: sweep step changed") + write(path, content.replace(old_step, new_step, 1)) + + quality_path = ".github/workflows/agent-mention-router-quality-ci.yml" + quality = read(quality_path).replace( + ' - "scripts/ci/agent_mention_invocation.py"\n', "" + ) + write(quality_path, quality) + + +def update_tests() -> None: + """Add executable regressions and repair full-suite-only brittle assertions.""" + + router_test_path = "tests/test_agent_mention_router.py" + old = dedent( + ''' + def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( + capsys, + ) -> None: + """OpenCode fails closed outside its allowlist while dry-run is mutation-free.""" + + module = load_module() + request = module.parse_event(event("@opencode-agent")) + assert request is not None + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + ) == () + assert central.calls == [] + assert "Rejected @opencode-agent" in target.calls[-1][1]["body"] + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + dry_run=True, + ) == () + assert target.calls == central.calls == [] + output = capsys.readouterr().out + assert "DRY-RUN agent mention" in output + assert "reject=opencode-agent" in output + ''' + ).strip() + new = dedent( + ''' + def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( + capsys, + ) -> None: + """Rejected-only and dry-run requests remain mutation-free.""" + + module = load_module() + request = module.parse_event(event("@opencode-agent")) + assert request is not None + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + ) == () + assert target.calls == central.calls == [] + assert "Rejected agent mention without target mutation" in capsys.readouterr().out + + target = FakeClient() + central = FakeClient() + assert module.dispatch_request( + request, + target_client=target, + dispatch_client=central, + opencode_allowlist=frozenset(), + dry_run=True, + ) == () + assert target.calls == central.calls == [] + output = capsys.readouterr().out + assert "DRY-RUN agent mention" in output + assert "reject=opencode-agent" in output + ''' + ).strip() + replace_once(router_test_path, old, new) + + write( + "tests/test_pr_review_fix_scheduler_coverage.py", + dedent( + ''' + """Coverage-only regressions for the review-fix scheduler.""" + + import builtins + import runpy + + import scripts.ci.pr_review_fix_scheduler as fix + + + def test_import_falls_back_to_package_module(monkeypatch): + """The scheduler remains importable when only the package path is available.""" + + real_import = builtins.__import__ + + def import_without_script_directory( + name, + globals_=None, + locals_=None, + fromlist=(), + level=0, + ): + """Reject the script-directory import and delegate every other import.""" + + if name == "pr_review_merge_scheduler": + raise ModuleNotFoundError(name) + return real_import(name, globals_, locals_, fromlist, level) + + monkeypatch.setattr( + builtins, + "__import__", + import_without_script_directory, + ) + namespace = runpy.run_path( + "scripts/ci/pr_review_fix_scheduler.py", + run_name="pr_review_fix_scheduler_package_fallback_test", + ) + + loaded = namespace["fetch_open_prs"] + assert loaded.__name__ == fix.fetch_open_prs.__name__ + assert loaded.__code__.co_filename == fix.fetch_open_prs.__code__.co_filename + + + def test_coverage_process_queue_skips_draft_and_wrong_base_and_external_repo(monkeypatch): + """Draft, wrong-base, and external-head PRs are skipped.""" + + def make_pr(number=1, **kwargs): + pr = { + "number": number, + "headRefOid": "abc", + "baseRefName": "main", + "headRefName": "feature", + "isDraft": False, + "headRepository": {"nameWithOwner": "owner/repo"}, + } + pr.update(kwargs) + return pr + + args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) + pr1 = make_pr(number=1, isDraft=True) + pr2 = make_pr(number=2, baseRefName="other") + pr3 = make_pr(number=3, headRepository={"nameWithOwner": "fork/repo"}) + monkeypatch.setattr( + fix, + "fetch_open_prs", + lambda repo, max_prs: [pr1, pr2, pr3], + ) + monkeypatch.setattr( + fix, + "inspect_pr", + lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), + ) + assert fix.process_queue(args) == 0 + + + def test_coverage_process_queue_exception_handling(monkeypatch): + """One issue-comment lookup failure does not crash queue processing.""" + + def make_pr(number=1, **kwargs): + pr = { + "number": number, + "headRefOid": "abc", + "baseRefName": "main", + "headRefName": "feature", + "isDraft": False, + "headRepository": {"nameWithOwner": "owner/repo"}, + } + pr.update(kwargs) + return pr + + args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) + pr1 = make_pr(number=1) + pr2 = make_pr(number=2) + monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2]) + monkeypatch.setattr(fix, "needs_autofix", lambda pr: (True, ("reason",))) + + def raise_error(repo, number): + raise RuntimeError("boom") + + monkeypatch.setattr(fix, "issue_comments", raise_error) + monkeypatch.setattr( + fix, + "inspect_pr", + lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), + ) + assert fix.process_queue(args) == 0 + ''' + ), + ) + + write( + "tests/test_agent_mention_downstream_idempotency.py", + dedent( + ''' + """Static contracts for downstream review-agent invocation idempotency.""" + + from pathlib import Path + + ROOT = Path(__file__).resolve().parents[1] + ROUTER_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" + QUALITY_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" + NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" + OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" + ROUTER_SCRIPT = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + + def test_router_can_read_durable_central_workflow_runs() -> None: + """Both local routing and sibling sweeping receive actions read access.""" + + text = ROUTER_WORKFLOW.read_text(encoding="utf-8") + local, sweep = text.split("\n sweep-organization-agent-mentions:\n", 1) + assert "permissions:\n actions: read" in local + assert "permissions:\n actions: read" in sweep + assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in local + assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep + + + def test_downstream_workflows_retry_visibility_and_bind_exact_key() -> None: + """Wrappers queue duplicates and never lose a request to eventual consistency.""" + + noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") + opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") + for text in (noema, opencode): + assert "github.event.client_payload.agent_invocation_key" in text + assert "cwl-agent-invocation:" in text + assert "source_comment_id" in text + assert "requested_agent" in text + assert "cancel-in-progress: false" in text + assert "queue: max" in text + assert "for attempt in 1 2 3" in text + assert 'sleep "$((attempt * 2))"' in text + assert "no lower durable run was observed" in text + assert "^[0-9a-f]{64}$" in text + assert "^[1-9][0-9]*$" in text + assert "repos/${GITHUB_REPOSITORY}/dispatches" in text + assert "types: [agent-mention-noema]" in noema + assert 'event_type: "noema-review"' in noema + assert 'REQUESTED_AGENT: "cwl-noema-review"' in noema + assert "types: [agent-mention-opencode]" in opencode + assert 'event_type: "merge-scheduler"' in opencode + assert 'REQUESTED_AGENT: "opencode-agent"' in opencode + assert '[[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' in opencode + assert '[[ "$BASE_BRANCH" == -* ]]' in opencode + + + def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: + """A syntactically valid key cannot authorize altered payload fields.""" + + router = ROUTER_SCRIPT.read_text(encoding="utf-8") + noema_function = router.split("def noema_payload", 1)[1].split( + "def opencode_payload", 1 + )[0] + assert '"base_branch": request.pull_request_base_branch' in noema_function + + canonical_fields = ( + '"actor"', + '"agent"', + '"base_branch"', + '"comment_id"', + '"head_sha"', + '"pr_number"', + '"repository"', + ) + for text in ( + NOEMA_WORKFLOW.read_text(encoding="utf-8"), + OPENCODE_WORKFLOW.read_text(encoding="utf-8"), + ): + assert "BASE_BRANCH:" in text + assert "import hashlib" in text + assert "import hmac" in text + assert "json.dumps(" in text + assert 'separators=(",", ":")' in text + assert "sort_keys=True" in text + assert "hashlib.sha256" in text + assert "hmac.compare_digest" in text + assert "INVOCATION_KEY" in text + for field in canonical_fields: + assert field in text + + + def test_quality_gate_runs_full_suite_for_docs_and_exact_diff() -> None: + """Every changed contract executes while coverage stays source-bounded.""" + + text = QUALITY_WORKFLOW.read_text(encoding="utf-8") + assert ' - "docs/automation/review-agent-comment-invocation.md"' in text + assert ' - "tests/test_agent_mention_*.py"' in text + assert "python -m coverage run -m pytest -q\n" in text + assert "python -m compileall -q scripts/ci tests" in text + assert "CHANGE_DIFF_RANGE" in text + assert 'git diff --check "$CHANGE_DIFF_RANGE"' in text + coverage_config = text.split("[run]\n", 1)[1].split("[report]\n", 1)[0] + assert "scripts/ci/agent_mention_router.py" in coverage_config + assert "scripts/ci/agent_mention_sweep.py" in coverage_config + ''' + ), + ) + + write( + "tests/test_agent_mention_review_regressions.py", + dedent( + ''' + """Review-driven runtime regressions for the agent mention control plane.""" + + from __future__ import annotations + + import importlib.util + import sys + from datetime import datetime, timezone + from pathlib import Path + from types import ModuleType, SimpleNamespace + + import pytest + + ROOT = Path(__file__).resolve().parents[1] + MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + + def load_module() -> ModuleType: + """Load the router under one isolated module name.""" + + module_name = "agent_mention_router_review_regressions" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + + def request(module: ModuleType, agents=("cwl-noema-review", "opencode-agent")): + """Build one exact invocation request.""" + + return module.MentionRequest( + "ContextualWisdomLab/Example", + 17, + "a" * 40, + "main", + 91, + "maintainer", + agents, + ) + + + class FakeClient: + """Capture API requests and expose endpoint-keyed run inventories.""" + + def __init__(self, responses=None) -> None: + """Initialize responses and an empty call ledger.""" + + self.responses = responses or {} + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Record a call and return its registered response.""" + + self.calls.append((list(args), input_payload)) + if args[0].endswith("/runs"): + return self.responses.get(args[0], {"workflow_runs": []}) + return None + + + def test_actor_and_allowlist_validation_are_wrapper_compatible() -> None: + """Router validation rejects actors wrappers cannot accept.""" + + module = load_module() + payload = { + "repository": {"full_name": "ContextualWisdomLab/Example"}, + "issue": {"number": 17, "pull_request": {"url": "x"}}, + "comment": { + "id": 91, + "body": "@opencode-agent", + "author_association": "MEMBER", + "user": {"login": "bad_actor", "type": "User"}, + }, + "pull_request": { + "state": "open", + "head": {"sha": "a" * 40}, + "base": {"ref": "main"}, + }, + } + with pytest.raises(ValueError, match="actor"): + module.parse_event(payload) + + mention = request(module, ("opencode-agent",)) + assert module.eligible_agents( + mention, + opencode_allowlist=frozenset({"contextualwisdomlab/example"}), + ) == (("opencode-agent",), ()) + + + @pytest.mark.parametrize( + ("stderr", "message"), + [("permission denied\n details", "permission denied details"), ("", "no stderr")], + ) + def test_github_client_surfaces_bounded_api_diagnostics( + monkeypatch, + stderr: str, + message: str, + ) -> None: + """A failed gh call identifies the real API boundary.""" + + module = load_module() + monkeypatch.setattr( + module.subprocess, + "run", + lambda *args, **kwargs: SimpleNamespace( + stdout="", + stderr=stderr, + returncode=1, + ), + ) + with pytest.raises(RuntimeError, match=message): + module.GitHubClient("token").request(["repos/x/y"]) + + + def test_workflow_run_cutoff_and_marker_cache_bound_api_cost() -> None: + """Each agent workflow inventory is queried once per sweep window.""" + + module = load_module() + now = datetime(2026, 8, 6, 12, tzinfo=timezone.utc) + cutoff = module.workflow_run_cutoff(now=now, lookback_hours=24) + assert cutoff == "2026-08-05T12:00:00Z" + with pytest.raises(ValueError, match="timezone-aware"): + module.workflow_run_cutoff(now=datetime(2026, 8, 6)) + + mention = request(module) + noema_endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] + noema_marker = module.agent_invocation_marker( + mention, "cwl-noema-review" + ) + client = FakeClient( + { + noema_endpoint: { + "workflow_runs": [ + { + "id": 1, + "event": "repository_dispatch", + "display_title": f"run {noema_marker}", + } + ] + } + } + ) + cache: dict[str, set[str]] = {} + expected = frozenset({"cwl-noema-review"}) + assert module.dispatched_agents( + mention, + client, + workflow_run_since=cutoff, + run_marker_cache=cache, + ) == expected + assert module.dispatched_agents( + mention, + client, + workflow_run_since=cutoff, + run_marker_cache=cache, + ) == expected + run_calls = [args for args, _ in client.calls if args[0].endswith("/runs")] + assert len(run_calls) == 2 + assert all(f"created=>={cutoff}" in args for args in run_calls) + + + def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> None: + """Accepted dispatches update the in-memory ledger before wrapper visibility.""" + + module = load_module() + mention = request(module) + target = FakeClient() + central = FakeClient() + cache: dict[str, set[str]] = {} + allowlist = frozenset({"contextualwisdomlab/example"}) + + assert module.dispatch_request( + mention, + target_client=target, + dispatch_client=central, + opencode_allowlist=allowlist, + workflow_run_since="2026-08-01T00:00:00Z", + run_marker_cache=cache, + ) == ("@cwl-noema-review", "@opencode-agent") + first_target_calls = len(target.calls) + assert module.dispatch_request( + mention, + target_client=target, + dispatch_client=central, + opencode_allowlist=allowlist, + workflow_run_since="2026-08-01T00:00:00Z", + run_marker_cache=cache, + ) == () + assert len(target.calls) == first_target_calls + dispatches = [ + payload["event_type"] + for args, payload in central.calls + if args[0].endswith("/dispatches") and payload + ] + assert dispatches == ["agent-mention-noema", "agent-mention-opencode"] + + mixed = request(module) + mixed_target = FakeClient() + mixed_central = FakeClient() + mixed_cache: dict[str, set[str]] = {} + assert module.dispatch_request( + mixed, + target_client=mixed_target, + dispatch_client=mixed_central, + opencode_allowlist=frozenset(), + run_marker_cache=mixed_cache, + ) == ("@cwl-noema-review",) + first_mixed_calls = len(mixed_target.calls) + assert module.dispatch_request( + mixed, + target_client=mixed_target, + dispatch_client=mixed_central, + opencode_allowlist=frozenset(), + run_marker_cache=mixed_cache, + ) == () + assert len(mixed_target.calls) == first_mixed_calls + ''' + ), + ) + + write( + "tests/test_agent_mention_sweep_regressions.py", + dedent( + ''' + """Review-driven pagination and failure-isolation regressions.""" + + from __future__ import annotations + + import importlib + import sys + from datetime import datetime, timezone + from pathlib import Path + + import pytest + + ROOT = Path(__file__).resolve().parents[1] + SCRIPTS = ROOT / "scripts" / "ci" + sys.path.insert(0, str(SCRIPTS)) + + + def module(): + """Reload the sweep module for isolated monkeypatching.""" + + return importlib.reload(importlib.import_module("agent_mention_sweep")) + + + def repository(name: str) -> dict: + """Build one active organization repository record.""" + + return { + "full_name": f"ContextualWisdomLab/{name}", + "owner": {"login": "ContextualWisdomLab"}, + "archived": False, + "disabled": False, + } + + + class PagingClient: + """Serve page-aware endpoint responses and deterministic failures.""" + + def __init__(self, responses) -> None: + """Initialize an endpoint/page response map.""" + + self.responses = responses + self.calls: list[list[str]] = [] + + def request(self, args, *, input_payload=None): + """Return one endpoint/page response or raise its configured error.""" + + del input_payload + args = list(args) + self.calls.append(args) + endpoint = args[0] + page = 1 + for index, value in enumerate(args[:-1]): + if value == "-f" and args[index + 1].startswith("page="): + page = int(args[index + 1].split("=", 1)[1]) + response = self.responses[(endpoint, page)] + if isinstance(response, Exception): + raise response + return response + + + def pull(number: int, updated_at: str = "2026-08-06T11:00:00Z") -> dict: + """Build one pull-list response record.""" + + return {"number": number, "updated_at": updated_at} + + + def test_pull_pagination_stops_at_cutoff_without_loading_later_pages() -> None: + """Updated-descending pages stop immediately at the first old record.""" + + sweep = module() + recent = [pull(number) for number in range(1, 101)] + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): recent, + ("repos/ContextualWisdomLab/example/pulls", 2): [ + pull(101, "2026-08-01T00:00:00Z") + ], + } + ) + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + assert len(results) == 100 + pull_calls = [ + args for args in client.calls if args[0].endswith("/pulls") + ] + assert len(pull_calls) == 2 + assert not any("page=3" in args for args in pull_calls) + assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] + + + def test_repository_failure_is_isolated_and_later_repository_runs() -> None: + """A repository-local API failure does not terminate organization traversal.""" + + sweep = module() + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[ + repository("broken"), + repository("healthy"), + ]], + ("repos/ContextualWisdomLab/broken/pulls", 1): RuntimeError( + "forbidden" + ), + ("repos/ContextualWisdomLab/healthy/pulls", 1): [pull(7)], + } + ) + failures = [] + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + on_error=lambda scope, error: failures.append( + (scope, str(error)) + ), + ) + ) + assert [result["repository"] for result in results] == [ + "ContextualWisdomLab/healthy" + ] + assert failures == [("ContextualWisdomLab/broken", "forbidden")] + + + def mention_request(comment_id: int): + """Build one Noema request for orchestration isolation tests.""" + + router = importlib.import_module("agent_mention_router") + return router.MentionRequest( + "ContextualWisdomLab/example", + 7, + "a" * 40, + "main", + comment_id, + "maintainer", + ("cwl-noema-review",), + ) + + + def test_sweep_continues_after_candidate_and_dispatch_failures( + monkeypatch, + capsys, + ) -> None: + """Candidate-local failures are counted while later work is queued.""" + + sweep = module() + issues = [ + {"repository": "ContextualWisdomLab/example", "number": 7}, + {"repository": "ContextualWisdomLab/example", "number": 8}, + ] + monkeypatch.setattr( + sweep, + "list_recent_pull_requests", + lambda *args, **kwargs: iter(issues), + ) + + def build_requests(client, *, issue, since): + del client, since + if issue["number"] == 7: + raise RuntimeError("comment inventory failed") + return (mention_request(10), mention_request(11)) + + monkeypatch.setattr(sweep, "build_requests_for_pull_request", build_requests) + dispatch_kwargs = [] + + def dispatch(request, **kwargs): + dispatch_kwargs.append(kwargs) + if request.comment_id == 10: + raise RuntimeError("dispatch failed") + return ("@cwl-noema-review",) + + monkeypatch.setattr(sweep, "dispatch_request", dispatch) + metrics = sweep.SweepMetrics() + assert sweep.sweep( + target_client=object(), + dispatch_client=object(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=5, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 6, tzinfo=timezone.utc), + metrics=metrics, + ) == 1 + assert metrics.failures == 2 + assert dispatch_kwargs[0]["run_marker_cache"] is dispatch_kwargs[1][ + "run_marker_cache" + ] + assert dispatch_kwargs[0]["workflow_run_since"].endswith("Z") + output = capsys.readouterr().out + assert "comment inventory failed" in output + assert "dispatch failed" in output + + + def test_main_returns_failure_when_isolated_errors_were_observed( + monkeypatch, + ) -> None: + """The scheduled workflow remains visibly failed after partial progress.""" + + sweep = module() + monkeypatch.setenv("TARGET_REPOSITORY_TOKEN", "target") + monkeypatch.setenv("AGENT_DISPATCH_TOKEN", "dispatch") + + def fail_partially(**kwargs): + kwargs["metrics"].failures = 1 + return 0 + + monkeypatch.setattr(sweep, "sweep", fail_partially) + assert sweep.main([]) == 1 + ''' + ), + ) + + +def main() -> int: + """Apply every deterministic final-state transformation.""" + + update_router() + update_sweep() + update_workflows() + update_tests() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 692147f42383af230574990aab7cc21580fb222e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:31:43 +0900 Subject: [PATCH 097/138] ci(automation): run verified final PR 787 repair --- .../finalize-pr787-review-findings.yml | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 .github/workflows/finalize-pr787-review-findings.yml diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml new file mode 100644 index 000000000..e9c404a91 --- /dev/null +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -0,0 +1,104 @@ +name: Finalize PR 787 Review Findings + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - ".github/workflows/finalize-pr787-review-findings.yml" + - "scripts/ci/finalize_pr787_review_findings.py" + +concurrency: + group: finalize-pr787-review-findings + cancel-in-progress: true + +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: github.repository == 'ContextualWisdomLab/.github' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + permissions: + contents: read + env: + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN }} + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout exact staging head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + - name: Install exact hash-locked tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + - name: Apply deterministic repairs and remove transient writer + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python3 scripts/ci/finalize_pr787_review_findings.py + rm -f \ + .github/workflows/finalize-pr787-review-findings.yml \ + scripts/ci/finalize_pr787_review_findings.py + - name: Verify complete suite, focused coverage, docs, and syntax + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci tests + git diff --check + test -z "$(git status --short --untracked-files=no | grep -E 'finalize-pr787|finalize_pr787' || true)" + - name: Commit and push verified final state + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + if [ -z "$PUSH_TOKEN" ]; then + echo "::error::A repository-scoped push token is required for the verified final-state commit." + exit 1 + fi + git config user.name "cwl-automation[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "fix(automation): close mention-router review findings" + askpass="$(mktemp)" + cat >"$askpass" <<'EOF' + #!/usr/bin/env bash + case "$1" in + *Username*) printf '%s\n' 'x-access-token' ;; + *Password*) printf '%s\n' "$PUSH_TOKEN" ;; + *) exit 1 ;; + esac + EOF + chmod 0700 "$askpass" + GIT_ASKPASS="$askpass" GIT_TERMINAL_PROMPT=0 \ + git push origin HEAD:feat/review-agent-mention-router-main + rm -f "$askpass" From 22bf2d446b5c6509cc638c16c1440ae3d756c887 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:33:41 +0900 Subject: [PATCH 098/138] ci(automation): verify transient writer removal correctly --- .github/workflows/finalize-pr787-review-findings.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml index e9c404a91..9eba4e79e 100644 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -77,7 +77,8 @@ jobs: scripts/ci/agent_mention_sweep.py python -m compileall -q scripts/ci tests git diff --check - test -z "$(git status --short --untracked-files=no | grep -E 'finalize-pr787|finalize_pr787' || true)" + test ! -e .github/workflows/finalize-pr787-review-findings.yml + test ! -e scripts/ci/finalize_pr787_review_findings.py - name: Commit and push verified final state shell: bash --noprofile --norc -e -o pipefail {0} run: | From 49f381c2333450fc087ee38edd45a4f20e6aacde Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:38:25 +0900 Subject: [PATCH 099/138] ci(automation): make PR 787 finalizer observable --- .../workflows/finalize-pr787-review-findings.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml index 9eba4e79e..10c27168a 100644 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -1,15 +1,14 @@ name: Finalize PR 787 Review Findings on: - push: - branches: - - feat/review-agent-mention-router-main + pull_request: + branches: [main] paths: - ".github/workflows/finalize-pr787-review-findings.yml" - "scripts/ci/finalize_pr787_review_findings.py" concurrency: - group: finalize-pr787-review-findings + group: finalize-pr787-review-findings-${{ github.event.pull_request.number }} cancel-in-progress: true permissions: @@ -20,13 +19,16 @@ env: jobs: finalize: - if: github.repository == 'ContextualWisdomLab/.github' + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: contents: read env: PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN }} + TARGET_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - name: Harden runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 @@ -35,7 +37,7 @@ jobs: - name: Checkout exact staging head uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ github.sha }} + ref: ${{ env.TARGET_HEAD_SHA }} fetch-depth: 0 persist-credentials: false - name: Set up Python @@ -51,6 +53,7 @@ jobs: - name: Apply deterministic repairs and remove transient writer shell: bash --noprofile --norc -e -o pipefail {0} run: | + test "$(git rev-parse HEAD)" = "$TARGET_HEAD_SHA" python3 scripts/ci/finalize_pr787_review_findings.py rm -f \ .github/workflows/finalize-pr787-review-findings.yml \ From b9ed228f07466227d0536c950a9ab1ab534a09f6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:41:03 +0900 Subject: [PATCH 100/138] fix(automation): repair transient transformer matching --- scripts/ci/repair_pr787_finalizer_source.py | 68 +++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scripts/ci/repair_pr787_finalizer_source.py diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py new file mode 100644 index 000000000..7014d9bcb --- /dev/null +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""Repair the transient PR 787 transformer before executing it.""" + +from __future__ import annotations + +from pathlib import Path + +TARGET = Path(__file__).with_name("finalize_pr787_review_findings.py") + +OLD_REPLACE_ONCE = '''def replace_once(path: str, old: str, new: str) -> None: + """Replace exactly one literal block and fail on an unexpected source tree.""" + + content = read(path) + count = content.count(old) + if count != 1: + raise RuntimeError(f"{path}: expected one replacement target, found {count}") + write(path, content.replace(old, new, 1)) +''' + +NEW_REPLACE_ONCE = '''def _indented(block: str, width: int) -> str: + """Return ``block`` with one uniform source indentation prefix.""" + + prefix = " " * width + return "\\n".join(prefix + line if line else line for line in block.split("\\n")) + + +def replace_once(path: str, old: str, new: str) -> None: + """Replace one literal block, accepting its repository indentation.""" + + content = read(path) + matches: list[tuple[str, str]] = [] + for width in range(0, 21): + candidate = _indented(old, width) + count = content.count(candidate) + if count > 1: + raise RuntimeError( + f"{path}: replacement target is ambiguous at indent {width}: {count}" + ) + if count == 1: + matches.append((candidate, _indented(new, width))) + if len(matches) != 1: + raise RuntimeError( + f"{path}: expected one indentation-aware replacement target, found {len(matches)}" + ) + candidate, replacement = matches[0] + write(path, content.replace(candidate, replacement, 1)) +''' + + +def main() -> int: + """Patch indentation matching and nested regex escaping deterministically.""" + + content = TARGET.read_text(encoding="utf-8") + if content.count(OLD_REPLACE_ONCE) != 1: + raise RuntimeError("transient replace_once source no longer matches its contract") + content = content.replace(OLD_REPLACE_ONCE, NEW_REPLACE_ONCE, 1) + for overescaped, corrected in ( + (r"\\\\d", r"\\d"), + (r"\\\\[", r"\\["), + (r"\\\\]", r"\\]"), + ): + content = content.replace(overescaped, corrected) + TARGET.write_text(content, encoding="utf-8") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 89fd7d05f1344014933268fd02222b666a30c260 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:41:45 +0900 Subject: [PATCH 101/138] ci(automation): repair and authenticate final state writer --- .github/workflows/finalize-pr787-review-findings.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml index 10c27168a..050b43f4a 100644 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -6,6 +6,7 @@ on: paths: - ".github/workflows/finalize-pr787-review-findings.yml" - "scripts/ci/finalize_pr787_review_findings.py" + - "scripts/ci/repair_pr787_finalizer_source.py" concurrency: group: finalize-pr787-review-findings-${{ github.event.pull_request.number }} @@ -25,9 +26,9 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: - contents: read + contents: write env: - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN }} + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} TARGET_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - name: Harden runner @@ -54,10 +55,12 @@ jobs: shell: bash --noprofile --norc -e -o pipefail {0} run: | test "$(git rev-parse HEAD)" = "$TARGET_HEAD_SHA" + python3 scripts/ci/repair_pr787_finalizer_source.py python3 scripts/ci/finalize_pr787_review_findings.py rm -f \ .github/workflows/finalize-pr787-review-findings.yml \ - scripts/ci/finalize_pr787_review_findings.py + scripts/ci/finalize_pr787_review_findings.py \ + scripts/ci/repair_pr787_finalizer_source.py - name: Verify complete suite, focused coverage, docs, and syntax shell: bash --noprofile --norc -e -o pipefail {0} run: | @@ -82,6 +85,7 @@ jobs: git diff --check test ! -e .github/workflows/finalize-pr787-review-findings.yml test ! -e scripts/ci/finalize_pr787_review_findings.py + test ! -e scripts/ci/repair_pr787_finalizer_source.py - name: Commit and push verified final state shell: bash --noprofile --norc -e -o pipefail {0} run: | From 6cb7b20f0c816256343884c355fb37898744396b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:44:00 +0900 Subject: [PATCH 102/138] fix(automation): tolerate typed function end markers --- scripts/ci/repair_pr787_finalizer_source.py | 44 +++++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index 7014d9bcb..c57464a1c 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -46,14 +46,50 @@ def replace_once(path: str, old: str, new: str) -> None: write(path, content.replace(candidate, replacement, 1)) ''' +OLD_REPLACE_BETWEEN = '''def replace_between(path: str, start: str, end: str, replacement: str) -> None: + """Replace one section delimited by stable function markers.""" + + content = read(path) + start_index = content.index(start) + end_index = content.index(end, start_index) + write(path, content[:start_index] + replacement.rstrip() + "\\n\\n" + content[end_index + 1 :]) +''' + +NEW_REPLACE_BETWEEN = '''def replace_between(path: str, start: str, end: str, replacement: str) -> None: + """Replace one section delimited by stable function markers.""" + + content = read(path) + start_index = content.index(start) + try: + end_index = content.index(end, start_index) + except ValueError: + if not end.endswith("(\\n"): + raise + end_index = content.index(end[:-1], start_index) + write(path, content[:start_index] + replacement.rstrip() + "\\n\\n" + content[end_index + 1 :]) +''' + def main() -> int: - """Patch indentation matching and nested regex escaping deterministically.""" + """Patch matching and nested regex escaping deterministically.""" content = TARGET.read_text(encoding="utf-8") - if content.count(OLD_REPLACE_ONCE) != 1: - raise RuntimeError("transient replace_once source no longer matches its contract") - content = content.replace(OLD_REPLACE_ONCE, NEW_REPLACE_ONCE, 1) + replacements = ( + ( + OLD_REPLACE_ONCE, + NEW_REPLACE_ONCE, + "transient replace_once source no longer matches its contract", + ), + ( + OLD_REPLACE_BETWEEN, + NEW_REPLACE_BETWEEN, + "transient replace_between source no longer matches its contract", + ), + ) + for old, new, error in replacements: + if content.count(old) != 1: + raise RuntimeError(error) + content = content.replace(old, new, 1) for overescaped, corrected in ( (r"\\\\d", r"\\d"), (r"\\\\[", r"\\["), From eaeadd952d002699a3ecc4a6de1d12f42e352f3b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:46:06 +0900 Subject: [PATCH 103/138] fix(automation): match indented workflow blocks --- scripts/ci/repair_pr787_finalizer_source.py | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index c57464a1c..8b4ea94f2 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -69,6 +69,40 @@ def replace_once(path: str, old: str, new: str) -> None: write(path, content[:start_index] + replacement.rstrip() + "\\n\\n" + content[end_index + 1 :]) ''' +OLD_OUTPUT_REPLACEMENT = ''' if old_output not in content: + raise RuntimeError("agent-mention-router.yml: token output block changed") + content = content.replace(old_output, new_output, 1) +''' + +NEW_OUTPUT_REPLACEMENT = ''' output_matches = [ + (_indented(old_output, width), _indented(new_output, width)) + for width in range(0, 21) + if content.count(_indented(old_output, width)) == 1 + ] + if len(output_matches) != 1: + raise RuntimeError( + "agent-mention-router.yml: token output block changed or ambiguous" + ) + content = content.replace(*output_matches[0], 1) +''' + +OLD_STEP_REPLACEMENT = ''' if old_step not in content: + raise RuntimeError("agent-mention-router.yml: sweep step changed") + write(path, content.replace(old_step, new_step, 1)) +''' + +NEW_STEP_REPLACEMENT = ''' step_matches = [ + (_indented(old_step, width), _indented(new_step, width)) + for width in range(0, 21) + if content.count(_indented(old_step, width)) == 1 + ] + if len(step_matches) != 1: + raise RuntimeError( + "agent-mention-router.yml: sweep step changed or ambiguous" + ) + write(path, content.replace(*step_matches[0], 1)) +''' + def main() -> int: """Patch matching and nested regex escaping deterministically.""" @@ -85,6 +119,16 @@ def main() -> int: NEW_REPLACE_BETWEEN, "transient replace_between source no longer matches its contract", ), + ( + OLD_OUTPUT_REPLACEMENT, + NEW_OUTPUT_REPLACEMENT, + "transient output replacement source no longer matches its contract", + ), + ( + OLD_STEP_REPLACEMENT, + NEW_STEP_REPLACEMENT, + "transient step replacement source no longer matches its contract", + ), ) for old, new, error in replacements: if content.count(old) != 1: From 7ddbc7ab8bb387ec1c95af42e61ae3d967d5666e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:48:23 +0900 Subject: [PATCH 104/138] fix(automation): preserve generated test escape sequences --- scripts/ci/repair_pr787_finalizer_source.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index 8b4ea94f2..48c4ac1a3 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -103,9 +103,16 @@ def replace_once(path: str, old: str, new: str) -> None: write(path, content.replace(*step_matches[0], 1)) ''' +RAW_TEST_HEADINGS = ( + '"""Coverage-only regressions for the review-fix scheduler."""', + '"""Static contracts for downstream review-agent invocation idempotency."""', + '"""Review-driven runtime regressions for the agent mention control plane."""', + '"""Review-driven pagination and failure-isolation regressions."""', +) + def main() -> int: - """Patch matching and nested regex escaping deterministically.""" + """Patch matching, generated-test literals, and regex escaping.""" content = TARGET.read_text(encoding="utf-8") replacements = ( @@ -134,6 +141,12 @@ def main() -> int: if content.count(old) != 1: raise RuntimeError(error) content = content.replace(old, new, 1) + for heading in RAW_TEST_HEADINGS: + old = "dedent(\n '''\n " + heading + new = "dedent(\n r'''\n " + heading + if content.count(old) != 1: + raise RuntimeError(f"generated test block no longer matches: {heading}") + content = content.replace(old, new, 1) for overescaped, corrected in ( (r"\\\\d", r"\\d"), (r"\\\\[", r"\\["), From 440143b2cb2062a7f902cfed660e0fca055a6534 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:52:36 +0900 Subject: [PATCH 105/138] fix(automation): preserve generated router newline escapes --- scripts/ci/repair_pr787_finalizer_source.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index 48c4ac1a3..5867c2290 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -110,9 +110,13 @@ def replace_once(path: str, old: str, new: str) -> None: '"""Review-driven pagination and failure-isolation regressions."""', ) +RAW_GENERATED_FUNCTIONS = ( + "def dispatch_request(", +) + def main() -> int: - """Patch matching, generated-test literals, and regex escaping.""" + """Patch matching, generated literals, and nested regex escaping.""" content = TARGET.read_text(encoding="utf-8") replacements = ( @@ -147,6 +151,14 @@ def main() -> int: if content.count(old) != 1: raise RuntimeError(f"generated test block no longer matches: {heading}") content = content.replace(old, new, 1) + for signature in RAW_GENERATED_FUNCTIONS: + old = "dedent(\n '''\n " + signature + new = "dedent(\n r'''\n " + signature + if content.count(old) != 1: + raise RuntimeError( + f"generated function block no longer matches: {signature}" + ) + content = content.replace(old, new, 1) for overescaped, corrected in ( (r"\\\\d", r"\\d"), (r"\\\\[", r"\\["), From 576141ed0ade1360337b93651c0ee406d1888f64 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 20:58:47 +0900 Subject: [PATCH 106/138] test(automation): close remaining router coverage branches --- scripts/ci/repair_pr787_finalizer_source.py | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index 5867c2290..e5e1a916d 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -103,6 +103,72 @@ def replace_once(path: str, old: str, new: str) -> None: write(path, content.replace(*step_matches[0], 1)) ''' +OLD_HANDLE_STATUS = ''' status_parts: list[str] = [] + if handles: + status_parts.append(f"Queued {' and '.join(handles)}") + existing_handles = tuple( +''' + +NEW_HANDLE_STATUS = ''' status_parts = [f"Queued {' and '.join(handles)}"] + existing_handles = tuple( +''' + +OLD_RUN_INVENTORY = ''' "workflow_runs": [ + { + "id": 1, + "event": "repository_dispatch", + "display_title": f"run {noema_marker}", + } + ] +''' + +NEW_RUN_INVENTORY = ''' "workflow_runs": [ + { + "id": 0, + "event": "repository_dispatch", + "display_title": f"ignored {noema_marker}", + }, + { + "id": 1, + "event": "repository_dispatch", + "display_title": f"run {noema_marker}", + }, + ] +''' + +OLD_SWEEP_TEST_ANCHOR = ''' assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] + + + def test_repository_failure_is_isolated_and_later_repository_runs() -> None: +''' + +NEW_SWEEP_TEST_ANCHOR = ''' assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] + + + def test_invalid_pull_number_fails_closed_without_error_sink() -> None: + """Malformed pull metadata raises when no isolation sink is supplied.""" + + sweep = module() + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): [pull(0)], + } + ) + with pytest.raises(ValueError, match="invalid pull request number"): + list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + + + def test_repository_failure_is_isolated_and_later_repository_runs() -> None: +''' + RAW_TEST_HEADINGS = ( '"""Coverage-only regressions for the review-fix scheduler."""', '"""Static contracts for downstream review-agent invocation idempotency."""', @@ -140,6 +206,21 @@ def main() -> int: NEW_STEP_REPLACEMENT, "transient step replacement source no longer matches its contract", ), + ( + OLD_HANDLE_STATUS, + NEW_HANDLE_STATUS, + "generated status block no longer matches its contract", + ), + ( + OLD_RUN_INVENTORY, + NEW_RUN_INVENTORY, + "generated workflow-run test inventory no longer matches", + ), + ( + OLD_SWEEP_TEST_ANCHOR, + NEW_SWEEP_TEST_ANCHOR, + "generated sweep coverage anchor no longer matches", + ), ) for old, new, error in replacements: if content.count(old) != 1: From 384b1b84a735aa521f4ec07f6f5946d88b5ea97c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:02:14 +0900 Subject: [PATCH 107/138] ci(automation): expose final uncovered sweep branch --- .github/workflows/finalize-pr787-review-findings.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml index 050b43f4a..b97a8fcfe 100644 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -77,7 +77,8 @@ jobs: export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" python -m coverage erase python -m coverage run -m pytest -q - python -m coverage report --fail-under=100 + nl -ba scripts/ci/agent_mention_sweep.py | sed -n '168,182p' + python -m coverage report --show-missing --fail-under=100 python -m interrogate --fail-under=100 \ scripts/ci/agent_mention_router.py \ scripts/ci/agent_mention_sweep.py From 50b039fcb9935a27ab05e32d1aba19ebb9d15133 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:05:38 +0900 Subject: [PATCH 108/138] test(automation): cover empty pagination termination --- scripts/ci/repair_pr787_finalizer_source.py | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py index e5e1a916d..c4fb31bbe 100644 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ b/scripts/ci/repair_pr787_finalizer_source.py @@ -145,6 +145,35 @@ def test_repository_failure_is_isolated_and_later_repository_runs() -> None: NEW_SWEEP_TEST_ANCHOR = ''' assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] + def test_pull_pagination_stops_on_empty_followup_page() -> None: + """A full page followed by an empty page terminates without page three.""" + + sweep = module() + recent = [pull(number) for number in range(1, 101)] + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): recent, + ("repos/ContextualWisdomLab/example/pulls", 2): [], + } + ) + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + assert len(results) == 100 + pull_calls = [ + args for args in client.calls if args[0].endswith("/pulls") + ] + assert len(pull_calls) == 2 + assert any("page=2" in args for args in pull_calls) + assert not any("page=3" in args for args in pull_calls) + + def test_invalid_pull_number_fails_closed_without_error_sink() -> None: """Malformed pull metadata raises when no isolation sink is supplied.""" From 107617fbddc256f5e5cf4fb0f7187ca5e3c0db56 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:08:55 +0900 Subject: [PATCH 109/138] ci(automation): split verified runtime and workflow publication --- .../finalize-pr787-review-findings.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml index b97a8fcfe..5a6c8c5d6 100644 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ b/.github/workflows/finalize-pr787-review-findings.yml @@ -28,7 +28,7 @@ jobs: permissions: contents: write env: - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} + PUSH_TOKEN: ${{ github.token }} TARGET_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - name: Harden runner @@ -77,7 +77,6 @@ jobs: export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" python -m coverage erase python -m coverage run -m pytest -q - nl -ba scripts/ci/agent_mention_sweep.py | sed -n '168,182p' python -m coverage report --show-missing --fail-under=100 python -m interrogate --fail-under=100 \ scripts/ci/agent_mention_router.py \ @@ -87,17 +86,23 @@ jobs: test ! -e .github/workflows/finalize-pr787-review-findings.yml test ! -e scripts/ci/finalize_pr787_review_findings.py test ! -e scripts/ci/repair_pr787_finalizer_source.py - - name: Commit and push verified final state + - name: Commit and push verified non-workflow final state shell: bash --noprofile --norc -e -o pipefail {0} run: | if [ -z "$PUSH_TOKEN" ]; then - echo "::error::A repository-scoped push token is required for the verified final-state commit." + echo "::error::The workflow GITHUB_TOKEN is required for the verified final-state commit." exit 1 fi - git config user.name "cwl-automation[bot]" + git checkout "$TARGET_HEAD_SHA" -- \ + .github/workflows/agent-mention-noema-dispatch.yml \ + .github/workflows/agent-mention-opencode-dispatch.yml \ + .github/workflows/agent-mention-router.yml \ + .github/workflows/agent-mention-router-quality-ci.yml \ + .github/workflows/finalize-pr787-review-findings.yml + git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add -A - git commit -m "fix(automation): close mention-router review findings" + git commit -m "fix(automation): close mention-router runtime findings" askpass="$(mktemp)" cat >"$askpass" <<'EOF' #!/usr/bin/env bash From 7ba61cbab941bb2724860aa31b2deb38d7f232cf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 12:10:28 +0000 Subject: [PATCH 110/138] fix(automation): close mention-router runtime findings --- scripts/ci/agent_mention_router.py | 154 +- scripts/ci/agent_mention_sweep.py | 174 +- scripts/ci/finalize_pr787_review_findings.py | 1632 ----------------- scripts/ci/repair_pr787_finalizer_source.py | 283 --- ...st_agent_mention_downstream_idempotency.py | 75 +- .../test_agent_mention_review_regressions.py | 222 +++ tests/test_agent_mention_router.py | 7 +- tests/test_agent_mention_sweep_regressions.py | 266 +++ .../test_pr_review_fix_scheduler_coverage.py | 50 +- 9 files changed, 787 insertions(+), 2076 deletions(-) delete mode 100644 scripts/ci/finalize_pr787_review_findings.py delete mode 100644 scripts/ci/repair_pr787_finalizer_source.py create mode 100644 tests/test_agent_mention_review_regressions.py create mode 100644 tests/test_agent_mention_sweep_regressions.py diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 8a08df6f4..1df34b010 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -10,6 +10,7 @@ import re import subprocess from dataclasses import dataclass +from datetime import datetime, timedelta, timezone from typing import Any, Sequence CENTRAL_AUTOMATION_REPOSITORY = "ContextualWisdomLab/.github" @@ -37,8 +38,11 @@ REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") HEAD_SHA_RE = re.compile(r"^[0-9a-fA-F]{40}$") BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$") +ACTOR_RE = re.compile(r"^[A-Za-z0-9-]+$") RECEIPT_RE = re.compile(r"") +INVOCATION_MARKER_RE = re.compile(r"\[cwl-agent-invocation:[0-9a-f]{64}\]") MAX_WORKFLOW_RUN_RECORDS = 10_000 +WORKFLOW_RUN_LOOKBACK_HOURS = 24 * 30 @dataclass(frozen=True) @@ -82,9 +86,19 @@ def request( input=None if input_payload is None else json.dumps(input_payload), text=True, capture_output=True, - check=True, + check=False, env=environment, ) + return_code = int(getattr(completed, "returncode", 0)) + if return_code: + diagnostic = " ".join( + str(getattr(completed, "stderr", "") or "").split() + ) + if not diagnostic: + diagnostic = "no stderr output" + raise RuntimeError( + f"gh api failed with exit code {return_code}: {diagnostic[:2000]}" + ) output = completed.stdout.strip() return None if not output else json.loads(output) @@ -167,8 +181,8 @@ def parse_event(event: dict[str, Any]) -> MentionRequest | None: raise ValueError("pull request head SHA is missing or invalid") if not BASE_BRANCH_RE.fullmatch(base_branch): raise ValueError("pull request base branch is missing or invalid") - if not actor: - raise ValueError("comment actor is missing") + if not ACTOR_RE.fullmatch(actor): + raise ValueError("comment actor is missing or invalid") return MentionRequest( repository_name, number, @@ -208,7 +222,8 @@ def eligible_agents( if "cwl-noema-review" in request.agents: dispatchable.append("cwl-noema-review") if "opencode-agent" in request.agents: - if request.repository in opencode_allowlist: + normalized_allowlist = {entry.casefold() for entry in opencode_allowlist} + if request.repository.casefold() in normalized_allowlist: dispatchable.append("opencode-agent") else: rejected.append("opencode-agent") @@ -248,6 +263,20 @@ def agent_invocation_marker(request: MentionRequest, agent: str) -> str: return f"[cwl-agent-invocation:{agent_invocation_key(request, agent)}]" +def workflow_run_cutoff( + *, + now: datetime | None = None, + lookback_hours: int = WORKFLOW_RUN_LOOKBACK_HOURS, +) -> str: + """Return the UTC lower bound for durable wrapper-run lookup.""" + + current = now or datetime.now(timezone.utc) + if current.tzinfo is None: + raise ValueError("workflow-run cutoff time must be timezone-aware") + cutoff = current.astimezone(timezone.utc) - timedelta(hours=lookback_hours) + return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") + + def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: """Validate and flatten bounded ``gh --paginate --slurp`` workflow runs.""" @@ -273,48 +302,59 @@ def dispatched_agents( request: MentionRequest, dispatch_client: GitHubClient, agents: Sequence[str] | None = None, + *, + workflow_run_since: str | None = None, + run_marker_cache: dict[str, set[str]] | None = None, ) -> frozenset[str]: """Return agents with a durable central run for this exact invocation. - A run record proves GitHub accepted the repository dispatch even when its - conclusion is failure. Repeating a failed invocation requires a new trusted - source comment, which produces a different key and preserves auditable - at-most-once behavior for each request. + Workflow inventories are bounded by the same maximum 30-day window as + the scheduled source-comment sweep. A caller-owned marker cache avoids + repeating the same agent workflow query for every candidate in one run. """ candidates = tuple(request.agents if agents is None else agents) observed: set[str] = set() + cutoff = workflow_run_since or workflow_run_cutoff() + marker_cache = run_marker_cache if run_marker_cache is not None else {} for agent in candidates: endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS.get(agent) if endpoint is None: raise ValueError(f"unsupported agent: {agent}") - response = dispatch_client.request( - [ - endpoint, - "-X", - "GET", - "-f", - "event=repository_dispatch", - "-f", - "per_page=100", - "--paginate", - "--slurp", - ] - ) - marker = agent_invocation_marker(request, agent) - for run in _workflow_run_records(response): - run_id = run.get("id") - if ( - isinstance(run_id, int) - and run_id > 0 - and run.get("event") == "repository_dispatch" - and marker in str(run.get("display_title") or "") - ): - observed.add(agent) - break + if endpoint not in marker_cache: + response = dispatch_client.request( + [ + endpoint, + "-X", + "GET", + "-f", + "event=repository_dispatch", + "-f", + f"created=>={cutoff}", + "-f", + "per_page=100", + "--paginate", + "--slurp", + ] + ) + markers: set[str] = set() + for run in _workflow_run_records(response): + run_id = run.get("id") + if ( + isinstance(run_id, int) + and run_id > 0 + and run.get("event") == "repository_dispatch" + ): + markers.update( + INVOCATION_MARKER_RE.findall( + str(run.get("display_title") or "") + ) + ) + marker_cache[endpoint] = markers + if agent_invocation_marker(request, agent) in marker_cache[endpoint]: + observed.add(agent) return frozenset(observed) - def noema_payload(request: MentionRequest) -> dict[str, Any]: """Return the durable Noema wrapper dispatch request body.""" @@ -365,8 +405,10 @@ def dispatch_request( dispatch_client: GitHubClient, opencode_allowlist: frozenset[str], dry_run: bool = False, + workflow_run_since: str | None = None, + run_marker_cache: dict[str, set[str]] | None = None, ) -> tuple[str, ...]: - """Dispatch only missing agents and acknowledge new work on the target PR.""" + """Dispatch missing agents and acknowledge only newly queued work.""" dispatchable, rejected = eligible_agents( request, @@ -383,10 +425,23 @@ def dispatch_request( ) return handles - existing = dispatched_agents(request, dispatch_client, dispatchable) + existing = dispatched_agents( + request, + dispatch_client, + dispatchable, + workflow_run_since=workflow_run_since, + run_marker_cache=run_marker_cache, + ) missing = tuple(agent for agent in dispatchable if agent not in existing) handles = tuple(f"@{agent}" for agent in missing) - if not missing and not rejected: + if not missing: + if rejected: + print( + "Rejected agent mention without target mutation " + f"repo={request.repository} pr={request.pull_request_number} " + f"comment={request.comment_id} " + f"agents={','.join(rejected)}" + ) return () dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" @@ -395,20 +450,32 @@ def dispatch_request( [dispatch_endpoint, "-X", "POST"], input_payload=noema_payload(request), ) + if run_marker_cache is not None: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] + run_marker_cache.setdefault(endpoint, set()).add( + agent_invocation_marker(request, "cwl-noema-review") + ) if "opencode-agent" in missing: dispatch_client.request( [dispatch_endpoint, "-X", "POST"], input_payload=opencode_payload(request), ) + if run_marker_cache is not None: + endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] + run_marker_cache.setdefault(endpoint, set()).add( + agent_invocation_marker(request, "opencode-agent") + ) target_api = f"repos/{request.repository}" target_client.request( - [f"{target_api}/issues/comments/{request.comment_id}/reactions", "-X", "POST"], + [ + f"{target_api}/issues/comments/{request.comment_id}/reactions", + "-X", + "POST", + ], input_payload={"content": "eyes"}, ) - status_parts: list[str] = [] - if handles: - status_parts.append(f"Queued {' and '.join(handles)}") + status_parts = [f"Queued {' and '.join(handles)}"] existing_handles = tuple( f"@{agent}" for agent in dispatchable if agent in existing ) @@ -430,12 +497,15 @@ def dispatch_request( "authoritative for the final verdict and failure evidence." ) target_client.request( - [f"{target_api}/issues/{request.pull_request_number}/comments", "-X", "POST"], + [ + f"{target_api}/issues/{request.pull_request_number}/comments", + "-X", + "POST", + ], input_payload={"body": acknowledgement}, ) return handles - def load_event(path: str) -> dict[str, Any]: """Load and validate a GitHub event JSON document.""" diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py index ae1ee0b4d..12d70d3b8 100644 --- a/scripts/ci/agent_mention_sweep.py +++ b/scripts/ci/agent_mention_sweep.py @@ -6,8 +6,9 @@ import argparse import os import re +from dataclasses import dataclass from datetime import datetime, timedelta, timezone -from typing import Any, Iterator, Sequence +from typing import Any, Callable, Iterator, Sequence from agent_mention_router import ( GitHubClient, @@ -22,6 +23,13 @@ REPOSITORY_SOURCES = frozenset({"organization", "installation"}) +@dataclass +class SweepMetrics: + """Mutable operational counters returned to the CLI boundary.""" + + failures: int = 0 + + def parse_timestamp(value: str) -> datetime: """Parse one GitHub ISO-8601 timestamp into timezone-aware UTC.""" @@ -51,6 +59,12 @@ def flatten_pages(value: Any, *, collection_key: str | None = None) -> list[dict if value is None: raise ValueError("paginated GitHub response is empty") + if ( + collection_key is None + and isinstance(value, list) + and all(isinstance(record, dict) for record in value) + ): + return list(value) pages = value if isinstance(value, list) else [value] records: list[dict[str, Any]] = [] for page in pages: @@ -125,46 +139,72 @@ def list_recent_pull_requests( organization: str, repository_source: str, since: str, + on_error: Callable[[str, Exception], None] | None = None, ) -> Iterator[dict[str, Any]]: - """Yield recent open pull requests and stop when the caller stops consuming.""" + """Yield recent open pull requests with lazy cutoff-aware pagination.""" cutoff = parse_timestamp(since) - for repository in list_accessible_repositories( + repositories = list_accessible_repositories( client, organization=organization, repository_source=repository_source, - ): - response = client.request( - [ - f"repos/{repository}/pulls", - "-X", - "GET", - "-f", - "state=open", - "-f", - "sort=updated", - "-f", - "direction=desc", - "-f", - "per_page=100", - "--paginate", - "--slurp", - ] - ) - for pull_request in flatten_pages(response): - if parse_timestamp(str(pull_request.get("updated_at") or "")) < cutoff: - continue - number = pull_request.get("number") - if not isinstance(number, int) or number < 1: - raise ValueError("GitHub returned an invalid pull request number") - yield { - "number": number, - "repository": repository, - "pull_request": { - "url": f"https://api.github.com/repos/{repository}/pulls/{number}" - }, - } - + ) + for repository in repositories: + try: + page = 1 + while True: + response = client.request( + [ + f"repos/{repository}/pulls", + "-X", + "GET", + "-f", + "state=open", + "-f", + "sort=updated", + "-f", + "direction=desc", + "-f", + "per_page=100", + "-f", + f"page={page}", + ] + ) + pull_requests = flatten_pages(response) + if not pull_requests: + break + reached_cutoff = False + for pull_request in pull_requests: + if ( + parse_timestamp( + str(pull_request.get("updated_at") or "") + ) + < cutoff + ): + reached_cutoff = True + break + number = pull_request.get("number") + if not isinstance(number, int) or number < 1: + raise ValueError( + "GitHub returned an invalid pull request number" + ) + yield { + "number": number, + "repository": repository, + "pull_request": { + "url": ( + "https://api.github.com/repos/" + f"{repository}/pulls/{number}" + ) + }, + } + if reached_cutoff or len(pull_requests) < 100: + break + page += 1 + except Exception as exc: + if on_error is None: + raise + on_error(repository, exc) def list_recent_comments( client: GitHubClient, @@ -239,41 +279,71 @@ def sweep( opencode_allowlist: frozenset[str], dry_run: bool = False, now: datetime | None = None, + metrics: SweepMetrics | None = None, ) -> int: - """Bound source requests that actually queue at least one new agent.""" + """Queue bounded new work while isolating candidate-local failures.""" if max_dispatches < 1 or max_dispatches > 100: raise ValueError("max dispatches must be between 1 and 100") since = cutoff_timestamp(lookback_hours, now=now) + counters = metrics if metrics is not None else SweepMetrics() + run_marker_cache: dict[str, set[str]] = {} dispatched = 0 + + def record_failure(scope: str, error: Exception) -> None: + """Record one isolated error and preserve the remaining sweep.""" + + counters.failures += 1 + message = " ".join(str(error).split()) or error.__class__.__name__ + print(f"::warning::Agent mention sweep skipped {scope}: {message[:1000]}") + for issue in list_recent_pull_requests( target_client, organization=organization, repository_source=repository_source, since=since, + on_error=record_failure, ): - for request in build_requests_for_pull_request( - target_client, - issue=issue, - since=since, - ): - queued_agents = dispatch_request( - request, - target_client=target_client, - dispatch_client=dispatch_client, - opencode_allowlist=opencode_allowlist, - dry_run=dry_run, + issue_scope = f"{issue.get('repository')}#{issue.get('number')}" + try: + requests = build_requests_for_pull_request( + target_client, + issue=issue, + since=since, ) + except Exception as exc: + record_failure(issue_scope, exc) + continue + for request in requests: + request_scope = f"{issue_scope}/comment-{request.comment_id}" + try: + queued_agents = dispatch_request( + request, + target_client=target_client, + dispatch_client=dispatch_client, + opencode_allowlist=opencode_allowlist, + dry_run=dry_run, + workflow_run_since=since, + run_marker_cache=run_marker_cache, + ) + except Exception as exc: + record_failure(request_scope, exc) + continue if not queued_agents: continue dispatched += 1 if dispatched >= max_dispatches: - print(f"Agent mention sweep reached dispatch limit {max_dispatches}.") + print( + "Agent mention sweep reached dispatch limit " + f"{max_dispatches}; isolated failures={counters.failures}." + ) return dispatched - print(f"Agent mention sweep completed with {dispatched} dispatch(es).") + print( + "Agent mention sweep completed with " + f"{dispatched} dispatch(es) and {counters.failures} isolated failure(s)." + ) return dispatched - def main(argv: Sequence[str] | None = None) -> int: """Run the scheduled organization mention sweep.""" @@ -291,6 +361,7 @@ def main(argv: Sequence[str] | None = None) -> int: allowlist = parse_repository_allowlist( os.environ.get("OPENCODE_REPOSITORY_DISPATCH_TARGETS", "") ) + metrics = SweepMetrics() sweep( target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), @@ -300,8 +371,9 @@ def main(argv: Sequence[str] | None = None) -> int: max_dispatches=args.max_dispatches, opencode_allowlist=allowlist, dry_run=args.dry_run, + metrics=metrics, ) - return 0 + return 1 if metrics.failures else 0 if __name__ == "__main__": # pragma: no cover diff --git a/scripts/ci/finalize_pr787_review_findings.py b/scripts/ci/finalize_pr787_review_findings.py deleted file mode 100644 index b443f55a4..000000000 --- a/scripts/ci/finalize_pr787_review_findings.py +++ /dev/null @@ -1,1632 +0,0 @@ -#!/usr/bin/env python3 -"""Apply the final deterministic review-finding repairs for PR 787.""" - -from __future__ import annotations - -from pathlib import Path -from textwrap import dedent - -ROOT = Path(__file__).resolve().parents[2] - - -def read(path: str) -> str: - """Read one repository file as UTF-8 text.""" - - return (ROOT / path).read_text(encoding="utf-8") - - -def write(path: str, content: str) -> None: - """Write one repository file as normalized UTF-8 text.""" - - target = ROOT / path - target.parent.mkdir(parents=True, exist_ok=True) - target.write_text(content.rstrip() + "\n", encoding="utf-8") - - -def replace_once(path: str, old: str, new: str) -> None: - """Replace exactly one literal block and fail on an unexpected source tree.""" - - content = read(path) - count = content.count(old) - if count != 1: - raise RuntimeError(f"{path}: expected one replacement target, found {count}") - write(path, content.replace(old, new, 1)) - - -def replace_between(path: str, start: str, end: str, replacement: str) -> None: - """Replace one section delimited by stable function markers.""" - - content = read(path) - start_index = content.index(start) - end_index = content.index(end, start_index) - write(path, content[:start_index] + replacement.rstrip() + "\n\n" + content[end_index + 1 :]) - - -def update_router() -> None: - """Harden validation, diagnostics, durable-run lookup, and rejection idempotency.""" - - path = "scripts/ci/agent_mention_router.py" - replace_once( - path, - "import subprocess\nfrom dataclasses import dataclass\nfrom typing import Any, Sequence\n", - "import subprocess\nfrom dataclasses import dataclass\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Sequence\n", - ) - replace_once( - path, - 'BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$")\nRECEIPT_RE = re.compile(r"")\nMAX_WORKFLOW_RUN_RECORDS = 10_000\n', - 'BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$")\nACTOR_RE = re.compile(r"^[A-Za-z0-9-]+$")\nRECEIPT_RE = re.compile(r"")\nINVOCATION_MARKER_RE = re.compile(r"\\[cwl-agent-invocation:[0-9a-f]{64}\\]")\nMAX_WORKFLOW_RUN_RECORDS = 10_000\nWORKFLOW_RUN_LOOKBACK_HOURS = 24 * 30\n', - ) - replace_once( - path, - dedent( - ''' - completed = subprocess.run( - command, - input=None if input_payload is None else json.dumps(input_payload), - text=True, - capture_output=True, - check=True, - env=environment, - ) - output = completed.stdout.strip() - return None if not output else json.loads(output) - ''' - ).strip(), - dedent( - ''' - completed = subprocess.run( - command, - input=None if input_payload is None else json.dumps(input_payload), - text=True, - capture_output=True, - check=False, - env=environment, - ) - return_code = int(getattr(completed, "returncode", 0)) - if return_code: - diagnostic = " ".join( - str(getattr(completed, "stderr", "") or "").split() - ) - if not diagnostic: - diagnostic = "no stderr output" - raise RuntimeError( - f"gh api failed with exit code {return_code}: {diagnostic[:2000]}" - ) - output = completed.stdout.strip() - return None if not output else json.loads(output) - ''' - ).strip(), - ) - replace_once( - path, - ' if not actor:\n raise ValueError("comment actor is missing")\n', - ' if not ACTOR_RE.fullmatch(actor):\n raise ValueError("comment actor is missing or invalid")\n', - ) - replace_once( - path, - " if request.repository in opencode_allowlist:\n", - " normalized_allowlist = {entry.casefold() for entry in opencode_allowlist}\n if request.repository.casefold() in normalized_allowlist:\n", - ) - replace_once( - path, - "def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]:\n", - dedent( - ''' - def workflow_run_cutoff( - *, - now: datetime | None = None, - lookback_hours: int = WORKFLOW_RUN_LOOKBACK_HOURS, - ) -> str: - """Return the UTC lower bound for durable wrapper-run lookup.""" - - current = now or datetime.now(timezone.utc) - if current.tzinfo is None: - raise ValueError("workflow-run cutoff time must be timezone-aware") - cutoff = current.astimezone(timezone.utc) - timedelta(hours=lookback_hours) - return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") - - - def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: - ''' - ).strip() + "\n", - ) - replace_between( - path, - "def dispatched_agents(\n", - "\ndef noema_payload(\n", - dedent( - ''' - def dispatched_agents( - request: MentionRequest, - dispatch_client: GitHubClient, - agents: Sequence[str] | None = None, - *, - workflow_run_since: str | None = None, - run_marker_cache: dict[str, set[str]] | None = None, - ) -> frozenset[str]: - """Return agents with a durable central run for this exact invocation. - - Workflow inventories are bounded by the same maximum 30-day window as - the scheduled source-comment sweep. A caller-owned marker cache avoids - repeating the same agent workflow query for every candidate in one run. - """ - - candidates = tuple(request.agents if agents is None else agents) - observed: set[str] = set() - cutoff = workflow_run_since or workflow_run_cutoff() - marker_cache = run_marker_cache if run_marker_cache is not None else {} - for agent in candidates: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS.get(agent) - if endpoint is None: - raise ValueError(f"unsupported agent: {agent}") - if endpoint not in marker_cache: - response = dispatch_client.request( - [ - endpoint, - "-X", - "GET", - "-f", - "event=repository_dispatch", - "-f", - f"created=>={cutoff}", - "-f", - "per_page=100", - "--paginate", - "--slurp", - ] - ) - markers: set[str] = set() - for run in _workflow_run_records(response): - run_id = run.get("id") - if ( - isinstance(run_id, int) - and run_id > 0 - and run.get("event") == "repository_dispatch" - ): - markers.update( - INVOCATION_MARKER_RE.findall( - str(run.get("display_title") or "") - ) - ) - marker_cache[endpoint] = markers - if agent_invocation_marker(request, agent) in marker_cache[endpoint]: - observed.add(agent) - return frozenset(observed) - ''' - ).strip(), - ) - replace_between( - path, - "def dispatch_request(\n", - "\ndef load_event(\n", - dedent( - ''' - def dispatch_request( - request: MentionRequest, - *, - target_client: GitHubClient, - dispatch_client: GitHubClient, - opencode_allowlist: frozenset[str], - dry_run: bool = False, - workflow_run_since: str | None = None, - run_marker_cache: dict[str, set[str]] | None = None, - ) -> tuple[str, ...]: - """Dispatch missing agents and acknowledge only newly queued work.""" - - dispatchable, rejected = eligible_agents( - request, - opencode_allowlist=opencode_allowlist, - ) - if dry_run: - handles = tuple(f"@{agent}" for agent in dispatchable) - print( - "DRY-RUN agent mention " - f"repo={request.repository} pr={request.pull_request_number} " - f"head={request.pull_request_head_sha} " - f"dispatch={','.join(dispatchable) or 'none'} " - f"reject={','.join(rejected) or 'none'}" - ) - return handles - - existing = dispatched_agents( - request, - dispatch_client, - dispatchable, - workflow_run_since=workflow_run_since, - run_marker_cache=run_marker_cache, - ) - missing = tuple(agent for agent in dispatchable if agent not in existing) - handles = tuple(f"@{agent}" for agent in missing) - if not missing: - if rejected: - print( - "Rejected agent mention without target mutation " - f"repo={request.repository} pr={request.pull_request_number} " - f"comment={request.comment_id} " - f"agents={','.join(rejected)}" - ) - return () - - dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" - if "cwl-noema-review" in missing: - dispatch_client.request( - [dispatch_endpoint, "-X", "POST"], - input_payload=noema_payload(request), - ) - if run_marker_cache is not None: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] - run_marker_cache.setdefault(endpoint, set()).add( - agent_invocation_marker(request, "cwl-noema-review") - ) - if "opencode-agent" in missing: - dispatch_client.request( - [dispatch_endpoint, "-X", "POST"], - input_payload=opencode_payload(request), - ) - if run_marker_cache is not None: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] - run_marker_cache.setdefault(endpoint, set()).add( - agent_invocation_marker(request, "opencode-agent") - ) - - target_api = f"repos/{request.repository}" - target_client.request( - [ - f"{target_api}/issues/comments/{request.comment_id}/reactions", - "-X", - "POST", - ], - input_payload={"content": "eyes"}, - ) - status_parts: list[str] = [] - if handles: - status_parts.append(f"Queued {' and '.join(handles)}") - existing_handles = tuple( - f"@{agent}" for agent in dispatchable if agent in existing - ) - if existing_handles: - status_parts.append( - f"Already queued {' and '.join(existing_handles)} on this exact request" - ) - if rejected: - rejected_handles = " and ".join(f"@{agent}" for agent in rejected) - status_parts.append( - f"Rejected {rejected_handles}: repository is absent from " - "OPENCODE_REPOSITORY_DISPATCH_TARGETS" - ) - acknowledgement = ( - f"{receipt_marker(request.comment_id)}\n" - f"{' ; '.join(status_parts)} for PR #{request.pull_request_number} at head " - f"`{request.pull_request_head_sha}`. Central exact-key workflow runs are " - "the durable dispatch ledger; existing review workflows remain " - "authoritative for the final verdict and failure evidence." - ) - target_client.request( - [ - f"{target_api}/issues/{request.pull_request_number}/comments", - "-X", - "POST", - ], - input_payload={"body": acknowledgement}, - ) - return handles - ''' - ).strip(), - ) - - -def update_sweep() -> None: - """Make repository traversal lazy and isolate per-repository/candidate failures.""" - - path = "scripts/ci/agent_mention_sweep.py" - replace_once( - path, - "import re\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Iterator, Sequence\n", - "import re\nfrom dataclasses import dataclass\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Callable, Iterator, Sequence\n", - ) - replace_once( - path, - 'REPOSITORY_SOURCES = frozenset({"organization", "installation"})\n', - dedent( - ''' - REPOSITORY_SOURCES = frozenset({"organization", "installation"}) - - - @dataclass - class SweepMetrics: - """Mutable operational counters returned to the CLI boundary.""" - - failures: int = 0 - ''' - ).strip() + "\n", - ) - replace_once( - path, - dedent( - ''' - pages = value if isinstance(value, list) else [value] - records: list[dict[str, Any]] = [] - ''' - ).strip(), - dedent( - ''' - if ( - collection_key is None - and isinstance(value, list) - and all(isinstance(record, dict) for record in value) - ): - return list(value) - pages = value if isinstance(value, list) else [value] - records: list[dict[str, Any]] = [] - ''' - ).strip(), - ) - replace_between( - path, - "def list_recent_pull_requests(\n", - "\ndef list_recent_comments(\n", - dedent( - ''' - def list_recent_pull_requests( - client: GitHubClient, - *, - organization: str, - repository_source: str, - since: str, - on_error: Callable[[str, Exception], None] | None = None, - ) -> Iterator[dict[str, Any]]: - """Yield recent open pull requests with lazy cutoff-aware pagination.""" - - cutoff = parse_timestamp(since) - repositories = list_accessible_repositories( - client, - organization=organization, - repository_source=repository_source, - ) - for repository in repositories: - try: - page = 1 - while True: - response = client.request( - [ - f"repos/{repository}/pulls", - "-X", - "GET", - "-f", - "state=open", - "-f", - "sort=updated", - "-f", - "direction=desc", - "-f", - "per_page=100", - "-f", - f"page={page}", - ] - ) - pull_requests = flatten_pages(response) - if not pull_requests: - break - reached_cutoff = False - for pull_request in pull_requests: - if ( - parse_timestamp( - str(pull_request.get("updated_at") or "") - ) - < cutoff - ): - reached_cutoff = True - break - number = pull_request.get("number") - if not isinstance(number, int) or number < 1: - raise ValueError( - "GitHub returned an invalid pull request number" - ) - yield { - "number": number, - "repository": repository, - "pull_request": { - "url": ( - "https://api.github.com/repos/" - f"{repository}/pulls/{number}" - ) - }, - } - if reached_cutoff or len(pull_requests) < 100: - break - page += 1 - except Exception as exc: - if on_error is None: - raise - on_error(repository, exc) - ''' - ).strip(), - ) - replace_between( - path, - "def sweep(\n", - "\ndef main(\n", - dedent( - ''' - def sweep( - *, - target_client: GitHubClient, - dispatch_client: GitHubClient, - organization: str, - repository_source: str, - lookback_hours: int, - max_dispatches: int, - opencode_allowlist: frozenset[str], - dry_run: bool = False, - now: datetime | None = None, - metrics: SweepMetrics | None = None, - ) -> int: - """Queue bounded new work while isolating candidate-local failures.""" - - if max_dispatches < 1 or max_dispatches > 100: - raise ValueError("max dispatches must be between 1 and 100") - since = cutoff_timestamp(lookback_hours, now=now) - counters = metrics if metrics is not None else SweepMetrics() - run_marker_cache: dict[str, set[str]] = {} - dispatched = 0 - - def record_failure(scope: str, error: Exception) -> None: - """Record one isolated error and preserve the remaining sweep.""" - - counters.failures += 1 - message = " ".join(str(error).split()) or error.__class__.__name__ - print(f"::warning::Agent mention sweep skipped {scope}: {message[:1000]}") - - for issue in list_recent_pull_requests( - target_client, - organization=organization, - repository_source=repository_source, - since=since, - on_error=record_failure, - ): - issue_scope = f"{issue.get('repository')}#{issue.get('number')}" - try: - requests = build_requests_for_pull_request( - target_client, - issue=issue, - since=since, - ) - except Exception as exc: - record_failure(issue_scope, exc) - continue - for request in requests: - request_scope = f"{issue_scope}/comment-{request.comment_id}" - try: - queued_agents = dispatch_request( - request, - target_client=target_client, - dispatch_client=dispatch_client, - opencode_allowlist=opencode_allowlist, - dry_run=dry_run, - workflow_run_since=since, - run_marker_cache=run_marker_cache, - ) - except Exception as exc: - record_failure(request_scope, exc) - continue - if not queued_agents: - continue - dispatched += 1 - if dispatched >= max_dispatches: - print( - "Agent mention sweep reached dispatch limit " - f"{max_dispatches}; isolated failures={counters.failures}." - ) - return dispatched - print( - "Agent mention sweep completed with " - f"{dispatched} dispatch(es) and {counters.failures} isolated failure(s)." - ) - return dispatched - ''' - ).strip(), - ) - replace_once( - path, - dedent( - ''' - sweep( - target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), - dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), - organization=args.organization, - repository_source=args.repository_source, - lookback_hours=args.lookback_hours, - max_dispatches=args.max_dispatches, - opencode_allowlist=allowlist, - dry_run=args.dry_run, - ) - return 0 - ''' - ).strip(), - dedent( - ''' - metrics = SweepMetrics() - sweep( - target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), - dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), - organization=args.organization, - repository_source=args.repository_source, - lookback_hours=args.lookback_hours, - max_dispatches=args.max_dispatches, - opencode_allowlist=allowlist, - dry_run=args.dry_run, - metrics=metrics, - ) - return 1 if metrics.failures else 0 - ''' - ).strip(), - ) - - -def wrapper_workflow(agent: str) -> str: - """Return one complete resilient agent-wrapper workflow.""" - - if agent == "noema": - display = "Noema" - requested_agent = "cwl-noema-review" - workflow_file = "agent-mention-noema-dispatch.yml" - source_event = "agent-mention-noema" - target_event = "noema-review" - extra_env = "" - extra_validation = "" - forwarded_controls = "" - target_label = "authoritative Noema workflow" - else: - display = "OpenCode" - requested_agent = "opencode-agent" - workflow_file = "agent-mention-opencode-dispatch.yml" - source_event = "agent-mention-opencode" - target_event = "merge-scheduler" - extra_env = dedent( - ''' - TRIGGER_REVIEWS: ${{ github.event.client_payload.trigger_reviews }} - REVIEW_DISPATCH_LIMIT: ${{ github.event.client_payload.review_dispatch_limit || '' }} - ENABLE_AUTO_MERGE: ${{ github.event.client_payload.enable_auto_merge }} - UPDATE_BRANCHES: ${{ github.event.client_payload.update_branches }} - MERGE_MODE: ${{ github.event.client_payload.merge_mode || '' }} - ''' - ) - extra_validation = dedent( - ''' - [ "$TRIGGER_REVIEWS" != "true" ] || - [ "$REVIEW_DISPATCH_LIMIT" != "1" ] || - [ "$ENABLE_AUTO_MERGE" != "false" ] || - [ "$UPDATE_BRANCHES" != "false" ] || - [ "$MERGE_MODE" != "disabled" ] || - ''' - ) - forwarded_controls = dedent( - ''' - trigger_reviews: true, - review_dispatch_limit: "1", - enable_auto_merge: false, - update_branches: false, - merge_mode: "disabled", - ''' - ) - target_label = "authoritative review-only scheduler" - - return dedent( - f''' - name: Agent Mention {display} Dispatch - run-name: >- - Agent Mention {display} ${{{{ github.event.client_payload.target_repository }}}}#${{{{ - github.event.client_payload.pr_number }}}} [cwl-agent-invocation:${{{{ - github.event.client_payload.agent_invocation_key }}}}] - - on: - repository_dispatch: - types: [{source_event}] - - concurrency: - group: agent-mention-{agent}-${{{{ github.event.client_payload.agent_invocation_key || github.run_id }}}} - cancel-in-progress: false - queue: max - - permissions: - contents: read - - jobs: - validate-and-forward: - if: github.repository == 'ContextualWisdomLab/.github' - runs-on: ubuntu-24.04 - timeout-minutes: 5 - permissions: - actions: read - contents: write - env: - GH_TOKEN: ${{{{ github.token }}}} - REQUESTED_AGENT: "{requested_agent}" - PAYLOAD_AGENT: ${{{{ github.event.client_payload.requested_agent || '' }}}} - INVOCATION_KEY: ${{{{ github.event.client_payload.agent_invocation_key || '' }}}} - TARGET_REPOSITORY: ${{{{ github.event.client_payload.target_repository || '' }}}} - PR_NUMBER: ${{{{ github.event.client_payload.pr_number || '' }}}} - PR_HEAD_SHA: ${{{{ github.event.client_payload.pr_head_sha || '' }}}} - BASE_BRANCH: ${{{{ github.event.client_payload.base_branch || '' }}}} - REQUESTED_BY: ${{{{ github.event.client_payload.requested_by || '' }}}} - SOURCE_COMMENT_ID: ${{{{ github.event.client_payload.source_comment_id || '' }}}} - {extra_env.rstrip()} - steps: - - name: Validate exact invocation and elect one durable leader - id: leader - run: | - set -euo pipefail - if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || - ! [[ "$INVOCATION_KEY" =~ ^[0-9a-f]{{64}}$ ]] || - ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || - ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || - ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{{40}}$ ]] || - ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || - [[ "$BASE_BRANCH" == -* ]] || - ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || - {extra_validation.rstrip()} - ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]]; then - echo "::error::Rejected malformed or mismatched {display} agent invocation payload." - exit 1 - fi - - python3 - <<'PYTHON' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - {{ - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }}, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - expected = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(expected, os.environ["INVOCATION_KEY"]): - raise SystemExit("invocation key does not match canonical payload") - PYTHON - - marker="[cwl-agent-invocation:${{INVOCATION_KEY}}]" - matching_run_ids() {{ - gh api --paginate --slurp \\ - "repos/${{GITHUB_REPOSITORY}}/actions/workflows/{workflow_file}/runs?event=repository_dispatch&per_page=100" \\ - | jq -r --arg marker "$marker" ' - [.[].workflow_runs[] - | select((.display_title // "") | contains($marker)) - | .id] - | unique - | sort - | .[] - ' - }} - - for attempt in 1 2 3; do - run_ids="$(matching_run_ids)" - lower_id="$( - awk -v current="$GITHUB_RUN_ID" '$1 < current {{ print $1; exit }}' \\ - <<<"$run_ids" - )" - if [ -n "$lower_id" ]; then - echo "forward=false" >>"$GITHUB_OUTPUT" - echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." - exit 0 - fi - if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then - echo "forward=true" >>"$GITHUB_OUTPUT" - exit 0 - fi - if [ "$attempt" -lt 3 ]; then - sleep "$((attempt * 2))" - fi - done - - echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." - echo "forward=true" >>"$GITHUB_OUTPUT" - - - name: Forward once to the {target_label} - if: steps.leader.outputs.forward == 'true' - run: | - set -euo pipefail - jq -n \\ - --arg target_repository "$TARGET_REPOSITORY" \\ - --argjson pr_number "$PR_NUMBER" \\ - --arg pr_head_sha "$PR_HEAD_SHA" \\ - --arg base_branch "$BASE_BRANCH" \\ - --arg requested_agent "$REQUESTED_AGENT" \\ - --arg agent_invocation_key "$INVOCATION_KEY" \\ - --arg requested_by "$REQUESTED_BY" \\ - --argjson source_comment_id "$SOURCE_COMMENT_ID" \\ - '{{ - event_type: "{target_event}", - client_payload: {{ - target_repository: $target_repository, - pr_number: $pr_number, - pr_head_sha: $pr_head_sha, - base_branch: $base_branch, - {forwarded_controls.rstrip()} - requested_agent: $requested_agent, - agent_invocation_key: $agent_invocation_key, - requested_by: $requested_by, - source_comment_id: $source_comment_id - }} - }}' \\ - | gh api "repos/${{GITHUB_REPOSITORY}}/dispatches" -X POST --input - - ''' - ) - - -def update_workflows() -> None: - """Harden wrapper election and keep exchanged credentials out of step outputs.""" - - write( - ".github/workflows/agent-mention-noema-dispatch.yml", - wrapper_workflow("noema"), - ) - write( - ".github/workflows/agent-mention-opencode-dispatch.yml", - wrapper_workflow("opencode"), - ) - path = ".github/workflows/agent-mention-router.yml" - content = read(path) - content = content.replace( - "curl -fsS \\\n -H \"Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}\"", - "curl -fsS --connect-timeout 10 --max-time 30 \\\n -H \"Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}\"", - ) - content = content.replace( - "curl -fsS \\\n -X POST \\\n -H \"Authorization: Bearer ${oidc_token}\"", - "curl -fsS --connect-timeout 10 --max-time 30 \\\n -X POST \\\n -H \"Authorization: Bearer ${oidc_token}\"", - ) - old_output = dedent( - ''' - { - echo "available=true" - echo "token=$app_token" - } >>"$GITHUB_OUTPUT" - ''' - ).strip() - new_output = dedent( - ''' - echo "available=true" >>"$GITHUB_OUTPUT" - echo "SWEEP_APP_TOKEN=$app_token" >>"$GITHUB_ENV" - ''' - ).strip() - if old_output not in content: - raise RuntimeError("agent-mention-router.yml: token output block changed") - content = content.replace(old_output, new_output, 1) - old_step = dedent( - ''' - - name: Sweep recent organization PR comments - env: - TARGET_REPOSITORY_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.sweep_app_token.outputs.token }} - TARGET_REPOSITORY_SOURCE: ${{ (secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '') && 'organization' || steps.sweep_app_token.outputs.available == 'true' && 'installation' || '' }} - AGENT_DISPATCH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - if [ -z "${TARGET_REPOSITORY_TOKEN:-}" ] || [ -z "${TARGET_REPOSITORY_SOURCE:-}" ]; then - echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." - exit 1 - fi - args=( - --organization ContextualWisdomLab - --repository-source "$TARGET_REPOSITORY_SOURCE" - --lookback-hours "$LOOKBACK_HOURS" - --max-dispatches "$MAX_DISPATCHES" - ) - if [ "$DRY_RUN" = "true" ]; then - args+=(--dry-run) - fi - python3 scripts/ci/agent_mention_sweep.py "${args[@]}" - ''' - ).strip() - new_step = dedent( - ''' - - name: Sweep recent organization PR comments - env: - PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} - AGENT_DISPATCH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - if [ -n "$PR_REVIEW_MERGE_TOKEN" ]; then - TARGET_REPOSITORY_TOKEN="$PR_REVIEW_MERGE_TOKEN" - TARGET_REPOSITORY_SOURCE="organization" - elif [ -n "$OPENCODE_APPROVE_TOKEN" ]; then - TARGET_REPOSITORY_TOKEN="$OPENCODE_APPROVE_TOKEN" - TARGET_REPOSITORY_SOURCE="organization" - else - TARGET_REPOSITORY_TOKEN="${SWEEP_APP_TOKEN:-}" - TARGET_REPOSITORY_SOURCE="${TARGET_REPOSITORY_TOKEN:+installation}" - fi - export TARGET_REPOSITORY_TOKEN - if [ -z "$TARGET_REPOSITORY_TOKEN" ] || [ -z "$TARGET_REPOSITORY_SOURCE" ]; then - echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." - exit 1 - fi - args=( - --organization ContextualWisdomLab - --repository-source "$TARGET_REPOSITORY_SOURCE" - --lookback-hours "$LOOKBACK_HOURS" - --max-dispatches "$MAX_DISPATCHES" - ) - if [ "$DRY_RUN" = "true" ]; then - args+=(--dry-run) - fi - python3 scripts/ci/agent_mention_sweep.py "${args[@]}" - ''' - ).strip() - if old_step not in content: - raise RuntimeError("agent-mention-router.yml: sweep step changed") - write(path, content.replace(old_step, new_step, 1)) - - quality_path = ".github/workflows/agent-mention-router-quality-ci.yml" - quality = read(quality_path).replace( - ' - "scripts/ci/agent_mention_invocation.py"\n', "" - ) - write(quality_path, quality) - - -def update_tests() -> None: - """Add executable regressions and repair full-suite-only brittle assertions.""" - - router_test_path = "tests/test_agent_mention_router.py" - old = dedent( - ''' - def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( - capsys, - ) -> None: - """OpenCode fails closed outside its allowlist while dry-run is mutation-free.""" - - module = load_module() - request = module.parse_event(event("@opencode-agent")) - assert request is not None - target = FakeClient() - central = FakeClient() - assert module.dispatch_request( - request, - target_client=target, - dispatch_client=central, - opencode_allowlist=frozenset(), - ) == () - assert central.calls == [] - assert "Rejected @opencode-agent" in target.calls[-1][1]["body"] - target = FakeClient() - central = FakeClient() - assert module.dispatch_request( - request, - target_client=target, - dispatch_client=central, - opencode_allowlist=frozenset(), - dry_run=True, - ) == () - assert target.calls == central.calls == [] - output = capsys.readouterr().out - assert "DRY-RUN agent mention" in output - assert "reject=opencode-agent" in output - ''' - ).strip() - new = dedent( - ''' - def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( - capsys, - ) -> None: - """Rejected-only and dry-run requests remain mutation-free.""" - - module = load_module() - request = module.parse_event(event("@opencode-agent")) - assert request is not None - target = FakeClient() - central = FakeClient() - assert module.dispatch_request( - request, - target_client=target, - dispatch_client=central, - opencode_allowlist=frozenset(), - ) == () - assert target.calls == central.calls == [] - assert "Rejected agent mention without target mutation" in capsys.readouterr().out - - target = FakeClient() - central = FakeClient() - assert module.dispatch_request( - request, - target_client=target, - dispatch_client=central, - opencode_allowlist=frozenset(), - dry_run=True, - ) == () - assert target.calls == central.calls == [] - output = capsys.readouterr().out - assert "DRY-RUN agent mention" in output - assert "reject=opencode-agent" in output - ''' - ).strip() - replace_once(router_test_path, old, new) - - write( - "tests/test_pr_review_fix_scheduler_coverage.py", - dedent( - ''' - """Coverage-only regressions for the review-fix scheduler.""" - - import builtins - import runpy - - import scripts.ci.pr_review_fix_scheduler as fix - - - def test_import_falls_back_to_package_module(monkeypatch): - """The scheduler remains importable when only the package path is available.""" - - real_import = builtins.__import__ - - def import_without_script_directory( - name, - globals_=None, - locals_=None, - fromlist=(), - level=0, - ): - """Reject the script-directory import and delegate every other import.""" - - if name == "pr_review_merge_scheduler": - raise ModuleNotFoundError(name) - return real_import(name, globals_, locals_, fromlist, level) - - monkeypatch.setattr( - builtins, - "__import__", - import_without_script_directory, - ) - namespace = runpy.run_path( - "scripts/ci/pr_review_fix_scheduler.py", - run_name="pr_review_fix_scheduler_package_fallback_test", - ) - - loaded = namespace["fetch_open_prs"] - assert loaded.__name__ == fix.fetch_open_prs.__name__ - assert loaded.__code__.co_filename == fix.fetch_open_prs.__code__.co_filename - - - def test_coverage_process_queue_skips_draft_and_wrong_base_and_external_repo(monkeypatch): - """Draft, wrong-base, and external-head PRs are skipped.""" - - def make_pr(number=1, **kwargs): - pr = { - "number": number, - "headRefOid": "abc", - "baseRefName": "main", - "headRefName": "feature", - "isDraft": False, - "headRepository": {"nameWithOwner": "owner/repo"}, - } - pr.update(kwargs) - return pr - - args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) - pr1 = make_pr(number=1, isDraft=True) - pr2 = make_pr(number=2, baseRefName="other") - pr3 = make_pr(number=3, headRepository={"nameWithOwner": "fork/repo"}) - monkeypatch.setattr( - fix, - "fetch_open_prs", - lambda repo, max_prs: [pr1, pr2, pr3], - ) - monkeypatch.setattr( - fix, - "inspect_pr", - lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), - ) - assert fix.process_queue(args) == 0 - - - def test_coverage_process_queue_exception_handling(monkeypatch): - """One issue-comment lookup failure does not crash queue processing.""" - - def make_pr(number=1, **kwargs): - pr = { - "number": number, - "headRefOid": "abc", - "baseRefName": "main", - "headRefName": "feature", - "isDraft": False, - "headRepository": {"nameWithOwner": "owner/repo"}, - } - pr.update(kwargs) - return pr - - args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) - pr1 = make_pr(number=1) - pr2 = make_pr(number=2) - monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2]) - monkeypatch.setattr(fix, "needs_autofix", lambda pr: (True, ("reason",))) - - def raise_error(repo, number): - raise RuntimeError("boom") - - monkeypatch.setattr(fix, "issue_comments", raise_error) - monkeypatch.setattr( - fix, - "inspect_pr", - lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), - ) - assert fix.process_queue(args) == 0 - ''' - ), - ) - - write( - "tests/test_agent_mention_downstream_idempotency.py", - dedent( - ''' - """Static contracts for downstream review-agent invocation idempotency.""" - - from pathlib import Path - - ROOT = Path(__file__).resolve().parents[1] - ROUTER_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" - QUALITY_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" - NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" - OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" - ROUTER_SCRIPT = ROOT / "scripts" / "ci" / "agent_mention_router.py" - - - def test_router_can_read_durable_central_workflow_runs() -> None: - """Both local routing and sibling sweeping receive actions read access.""" - - text = ROUTER_WORKFLOW.read_text(encoding="utf-8") - local, sweep = text.split("\n sweep-organization-agent-mentions:\n", 1) - assert "permissions:\n actions: read" in local - assert "permissions:\n actions: read" in sweep - assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in local - assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep - - - def test_downstream_workflows_retry_visibility_and_bind_exact_key() -> None: - """Wrappers queue duplicates and never lose a request to eventual consistency.""" - - noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") - opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") - for text in (noema, opencode): - assert "github.event.client_payload.agent_invocation_key" in text - assert "cwl-agent-invocation:" in text - assert "source_comment_id" in text - assert "requested_agent" in text - assert "cancel-in-progress: false" in text - assert "queue: max" in text - assert "for attempt in 1 2 3" in text - assert 'sleep "$((attempt * 2))"' in text - assert "no lower durable run was observed" in text - assert "^[0-9a-f]{64}$" in text - assert "^[1-9][0-9]*$" in text - assert "repos/${GITHUB_REPOSITORY}/dispatches" in text - assert "types: [agent-mention-noema]" in noema - assert 'event_type: "noema-review"' in noema - assert 'REQUESTED_AGENT: "cwl-noema-review"' in noema - assert "types: [agent-mention-opencode]" in opencode - assert 'event_type: "merge-scheduler"' in opencode - assert 'REQUESTED_AGENT: "opencode-agent"' in opencode - assert '[[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' in opencode - assert '[[ "$BASE_BRANCH" == -* ]]' in opencode - - - def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: - """A syntactically valid key cannot authorize altered payload fields.""" - - router = ROUTER_SCRIPT.read_text(encoding="utf-8") - noema_function = router.split("def noema_payload", 1)[1].split( - "def opencode_payload", 1 - )[0] - assert '"base_branch": request.pull_request_base_branch' in noema_function - - canonical_fields = ( - '"actor"', - '"agent"', - '"base_branch"', - '"comment_id"', - '"head_sha"', - '"pr_number"', - '"repository"', - ) - for text in ( - NOEMA_WORKFLOW.read_text(encoding="utf-8"), - OPENCODE_WORKFLOW.read_text(encoding="utf-8"), - ): - assert "BASE_BRANCH:" in text - assert "import hashlib" in text - assert "import hmac" in text - assert "json.dumps(" in text - assert 'separators=(",", ":")' in text - assert "sort_keys=True" in text - assert "hashlib.sha256" in text - assert "hmac.compare_digest" in text - assert "INVOCATION_KEY" in text - for field in canonical_fields: - assert field in text - - - def test_quality_gate_runs_full_suite_for_docs_and_exact_diff() -> None: - """Every changed contract executes while coverage stays source-bounded.""" - - text = QUALITY_WORKFLOW.read_text(encoding="utf-8") - assert ' - "docs/automation/review-agent-comment-invocation.md"' in text - assert ' - "tests/test_agent_mention_*.py"' in text - assert "python -m coverage run -m pytest -q\n" in text - assert "python -m compileall -q scripts/ci tests" in text - assert "CHANGE_DIFF_RANGE" in text - assert 'git diff --check "$CHANGE_DIFF_RANGE"' in text - coverage_config = text.split("[run]\n", 1)[1].split("[report]\n", 1)[0] - assert "scripts/ci/agent_mention_router.py" in coverage_config - assert "scripts/ci/agent_mention_sweep.py" in coverage_config - ''' - ), - ) - - write( - "tests/test_agent_mention_review_regressions.py", - dedent( - ''' - """Review-driven runtime regressions for the agent mention control plane.""" - - from __future__ import annotations - - import importlib.util - import sys - from datetime import datetime, timezone - from pathlib import Path - from types import ModuleType, SimpleNamespace - - import pytest - - ROOT = Path(__file__).resolve().parents[1] - MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" - - - def load_module() -> ModuleType: - """Load the router under one isolated module name.""" - - module_name = "agent_mention_router_review_regressions" - spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) - return module - - - def request(module: ModuleType, agents=("cwl-noema-review", "opencode-agent")): - """Build one exact invocation request.""" - - return module.MentionRequest( - "ContextualWisdomLab/Example", - 17, - "a" * 40, - "main", - 91, - "maintainer", - agents, - ) - - - class FakeClient: - """Capture API requests and expose endpoint-keyed run inventories.""" - - def __init__(self, responses=None) -> None: - """Initialize responses and an empty call ledger.""" - - self.responses = responses or {} - self.calls: list[tuple[list[str], dict | None]] = [] - - def request(self, args, *, input_payload=None): - """Record a call and return its registered response.""" - - self.calls.append((list(args), input_payload)) - if args[0].endswith("/runs"): - return self.responses.get(args[0], {"workflow_runs": []}) - return None - - - def test_actor_and_allowlist_validation_are_wrapper_compatible() -> None: - """Router validation rejects actors wrappers cannot accept.""" - - module = load_module() - payload = { - "repository": {"full_name": "ContextualWisdomLab/Example"}, - "issue": {"number": 17, "pull_request": {"url": "x"}}, - "comment": { - "id": 91, - "body": "@opencode-agent", - "author_association": "MEMBER", - "user": {"login": "bad_actor", "type": "User"}, - }, - "pull_request": { - "state": "open", - "head": {"sha": "a" * 40}, - "base": {"ref": "main"}, - }, - } - with pytest.raises(ValueError, match="actor"): - module.parse_event(payload) - - mention = request(module, ("opencode-agent",)) - assert module.eligible_agents( - mention, - opencode_allowlist=frozenset({"contextualwisdomlab/example"}), - ) == (("opencode-agent",), ()) - - - @pytest.mark.parametrize( - ("stderr", "message"), - [("permission denied\n details", "permission denied details"), ("", "no stderr")], - ) - def test_github_client_surfaces_bounded_api_diagnostics( - monkeypatch, - stderr: str, - message: str, - ) -> None: - """A failed gh call identifies the real API boundary.""" - - module = load_module() - monkeypatch.setattr( - module.subprocess, - "run", - lambda *args, **kwargs: SimpleNamespace( - stdout="", - stderr=stderr, - returncode=1, - ), - ) - with pytest.raises(RuntimeError, match=message): - module.GitHubClient("token").request(["repos/x/y"]) - - - def test_workflow_run_cutoff_and_marker_cache_bound_api_cost() -> None: - """Each agent workflow inventory is queried once per sweep window.""" - - module = load_module() - now = datetime(2026, 8, 6, 12, tzinfo=timezone.utc) - cutoff = module.workflow_run_cutoff(now=now, lookback_hours=24) - assert cutoff == "2026-08-05T12:00:00Z" - with pytest.raises(ValueError, match="timezone-aware"): - module.workflow_run_cutoff(now=datetime(2026, 8, 6)) - - mention = request(module) - noema_endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] - noema_marker = module.agent_invocation_marker( - mention, "cwl-noema-review" - ) - client = FakeClient( - { - noema_endpoint: { - "workflow_runs": [ - { - "id": 1, - "event": "repository_dispatch", - "display_title": f"run {noema_marker}", - } - ] - } - } - ) - cache: dict[str, set[str]] = {} - expected = frozenset({"cwl-noema-review"}) - assert module.dispatched_agents( - mention, - client, - workflow_run_since=cutoff, - run_marker_cache=cache, - ) == expected - assert module.dispatched_agents( - mention, - client, - workflow_run_since=cutoff, - run_marker_cache=cache, - ) == expected - run_calls = [args for args, _ in client.calls if args[0].endswith("/runs")] - assert len(run_calls) == 2 - assert all(f"created=>={cutoff}" in args for args in run_calls) - - - def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> None: - """Accepted dispatches update the in-memory ledger before wrapper visibility.""" - - module = load_module() - mention = request(module) - target = FakeClient() - central = FakeClient() - cache: dict[str, set[str]] = {} - allowlist = frozenset({"contextualwisdomlab/example"}) - - assert module.dispatch_request( - mention, - target_client=target, - dispatch_client=central, - opencode_allowlist=allowlist, - workflow_run_since="2026-08-01T00:00:00Z", - run_marker_cache=cache, - ) == ("@cwl-noema-review", "@opencode-agent") - first_target_calls = len(target.calls) - assert module.dispatch_request( - mention, - target_client=target, - dispatch_client=central, - opencode_allowlist=allowlist, - workflow_run_since="2026-08-01T00:00:00Z", - run_marker_cache=cache, - ) == () - assert len(target.calls) == first_target_calls - dispatches = [ - payload["event_type"] - for args, payload in central.calls - if args[0].endswith("/dispatches") and payload - ] - assert dispatches == ["agent-mention-noema", "agent-mention-opencode"] - - mixed = request(module) - mixed_target = FakeClient() - mixed_central = FakeClient() - mixed_cache: dict[str, set[str]] = {} - assert module.dispatch_request( - mixed, - target_client=mixed_target, - dispatch_client=mixed_central, - opencode_allowlist=frozenset(), - run_marker_cache=mixed_cache, - ) == ("@cwl-noema-review",) - first_mixed_calls = len(mixed_target.calls) - assert module.dispatch_request( - mixed, - target_client=mixed_target, - dispatch_client=mixed_central, - opencode_allowlist=frozenset(), - run_marker_cache=mixed_cache, - ) == () - assert len(mixed_target.calls) == first_mixed_calls - ''' - ), - ) - - write( - "tests/test_agent_mention_sweep_regressions.py", - dedent( - ''' - """Review-driven pagination and failure-isolation regressions.""" - - from __future__ import annotations - - import importlib - import sys - from datetime import datetime, timezone - from pathlib import Path - - import pytest - - ROOT = Path(__file__).resolve().parents[1] - SCRIPTS = ROOT / "scripts" / "ci" - sys.path.insert(0, str(SCRIPTS)) - - - def module(): - """Reload the sweep module for isolated monkeypatching.""" - - return importlib.reload(importlib.import_module("agent_mention_sweep")) - - - def repository(name: str) -> dict: - """Build one active organization repository record.""" - - return { - "full_name": f"ContextualWisdomLab/{name}", - "owner": {"login": "ContextualWisdomLab"}, - "archived": False, - "disabled": False, - } - - - class PagingClient: - """Serve page-aware endpoint responses and deterministic failures.""" - - def __init__(self, responses) -> None: - """Initialize an endpoint/page response map.""" - - self.responses = responses - self.calls: list[list[str]] = [] - - def request(self, args, *, input_payload=None): - """Return one endpoint/page response or raise its configured error.""" - - del input_payload - args = list(args) - self.calls.append(args) - endpoint = args[0] - page = 1 - for index, value in enumerate(args[:-1]): - if value == "-f" and args[index + 1].startswith("page="): - page = int(args[index + 1].split("=", 1)[1]) - response = self.responses[(endpoint, page)] - if isinstance(response, Exception): - raise response - return response - - - def pull(number: int, updated_at: str = "2026-08-06T11:00:00Z") -> dict: - """Build one pull-list response record.""" - - return {"number": number, "updated_at": updated_at} - - - def test_pull_pagination_stops_at_cutoff_without_loading_later_pages() -> None: - """Updated-descending pages stop immediately at the first old record.""" - - sweep = module() - recent = [pull(number) for number in range(1, 101)] - client = PagingClient( - { - ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], - ("repos/ContextualWisdomLab/example/pulls", 1): recent, - ("repos/ContextualWisdomLab/example/pulls", 2): [ - pull(101, "2026-08-01T00:00:00Z") - ], - } - ) - results = list( - sweep.list_recent_pull_requests( - client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-05T00:00:00Z", - ) - ) - assert len(results) == 100 - pull_calls = [ - args for args in client.calls if args[0].endswith("/pulls") - ] - assert len(pull_calls) == 2 - assert not any("page=3" in args for args in pull_calls) - assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] - - - def test_repository_failure_is_isolated_and_later_repository_runs() -> None: - """A repository-local API failure does not terminate organization traversal.""" - - sweep = module() - client = PagingClient( - { - ("orgs/ContextualWisdomLab/repos", 1): [[ - repository("broken"), - repository("healthy"), - ]], - ("repos/ContextualWisdomLab/broken/pulls", 1): RuntimeError( - "forbidden" - ), - ("repos/ContextualWisdomLab/healthy/pulls", 1): [pull(7)], - } - ) - failures = [] - results = list( - sweep.list_recent_pull_requests( - client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-05T00:00:00Z", - on_error=lambda scope, error: failures.append( - (scope, str(error)) - ), - ) - ) - assert [result["repository"] for result in results] == [ - "ContextualWisdomLab/healthy" - ] - assert failures == [("ContextualWisdomLab/broken", "forbidden")] - - - def mention_request(comment_id: int): - """Build one Noema request for orchestration isolation tests.""" - - router = importlib.import_module("agent_mention_router") - return router.MentionRequest( - "ContextualWisdomLab/example", - 7, - "a" * 40, - "main", - comment_id, - "maintainer", - ("cwl-noema-review",), - ) - - - def test_sweep_continues_after_candidate_and_dispatch_failures( - monkeypatch, - capsys, - ) -> None: - """Candidate-local failures are counted while later work is queued.""" - - sweep = module() - issues = [ - {"repository": "ContextualWisdomLab/example", "number": 7}, - {"repository": "ContextualWisdomLab/example", "number": 8}, - ] - monkeypatch.setattr( - sweep, - "list_recent_pull_requests", - lambda *args, **kwargs: iter(issues), - ) - - def build_requests(client, *, issue, since): - del client, since - if issue["number"] == 7: - raise RuntimeError("comment inventory failed") - return (mention_request(10), mention_request(11)) - - monkeypatch.setattr(sweep, "build_requests_for_pull_request", build_requests) - dispatch_kwargs = [] - - def dispatch(request, **kwargs): - dispatch_kwargs.append(kwargs) - if request.comment_id == 10: - raise RuntimeError("dispatch failed") - return ("@cwl-noema-review",) - - monkeypatch.setattr(sweep, "dispatch_request", dispatch) - metrics = sweep.SweepMetrics() - assert sweep.sweep( - target_client=object(), - dispatch_client=object(), - organization="ContextualWisdomLab", - repository_source="organization", - lookback_hours=24, - max_dispatches=5, - opencode_allowlist=frozenset(), - now=datetime(2026, 8, 6, tzinfo=timezone.utc), - metrics=metrics, - ) == 1 - assert metrics.failures == 2 - assert dispatch_kwargs[0]["run_marker_cache"] is dispatch_kwargs[1][ - "run_marker_cache" - ] - assert dispatch_kwargs[0]["workflow_run_since"].endswith("Z") - output = capsys.readouterr().out - assert "comment inventory failed" in output - assert "dispatch failed" in output - - - def test_main_returns_failure_when_isolated_errors_were_observed( - monkeypatch, - ) -> None: - """The scheduled workflow remains visibly failed after partial progress.""" - - sweep = module() - monkeypatch.setenv("TARGET_REPOSITORY_TOKEN", "target") - monkeypatch.setenv("AGENT_DISPATCH_TOKEN", "dispatch") - - def fail_partially(**kwargs): - kwargs["metrics"].failures = 1 - return 0 - - monkeypatch.setattr(sweep, "sweep", fail_partially) - assert sweep.main([]) == 1 - ''' - ), - ) - - -def main() -> int: - """Apply every deterministic final-state transformation.""" - - update_router() - update_sweep() - update_workflows() - update_tests() - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/ci/repair_pr787_finalizer_source.py b/scripts/ci/repair_pr787_finalizer_source.py deleted file mode 100644 index c4fb31bbe..000000000 --- a/scripts/ci/repair_pr787_finalizer_source.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/env python3 -"""Repair the transient PR 787 transformer before executing it.""" - -from __future__ import annotations - -from pathlib import Path - -TARGET = Path(__file__).with_name("finalize_pr787_review_findings.py") - -OLD_REPLACE_ONCE = '''def replace_once(path: str, old: str, new: str) -> None: - """Replace exactly one literal block and fail on an unexpected source tree.""" - - content = read(path) - count = content.count(old) - if count != 1: - raise RuntimeError(f"{path}: expected one replacement target, found {count}") - write(path, content.replace(old, new, 1)) -''' - -NEW_REPLACE_ONCE = '''def _indented(block: str, width: int) -> str: - """Return ``block`` with one uniform source indentation prefix.""" - - prefix = " " * width - return "\\n".join(prefix + line if line else line for line in block.split("\\n")) - - -def replace_once(path: str, old: str, new: str) -> None: - """Replace one literal block, accepting its repository indentation.""" - - content = read(path) - matches: list[tuple[str, str]] = [] - for width in range(0, 21): - candidate = _indented(old, width) - count = content.count(candidate) - if count > 1: - raise RuntimeError( - f"{path}: replacement target is ambiguous at indent {width}: {count}" - ) - if count == 1: - matches.append((candidate, _indented(new, width))) - if len(matches) != 1: - raise RuntimeError( - f"{path}: expected one indentation-aware replacement target, found {len(matches)}" - ) - candidate, replacement = matches[0] - write(path, content.replace(candidate, replacement, 1)) -''' - -OLD_REPLACE_BETWEEN = '''def replace_between(path: str, start: str, end: str, replacement: str) -> None: - """Replace one section delimited by stable function markers.""" - - content = read(path) - start_index = content.index(start) - end_index = content.index(end, start_index) - write(path, content[:start_index] + replacement.rstrip() + "\\n\\n" + content[end_index + 1 :]) -''' - -NEW_REPLACE_BETWEEN = '''def replace_between(path: str, start: str, end: str, replacement: str) -> None: - """Replace one section delimited by stable function markers.""" - - content = read(path) - start_index = content.index(start) - try: - end_index = content.index(end, start_index) - except ValueError: - if not end.endswith("(\\n"): - raise - end_index = content.index(end[:-1], start_index) - write(path, content[:start_index] + replacement.rstrip() + "\\n\\n" + content[end_index + 1 :]) -''' - -OLD_OUTPUT_REPLACEMENT = ''' if old_output not in content: - raise RuntimeError("agent-mention-router.yml: token output block changed") - content = content.replace(old_output, new_output, 1) -''' - -NEW_OUTPUT_REPLACEMENT = ''' output_matches = [ - (_indented(old_output, width), _indented(new_output, width)) - for width in range(0, 21) - if content.count(_indented(old_output, width)) == 1 - ] - if len(output_matches) != 1: - raise RuntimeError( - "agent-mention-router.yml: token output block changed or ambiguous" - ) - content = content.replace(*output_matches[0], 1) -''' - -OLD_STEP_REPLACEMENT = ''' if old_step not in content: - raise RuntimeError("agent-mention-router.yml: sweep step changed") - write(path, content.replace(old_step, new_step, 1)) -''' - -NEW_STEP_REPLACEMENT = ''' step_matches = [ - (_indented(old_step, width), _indented(new_step, width)) - for width in range(0, 21) - if content.count(_indented(old_step, width)) == 1 - ] - if len(step_matches) != 1: - raise RuntimeError( - "agent-mention-router.yml: sweep step changed or ambiguous" - ) - write(path, content.replace(*step_matches[0], 1)) -''' - -OLD_HANDLE_STATUS = ''' status_parts: list[str] = [] - if handles: - status_parts.append(f"Queued {' and '.join(handles)}") - existing_handles = tuple( -''' - -NEW_HANDLE_STATUS = ''' status_parts = [f"Queued {' and '.join(handles)}"] - existing_handles = tuple( -''' - -OLD_RUN_INVENTORY = ''' "workflow_runs": [ - { - "id": 1, - "event": "repository_dispatch", - "display_title": f"run {noema_marker}", - } - ] -''' - -NEW_RUN_INVENTORY = ''' "workflow_runs": [ - { - "id": 0, - "event": "repository_dispatch", - "display_title": f"ignored {noema_marker}", - }, - { - "id": 1, - "event": "repository_dispatch", - "display_title": f"run {noema_marker}", - }, - ] -''' - -OLD_SWEEP_TEST_ANCHOR = ''' assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] - - - def test_repository_failure_is_isolated_and_later_repository_runs() -> None: -''' - -NEW_SWEEP_TEST_ANCHOR = ''' assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] - - - def test_pull_pagination_stops_on_empty_followup_page() -> None: - """A full page followed by an empty page terminates without page three.""" - - sweep = module() - recent = [pull(number) for number in range(1, 101)] - client = PagingClient( - { - ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], - ("repos/ContextualWisdomLab/example/pulls", 1): recent, - ("repos/ContextualWisdomLab/example/pulls", 2): [], - } - ) - results = list( - sweep.list_recent_pull_requests( - client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-05T00:00:00Z", - ) - ) - assert len(results) == 100 - pull_calls = [ - args for args in client.calls if args[0].endswith("/pulls") - ] - assert len(pull_calls) == 2 - assert any("page=2" in args for args in pull_calls) - assert not any("page=3" in args for args in pull_calls) - - - def test_invalid_pull_number_fails_closed_without_error_sink() -> None: - """Malformed pull metadata raises when no isolation sink is supplied.""" - - sweep = module() - client = PagingClient( - { - ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], - ("repos/ContextualWisdomLab/example/pulls", 1): [pull(0)], - } - ) - with pytest.raises(ValueError, match="invalid pull request number"): - list( - sweep.list_recent_pull_requests( - client, - organization="ContextualWisdomLab", - repository_source="organization", - since="2026-08-05T00:00:00Z", - ) - ) - - - def test_repository_failure_is_isolated_and_later_repository_runs() -> None: -''' - -RAW_TEST_HEADINGS = ( - '"""Coverage-only regressions for the review-fix scheduler."""', - '"""Static contracts for downstream review-agent invocation idempotency."""', - '"""Review-driven runtime regressions for the agent mention control plane."""', - '"""Review-driven pagination and failure-isolation regressions."""', -) - -RAW_GENERATED_FUNCTIONS = ( - "def dispatch_request(", -) - - -def main() -> int: - """Patch matching, generated literals, and nested regex escaping.""" - - content = TARGET.read_text(encoding="utf-8") - replacements = ( - ( - OLD_REPLACE_ONCE, - NEW_REPLACE_ONCE, - "transient replace_once source no longer matches its contract", - ), - ( - OLD_REPLACE_BETWEEN, - NEW_REPLACE_BETWEEN, - "transient replace_between source no longer matches its contract", - ), - ( - OLD_OUTPUT_REPLACEMENT, - NEW_OUTPUT_REPLACEMENT, - "transient output replacement source no longer matches its contract", - ), - ( - OLD_STEP_REPLACEMENT, - NEW_STEP_REPLACEMENT, - "transient step replacement source no longer matches its contract", - ), - ( - OLD_HANDLE_STATUS, - NEW_HANDLE_STATUS, - "generated status block no longer matches its contract", - ), - ( - OLD_RUN_INVENTORY, - NEW_RUN_INVENTORY, - "generated workflow-run test inventory no longer matches", - ), - ( - OLD_SWEEP_TEST_ANCHOR, - NEW_SWEEP_TEST_ANCHOR, - "generated sweep coverage anchor no longer matches", - ), - ) - for old, new, error in replacements: - if content.count(old) != 1: - raise RuntimeError(error) - content = content.replace(old, new, 1) - for heading in RAW_TEST_HEADINGS: - old = "dedent(\n '''\n " + heading - new = "dedent(\n r'''\n " + heading - if content.count(old) != 1: - raise RuntimeError(f"generated test block no longer matches: {heading}") - content = content.replace(old, new, 1) - for signature in RAW_GENERATED_FUNCTIONS: - old = "dedent(\n '''\n " + signature - new = "dedent(\n r'''\n " + signature - if content.count(old) != 1: - raise RuntimeError( - f"generated function block no longer matches: {signature}" - ) - content = content.replace(old, new, 1) - for overescaped, corrected in ( - (r"\\\\d", r"\\d"), - (r"\\\\[", r"\\["), - (r"\\\\]", r"\\]"), - ): - content = content.replace(overescaped, corrected) - TARGET.write_text(content, encoding="utf-8") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index 2235f5a5a..c369763a0 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -1,18 +1,13 @@ + """Static contracts for downstream review-agent invocation idempotency.""" from pathlib import Path ROOT = Path(__file__).resolve().parents[1] ROUTER_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router.yml" -QUALITY_WORKFLOW = ( - ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" -) -NOEMA_WORKFLOW = ( - ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" -) -OPENCODE_WORKFLOW = ( - ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" -) +QUALITY_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-router-quality-ci.yml" +NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" +OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" ROUTER_SCRIPT = ROOT / "scripts" / "ci" / "agent_mention_router.py" @@ -27,8 +22,8 @@ def test_router_can_read_durable_central_workflow_runs() -> None: assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep -def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> None: - """Agent wrappers serialize and validate one exact invocation key.""" +def test_downstream_workflows_retry_visibility_and_bind_exact_key() -> None: + """Wrappers queue duplicates and never lose a request to eventual consistency.""" noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") @@ -38,6 +33,10 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No assert "source_comment_id" in text assert "requested_agent" in text assert "cancel-in-progress: false" in text + assert "queue: max" in text + assert "for attempt in 1 2 3" in text + assert 'sleep "$((attempt * 2))"' in text + assert "no lower durable run was observed" in text assert "^[0-9a-f]{64}$" in text assert "^[1-9][0-9]*$" in text assert "repos/${GITHUB_REPOSITORY}/dispatches" in text @@ -47,7 +46,6 @@ def test_downstream_workflows_bind_run_name_and_concurrency_to_exact_key() -> No assert "types: [agent-mention-opencode]" in opencode assert 'event_type: "merge-scheduler"' in opencode assert 'REQUESTED_AGENT: "opencode-agent"' in opencode - assert "^(?!-)" not in opencode assert '[[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' in opencode assert '[[ "$BASE_BRANCH" == -* ]]' in opencode @@ -61,8 +59,6 @@ def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: )[0] assert '"base_branch": request.pull_request_base_branch' in noema_function - noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") - opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") canonical_fields = ( '"actor"', '"agent"', @@ -72,7 +68,10 @@ def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: '"pr_number"', '"repository"', ) - for text in (noema, opencode): + for text in ( + NOEMA_WORKFLOW.read_text(encoding="utf-8"), + OPENCODE_WORKFLOW.read_text(encoding="utf-8"), + ): assert "BASE_BRANCH:" in text assert "import hashlib" in text assert "import hmac" in text @@ -86,42 +85,16 @@ def test_wrappers_recompute_the_router_canonical_payload_digest() -> None: assert field in text -def test_quality_gate_tracks_every_idempotency_surface() -> None: - """The permanent focused gate reruns and executes all bounded contracts.""" +def test_quality_gate_runs_full_suite_for_docs_and_exact_diff() -> None: + """Every changed contract executes while coverage stays source-bounded.""" text = QUALITY_WORKFLOW.read_text(encoding="utf-8") - for workflow_path in ( - ".github/workflows/agent-mention-noema-dispatch.yml", - ".github/workflows/agent-mention-opencode-dispatch.yml", - ): - assert f' - "{workflow_path}"' in text - + assert ' - "docs/automation/review-agent-comment-invocation.md"' in text assert ' - "tests/test_agent_mention_*.py"' in text - test_command = text.split("python -m coverage run -m pytest -q", 1)[1] - compile_command = text.split("python -m compileall -q", 1)[1] - for test_path in ( - "tests/test_agent_mention_idempotency.py", - "tests/test_agent_mention_downstream_idempotency.py", - ): - assert test_path in test_command - assert test_path in compile_command - - -def test_branch_contains_no_transient_pr787_repair_automation() -> None: - """One-shot branch writers and repair helpers must not ship with the router.""" - - transient_paths = ( - ".github/pr787-payload-repair.trigger", - ".github/workflows/repair-pr787-export-reviewed-files.yml", - ".github/workflows/repair-pr787-export-workflows.yml", - ".github/workflows/repair-pr787-noema-base-branch.yml", - ".github/workflows/repair-pr787-payload-binding-push.yml", - ".github/workflows/repair-pr787-payload-bound-invocation.yml", - ".github/workflows/repair-pr787-payload-bound-v2.yml", - ".github/workflows/repair-pr787-payload-candidate.yml", - ".github/workflows/repair-pr787-payload-digest.yml", - ".github/workflows/repair-pr787-payload-upload.yml", - "scripts/ci/apply_pr787_payload_binding.py", - "scripts/ci/repair_pr787_payload_bound_once.py", - ) - assert all(not (ROOT / relative_path).exists() for relative_path in transient_paths) + assert "python -m coverage run -m pytest -q\n" in text + assert "python -m compileall -q scripts/ci tests" in text + assert "CHANGE_DIFF_RANGE" in text + assert 'git diff --check "$CHANGE_DIFF_RANGE"' in text + coverage_config = text.split("[run]\n", 1)[1].split("[report]\n", 1)[0] + assert "scripts/ci/agent_mention_router.py" in coverage_config + assert "scripts/ci/agent_mention_sweep.py" in coverage_config diff --git a/tests/test_agent_mention_review_regressions.py b/tests/test_agent_mention_review_regressions.py new file mode 100644 index 000000000..db5051e23 --- /dev/null +++ b/tests/test_agent_mention_review_regressions.py @@ -0,0 +1,222 @@ + +"""Review-driven runtime regressions for the agent mention control plane.""" + +from __future__ import annotations + +import importlib.util +import sys +from datetime import datetime, timezone +from pathlib import Path +from types import ModuleType, SimpleNamespace + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" + + +def load_module() -> ModuleType: + """Load the router under one isolated module name.""" + + module_name = "agent_mention_router_review_regressions" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def request(module: ModuleType, agents=("cwl-noema-review", "opencode-agent")): + """Build one exact invocation request.""" + + return module.MentionRequest( + "ContextualWisdomLab/Example", + 17, + "a" * 40, + "main", + 91, + "maintainer", + agents, + ) + + +class FakeClient: + """Capture API requests and expose endpoint-keyed run inventories.""" + + def __init__(self, responses=None) -> None: + """Initialize responses and an empty call ledger.""" + + self.responses = responses or {} + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Record a call and return its registered response.""" + + self.calls.append((list(args), input_payload)) + if args[0].endswith("/runs"): + return self.responses.get(args[0], {"workflow_runs": []}) + return None + + +def test_actor_and_allowlist_validation_are_wrapper_compatible() -> None: + """Router validation rejects actors wrappers cannot accept.""" + + module = load_module() + payload = { + "repository": {"full_name": "ContextualWisdomLab/Example"}, + "issue": {"number": 17, "pull_request": {"url": "x"}}, + "comment": { + "id": 91, + "body": "@opencode-agent", + "author_association": "MEMBER", + "user": {"login": "bad_actor", "type": "User"}, + }, + "pull_request": { + "state": "open", + "head": {"sha": "a" * 40}, + "base": {"ref": "main"}, + }, + } + with pytest.raises(ValueError, match="actor"): + module.parse_event(payload) + + mention = request(module, ("opencode-agent",)) + assert module.eligible_agents( + mention, + opencode_allowlist=frozenset({"contextualwisdomlab/example"}), + ) == (("opencode-agent",), ()) + + +@pytest.mark.parametrize( + ("stderr", "message"), + [("permission denied\n details", "permission denied details"), ("", "no stderr")], +) +def test_github_client_surfaces_bounded_api_diagnostics( + monkeypatch, + stderr: str, + message: str, +) -> None: + """A failed gh call identifies the real API boundary.""" + + module = load_module() + monkeypatch.setattr( + module.subprocess, + "run", + lambda *args, **kwargs: SimpleNamespace( + stdout="", + stderr=stderr, + returncode=1, + ), + ) + with pytest.raises(RuntimeError, match=message): + module.GitHubClient("token").request(["repos/x/y"]) + + +def test_workflow_run_cutoff_and_marker_cache_bound_api_cost() -> None: + """Each agent workflow inventory is queried once per sweep window.""" + + module = load_module() + now = datetime(2026, 8, 6, 12, tzinfo=timezone.utc) + cutoff = module.workflow_run_cutoff(now=now, lookback_hours=24) + assert cutoff == "2026-08-05T12:00:00Z" + with pytest.raises(ValueError, match="timezone-aware"): + module.workflow_run_cutoff(now=datetime(2026, 8, 6)) + + mention = request(module) + noema_endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] + noema_marker = module.agent_invocation_marker( + mention, "cwl-noema-review" + ) + client = FakeClient( + { + noema_endpoint: { + "workflow_runs": [ + { + "id": 0, + "event": "repository_dispatch", + "display_title": f"ignored {noema_marker}", + }, + { + "id": 1, + "event": "repository_dispatch", + "display_title": f"run {noema_marker}", + }, + ] + } + } + ) + cache: dict[str, set[str]] = {} + expected = frozenset({"cwl-noema-review"}) + assert module.dispatched_agents( + mention, + client, + workflow_run_since=cutoff, + run_marker_cache=cache, + ) == expected + assert module.dispatched_agents( + mention, + client, + workflow_run_since=cutoff, + run_marker_cache=cache, + ) == expected + run_calls = [args for args, _ in client.calls if args[0].endswith("/runs")] + assert len(run_calls) == 2 + assert all(f"created=>={cutoff}" in args for args in run_calls) + + +def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> None: + """Accepted dispatches update the in-memory ledger before wrapper visibility.""" + + module = load_module() + mention = request(module) + target = FakeClient() + central = FakeClient() + cache: dict[str, set[str]] = {} + allowlist = frozenset({"contextualwisdomlab/example"}) + + assert module.dispatch_request( + mention, + target_client=target, + dispatch_client=central, + opencode_allowlist=allowlist, + workflow_run_since="2026-08-01T00:00:00Z", + run_marker_cache=cache, + ) == ("@cwl-noema-review", "@opencode-agent") + first_target_calls = len(target.calls) + assert module.dispatch_request( + mention, + target_client=target, + dispatch_client=central, + opencode_allowlist=allowlist, + workflow_run_since="2026-08-01T00:00:00Z", + run_marker_cache=cache, + ) == () + assert len(target.calls) == first_target_calls + dispatches = [ + payload["event_type"] + for args, payload in central.calls + if args[0].endswith("/dispatches") and payload + ] + assert dispatches == ["agent-mention-noema", "agent-mention-opencode"] + + mixed = request(module) + mixed_target = FakeClient() + mixed_central = FakeClient() + mixed_cache: dict[str, set[str]] = {} + assert module.dispatch_request( + mixed, + target_client=mixed_target, + dispatch_client=mixed_central, + opencode_allowlist=frozenset(), + run_marker_cache=mixed_cache, + ) == ("@cwl-noema-review",) + first_mixed_calls = len(mixed_target.calls) + assert module.dispatch_request( + mixed, + target_client=mixed_target, + dispatch_client=mixed_central, + opencode_allowlist=frozenset(), + run_marker_cache=mixed_cache, + ) == () + assert len(mixed_target.calls) == first_mixed_calls diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 3cc9fcbf4..5db819071 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -254,7 +254,7 @@ def test_dispatch_uses_central_events_and_acknowledges() -> None: def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( capsys, ) -> None: - """OpenCode fails closed outside its allowlist while dry-run is mutation-free.""" + """Rejected-only and dry-run requests remain mutation-free.""" module = load_module() request = module.parse_event(event("@opencode-agent")) @@ -267,8 +267,9 @@ def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( dispatch_client=central, opencode_allowlist=frozenset(), ) == () - assert central.calls == [] - assert "Rejected @opencode-agent" in target.calls[-1][1]["body"] + assert target.calls == central.calls == [] + assert "Rejected agent mention without target mutation" in capsys.readouterr().out + target = FakeClient() central = FakeClient() assert module.dispatch_request( diff --git a/tests/test_agent_mention_sweep_regressions.py b/tests/test_agent_mention_sweep_regressions.py new file mode 100644 index 000000000..93a505dc3 --- /dev/null +++ b/tests/test_agent_mention_sweep_regressions.py @@ -0,0 +1,266 @@ + +"""Review-driven pagination and failure-isolation regressions.""" + +from __future__ import annotations + +import importlib +import sys +from datetime import datetime, timezone +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +SCRIPTS = ROOT / "scripts" / "ci" +sys.path.insert(0, str(SCRIPTS)) + + +def module(): + """Reload the sweep module for isolated monkeypatching.""" + + return importlib.reload(importlib.import_module("agent_mention_sweep")) + + +def repository(name: str) -> dict: + """Build one active organization repository record.""" + + return { + "full_name": f"ContextualWisdomLab/{name}", + "owner": {"login": "ContextualWisdomLab"}, + "archived": False, + "disabled": False, + } + + +class PagingClient: + """Serve page-aware endpoint responses and deterministic failures.""" + + def __init__(self, responses) -> None: + """Initialize an endpoint/page response map.""" + + self.responses = responses + self.calls: list[list[str]] = [] + + def request(self, args, *, input_payload=None): + """Return one endpoint/page response or raise its configured error.""" + + del input_payload + args = list(args) + self.calls.append(args) + endpoint = args[0] + page = 1 + for index, value in enumerate(args[:-1]): + if value == "-f" and args[index + 1].startswith("page="): + page = int(args[index + 1].split("=", 1)[1]) + response = self.responses[(endpoint, page)] + if isinstance(response, Exception): + raise response + return response + + +def pull(number: int, updated_at: str = "2026-08-06T11:00:00Z") -> dict: + """Build one pull-list response record.""" + + return {"number": number, "updated_at": updated_at} + + +def test_pull_pagination_stops_at_cutoff_without_loading_later_pages() -> None: + """Updated-descending pages stop immediately at the first old record.""" + + sweep = module() + recent = [pull(number) for number in range(1, 101)] + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): recent, + ("repos/ContextualWisdomLab/example/pulls", 2): [ + pull(101, "2026-08-01T00:00:00Z") + ], + } + ) + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + assert len(results) == 100 + pull_calls = [ + args for args in client.calls if args[0].endswith("/pulls") + ] + assert len(pull_calls) == 2 + assert not any("page=3" in args for args in pull_calls) + assert sweep.flatten_pages([{"number": 1}]) == [{"number": 1}] + + +def test_pull_pagination_stops_on_empty_followup_page() -> None: + """A full page followed by an empty page terminates without page three.""" + + sweep = module() + recent = [pull(number) for number in range(1, 101)] + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): recent, + ("repos/ContextualWisdomLab/example/pulls", 2): [], + } + ) + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + assert len(results) == 100 + pull_calls = [ + args for args in client.calls if args[0].endswith("/pulls") + ] + assert len(pull_calls) == 2 + assert any("page=2" in args for args in pull_calls) + assert not any("page=3" in args for args in pull_calls) + + +def test_invalid_pull_number_fails_closed_without_error_sink() -> None: + """Malformed pull metadata raises when no isolation sink is supplied.""" + + sweep = module() + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[repository("example")]], + ("repos/ContextualWisdomLab/example/pulls", 1): [pull(0)], + } + ) + with pytest.raises(ValueError, match="invalid pull request number"): + list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + ) + ) + + +def test_repository_failure_is_isolated_and_later_repository_runs() -> None: + """A repository-local API failure does not terminate organization traversal.""" + + sweep = module() + client = PagingClient( + { + ("orgs/ContextualWisdomLab/repos", 1): [[ + repository("broken"), + repository("healthy"), + ]], + ("repos/ContextualWisdomLab/broken/pulls", 1): RuntimeError( + "forbidden" + ), + ("repos/ContextualWisdomLab/healthy/pulls", 1): [pull(7)], + } + ) + failures = [] + results = list( + sweep.list_recent_pull_requests( + client, + organization="ContextualWisdomLab", + repository_source="organization", + since="2026-08-05T00:00:00Z", + on_error=lambda scope, error: failures.append( + (scope, str(error)) + ), + ) + ) + assert [result["repository"] for result in results] == [ + "ContextualWisdomLab/healthy" + ] + assert failures == [("ContextualWisdomLab/broken", "forbidden")] + + +def mention_request(comment_id: int): + """Build one Noema request for orchestration isolation tests.""" + + router = importlib.import_module("agent_mention_router") + return router.MentionRequest( + "ContextualWisdomLab/example", + 7, + "a" * 40, + "main", + comment_id, + "maintainer", + ("cwl-noema-review",), + ) + + +def test_sweep_continues_after_candidate_and_dispatch_failures( + monkeypatch, + capsys, +) -> None: + """Candidate-local failures are counted while later work is queued.""" + + sweep = module() + issues = [ + {"repository": "ContextualWisdomLab/example", "number": 7}, + {"repository": "ContextualWisdomLab/example", "number": 8}, + ] + monkeypatch.setattr( + sweep, + "list_recent_pull_requests", + lambda *args, **kwargs: iter(issues), + ) + + def build_requests(client, *, issue, since): + del client, since + if issue["number"] == 7: + raise RuntimeError("comment inventory failed") + return (mention_request(10), mention_request(11)) + + monkeypatch.setattr(sweep, "build_requests_for_pull_request", build_requests) + dispatch_kwargs = [] + + def dispatch(request, **kwargs): + dispatch_kwargs.append(kwargs) + if request.comment_id == 10: + raise RuntimeError("dispatch failed") + return ("@cwl-noema-review",) + + monkeypatch.setattr(sweep, "dispatch_request", dispatch) + metrics = sweep.SweepMetrics() + assert sweep.sweep( + target_client=object(), + dispatch_client=object(), + organization="ContextualWisdomLab", + repository_source="organization", + lookback_hours=24, + max_dispatches=5, + opencode_allowlist=frozenset(), + now=datetime(2026, 8, 6, tzinfo=timezone.utc), + metrics=metrics, + ) == 1 + assert metrics.failures == 2 + assert dispatch_kwargs[0]["run_marker_cache"] is dispatch_kwargs[1][ + "run_marker_cache" + ] + assert dispatch_kwargs[0]["workflow_run_since"].endswith("Z") + output = capsys.readouterr().out + assert "comment inventory failed" in output + assert "dispatch failed" in output + + +def test_main_returns_failure_when_isolated_errors_were_observed( + monkeypatch, +) -> None: + """The scheduled workflow remains visibly failed after partial progress.""" + + sweep = module() + monkeypatch.setenv("TARGET_REPOSITORY_TOKEN", "target") + monkeypatch.setenv("AGENT_DISPATCH_TOKEN", "dispatch") + + def fail_partially(**kwargs): + kwargs["metrics"].failures = 1 + return 0 + + monkeypatch.setattr(sweep, "sweep", fail_partially) + assert sweep.main([]) == 1 diff --git a/tests/test_pr_review_fix_scheduler_coverage.py b/tests/test_pr_review_fix_scheduler_coverage.py index 657e4613e..d79956714 100644 --- a/tests/test_pr_review_fix_scheduler_coverage.py +++ b/tests/test_pr_review_fix_scheduler_coverage.py @@ -1,3 +1,6 @@ + +"""Coverage-only regressions for the review-fix scheduler.""" + import builtins import runpy @@ -6,29 +9,40 @@ def test_import_falls_back_to_package_module(monkeypatch): """The scheduler remains importable when only the package path is available.""" + real_import = builtins.__import__ def import_without_script_directory( name, - globals=None, - locals=None, + globals_=None, + locals_=None, fromlist=(), level=0, ): + """Reject the script-directory import and delegate every other import.""" + if name == "pr_review_merge_scheduler": raise ModuleNotFoundError(name) - return real_import(name, globals, locals, fromlist, level) + return real_import(name, globals_, locals_, fromlist, level) - monkeypatch.setattr(builtins, "__import__", import_without_script_directory) + monkeypatch.setattr( + builtins, + "__import__", + import_without_script_directory, + ) namespace = runpy.run_path( "scripts/ci/pr_review_fix_scheduler.py", run_name="pr_review_fix_scheduler_package_fallback_test", ) - assert namespace["fetch_open_prs"] is fix.fetch_open_prs + loaded = namespace["fetch_open_prs"] + assert loaded.__name__ == fix.fetch_open_prs.__name__ + assert loaded.__code__.co_filename == fix.fetch_open_prs.__code__.co_filename def test_coverage_process_queue_skips_draft_and_wrong_base_and_external_repo(monkeypatch): + """Draft, wrong-base, and external-head PRs are skipped.""" + def make_pr(number=1, **kwargs): pr = { "number": number, @@ -42,18 +56,25 @@ def make_pr(number=1, **kwargs): return pr args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) - pr1 = make_pr(number=1, isDraft=True) pr2 = make_pr(number=2, baseRefName="other") pr3 = make_pr(number=3, headRepository={"nameWithOwner": "fork/repo"}) - - monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2, pr3]) - monkeypatch.setattr(fix, "inspect_pr", lambda repo, pr, args, **kwargs: ("skip", ("skip reason",))) - + monkeypatch.setattr( + fix, + "fetch_open_prs", + lambda repo, max_prs: [pr1, pr2, pr3], + ) + monkeypatch.setattr( + fix, + "inspect_pr", + lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), + ) assert fix.process_queue(args) == 0 def test_coverage_process_queue_exception_handling(monkeypatch): + """One issue-comment lookup failure does not crash queue processing.""" + def make_pr(number=1, **kwargs): pr = { "number": number, @@ -67,10 +88,8 @@ def make_pr(number=1, **kwargs): return pr args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) - pr1 = make_pr(number=1) pr2 = make_pr(number=2) - monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2]) monkeypatch.setattr(fix, "needs_autofix", lambda pr: (True, ("reason",))) @@ -78,6 +97,9 @@ def raise_error(repo, number): raise RuntimeError("boom") monkeypatch.setattr(fix, "issue_comments", raise_error) - monkeypatch.setattr(fix, "inspect_pr", lambda repo, pr, args, **kwargs: ("skip", ("skip reason",))) - + monkeypatch.setattr( + fix, + "inspect_pr", + lambda repo, pr, args, **kwargs: ("skip", ("skip reason",)), + ) assert fix.process_queue(args) == 0 From 2744718dd9cf31b42f5a21c22e6cfdf01a5dac79 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:12:25 +0900 Subject: [PATCH 111/138] ci(automation): remove nonexistent router path trigger --- .github/workflows/agent-mention-router-quality-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/agent-mention-router-quality-ci.yml b/.github/workflows/agent-mention-router-quality-ci.yml index 658c6beca..f69cdce10 100644 --- a/.github/workflows/agent-mention-router-quality-ci.yml +++ b/.github/workflows/agent-mention-router-quality-ci.yml @@ -9,7 +9,6 @@ on: - ".github/workflows/agent-mention-noema-dispatch.yml" - ".github/workflows/agent-mention-opencode-dispatch.yml" - "docs/automation/review-agent-comment-invocation.md" - - "scripts/ci/agent_mention_invocation.py" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" @@ -23,7 +22,6 @@ on: - ".github/workflows/agent-mention-noema-dispatch.yml" - ".github/workflows/agent-mention-opencode-dispatch.yml" - "docs/automation/review-agent-comment-invocation.md" - - "scripts/ci/agent_mention_invocation.py" - "scripts/ci/agent_mention_router.py" - "scripts/ci/agent_mention_sweep.py" - "tests/test_agent_mention_*.py" From 100203da05554a466db6e3fc0b6fddc00702fbc0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:13:25 +0900 Subject: [PATCH 112/138] fix(automation): make Noema wrapper leader election resilient --- .../agent-mention-noema-dispatch.yml | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/.github/workflows/agent-mention-noema-dispatch.yml b/.github/workflows/agent-mention-noema-dispatch.yml index 7c41e7cab..e3bdfbf49 100644 --- a/.github/workflows/agent-mention-noema-dispatch.yml +++ b/.github/workflows/agent-mention-noema-dispatch.yml @@ -11,6 +11,7 @@ on: concurrency: group: agent-mention-noema-${{ github.event.client_payload.agent_invocation_key || github.run_id }} cancel-in-progress: false + queue: max permissions: contents: read @@ -78,25 +79,40 @@ jobs: PYTHON marker="[cwl-agent-invocation:${INVOCATION_KEY}]" - leader_id="$( + matching_run_ids() { gh api --paginate --slurp \ "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-noema-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ | jq -r --arg marker "$marker" ' [.[].workflow_runs[] | select((.display_title // "") | contains($marker)) | .id] - | min // empty + | unique + | sort + | .[] ' - )" - if [ -z "$leader_id" ]; then - echo "::error::Could not establish the durable Noema invocation leader." - exit 1 - fi - if [ "$leader_id" != "$GITHUB_RUN_ID" ]; then - echo "forward=false" >>"$GITHUB_OUTPUT" - echo "Duplicate exact-key invocation suppressed by durable workflow-run identity." - exit 0 - fi + } + + for attempt in 1 2 3; do + run_ids="$(matching_run_ids)" + lower_id="$( + awk -v current="$GITHUB_RUN_ID" '$1 < current { print $1; exit }' \ + <<<"$run_ids" + )" + if [ -n "$lower_id" ]; then + echo "forward=false" >>"$GITHUB_OUTPUT" + echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." + exit 0 + fi + if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then + echo "forward=true" >>"$GITHUB_OUTPUT" + exit 0 + fi + if [ "$attempt" -lt 3 ]; then + sleep "$((attempt * 2))" + fi + done + + echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." echo "forward=true" >>"$GITHUB_OUTPUT" - name: Forward once to the authoritative Noema workflow From c24721dbaee3c43fd0286a95342d35ad68d44725 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:14:20 +0900 Subject: [PATCH 113/138] fix(automation): make OpenCode wrapper leader election resilient --- .../agent-mention-opencode-dispatch.yml | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml index e2a964ca6..10b0ce9b2 100644 --- a/.github/workflows/agent-mention-opencode-dispatch.yml +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -11,6 +11,7 @@ on: concurrency: group: agent-mention-opencode-${{ github.event.client_payload.agent_invocation_key || github.run_id }} cancel-in-progress: false + queue: max permissions: contents: read @@ -40,7 +41,7 @@ jobs: UPDATE_BRANCHES: ${{ github.event.client_payload.update_branches }} MERGE_MODE: ${{ github.event.client_payload.merge_mode || '' }} steps: - - name: Validate exact review-only invocation and elect one durable leader + - name: Validate exact invocation and elect one durable leader id: leader run: | set -euo pipefail @@ -52,13 +53,13 @@ jobs: ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || [[ "$BASE_BRANCH" == -* ]] || ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || - ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]] || [ "$TRIGGER_REVIEWS" != "true" ] || [ "$REVIEW_DISPATCH_LIMIT" != "1" ] || [ "$ENABLE_AUTO_MERGE" != "false" ] || [ "$UPDATE_BRANCHES" != "false" ] || - [ "$MERGE_MODE" != "disabled" ]; then - echo "::error::Rejected malformed, mismatched, or mutation-capable OpenCode invocation payload." + [ "$MERGE_MODE" != "disabled" ] || + ! [[ "$REQUESTED_BY" =~ ^[A-Za-z0-9-]+$ ]]; then + echo "::error::Rejected malformed or mismatched OpenCode agent invocation payload." exit 1 fi @@ -88,25 +89,40 @@ jobs: PYTHON marker="[cwl-agent-invocation:${INVOCATION_KEY}]" - leader_id="$( + matching_run_ids() { gh api --paginate --slurp \ "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-opencode-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ | jq -r --arg marker "$marker" ' [.[].workflow_runs[] | select((.display_title // "") | contains($marker)) | .id] - | min // empty + | unique + | sort + | .[] ' - )" - if [ -z "$leader_id" ]; then - echo "::error::Could not establish the durable OpenCode invocation leader." - exit 1 - fi - if [ "$leader_id" != "$GITHUB_RUN_ID" ]; then - echo "forward=false" >>"$GITHUB_OUTPUT" - echo "Duplicate exact-key invocation suppressed by durable workflow-run identity." - exit 0 - fi + } + + for attempt in 1 2 3; do + run_ids="$(matching_run_ids)" + lower_id="$( + awk -v current="$GITHUB_RUN_ID" '$1 < current { print $1; exit }' \ + <<<"$run_ids" + )" + if [ -n "$lower_id" ]; then + echo "forward=false" >>"$GITHUB_OUTPUT" + echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." + exit 0 + fi + if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then + echo "forward=true" >>"$GITHUB_OUTPUT" + exit 0 + fi + if [ "$attempt" -lt 3 ]; then + sleep "$((attempt * 2))" + fi + done + + echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." echo "forward=true" >>"$GITHUB_OUTPUT" - name: Forward once to the authoritative review-only scheduler From e028648387211bba9855f5520294578bf29d72c2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:15:19 +0900 Subject: [PATCH 114/138] fix(automation): harden sweep token exchange and handoff --- .github/workflows/agent-mention-router.yml | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index f8b362bb9..f14667a93 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -111,7 +111,7 @@ jobs: *) separator="?" ;; esac if ! oidc_response="$( - curl -fsS \ + curl -fsS --connect-timeout 10 --max-time 30 \ -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ "${request_url}${separator}audience=${OIDC_AUDIENCE}" )"; then @@ -126,7 +126,7 @@ jobs: exit 0 fi if ! token_response="$( - curl -fsS \ + curl -fsS --connect-timeout 10 --max-time 30 \ -X POST \ -H "Authorization: Bearer ${oidc_token}" \ "${OPENCODE_API_BASE_URL}/exchange_github_app_token" @@ -142,10 +142,8 @@ jobs: exit 0 fi echo "::add-mask::$app_token" - { - echo "available=true" - echo "token=$app_token" - } >>"$GITHUB_OUTPUT" + echo "available=true" >>"$GITHUB_OUTPUT" + echo "SWEEP_APP_TOKEN=$app_token" >>"$GITHUB_ENV" - name: Check out trusted central router uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -155,12 +153,23 @@ jobs: - name: Sweep recent organization PR comments env: - TARGET_REPOSITORY_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.sweep_app_token.outputs.token }} - TARGET_REPOSITORY_SOURCE: ${{ (secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '') && 'organization' || steps.sweep_app_token.outputs.available == 'true' && 'installation' || '' }} + PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} AGENT_DISPATCH_TOKEN: ${{ github.token }} run: | set -euo pipefail - if [ -z "${TARGET_REPOSITORY_TOKEN:-}" ] || [ -z "${TARGET_REPOSITORY_SOURCE:-}" ]; then + if [ -n "$PR_REVIEW_MERGE_TOKEN" ]; then + TARGET_REPOSITORY_TOKEN="$PR_REVIEW_MERGE_TOKEN" + TARGET_REPOSITORY_SOURCE="organization" + elif [ -n "$OPENCODE_APPROVE_TOKEN" ]; then + TARGET_REPOSITORY_TOKEN="$OPENCODE_APPROVE_TOKEN" + TARGET_REPOSITORY_SOURCE="organization" + else + TARGET_REPOSITORY_TOKEN="${SWEEP_APP_TOKEN:-}" + TARGET_REPOSITORY_SOURCE="${TARGET_REPOSITORY_TOKEN:+installation}" + fi + export TARGET_REPOSITORY_TOKEN + if [ -z "$TARGET_REPOSITORY_TOKEN" ] || [ -z "$TARGET_REPOSITORY_SOURCE" ]; then echo "::error::Agent mention sweep requires PR_REVIEW_MERGE_TOKEN, OPENCODE_APPROVE_TOKEN, or the OpenCode app token exchange." exit 1 fi From f572094a3a294fc0f55d21cf2fe1666f2a36390f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:15:44 +0900 Subject: [PATCH 115/138] chore(automation): remove transient PR 787 finalizer --- .../finalize-pr787-review-findings.yml | 118 ------------------ 1 file changed, 118 deletions(-) delete mode 100644 .github/workflows/finalize-pr787-review-findings.yml diff --git a/.github/workflows/finalize-pr787-review-findings.yml b/.github/workflows/finalize-pr787-review-findings.yml deleted file mode 100644 index 5a6c8c5d6..000000000 --- a/.github/workflows/finalize-pr787-review-findings.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Finalize PR 787 Review Findings - -on: - pull_request: - branches: [main] - paths: - - ".github/workflows/finalize-pr787-review-findings.yml" - - "scripts/ci/finalize_pr787_review_findings.py" - - "scripts/ci/repair_pr787_finalizer_source.py" - -concurrency: - group: finalize-pr787-review-findings-${{ github.event.pull_request.number }} - cancel-in-progress: true - -permissions: - contents: read - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-24.04 - timeout-minutes: 20 - permissions: - contents: write - env: - PUSH_TOKEN: ${{ github.token }} - TARGET_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - name: Checkout exact staging head - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ env.TARGET_HEAD_SHA }} - fetch-depth: 0 - persist-credentials: false - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - name: Install exact hash-locked tooling - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - name: Apply deterministic repairs and remove transient writer - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$TARGET_HEAD_SHA" - python3 scripts/ci/repair_pr787_finalizer_source.py - python3 scripts/ci/finalize_pr787_review_findings.py - rm -f \ - .github/workflows/finalize-pr787-review-findings.yml \ - scripts/ci/finalize_pr787_review_findings.py \ - scripts/ci/repair_pr787_finalizer_source.py - - name: Verify complete suite, focused coverage, docs, and syntax - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q - python -m coverage report --show-missing --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci tests - git diff --check - test ! -e .github/workflows/finalize-pr787-review-findings.yml - test ! -e scripts/ci/finalize_pr787_review_findings.py - test ! -e scripts/ci/repair_pr787_finalizer_source.py - - name: Commit and push verified non-workflow final state - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - if [ -z "$PUSH_TOKEN" ]; then - echo "::error::The workflow GITHUB_TOKEN is required for the verified final-state commit." - exit 1 - fi - git checkout "$TARGET_HEAD_SHA" -- \ - .github/workflows/agent-mention-noema-dispatch.yml \ - .github/workflows/agent-mention-opencode-dispatch.yml \ - .github/workflows/agent-mention-router.yml \ - .github/workflows/agent-mention-router-quality-ci.yml \ - .github/workflows/finalize-pr787-review-findings.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "fix(automation): close mention-router runtime findings" - askpass="$(mktemp)" - cat >"$askpass" <<'EOF' - #!/usr/bin/env bash - case "$1" in - *Username*) printf '%s\n' 'x-access-token' ;; - *Password*) printf '%s\n' "$PUSH_TOKEN" ;; - *) exit 1 ;; - esac - EOF - chmod 0700 "$askpass" - GIT_ASKPASS="$askpass" GIT_TERMINAL_PROMPT=0 \ - git push origin HEAD:feat/review-agent-mention-router-main - rm -f "$askpass" From 11a6a8d0567774ff6930f70c88329ff632e97bb9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:20:53 +0900 Subject: [PATCH 116/138] test(automation): specify exact-name artifact ledger --- tests/test_agent_mention_artifact_ledger.py | 199 ++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 tests/test_agent_mention_artifact_ledger.py diff --git a/tests/test_agent_mention_artifact_ledger.py b/tests/test_agent_mention_artifact_ledger.py new file mode 100644 index 000000000..c527f4a6e --- /dev/null +++ b/tests/test_agent_mention_artifact_ledger.py @@ -0,0 +1,199 @@ +"""Regression tests for the exact-name Actions artifact invocation ledger.""" + +from __future__ import annotations + +import importlib.util +import re +import sys +from pathlib import Path +from types import ModuleType + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" +NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" +OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" +DOC = ROOT / "docs" / "automation" / "review-agent-comment-invocation.md" +UPLOAD_ARTIFACT_SHA = "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" + + +def load_module() -> ModuleType: + """Load the router module from its script path.""" + + module_name = "agent_mention_router_artifact_ledger" + spec = importlib.util.spec_from_file_location(module_name, MODULE_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def request(module: ModuleType): + """Build one exact request containing both supported agents.""" + + return module.MentionRequest( + "ContextualWisdomLab/example", + 17, + "a" * 40, + "main", + 91, + "maintainer", + ("cwl-noema-review", "opencode-agent"), + ) + + +def artifact(module: ModuleType, mention, agent: str, *, expired: bool = False) -> dict: + """Build one exact-name artifact record for an invocation.""" + + return { + "id": 7, + "name": module.agent_ledger_artifact_name(mention, agent), + "expired": expired, + "created_at": "2026-08-06T12:00:00Z", + "expires_at": "2026-09-05T12:00:00Z", + } + + +class ArtifactClient: + """Return artifact inventories while rejecting workflow-run scans.""" + + def __init__(self, responses=None) -> None: + """Initialize exact artifact-name responses and a request ledger.""" + + self.responses = responses or {} + self.calls: list[tuple[list[str], dict | None]] = [] + + def request(self, args, *, input_payload=None): + """Return a name-filtered artifact response for one API call.""" + + args = list(args) + self.calls.append((args, input_payload)) + if args[0].endswith("/runs"): + raise AssertionError("workflow-run listings are not a durable ledger") + if args[0].endswith("/actions/artifacts"): + name = next( + value.split("=", 1)[1] + for value in args + if value.startswith("name=") + ) + return self.responses.get(name, {"total_count": 0, "artifacts": []}) + return None + + +def test_artifact_name_is_exact_key_addressable() -> None: + """The durable ledger name contains one complete invocation digest.""" + + module = load_module() + mention = request(module) + noema_name = module.agent_ledger_artifact_name(mention, "cwl-noema-review") + opencode_name = module.agent_ledger_artifact_name(mention, "opencode-agent") + + assert re.fullmatch(r"cwl-agent-invocation-[0-9a-f]{64}", noema_name) + assert noema_name != opencode_name + assert noema_name.endswith( + module.agent_invocation_key(mention, "cwl-noema-review") + ) + + +def test_exact_artifact_lookup_is_cached_without_workflow_run_pagination() -> None: + """Each exact artifact name is queried once and reused for the sweep run.""" + + module = load_module() + mention = request(module) + noema_name = module.agent_ledger_artifact_name(mention, "cwl-noema-review") + client = ArtifactClient( + { + noema_name: { + "total_count": 1, + "artifacts": [artifact(module, mention, "cwl-noema-review")], + } + } + ) + cache: dict[str, bool] = {} + + expected = frozenset({"cwl-noema-review"}) + assert module.dispatched_agents( + mention, + client, + ledger_artifact_cache=cache, + ) == expected + assert module.dispatched_agents( + mention, + client, + ledger_artifact_cache=cache, + ) == expected + + artifact_calls = [ + args for args, _ in client.calls if args[0].endswith("/actions/artifacts") + ] + assert len(artifact_calls) == 2 + assert all("per_page=100" in args for args in artifact_calls) + assert all(any(value.startswith("name=") for value in args) for args in artifact_calls) + assert all(not args[0].endswith("/runs") for args, _ in client.calls) + + +def test_artifact_inventory_validation_fails_closed() -> None: + """Malformed, mismatched, or expired artifact evidence is never trusted.""" + + module = load_module() + mention = request(module) + name = module.agent_ledger_artifact_name(mention, "cwl-noema-review") + + for malformed in ( + None, + [], + {"total_count": "1", "artifacts": []}, + {"total_count": 1, "artifacts": "bad"}, + {"total_count": 1, "artifacts": [{}]}, + { + "total_count": 1, + "artifacts": [{"id": 1, "name": "wrong", "expired": False}], + }, + ): + with pytest.raises(ValueError, match="artifact"): + module._artifact_records(malformed, expected_name=name) + + assert module._artifact_records( + {"total_count": 1, "artifacts": [artifact(module, mention, "cwl-noema-review", expired=True)]}, + expected_name=name, + ) == () + + +def test_thousand_workflow_runs_cannot_truncate_exact_ledger_lookup() -> None: + """The router uses an exact-name endpoint rather than the capped run search.""" + + module = load_module() + mention = request(module) + client = ArtifactClient() + + assert module.dispatched_agents(mention, client) == frozenset() + assert len(client.calls) == 2 + assert all(call[0][0].endswith("/actions/artifacts") for call in client.calls) + + +def test_wrappers_claim_the_artifact_before_forwarding() -> None: + """Both wrappers upload a 30-day immutable claim before repository dispatch.""" + + for path in (NOEMA_WORKFLOW, OPENCODE_WORKFLOW): + text = path.read_text(encoding="utf-8") + assert "actions/artifacts" in text + assert "name=${LEDGER_ARTIFACT_NAME}" in text + assert f"actions/upload-artifact@{UPLOAD_ARTIFACT_SHA}" in text + assert "name: cwl-agent-invocation-${{ env.INVOCATION_KEY }}" in text + assert "retention-days: 30" in text + assert text.index("actions/upload-artifact@") < text.index( + "Forward once to the authoritative" + ) + assert "workflow_runs" not in text + + +def test_doctoring_records_artifact_ledger_contract() -> None: + """Operator documentation cites the exact-name artifact API and retention.""" + + text = DOC.read_text(encoding="utf-8") + assert "exact-name Actions artifact ledger" in text + assert "30-day" in text + assert "REST API endpoints for GitHub Actions artifacts" in text + assert "Store and share data with workflow artifacts" in text From 613718e1f18d7b3b3aeebc26631e22aa51f3a4e9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:28:59 +0900 Subject: [PATCH 117/138] fix(automation): use exact-name artifact dispatch ledger --- scripts/ci/agent_mention_router.py | 173 +++++++++++++---------------- 1 file changed, 77 insertions(+), 96 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 1df34b010..8181b989a 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -10,7 +10,6 @@ import re import subprocess from dataclasses import dataclass -from datetime import datetime, timedelta, timezone from typing import Any, Sequence CENTRAL_AUTOMATION_REPOSITORY = "ContextualWisdomLab/.github" @@ -25,24 +24,15 @@ re.IGNORECASE, ), } -AGENT_WORKFLOW_RUN_ENDPOINTS = { - "cwl-noema-review": ( - f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" - "agent-mention-noema-dispatch.yml/runs" - ), - "opencode-agent": ( - f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/workflows/" - "agent-mention-opencode-dispatch.yml/runs" - ), -} +LEDGER_ARTIFACTS_ENDPOINT = ( + f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/actions/artifacts" +) +LEDGER_ARTIFACT_PREFIX = "cwl-agent-invocation-" REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") HEAD_SHA_RE = re.compile(r"^[0-9a-fA-F]{40}$") BASE_BRANCH_RE = re.compile(r"^(?!-)[A-Za-z0-9._/-]+$") ACTOR_RE = re.compile(r"^[A-Za-z0-9-]+$") RECEIPT_RE = re.compile(r"") -INVOCATION_MARKER_RE = re.compile(r"\[cwl-agent-invocation:[0-9a-f]{64}\]") -MAX_WORKFLOW_RUN_RECORDS = 10_000 -WORKFLOW_RUN_LOOKBACK_HOURS = 24 * 30 @dataclass(frozen=True) @@ -123,7 +113,7 @@ def processed_comment_ids(comments: Sequence[dict[str, Any]]) -> frozenset[int]: """Extract local receipts authored by the trusted GitHub Actions bot only. These target-repository comments are a local optimization and user-facing - acknowledgement. Central exact-key workflow-run records remain authoritative + acknowledgement. Central exact-name Actions artifacts remain authoritative for cross-repository dispatch idempotency because PAT and installation-token identities can rotate and target-repository actors can be spoofed. """ @@ -235,10 +225,10 @@ def agent_invocation_key(request: MentionRequest, agent: str) -> str: The key binds repository, pull request, exact head, base branch, requested agent, source comment, and requesting actor. It contains no credential or - provider response and is safe to place in workflow run names. + provider response and is safe to place in workflow and artifact names. """ - if agent not in AGENT_WORKFLOW_RUN_ENDPOINTS: + if agent not in MENTION_PATTERNS: raise ValueError(f"unsupported agent: {agent}") canonical = json.dumps( { @@ -258,44 +248,56 @@ def agent_invocation_key(request: MentionRequest, agent: str) -> str: def agent_invocation_marker(request: MentionRequest, agent: str) -> str: - """Return the exact workflow-run marker for one agent invocation.""" + """Return the exact human-readable workflow-run marker for one invocation.""" return f"[cwl-agent-invocation:{agent_invocation_key(request, agent)}]" -def workflow_run_cutoff( - *, - now: datetime | None = None, - lookback_hours: int = WORKFLOW_RUN_LOOKBACK_HOURS, -) -> str: - """Return the UTC lower bound for durable wrapper-run lookup.""" +def agent_ledger_artifact_name(request: MentionRequest, agent: str) -> str: + """Return the exact-name durable artifact ledger key for one invocation.""" - current = now or datetime.now(timezone.utc) - if current.tzinfo is None: - raise ValueError("workflow-run cutoff time must be timezone-aware") - cutoff = current.astimezone(timezone.utc) - timedelta(hours=lookback_hours) - return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") + return f"{LEDGER_ARTIFACT_PREFIX}{agent_invocation_key(request, agent)}" -def _workflow_run_records(value: Any) -> tuple[dict[str, Any], ...]: - """Validate and flatten bounded ``gh --paginate --slurp`` workflow runs.""" +def _artifact_records( + value: Any, + *, + expected_name: str, +) -> tuple[dict[str, Any], ...]: + """Validate one exact-name repository artifact response and return live claims. - if value is None: - return () - pages = value if isinstance(value, list) else [value] - if not pages or not all(isinstance(page, dict) for page in pages): - raise ValueError("workflow-run response must contain object pages") - records: list[dict[str, Any]] = [] - for page in pages: - page_records = page.get("workflow_runs") - if not isinstance(page_records, list) or not all( - isinstance(record, dict) for record in page_records - ): - raise ValueError("workflow-run response contains invalid records") - records.extend(page_records) - if len(records) > MAX_WORKFLOW_RUN_RECORDS: - raise ValueError("workflow-run response exceeds the bounded record limit") - return tuple(records) + The server-side ``name`` filter makes this response directly addressable by + invocation key. Any malformed, mismatched, truncated, or ambiguous response + fails closed rather than being interpreted as permission to redispatch. + """ + + if not isinstance(value, dict): + raise ValueError("artifact response must be an object") + total_count = value.get("total_count") + artifacts = value.get("artifacts") + if type(total_count) is not int or total_count < 0: + raise ValueError("artifact response has an invalid total_count") + if not isinstance(artifacts, list): + raise ValueError("artifact response has an invalid artifacts collection") + if total_count != len(artifacts): + raise ValueError("artifact response is truncated or internally inconsistent") + + live: list[dict[str, Any]] = [] + for artifact in artifacts: + if not isinstance(artifact, dict): + raise ValueError("artifact response contains a non-object record") + artifact_id = artifact.get("id") + name = artifact.get("name") + expired = artifact.get("expired") + if type(artifact_id) is not int or artifact_id < 1: + raise ValueError("artifact response contains an invalid artifact id") + if not isinstance(name, str) or name != expected_name: + raise ValueError("artifact response contains a mismatched artifact name") + if type(expired) is not bool: + raise ValueError("artifact response contains an invalid expired flag") + if not expired: + live.append(artifact) + return tuple(live) def dispatched_agents( @@ -303,58 +305,42 @@ def dispatched_agents( dispatch_client: GitHubClient, agents: Sequence[str] | None = None, *, - workflow_run_since: str | None = None, - run_marker_cache: dict[str, set[str]] | None = None, + ledger_artifact_cache: dict[str, bool] | None = None, ) -> frozenset[str]: - """Return agents with a durable central run for this exact invocation. + """Return agents with a durable exact-name artifact for this invocation. - Workflow inventories are bounded by the same maximum 30-day window as - the scheduled source-comment sweep. A caller-owned marker cache avoids - repeating the same agent workflow query for every candidate in one run. + Each candidate uses the repository artifact endpoint's exact ``name`` filter, + avoiding workflow-run enumeration and its filtered-result cap. A caller-owned + cache bounds repeated API work during one local route or organization sweep. """ candidates = tuple(request.agents if agents is None else agents) observed: set[str] = set() - cutoff = workflow_run_since or workflow_run_cutoff() - marker_cache = run_marker_cache if run_marker_cache is not None else {} + artifact_cache = ( + ledger_artifact_cache if ledger_artifact_cache is not None else {} + ) for agent in candidates: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS.get(agent) - if endpoint is None: - raise ValueError(f"unsupported agent: {agent}") - if endpoint not in marker_cache: + artifact_name = agent_ledger_artifact_name(request, agent) + if artifact_name not in artifact_cache: response = dispatch_client.request( [ - endpoint, + LEDGER_ARTIFACTS_ENDPOINT, "-X", "GET", "-f", - "event=repository_dispatch", - "-f", - f"created=>={cutoff}", + f"name={artifact_name}", "-f", "per_page=100", - "--paginate", - "--slurp", ] ) - markers: set[str] = set() - for run in _workflow_run_records(response): - run_id = run.get("id") - if ( - isinstance(run_id, int) - and run_id > 0 - and run.get("event") == "repository_dispatch" - ): - markers.update( - INVOCATION_MARKER_RE.findall( - str(run.get("display_title") or "") - ) - ) - marker_cache[endpoint] = markers - if agent_invocation_marker(request, agent) in marker_cache[endpoint]: + artifact_cache[artifact_name] = bool( + _artifact_records(response, expected_name=artifact_name) + ) + if artifact_cache[artifact_name]: observed.add(agent) return frozenset(observed) + def noema_payload(request: MentionRequest) -> dict[str, Any]: """Return the durable Noema wrapper dispatch request body.""" @@ -405,8 +391,7 @@ def dispatch_request( dispatch_client: GitHubClient, opencode_allowlist: frozenset[str], dry_run: bool = False, - workflow_run_since: str | None = None, - run_marker_cache: dict[str, set[str]] | None = None, + ledger_artifact_cache: dict[str, bool] | None = None, ) -> tuple[str, ...]: """Dispatch missing agents and acknowledge only newly queued work.""" @@ -429,8 +414,7 @@ def dispatch_request( request, dispatch_client, dispatchable, - workflow_run_since=workflow_run_since, - run_marker_cache=run_marker_cache, + ledger_artifact_cache=ledger_artifact_cache, ) missing = tuple(agent for agent in dispatchable if agent not in existing) handles = tuple(f"@{agent}" for agent in missing) @@ -446,25 +430,21 @@ def dispatch_request( dispatch_endpoint = f"repos/{CENTRAL_AUTOMATION_REPOSITORY}/dispatches" if "cwl-noema-review" in missing: + agent = "cwl-noema-review" dispatch_client.request( [dispatch_endpoint, "-X", "POST"], input_payload=noema_payload(request), ) - if run_marker_cache is not None: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] - run_marker_cache.setdefault(endpoint, set()).add( - agent_invocation_marker(request, "cwl-noema-review") - ) + if ledger_artifact_cache is not None: + ledger_artifact_cache[agent_ledger_artifact_name(request, agent)] = True if "opencode-agent" in missing: + agent = "opencode-agent" dispatch_client.request( [dispatch_endpoint, "-X", "POST"], input_payload=opencode_payload(request), ) - if run_marker_cache is not None: - endpoint = AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] - run_marker_cache.setdefault(endpoint, set()).add( - agent_invocation_marker(request, "opencode-agent") - ) + if ledger_artifact_cache is not None: + ledger_artifact_cache[agent_ledger_artifact_name(request, agent)] = True target_api = f"repos/{request.repository}" target_client.request( @@ -492,8 +472,8 @@ def dispatch_request( acknowledgement = ( f"{receipt_marker(request.comment_id)}\n" f"{' ; '.join(status_parts)} for PR #{request.pull_request_number} at head " - f"`{request.pull_request_head_sha}`. Central exact-key workflow runs are " - "the durable dispatch ledger; existing review workflows remain " + f"`{request.pull_request_head_sha}`. Central exact-name Actions artifacts " + "are the durable dispatch ledger; existing review workflows remain " "authoritative for the final verdict and failure evidence." ) target_client.request( @@ -506,6 +486,7 @@ def dispatch_request( ) return handles + def load_event(path: str) -> dict[str, Any]: """Load and validate a GitHub event JSON document.""" From 7e4ba8c4de1e012110a1c27bc2cb763dec95c21d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:31:00 +0900 Subject: [PATCH 118/138] fix(automation): share exact artifact ledger cache in sweep --- scripts/ci/agent_mention_sweep.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py index 12d70d3b8..3ddbc1bfc 100644 --- a/scripts/ci/agent_mention_sweep.py +++ b/scripts/ci/agent_mention_sweep.py @@ -206,6 +206,7 @@ def list_recent_pull_requests( raise on_error(repository, exc) + def list_recent_comments( client: GitHubClient, *, @@ -287,7 +288,7 @@ def sweep( raise ValueError("max dispatches must be between 1 and 100") since = cutoff_timestamp(lookback_hours, now=now) counters = metrics if metrics is not None else SweepMetrics() - run_marker_cache: dict[str, set[str]] = {} + ledger_artifact_cache: dict[str, bool] = {} dispatched = 0 def record_failure(scope: str, error: Exception) -> None: @@ -323,8 +324,7 @@ def record_failure(scope: str, error: Exception) -> None: dispatch_client=dispatch_client, opencode_allowlist=opencode_allowlist, dry_run=dry_run, - workflow_run_since=since, - run_marker_cache=run_marker_cache, + ledger_artifact_cache=ledger_artifact_cache, ) except Exception as exc: record_failure(request_scope, exc) @@ -344,6 +344,7 @@ def record_failure(scope: str, error: Exception) -> None: ) return dispatched + def main(argv: Sequence[str] | None = None) -> int: """Run the scheduled organization mention sweep.""" From 8846c5218c66334b262615127fa029b4c4856f80 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:33:10 +0900 Subject: [PATCH 119/138] fix(automation): claim Noema dispatches with exact artifacts --- .../agent-mention-noema-dispatch.yml | 120 ++++++++++++------ 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/.github/workflows/agent-mention-noema-dispatch.yml b/.github/workflows/agent-mention-noema-dispatch.yml index e3bdfbf49..b78d5a815 100644 --- a/.github/workflows/agent-mention-noema-dispatch.yml +++ b/.github/workflows/agent-mention-noema-dispatch.yml @@ -36,8 +36,7 @@ jobs: REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} steps: - - name: Validate exact invocation and elect one durable leader - id: leader + - name: Validate exact invocation payload run: | set -euo pipefail if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || @@ -78,45 +77,92 @@ jobs: raise SystemExit("invocation key does not match canonical payload") PYTHON - marker="[cwl-agent-invocation:${INVOCATION_KEY}]" - matching_run_ids() { - gh api --paginate --slurp \ - "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-noema-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ - | jq -r --arg marker "$marker" ' - [.[].workflow_runs[] - | select((.display_title // "") | contains($marker)) - | .id] - | unique - | sort - | .[] - ' - } + - name: Inspect exact-name Actions artifact ledger + id: ledger + run: | + set -euo pipefail + LEDGER_ARTIFACT_NAME="cwl-agent-invocation-${INVOCATION_KEY}" + export LEDGER_ARTIFACT_NAME + echo "LEDGER_ARTIFACT_NAME=$LEDGER_ARTIFACT_NAME" >>"$GITHUB_ENV" + response_file="${RUNNER_TEMP}/agent-mention-artifacts.json" + gh api "repos/${GITHUB_REPOSITORY}/actions/artifacts" \ + -X GET \ + -f "name=${LEDGER_ARTIFACT_NAME}" \ + -f "per_page=100" >"$response_file" + python3 - "$response_file" <<'PYTHON' + import json + import os + from pathlib import Path + import sys - for attempt in 1 2 3; do - run_ids="$(matching_run_ids)" - lower_id="$( - awk -v current="$GITHUB_RUN_ID" '$1 < current { print $1; exit }' \ - <<<"$run_ids" - )" - if [ -n "$lower_id" ]; then - echo "forward=false" >>"$GITHUB_OUTPUT" - echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." - exit 0 - fi - if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then - echo "forward=true" >>"$GITHUB_OUTPUT" - exit 0 - fi - if [ "$attempt" -lt 3 ]; then - sleep "$((attempt * 2))" - fi - done + response_path = Path(sys.argv[1]) + payload = json.loads(response_path.read_text(encoding="utf-8")) + expected_name = os.environ["LEDGER_ARTIFACT_NAME"] + if not isinstance(payload, dict): + raise SystemExit("artifact response must be an object") + total_count = payload.get("total_count") + artifacts = payload.get("artifacts") + if type(total_count) is not int or total_count < 0: + raise SystemExit("artifact response has an invalid total_count") + if not isinstance(artifacts, list): + raise SystemExit("artifact response has an invalid artifacts collection") + if total_count != len(artifacts): + raise SystemExit("artifact response is truncated or inconsistent") + live = False + for artifact in artifacts: + if not isinstance(artifact, dict): + raise SystemExit("artifact response contains a non-object record") + artifact_id = artifact.get("id") + name = artifact.get("name") + expired = artifact.get("expired") + if type(artifact_id) is not int or artifact_id < 1: + raise SystemExit("artifact response contains an invalid artifact id") + if not isinstance(name, str) or name != expected_name: + raise SystemExit("artifact response contains a mismatched artifact name") + if type(expired) is not bool: + raise SystemExit("artifact response contains an invalid expired flag") + live = live or not expired + + output_path = Path(os.environ["GITHUB_OUTPUT"]) + if live: + with output_path.open("a", encoding="utf-8") as handle: + handle.write("claim=false\n") + raise SystemExit(0) + + claim_dir = Path(os.environ["RUNNER_TEMP"]) / "cwl-agent-invocation-ledger" + claim_dir.mkdir(mode=0o700, parents=True, exist_ok=True) + claim = { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "invocation_key": os.environ["INVOCATION_KEY"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + } + (claim_dir / "claim.json").write_text( + json.dumps(claim, ensure_ascii=True, indent=2, sort_keys=True) + "\n", + encoding="utf-8", + ) + with output_path.open("a", encoding="utf-8") as handle: + handle.write("claim=true\n") + PYTHON - echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." - echo "forward=true" >>"$GITHUB_OUTPUT" + - name: Claim exact invocation in the durable artifact ledger + if: steps.ledger.outputs.claim == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cwl-agent-invocation-${{ env.INVOCATION_KEY }} + path: ${{ runner.temp }}/cwl-agent-invocation-ledger/claim.json + if-no-files-found: error + retention-days: 30 + compression-level: 0 + overwrite: false + include-hidden-files: false - name: Forward once to the authoritative Noema workflow - if: steps.leader.outputs.forward == 'true' + if: steps.ledger.outputs.claim == 'true' run: | set -euo pipefail jq -n \ From bada44c61c27554267d58ad7e2d1a0765b5515e0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:35:00 +0900 Subject: [PATCH 120/138] fix(automation): claim OpenCode dispatches with exact artifacts --- .../agent-mention-opencode-dispatch.yml | 120 ++++++++++++------ 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml index 10b0ce9b2..676faac08 100644 --- a/.github/workflows/agent-mention-opencode-dispatch.yml +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -41,8 +41,7 @@ jobs: UPDATE_BRANCHES: ${{ github.event.client_payload.update_branches }} MERGE_MODE: ${{ github.event.client_payload.merge_mode || '' }} steps: - - name: Validate exact invocation and elect one durable leader - id: leader + - name: Validate exact invocation payload run: | set -euo pipefail if [ "$PAYLOAD_AGENT" != "$REQUESTED_AGENT" ] || @@ -88,45 +87,92 @@ jobs: raise SystemExit("invocation key does not match canonical payload") PYTHON - marker="[cwl-agent-invocation:${INVOCATION_KEY}]" - matching_run_ids() { - gh api --paginate --slurp \ - "repos/${GITHUB_REPOSITORY}/actions/workflows/agent-mention-opencode-dispatch.yml/runs?event=repository_dispatch&per_page=100" \ - | jq -r --arg marker "$marker" ' - [.[].workflow_runs[] - | select((.display_title // "") | contains($marker)) - | .id] - | unique - | sort - | .[] - ' - } + - name: Inspect exact-name Actions artifact ledger + id: ledger + run: | + set -euo pipefail + LEDGER_ARTIFACT_NAME="cwl-agent-invocation-${INVOCATION_KEY}" + export LEDGER_ARTIFACT_NAME + echo "LEDGER_ARTIFACT_NAME=$LEDGER_ARTIFACT_NAME" >>"$GITHUB_ENV" + response_file="${RUNNER_TEMP}/agent-mention-artifacts.json" + gh api "repos/${GITHUB_REPOSITORY}/actions/artifacts" \ + -X GET \ + -f "name=${LEDGER_ARTIFACT_NAME}" \ + -f "per_page=100" >"$response_file" + python3 - "$response_file" <<'PYTHON' + import json + import os + from pathlib import Path + import sys - for attempt in 1 2 3; do - run_ids="$(matching_run_ids)" - lower_id="$( - awk -v current="$GITHUB_RUN_ID" '$1 < current { print $1; exit }' \ - <<<"$run_ids" - )" - if [ -n "$lower_id" ]; then - echo "forward=false" >>"$GITHUB_OUTPUT" - echo "Duplicate exact-key invocation suppressed by lower durable run $lower_id." - exit 0 - fi - if grep -Fxq "$GITHUB_RUN_ID" <<<"$run_ids"; then - echo "forward=true" >>"$GITHUB_OUTPUT" - exit 0 - fi - if [ "$attempt" -lt 3 ]; then - sleep "$((attempt * 2))" - fi - done + response_path = Path(sys.argv[1]) + payload = json.loads(response_path.read_text(encoding="utf-8")) + expected_name = os.environ["LEDGER_ARTIFACT_NAME"] + if not isinstance(payload, dict): + raise SystemExit("artifact response must be an object") + total_count = payload.get("total_count") + artifacts = payload.get("artifacts") + if type(total_count) is not int or total_count < 0: + raise SystemExit("artifact response has an invalid total_count") + if not isinstance(artifacts, list): + raise SystemExit("artifact response has an invalid artifacts collection") + if total_count != len(artifacts): + raise SystemExit("artifact response is truncated or inconsistent") + live = False + for artifact in artifacts: + if not isinstance(artifact, dict): + raise SystemExit("artifact response contains a non-object record") + artifact_id = artifact.get("id") + name = artifact.get("name") + expired = artifact.get("expired") + if type(artifact_id) is not int or artifact_id < 1: + raise SystemExit("artifact response contains an invalid artifact id") + if not isinstance(name, str) or name != expected_name: + raise SystemExit("artifact response contains a mismatched artifact name") + if type(expired) is not bool: + raise SystemExit("artifact response contains an invalid expired flag") + live = live or not expired + + output_path = Path(os.environ["GITHUB_OUTPUT"]) + if live: + with output_path.open("a", encoding="utf-8") as handle: + handle.write("claim=false\n") + raise SystemExit(0) + + claim_dir = Path(os.environ["RUNNER_TEMP"]) / "cwl-agent-invocation-ledger" + claim_dir.mkdir(mode=0o700, parents=True, exist_ok=True) + claim = { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "invocation_key": os.environ["INVOCATION_KEY"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + } + (claim_dir / "claim.json").write_text( + json.dumps(claim, ensure_ascii=True, indent=2, sort_keys=True) + "\n", + encoding="utf-8", + ) + with output_path.open("a", encoding="utf-8") as handle: + handle.write("claim=true\n") + PYTHON - echo "::notice::Current run remained absent from the eventually consistent workflow-run list after retries; self-electing because no lower durable run was observed." - echo "forward=true" >>"$GITHUB_OUTPUT" + - name: Claim exact invocation in the durable artifact ledger + if: steps.ledger.outputs.claim == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cwl-agent-invocation-${{ env.INVOCATION_KEY }} + path: ${{ runner.temp }}/cwl-agent-invocation-ledger/claim.json + if-no-files-found: error + retention-days: 30 + compression-level: 0 + overwrite: false + include-hidden-files: false - name: Forward once to the authoritative review-only scheduler - if: steps.leader.outputs.forward == 'true' + if: steps.ledger.outputs.claim == 'true' run: | set -euo pipefail jq -n \ From ff37f9880f346a9ba757da25ff302cbf3251b44d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:37:24 +0900 Subject: [PATCH 121/138] test(automation): migrate idempotency coverage to artifacts --- tests/test_agent_mention_idempotency.py | 203 ++++++++++++------------ 1 file changed, 104 insertions(+), 99 deletions(-) diff --git a/tests/test_agent_mention_idempotency.py b/tests/test_agent_mention_idempotency.py index 2cd19a8ed..499730a22 100644 --- a/tests/test_agent_mention_idempotency.py +++ b/tests/test_agent_mention_idempotency.py @@ -40,25 +40,40 @@ def request(module: ModuleType): ) -class RunAwareClient: - """Fake GitHub client with workflow-run inventory and fault injection.""" - - def __init__(self, *, runs=None, fail_event=None, fail_target_call=None) -> None: +class ArtifactAwareClient: + """Fake GitHub client with exact artifact inventory and fault injection.""" + + def __init__( + self, + *, + artifacts=None, + fail_event=None, + fail_target_call=None, + ) -> None: """Initialize bounded responses and optional deterministic failures.""" - self.runs = runs or {} + self.artifacts = artifacts or {} self.fail_event = fail_event self.fail_target_call = fail_target_call self.calls: list[tuple[list[str], dict | None]] = [] def request(self, args, *, input_payload=None): - """Return workflow runs, record mutations, or raise at a selected boundary.""" + """Return exact artifacts, record mutations, or raise at one boundary.""" call_number = len(self.calls) + 1 - self.calls.append((list(args), input_payload)) + args = list(args) + self.calls.append((args, input_payload)) endpoint = args[0] - if endpoint.endswith("/runs"): - return self.runs.get(endpoint, {"workflow_runs": []}) + if endpoint.endswith("/actions/artifacts"): + name = next( + value.split("=", 1)[1] + for value in args + if value.startswith("name=") + ) + return self.artifacts.get( + name, + {"total_count": 0, "artifacts": []}, + ) if endpoint.endswith("/dispatches"): event_type = (input_payload or {}).get("event_type") if event_type == self.fail_event: @@ -68,34 +83,30 @@ def request(self, args, *, input_payload=None): return None -def workflow_run(module: ModuleType, mention_request, agent: str, run_id: int) -> dict: - """Build one durable central workflow-run record for an exact agent request.""" +def artifact(module: ModuleType, mention_request, agent: str, artifact_id: int) -> dict: + """Build one live exact-name artifact record for an agent request.""" return { - "id": run_id, - "event": "repository_dispatch", - "status": "completed", - "conclusion": "failure", - "display_title": ( - "Required review " - f"{module.agent_invocation_marker(mention_request, agent)}" - ), + "id": artifact_id, + "name": module.agent_ledger_artifact_name(mention_request, agent), + "expired": False, } -def run_inventory(module: ModuleType, mention_request, *agents: str) -> dict: - """Return endpoint-keyed workflow-run responses for selected agents.""" +def artifact_inventory(module: ModuleType, mention_request, *agents: str) -> dict: + """Return artifact-name-keyed responses for selected agents.""" inventory = {} for index, agent in enumerate(agents, start=1): - endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS[agent] - inventory[endpoint] = { - "workflow_runs": [workflow_run(module, mention_request, agent, index)] + name = module.agent_ledger_artifact_name(mention_request, agent) + inventory[name] = { + "total_count": 1, + "artifacts": [artifact(module, mention_request, agent, index)], } return inventory -def dispatch_events(client: RunAwareClient) -> list[str]: +def dispatch_events(client: ArtifactAwareClient) -> list[str]: """Return repository-dispatch event types recorded by one fake client.""" return [ @@ -106,7 +117,7 @@ def dispatch_events(client: RunAwareClient) -> list[str]: def test_invocation_key_binds_complete_request_identity() -> None: - """The opaque key changes with agent, head, PR, repository, or source comment.""" + """The opaque key changes with agent, head, PR, repository, or comment.""" module = load_module() original = request(module) @@ -117,6 +128,9 @@ def test_invocation_key_binds_complete_request_identity() -> None: assert module.agent_invocation_marker(original, "cwl-noema-review") == ( f"[cwl-agent-invocation:{noema_key}]" ) + assert module.agent_ledger_artifact_name( + original, "cwl-noema-review" + ).endswith(noema_key) changed_values = ( module.MentionRequest( @@ -191,75 +205,85 @@ def test_payloads_carry_exact_agent_invocation_identity() -> None: assert payload["source_comment_id"] == mention_request.comment_id -def test_existing_workflow_runs_are_per_agent_durable_evidence() -> None: - """Queued, running, completed, or failed exact-key runs suppress only that agent.""" +def test_existing_artifacts_are_per_agent_durable_evidence() -> None: + """A live exact-name artifact suppresses only its matching agent.""" module = load_module() mention_request = request(module) - client = RunAwareClient( - runs=run_inventory(module, mention_request, "cwl-noema-review") + client = ArtifactAwareClient( + artifacts=artifact_inventory(module, mention_request, "cwl-noema-review") ) assert module.dispatched_agents(mention_request, client) == frozenset( {"cwl-noema-review"} ) - forged = { - module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"]: { - "workflow_runs": [ - { - **workflow_run( - module, mention_request, "cwl-noema-review", 2 - ), - "display_title": "forged unrelated title", + with pytest.raises(ValueError, match="artifact"): + module.dispatched_agents( + mention_request, + ArtifactAwareClient( + artifacts={ + module.agent_ledger_artifact_name( + mention_request, "cwl-noema-review" + ): {"total_count": 1, "artifacts": "not-a-list"} } - ] - } - } - assert module.dispatched_agents( - mention_request, RunAwareClient(runs=forged) - ) == frozenset() - - malformed = RunAwareClient( - runs={ - module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"]: { - "workflow_runs": "not-a-list" - } - } - ) - with pytest.raises(ValueError, match="workflow-run"): - module.dispatched_agents(mention_request, malformed) + ), + ) -def test_workflow_run_inventory_edge_cases_fail_closed(monkeypatch) -> None: - """Empty, malformed, oversized, and unsupported run queries fail safely.""" +def test_artifact_inventory_edge_cases_fail_closed() -> None: + """Malformed, inconsistent, and unsupported evidence fails safely.""" module = load_module() mention_request = request(module) + expected_name = module.agent_ledger_artifact_name( + mention_request, "cwl-noema-review" + ) + malformed = ( + None, + [], + {"total_count": True, "artifacts": []}, + {"total_count": -1, "artifacts": []}, + {"total_count": 0, "artifacts": "bad"}, + {"total_count": 1, "artifacts": []}, + {"total_count": 1, "artifacts": ["bad"]}, + {"total_count": 1, "artifacts": [{"id": True, "name": expected_name, "expired": False}]}, + {"total_count": 1, "artifacts": [{"id": 0, "name": expected_name, "expired": False}]}, + {"total_count": 1, "artifacts": [{"id": 1, "name": "wrong", "expired": False}]}, + {"total_count": 1, "artifacts": [{"id": 1, "name": expected_name, "expired": 0}]}, + ) + for value in malformed: + with pytest.raises(ValueError, match="artifact"): + module._artifact_records(value, expected_name=expected_name) - assert module._workflow_run_records(None) == () - for malformed in ([], ["not-an-object"]): - with pytest.raises(ValueError, match="object pages"): - module._workflow_run_records(malformed) - - monkeypatch.setattr(module, "MAX_WORKFLOW_RUN_RECORDS", 0) - with pytest.raises(ValueError, match="bounded record limit"): - module._workflow_run_records({"workflow_runs": [{}]}) + assert module._artifact_records( + {"total_count": 0, "artifacts": []}, + expected_name=expected_name, + ) == () + assert module._artifact_records( + { + "total_count": 1, + "artifacts": [ + {"id": 1, "name": expected_name, "expired": True} + ], + }, + expected_name=expected_name, + ) == () with pytest.raises(ValueError, match="unsupported agent"): module.dispatched_agents( mention_request, - RunAwareClient(), + ArtifactAwareClient(), agents=("unknown-agent",), ) def test_partial_failure_retries_only_the_missing_agent() -> None: - """A later dispatch failure never repeats an already materialized agent run.""" + """A later dispatch failure never repeats an already claimed agent.""" module = load_module() mention_request = request(module) - target = RunAwareClient() - first = RunAwareClient(fail_event="agent-mention-opencode") + target = ArtifactAwareClient() + first = ArtifactAwareClient(fail_event="agent-mention-opencode") with pytest.raises(RuntimeError, match="agent-mention-opencode"): module.dispatch_request( @@ -273,12 +297,16 @@ def test_partial_failure_retries_only_the_missing_agent() -> None: "agent-mention-opencode", ] - retry = RunAwareClient( - runs=run_inventory(module, mention_request, "cwl-noema-review") + retry = ArtifactAwareClient( + artifacts=artifact_inventory( + module, + mention_request, + "cwl-noema-review", + ) ) assert module.dispatch_request( mention_request, - target_client=RunAwareClient(), + target_client=ArtifactAwareClient(), dispatch_client=retry, opencode_allowlist=frozenset({mention_request.repository}), ) == ("@opencode-agent",) @@ -290,8 +318,8 @@ def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: module = load_module() mention_request = request(module) - central = RunAwareClient() - failing_target = RunAwareClient(fail_target_call=1) + central = ArtifactAwareClient() + failing_target = ArtifactAwareClient(fail_target_call=1) with pytest.raises(RuntimeError, match="target call"): module.dispatch_request( mention_request, @@ -304,15 +332,15 @@ def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: "agent-mention-opencode", ] - retry = RunAwareClient( - runs=run_inventory( + retry = ArtifactAwareClient( + artifacts=artifact_inventory( module, mention_request, "cwl-noema-review", "opencode-agent", ) ) - retry_target = RunAwareClient(fail_target_call=1) + retry_target = ArtifactAwareClient(fail_target_call=1) assert module.dispatch_request( mention_request, target_client=retry_target, @@ -321,26 +349,3 @@ def test_reaction_or_ack_failure_cannot_redispatch_completed_agents() -> None: ) == () assert dispatch_events(retry) == [] assert retry_target.calls == [] - - -def test_exact_run_inventory_accepts_paginated_slurp_shape() -> None: - """The bounded parser handles gh --paginate --slurp pages deterministically.""" - - module = load_module() - mention_request = request(module) - endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["opencode-agent"] - client = RunAwareClient( - runs={ - endpoint: [ - {"workflow_runs": []}, - { - "workflow_runs": [ - workflow_run(module, mention_request, "opencode-agent", 9) - ] - }, - ] - } - ) - assert module.dispatched_agents(mention_request, client) == frozenset( - {"opencode-agent"} - ) From 0e95e158149033e1219f80e79c3ce31972559b8c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:38:36 +0900 Subject: [PATCH 122/138] test(automation): migrate review regressions to artifacts --- .../test_agent_mention_review_regressions.py | 88 ++++++++----------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/tests/test_agent_mention_review_regressions.py b/tests/test_agent_mention_review_regressions.py index db5051e23..23e11d45a 100644 --- a/tests/test_agent_mention_review_regressions.py +++ b/tests/test_agent_mention_review_regressions.py @@ -1,11 +1,9 @@ - """Review-driven runtime regressions for the agent mention control plane.""" from __future__ import annotations import importlib.util import sys -from datetime import datetime, timezone from pathlib import Path from types import ModuleType, SimpleNamespace @@ -42,7 +40,7 @@ def request(module: ModuleType, agents=("cwl-noema-review", "opencode-agent")): class FakeClient: - """Capture API requests and expose endpoint-keyed run inventories.""" + """Capture API requests and expose exact-name artifact inventories.""" def __init__(self, responses=None) -> None: """Initialize responses and an empty call ledger.""" @@ -51,11 +49,20 @@ def __init__(self, responses=None) -> None: self.calls: list[tuple[list[str], dict | None]] = [] def request(self, args, *, input_payload=None): - """Record a call and return its registered response.""" - - self.calls.append((list(args), input_payload)) - if args[0].endswith("/runs"): - return self.responses.get(args[0], {"workflow_runs": []}) + """Record a call and return its registered artifact response.""" + + args = list(args) + self.calls.append((args, input_payload)) + if args[0].endswith("/actions/artifacts"): + name = next( + value.split("=", 1)[1] + for value in args + if value.startswith("name=") + ) + return self.responses.get( + name, + {"total_count": 0, "artifacts": []}, + ) return None @@ -113,66 +120,49 @@ def test_github_client_surfaces_bounded_api_diagnostics( module.GitHubClient("token").request(["repos/x/y"]) -def test_workflow_run_cutoff_and_marker_cache_bound_api_cost() -> None: - """Each agent workflow inventory is queried once per sweep window.""" +def test_exact_artifact_cache_bounds_api_cost() -> None: + """Each exact artifact name is queried once per router or sweep run.""" module = load_module() - now = datetime(2026, 8, 6, 12, tzinfo=timezone.utc) - cutoff = module.workflow_run_cutoff(now=now, lookback_hours=24) - assert cutoff == "2026-08-05T12:00:00Z" - with pytest.raises(ValueError, match="timezone-aware"): - module.workflow_run_cutoff(now=datetime(2026, 8, 6)) - mention = request(module) - noema_endpoint = module.AGENT_WORKFLOW_RUN_ENDPOINTS["cwl-noema-review"] - noema_marker = module.agent_invocation_marker( - mention, "cwl-noema-review" - ) + name = module.agent_ledger_artifact_name(mention, "cwl-noema-review") client = FakeClient( { - noema_endpoint: { - "workflow_runs": [ - { - "id": 0, - "event": "repository_dispatch", - "display_title": f"ignored {noema_marker}", - }, - { - "id": 1, - "event": "repository_dispatch", - "display_title": f"run {noema_marker}", - }, - ] + name: { + "total_count": 1, + "artifacts": [ + {"id": 1, "name": name, "expired": False} + ], } } ) - cache: dict[str, set[str]] = {} + cache: dict[str, bool] = {} expected = frozenset({"cwl-noema-review"}) assert module.dispatched_agents( mention, client, - workflow_run_since=cutoff, - run_marker_cache=cache, + ledger_artifact_cache=cache, ) == expected assert module.dispatched_agents( mention, client, - workflow_run_since=cutoff, - run_marker_cache=cache, + ledger_artifact_cache=cache, ) == expected - run_calls = [args for args, _ in client.calls if args[0].endswith("/runs")] - assert len(run_calls) == 2 - assert all(f"created=>={cutoff}" in args for args in run_calls) + artifact_calls = [ + args for args, _ in client.calls if args[0].endswith("/actions/artifacts") + ] + assert len(artifact_calls) == 2 + assert all("per_page=100" in args for args in artifact_calls) def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> None: - """Accepted dispatches update the in-memory ledger before wrapper visibility.""" + """Accepted dispatches update the in-memory ledger before artifact visibility.""" module = load_module() mention = request(module) target = FakeClient() central = FakeClient() - cache: dict[str, set[str]] = {} + cache: dict[str, bool] = {} allowlist = frozenset({"contextualwisdomlab/example"}) assert module.dispatch_request( @@ -180,8 +170,7 @@ def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> Non target_client=target, dispatch_client=central, opencode_allowlist=allowlist, - workflow_run_since="2026-08-01T00:00:00Z", - run_marker_cache=cache, + ledger_artifact_cache=cache, ) == ("@cwl-noema-review", "@opencode-agent") first_target_calls = len(target.calls) assert module.dispatch_request( @@ -189,8 +178,7 @@ def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> Non target_client=target, dispatch_client=central, opencode_allowlist=allowlist, - workflow_run_since="2026-08-01T00:00:00Z", - run_marker_cache=cache, + ledger_artifact_cache=cache, ) == () assert len(target.calls) == first_target_calls dispatches = [ @@ -203,13 +191,13 @@ def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> Non mixed = request(module) mixed_target = FakeClient() mixed_central = FakeClient() - mixed_cache: dict[str, set[str]] = {} + mixed_cache: dict[str, bool] = {} assert module.dispatch_request( mixed, target_client=mixed_target, dispatch_client=mixed_central, opencode_allowlist=frozenset(), - run_marker_cache=mixed_cache, + ledger_artifact_cache=mixed_cache, ) == ("@cwl-noema-review",) first_mixed_calls = len(mixed_target.calls) assert module.dispatch_request( @@ -217,6 +205,6 @@ def test_dispatch_cache_suppresses_same_run_retries_and_rejection_noise() -> Non target_client=mixed_target, dispatch_client=mixed_central, opencode_allowlist=frozenset(), - run_marker_cache=mixed_cache, + ledger_artifact_cache=mixed_cache, ) == () assert len(mixed_target.calls) == first_mixed_calls From f732cdb768f5bb56f9a6efc37292033dbbd178a3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:39:52 +0900 Subject: [PATCH 123/138] test(automation): assert artifact-first wrapper claims --- ...st_agent_mention_downstream_idempotency.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/test_agent_mention_downstream_idempotency.py b/tests/test_agent_mention_downstream_idempotency.py index c369763a0..4fc40a782 100644 --- a/tests/test_agent_mention_downstream_idempotency.py +++ b/tests/test_agent_mention_downstream_idempotency.py @@ -1,4 +1,3 @@ - """Static contracts for downstream review-agent invocation idempotency.""" from pathlib import Path @@ -9,9 +8,10 @@ NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" ROUTER_SCRIPT = ROOT / "scripts" / "ci" / "agent_mention_router.py" +UPLOAD_ARTIFACT_SHA = "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" -def test_router_can_read_durable_central_workflow_runs() -> None: +def test_router_can_read_durable_central_artifacts() -> None: """Both local routing and sibling sweeping receive actions read access.""" text = ROUTER_WORKFLOW.read_text(encoding="utf-8") @@ -22,8 +22,8 @@ def test_router_can_read_durable_central_workflow_runs() -> None: assert "AGENT_DISPATCH_TOKEN: ${{ github.token }}" in sweep -def test_downstream_workflows_retry_visibility_and_bind_exact_key() -> None: - """Wrappers queue duplicates and never lose a request to eventual consistency.""" +def test_downstream_workflows_claim_artifacts_and_bind_exact_key() -> None: + """Exact-key concurrency serializes claims before authoritative forwarding.""" noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") @@ -34,11 +34,17 @@ def test_downstream_workflows_retry_visibility_and_bind_exact_key() -> None: assert "requested_agent" in text assert "cancel-in-progress: false" in text assert "queue: max" in text - assert "for attempt in 1 2 3" in text - assert 'sleep "$((attempt * 2))"' in text - assert "no lower durable run was observed" in text assert "^[0-9a-f]{64}$" in text assert "^[1-9][0-9]*$" in text + assert "actions/artifacts" in text + assert "name=${LEDGER_ARTIFACT_NAME}" in text + assert f"actions/upload-artifact@{UPLOAD_ARTIFACT_SHA}" in text + assert "retention-days: 30" in text + assert "overwrite: false" in text + assert text.index("actions/upload-artifact@") < text.index( + "Forward once to the authoritative" + ) + assert "workflow_runs" not in text assert "repos/${GITHUB_REPOSITORY}/dispatches" in text assert "types: [agent-mention-noema]" in noema assert 'event_type: "noema-review"' in noema From 1282c014eb4f9c1fa8b1e3679d9af7ba9b76d134 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:41:54 +0900 Subject: [PATCH 124/138] test(automation): assert shared artifact cache in sweep --- tests/test_agent_mention_sweep_regressions.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_agent_mention_sweep_regressions.py b/tests/test_agent_mention_sweep_regressions.py index 93a505dc3..d9c0c4f2a 100644 --- a/tests/test_agent_mention_sweep_regressions.py +++ b/tests/test_agent_mention_sweep_regressions.py @@ -1,4 +1,3 @@ - """Review-driven pagination and failure-isolation regressions.""" from __future__ import annotations @@ -240,10 +239,10 @@ def dispatch(request, **kwargs): metrics=metrics, ) == 1 assert metrics.failures == 2 - assert dispatch_kwargs[0]["run_marker_cache"] is dispatch_kwargs[1][ - "run_marker_cache" + assert dispatch_kwargs[0]["ledger_artifact_cache"] is dispatch_kwargs[1][ + "ledger_artifact_cache" ] - assert dispatch_kwargs[0]["workflow_run_since"].endswith("Z") + assert dispatch_kwargs[0]["dry_run"] is False output = capsys.readouterr().out assert "comment inventory failed" in output assert "dispatch failed" in output From 76d79d7a71a20f6f410939bd8cd806c322de5c53 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:43:42 +0900 Subject: [PATCH 125/138] docs(automation): document exact artifact ledger --- .../review-agent-comment-invocation.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index 40173bc90..51c84dcde 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -18,9 +18,13 @@ GitHub organization ruleset workflows support `pull_request`, `pull_request_targ The implementation uses two bounded paths: 1. **Local fast path.** Comments on `ContextualWisdomLab/.github` trigger `issue_comment` immediately. -2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and consults the central exact-key workflow-run ledger before queuing work. +2. **Organization sweep.** Every five minutes, the central workflow enumerates repositories visible to its cross-repository credential, finds recently updated open PRs and recent comments, validates trusted exact mentions, and consults the central exact-name Actions artifact ledger before queuing work. -Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Before durable-leader election, each agent-specific wrapper reconstructs the same canonical JSON from its validated payload, hashes it with SHA-256, and compares the result in constant time with the supplied key. Altering any bound field while retaining a syntactically valid key therefore fails closed. Wrapper workflows use the verified key in their run title and non-cancelling concurrency group. The earliest central wrapper run is the durable leader; later exact-key runs suppress forwarding. Completed, failed, queued, and in-progress wrapper records therefore prevent duplicate forwarding, while a partially completed multi-agent request can retry only its missing agent. +Each requested agent receives a deterministic invocation key containing the target repository, PR number, exact head SHA, base branch, requested agent, source comment ID, and requesting actor. Each agent-specific wrapper reconstructs the same canonical JSON from its validated payload, hashes it with SHA-256, and compares the result in constant time with the supplied key. Altering any bound field while retaining a syntactically valid key therefore fails closed. + +The exact-name Actions artifact ledger uses `cwl-agent-invocation-` as the artifact name. The router queries GitHub's repository artifact endpoint with the server-side exact `name` filter, validates the complete response, and treats any live exact-name artifact as durable dispatch evidence. This avoids depending on filtered workflow-run enumeration, which GitHub caps at 1,000 results even when pagination is requested. + +Wrapper workflows use the verified key in their non-cancelling concurrency group, inspect the exact artifact name, and upload a 30-day immutable claim before forwarding to the authoritative review plane. Exact-key concurrency serializes duplicate wrapper runs. If a prior live claim exists, the wrapper performs no forward. If artifact visibility is delayed and a duplicate upload collides, the upload fails before the forwarding step, so the control plane fails closed rather than forwarding twice. Completed or failed authoritative work remains claimed for the retention window; a maintainer who needs a new attempt creates a new trusted source comment, which produces a distinct key. Target-repository acknowledgement comments and reactions are user-experience signals only. They are not dispatch authority because repository writers, bot identities, or credential rotation could otherwise forge or invalidate a marker. A failed acknowledgement cannot cause completed agent work to be redispatched. @@ -37,6 +41,7 @@ This preserves the central MSA boundary without copying privileged workflow code - The local routing job receives job-scoped `actions: read`, `contents: write`, `issues: write`, and `pull-requests: read`. - The organization sweep receives job-scoped `actions: read`, `contents: write`, and `id-token: write`. - The two agent-specific wrapper workflows receive only job-scoped `actions: read` and `contents: write`; their workflow defaults remain `contents: read`. +- `actions: read` permits exact-name artifact inventory checks. Artifact upload uses the workflow artifact service and is pinned to immutable `actions/upload-artifact` v7.0.1. - `contents: write` is intentionally retained only on jobs that call GitHub's create-repository-dispatch endpoint. GitHub documents that endpoint as requiring Contents repository permission at write level. Removing it would disable the bounded central dispatch path; broad workflow-default write access is not granted. - The organization sweep uses the established cross-repository credential chain for reading target comments, while the central repository's own short-lived job token dispatches the central workflows. - OpenCode dispatch is restricted to the exact `OPENCODE_REPOSITORY_DISPATCH_TARGETS` allowlist. @@ -49,19 +54,20 @@ This preserves the central MSA boundary without copying privileged workflow code - `AGENT_MENTION_LOOKBACK_HOURS`: default `168`, allowed range 1–720. - `AGENT_MENTION_MAX_DISPATCHES`: default `20`, allowed range 1–100. The bound counts source requests that actually queue at least one new agent, not historical no-ops. +- Durable invocation claims use 30-day artifact retention. A new source comment creates a new invocation key when an intentional retry is required. - Operators request immediate work by writing an exact trusted mention on the target pull request; otherwise, the five-minute protected-default-branch sweep processes it. - The sweep fails visibly when no cross-repository credential is available. - `PR_REVIEW_MERGE_TOKEN` or `OPENCODE_APPROVE_TOKEN` takes precedence. Otherwise, the workflow exchanges its OIDC token for the existing OpenCode installation token and enumerates that installation's repositories. ## Verification and rollback -The permanent quality workflow runs the deterministic router, sweep, durable-ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. A permanent regression contract also rejects the transient PR-specific branch-writer workflows and repair helpers used during development, so they cannot ship with the control plane. +The permanent quality workflow runs the deterministic router, sweep, exact-name artifact ledger, wrapper, receipt-authority, and workflow-contract suites under Python 3.14 and requires 100% production statement coverage, branch coverage, and public docstring coverage. It also compiles the Python files and checks the final diff for whitespace errors. A permanent regression contract also rejects the transient PR-specific branch-writer workflows and repair helpers used during development, so they cannot ship with the control plane. ### Activation gate The router is inactive until its workflows and helper code are merged into the protected default branch. A materialization, predecessor, cancelled, queued, or stale-head run is not activation evidence. Production activation requires the exact final head to pass the permanent quality workflow, security and supply-chain checks, current-head automated review, an independent approval, unresolved-thread policy, and branch protection without bypass. -Rollback is deletion of the three mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. +Rollback is deletion of the four mention-router workflows, the two Python helpers, and their focused tests. Existing Noema and OpenCode review workflows remain independently invocable and authoritative; the router does not own reviewer identity, credentials, verdict acceptance, approval, merge, or release. ## References @@ -71,8 +77,14 @@ GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 6 GitHub. (n.d.). *GITHUB_TOKEN*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/actions/concepts/security/github_token +GitHub. (n.d.). *REST API endpoints for GitHub Actions artifacts*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/actions/artifacts + +GitHub. (n.d.). *REST API endpoints for GitHub Actions: List workflow runs for a workflow*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs-for-a-workflow + GitHub. (n.d.). *REST API endpoints for GitHub App installations*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/apps/installations GitHub. (n.d.). *REST API endpoints for issues*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/issues/issues GitHub. (n.d.). *REST API endpoints for repositories: Create a repository dispatch event*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/rest/repos/repos#create-a-repository-dispatch-event + +GitHub. (n.d.). *Store and share data with workflow artifacts*. GitHub Docs. Retrieved August 6, 2026, from https://docs.github.com/en/actions/tutorials/store-and-share-data From d2c7d410f5740c6382012e9daaea77e1f5749894 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:46:48 +0900 Subject: [PATCH 126/138] test(automation): return artifact inventories in router fakes --- tests/test_agent_mention_router.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 5db819071..1c094df9a 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -75,11 +75,11 @@ def __init__(self) -> None: self.calls: list[tuple[list[str], dict | None]] = [] def request(self, args, *, input_payload=None): - """Record one request and return an empty run inventory for reads.""" + """Record one request and return an empty artifact inventory for reads.""" self.calls.append((list(args), input_payload)) - if args[0].endswith("/runs"): - return {"workflow_runs": []} + if args[0].endswith("/actions/artifacts"): + return {"total_count": 0, "artifacts": []} return None @@ -249,6 +249,7 @@ def test_dispatch_uses_central_events_and_acknowledges() -> None: ) assert target.calls[0][1] == {"content": "eyes"} assert "cwl-agent-mention-receipt:91" in target.calls[1][1]["body"] + assert "exact-name Actions artifacts" in target.calls[1][1]["body"] def test_dispatch_rejects_unallowlisted_opencode_and_supports_dry_run( From 29ff8b5017c41f591eaa5fb8531aac53ce50f798 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 21:53:54 +0900 Subject: [PATCH 127/138] style(automation): annotate intentional failure isolation --- scripts/ci/agent_mention_sweep.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/scripts/ci/agent_mention_sweep.py b/scripts/ci/agent_mention_sweep.py index 3ddbc1bfc..9b64909a0 100644 --- a/scripts/ci/agent_mention_sweep.py +++ b/scripts/ci/agent_mention_sweep.py @@ -54,7 +54,11 @@ def cutoff_timestamp(lookback_hours: int, *, now: datetime | None = None) -> str return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") -def flatten_pages(value: Any, *, collection_key: str | None = None) -> list[dict[str, Any]]: +def flatten_pages( + value: Any, + *, + collection_key: str | None = None, +) -> list[dict[str, Any]]: """Flatten ``gh api --paginate --slurp`` output into object records.""" if value is None: @@ -74,7 +78,9 @@ def flatten_pages(value: Any, *, collection_key: str | None = None) -> list[dict if not isinstance(collection, list): raise ValueError("paginated GitHub response is not a list") if not all(isinstance(record, dict) for record in collection): - raise ValueError("paginated GitHub response contains a non-object record") + raise ValueError( + "paginated GitHub response contains a non-object record" + ) records.extend(collection) return records @@ -201,7 +207,7 @@ def list_recent_pull_requests( if reached_cutoff or len(pull_requests) < 100: break page += 1 - except Exception as exc: + except Exception as exc: # noqa: BLE001 - repository isolation boundary if on_error is None: raise on_error(repository, exc) @@ -259,7 +265,10 @@ def build_requests_for_pull_request( for comment in comments: event = { "repository": {"full_name": repository}, - "issue": {"number": number, "pull_request": issue.get("pull_request")}, + "issue": { + "number": number, + "pull_request": issue.get("pull_request"), + }, "comment": comment, "pull_request": live_pull, } @@ -296,7 +305,9 @@ def record_failure(scope: str, error: Exception) -> None: counters.failures += 1 message = " ".join(str(error).split()) or error.__class__.__name__ - print(f"::warning::Agent mention sweep skipped {scope}: {message[:1000]}") + print( + f"::warning::Agent mention sweep skipped {scope}: {message[:1000]}" + ) for issue in list_recent_pull_requests( target_client, @@ -312,7 +323,7 @@ def record_failure(scope: str, error: Exception) -> None: issue=issue, since=since, ) - except Exception as exc: + except Exception as exc: # noqa: BLE001 - pull-request isolation boundary record_failure(issue_scope, exc) continue for request in requests: @@ -326,7 +337,7 @@ def record_failure(scope: str, error: Exception) -> None: dry_run=dry_run, ledger_artifact_cache=ledger_artifact_cache, ) - except Exception as exc: + except Exception as exc: # noqa: BLE001 - request isolation boundary record_failure(request_scope, exc) continue if not queued_agents: @@ -364,7 +375,9 @@ def main(argv: Sequence[str] | None = None) -> int: ) metrics = SweepMetrics() sweep( - target_client=GitHubClient(os.environ.get("TARGET_REPOSITORY_TOKEN", "")), + target_client=GitHubClient( + os.environ.get("TARGET_REPOSITORY_TOKEN", "") + ), dispatch_client=GitHubClient(os.environ.get("AGENT_DISPATCH_TOKEN", "")), organization=args.organization, repository_source=args.repository_source, From b49d9827be7d896ab87b4afdad1f110619d68ba4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:09:41 +0900 Subject: [PATCH 128/138] ci(pr787): finalize verified payload binding --- .../repair-pr787-finalize-payload-binding.yml | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 .github/workflows/repair-pr787-finalize-payload-binding.yml diff --git a/.github/workflows/repair-pr787-finalize-payload-binding.yml b/.github/workflows/repair-pr787-finalize-payload-binding.yml new file mode 100644 index 000000000..3675d14bf --- /dev/null +++ b/.github/workflows/repair-pr787-finalize-payload-binding.yml @@ -0,0 +1,327 @@ +name: Repair PR 787 finalize payload binding + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-finalize-payload-binding.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-finalize-payload-binding + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + finalize: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.14' + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply the idempotent reviewed repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from __future__ import annotations + + import textwrap + from pathlib import Path + + + def replace_once(source: str, old: str, new: str, label: str) -> str: + count = source.count(old) + if count != 1: + raise RuntimeError(f'expected exactly one {label}, found {count}') + return source.replace(old, new, 1) + + + def indented_digest_block() -> str: + block = textwrap.dedent( + '''\ + python3 - <<'PY_DIGEST' + import hashlib + import hmac + import json + import os + + canonical = json.dumps( + { + "actor": os.environ["REQUESTED_BY"], + "agent": os.environ["REQUESTED_AGENT"], + "base_branch": os.environ["BASE_BRANCH"], + "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "head_sha": os.environ["PR_HEAD_SHA"], + "pr_number": int(os.environ["PR_NUMBER"]), + "repository": os.environ["TARGET_REPOSITORY"], + }, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + calculated_key = hashlib.sha256(canonical).hexdigest() + if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): + raise SystemExit("agent invocation key does not match canonical payload") + PY_DIGEST + + ''' + ) + return ''.join( + f' {line}' if line.strip() else line + for line in block.splitlines(keepends=True) + ) + + + router_path = Path('scripts/ci/agent_mention_router.py') + router = router_path.read_text(encoding='utf-8') + if '"base_branch": request.pull_request_base_branch' not in router.split('def noema_payload', 1)[1].split('def opencode_payload', 1)[0]: + router = replace_once( + router, + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "requested_agent": agent,\n', + ' "pr_head_sha": request.pull_request_head_sha,\n' + ' "base_branch": request.pull_request_base_branch,\n' + ' "requested_agent": agent,\n', + 'Noema base-branch payload boundary', + ) + router_path.write_text(router, encoding='utf-8') + + noema_path = Path('.github/workflows/agent-mention-noema-dispatch.yml') + noema = noema_path.read_text(encoding='utf-8') + old_permissions = ( + "permissions:\n actions: read\n contents: write\n\n" + "jobs:\n validate-and-forward:\n" + " if: github.repository == 'ContextualWisdomLab/.github'\n" + ) + new_permissions = ( + "permissions:\n contents: read\n\n" + "jobs:\n validate-and-forward:\n" + " if: github.repository == 'ContextualWisdomLab/.github'\n" + " permissions:\n actions: read\n contents: write\n" + ) + if old_permissions in noema: + noema = replace_once(noema, old_permissions, new_permissions, 'Noema job-scoped write permission') + if ' BASE_BRANCH: ${{ github.event.client_payload.base_branch || \'\' }}\n' not in noema: + noema = replace_once( + noema, + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" + " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" + " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", + 'Noema base-branch environment binding', + ) + if '! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' not in noema: + noema = replace_once( + noema, + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' + ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' + ' [[ "$BASE_BRANCH" == -* ]] ||\n' + ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', + 'Noema base-branch validation', + ) + if 'hmac.compare_digest' not in noema: + noema = replace_once( + noema, + ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + ' fi\n\n' + indented_digest_block() + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + 'Noema digest verification insertion point', + ) + if ' --arg base_branch "$BASE_BRANCH" \\\n' not in noema: + noema = replace_once( + noema, + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' + ' --arg base_branch "$BASE_BRANCH" \\\n' + ' --arg requested_agent "$REQUESTED_AGENT" \\\n', + 'Noema forwarded base-branch argument', + ) + if ' base_branch: $base_branch,\n' not in noema: + noema = replace_once( + noema, + ' pr_head_sha: $pr_head_sha,\n' + ' requested_agent: $requested_agent,\n', + ' pr_head_sha: $pr_head_sha,\n' + ' base_branch: $base_branch,\n' + ' requested_agent: $requested_agent,\n', + 'Noema forwarded base-branch field', + ) + noema_path.write_text(noema, encoding='utf-8') + + opencode_path = Path('.github/workflows/agent-mention-opencode-dispatch.yml') + opencode = opencode_path.read_text(encoding='utf-8') + if old_permissions in opencode: + opencode = replace_once(opencode, old_permissions, new_permissions, 'OpenCode job-scoped write permission') + if 'hmac.compare_digest' not in opencode: + opencode = replace_once( + opencode, + ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + ' fi\n\n' + indented_digest_block() + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', + 'OpenCode digest verification insertion point', + ) + opencode_path.write_text(opencode, encoding='utf-8') + + tests_path = Path('tests/test_agent_mention_idempotency.py') + tests = tests_path.read_text(encoding='utf-8') + base_variant = ''' module.MentionRequest( + original.repository, + original.pull_request_number, + original.pull_request_head_sha, + "develop", + original.comment_id, + original.actor, + original.agents, + ), + ''' + if ' "develop",\n' not in tests: + anchor = ''' module.MentionRequest( + original.repository, + original.pull_request_number, + "b" * 40, + original.pull_request_base_branch, + original.comment_id, + original.actor, + original.agents, + ), + ''' + tests = replace_once(tests, anchor, anchor + base_variant, 'base-branch-only invocation-key regression') + assertion = ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' + if assertion not in tests: + tests = replace_once( + tests, + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' + + assertion + + ' assert payload["source_comment_id"] == mention_request.comment_id\n', + 'payload base-branch identity assertion', + ) + tests_path.write_text(tests, encoding='utf-8') + + docs_path = Path('docs/automation/review-agent-comment-invocation.md') + docs = docs_path.read_text(encoding='utf-8') + digest_sentence = ( + 'Each wrapper reconstructs the complete sorted compact JSON invocation identity—repository, pull request, exact head SHA, base branch, requested agent, source comment ID, and requesting actor—and compares its SHA-256 digest before durable-leader election or forwarding. A valid-format key paired with altered payload fields therefore fails closed.\n' + ) + if digest_sentence not in docs: + marker = '## Idempotency\n' + if marker not in docs: + marker = '# Review-agent comment invocation\n' + docs = docs.replace(marker, marker + '\n' + digest_sentence, 1) + permission_sentence = ( + 'Workflow defaults remain contents-read-only; only the validated forwarding jobs receive the narrow write permission required to create repository-dispatch events.\n' + ) + if permission_sentence not in docs: + docs += '\n' + permission_sentence + docs_path.write_text(docs, encoding='utf-8') + + changelog_path = Path('CHANGELOG.md') + changelog = changelog_path.read_text(encoding='utf-8') + entry = ( + '- Bound each review-agent invocation key to the wrapper\'s complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n' + ) + if entry not in changelog: + changelog = replace_once(changelog, '### Fixed\n\n', '### Fixed\n\n' + entry, 'Unreleased Fixed heading') + changelog_path.write_text(changelog, encoding='utf-8') + PY + git diff --check + + - name: Verify focused quality and payload identity + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Publish only the verified product tree + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + test -n "$PUSH_TOKEN" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm -f .github/pr787-payload-repair.trigger + find .github/workflows -maxdepth 1 -type f -name 'repair-pr787-*' -delete + rm -f scripts/ci/repair_pr787_payload_bound_once.py + git add -A + git diff --cached --check + git diff --cached --quiet && { echo 'No verified PR 787 repair generated.' >&2; exit 1; } + test -z "$(git diff --cached --name-only | grep -E '(^|/)repair-pr787-|repair_pr787_payload_bound_once' || true)" + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git commit -m 'fix(automation): bind invocation keys to complete payloads' + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 0e5e597469b53a629a65c09f7b48637776cd0fdb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:00:14 +0900 Subject: [PATCH 129/138] chore(automation): remove PR-controlled router repair workflow --- .../repair-pr787-finalize-payload-binding.yml | 327 ------------------ 1 file changed, 327 deletions(-) delete mode 100644 .github/workflows/repair-pr787-finalize-payload-binding.yml diff --git a/.github/workflows/repair-pr787-finalize-payload-binding.yml b/.github/workflows/repair-pr787-finalize-payload-binding.yml deleted file mode 100644 index 3675d14bf..000000000 --- a/.github/workflows/repair-pr787-finalize-payload-binding.yml +++ /dev/null @@ -1,327 +0,0 @@ -name: Repair PR 787 finalize payload binding - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-finalize-payload-binding.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-finalize-payload-binding - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - finalize: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.14' - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply the idempotent reviewed repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from __future__ import annotations - - import textwrap - from pathlib import Path - - - def replace_once(source: str, old: str, new: str, label: str) -> str: - count = source.count(old) - if count != 1: - raise RuntimeError(f'expected exactly one {label}, found {count}') - return source.replace(old, new, 1) - - - def indented_digest_block() -> str: - block = textwrap.dedent( - '''\ - python3 - <<'PY_DIGEST' - import hashlib - import hmac - import json - import os - - canonical = json.dumps( - { - "actor": os.environ["REQUESTED_BY"], - "agent": os.environ["REQUESTED_AGENT"], - "base_branch": os.environ["BASE_BRANCH"], - "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), - "head_sha": os.environ["PR_HEAD_SHA"], - "pr_number": int(os.environ["PR_NUMBER"]), - "repository": os.environ["TARGET_REPOSITORY"], - }, - ensure_ascii=True, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - calculated_key = hashlib.sha256(canonical).hexdigest() - if not hmac.compare_digest(calculated_key, os.environ["INVOCATION_KEY"]): - raise SystemExit("agent invocation key does not match canonical payload") - PY_DIGEST - - ''' - ) - return ''.join( - f' {line}' if line.strip() else line - for line in block.splitlines(keepends=True) - ) - - - router_path = Path('scripts/ci/agent_mention_router.py') - router = router_path.read_text(encoding='utf-8') - if '"base_branch": request.pull_request_base_branch' not in router.split('def noema_payload', 1)[1].split('def opencode_payload', 1)[0]: - router = replace_once( - router, - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "requested_agent": agent,\n', - ' "pr_head_sha": request.pull_request_head_sha,\n' - ' "base_branch": request.pull_request_base_branch,\n' - ' "requested_agent": agent,\n', - 'Noema base-branch payload boundary', - ) - router_path.write_text(router, encoding='utf-8') - - noema_path = Path('.github/workflows/agent-mention-noema-dispatch.yml') - noema = noema_path.read_text(encoding='utf-8') - old_permissions = ( - "permissions:\n actions: read\n contents: write\n\n" - "jobs:\n validate-and-forward:\n" - " if: github.repository == 'ContextualWisdomLab/.github'\n" - ) - new_permissions = ( - "permissions:\n contents: read\n\n" - "jobs:\n validate-and-forward:\n" - " if: github.repository == 'ContextualWisdomLab/.github'\n" - " permissions:\n actions: read\n contents: write\n" - ) - if old_permissions in noema: - noema = replace_once(noema, old_permissions, new_permissions, 'Noema job-scoped write permission') - if ' BASE_BRANCH: ${{ github.event.client_payload.base_branch || \'\' }}\n' not in noema: - noema = replace_once( - noema, - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - " PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }}\n" - " BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }}\n" - " REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }}\n", - 'Noema base-branch environment binding', - ) - if '! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]]' not in noema: - noema = replace_once( - noema, - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - ' ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] ||\n' - ' ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] ||\n' - ' [[ "$BASE_BRANCH" == -* ]] ||\n' - ' ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] ||\n', - 'Noema base-branch validation', - ) - if 'hmac.compare_digest' not in noema: - noema = replace_once( - noema, - ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - ' fi\n\n' + indented_digest_block() + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - 'Noema digest verification insertion point', - ) - if ' --arg base_branch "$BASE_BRANCH" \\\n' not in noema: - noema = replace_once( - noema, - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - ' --arg pr_head_sha "$PR_HEAD_SHA" \\\n' - ' --arg base_branch "$BASE_BRANCH" \\\n' - ' --arg requested_agent "$REQUESTED_AGENT" \\\n', - 'Noema forwarded base-branch argument', - ) - if ' base_branch: $base_branch,\n' not in noema: - noema = replace_once( - noema, - ' pr_head_sha: $pr_head_sha,\n' - ' requested_agent: $requested_agent,\n', - ' pr_head_sha: $pr_head_sha,\n' - ' base_branch: $base_branch,\n' - ' requested_agent: $requested_agent,\n', - 'Noema forwarded base-branch field', - ) - noema_path.write_text(noema, encoding='utf-8') - - opencode_path = Path('.github/workflows/agent-mention-opencode-dispatch.yml') - opencode = opencode_path.read_text(encoding='utf-8') - if old_permissions in opencode: - opencode = replace_once(opencode, old_permissions, new_permissions, 'OpenCode job-scoped write permission') - if 'hmac.compare_digest' not in opencode: - opencode = replace_once( - opencode, - ' fi\n\n marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - ' fi\n\n' + indented_digest_block() + ' marker="[cwl-agent-invocation:${INVOCATION_KEY}]"\n', - 'OpenCode digest verification insertion point', - ) - opencode_path.write_text(opencode, encoding='utf-8') - - tests_path = Path('tests/test_agent_mention_idempotency.py') - tests = tests_path.read_text(encoding='utf-8') - base_variant = ''' module.MentionRequest( - original.repository, - original.pull_request_number, - original.pull_request_head_sha, - "develop", - original.comment_id, - original.actor, - original.agents, - ), - ''' - if ' "develop",\n' not in tests: - anchor = ''' module.MentionRequest( - original.repository, - original.pull_request_number, - "b" * 40, - original.pull_request_base_branch, - original.comment_id, - original.actor, - original.agents, - ), - ''' - tests = replace_once(tests, anchor, anchor + base_variant, 'base-branch-only invocation-key regression') - assertion = ' assert payload["base_branch"] == mention_request.pull_request_base_branch\n' - if assertion not in tests: - tests = replace_once( - tests, - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - ' assert payload["source_comment_id"] == mention_request.comment_id\n', - ' assert payload["pr_head_sha"] == mention_request.pull_request_head_sha\n' - + assertion - + ' assert payload["source_comment_id"] == mention_request.comment_id\n', - 'payload base-branch identity assertion', - ) - tests_path.write_text(tests, encoding='utf-8') - - docs_path = Path('docs/automation/review-agent-comment-invocation.md') - docs = docs_path.read_text(encoding='utf-8') - digest_sentence = ( - 'Each wrapper reconstructs the complete sorted compact JSON invocation identity—repository, pull request, exact head SHA, base branch, requested agent, source comment ID, and requesting actor—and compares its SHA-256 digest before durable-leader election or forwarding. A valid-format key paired with altered payload fields therefore fails closed.\n' - ) - if digest_sentence not in docs: - marker = '## Idempotency\n' - if marker not in docs: - marker = '# Review-agent comment invocation\n' - docs = docs.replace(marker, marker + '\n' + digest_sentence, 1) - permission_sentence = ( - 'Workflow defaults remain contents-read-only; only the validated forwarding jobs receive the narrow write permission required to create repository-dispatch events.\n' - ) - if permission_sentence not in docs: - docs += '\n' + permission_sentence - docs_path.write_text(docs, encoding='utf-8') - - changelog_path = Path('CHANGELOG.md') - changelog = changelog_path.read_text(encoding='utf-8') - entry = ( - '- Bound each review-agent invocation key to the wrapper\'s complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.\n' - ) - if entry not in changelog: - changelog = replace_once(changelog, '### Fixed\n\n', '### Fixed\n\n' + entry, 'Unreleased Fixed heading') - changelog_path.write_text(changelog, encoding='utf-8') - PY - git diff --check - - - name: Verify focused quality and payload identity - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Publish only the verified product tree - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - test -n "$PUSH_TOKEN" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm -f .github/pr787-payload-repair.trigger - find .github/workflows -maxdepth 1 -type f -name 'repair-pr787-*' -delete - rm -f scripts/ci/repair_pr787_payload_bound_once.py - git add -A - git diff --cached --check - git diff --cached --quiet && { echo 'No verified PR 787 repair generated.' >&2; exit 1; } - test -z "$(git diff --cached --name-only | grep -E '(^|/)repair-pr787-|repair_pr787_payload_bound_once' || true)" - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git commit -m 'fix(automation): bind invocation keys to complete payloads' - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From a32efd5abe2de84cf4dda82b8642093ce3d5a86b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:51:38 +0900 Subject: [PATCH 130/138] ci(pr787): run final workflow-authorized payload repair --- .../repair-pr787-final-payload-binding.yml | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 .github/workflows/repair-pr787-final-payload-binding.yml diff --git a/.github/workflows/repair-pr787-final-payload-binding.yml b/.github/workflows/repair-pr787-final-payload-binding.yml new file mode 100644 index 000000000..940b30af6 --- /dev/null +++ b/.github/workflows/repair-pr787-final-payload-binding.yml @@ -0,0 +1,113 @@ +name: Repair PR 787 final payload binding + +on: + push: + branches: + - feat/review-agent-mention-router-main + paths: + - .github/workflows/repair-pr787-final-payload-binding.yml + +permissions: + contents: read + +concurrency: + group: repair-pr787-final-payload-binding + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/feat/review-agent-mention-router-main' + permissions: + contents: read + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply and verify complete payload binding + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test -f scripts/ci/repair_pr787_payload_bound_once.py + python scripts/ci/repair_pr787_payload_bound_once.py + cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' + [run] + branch = True + include = + scripts/ci/agent_mention_router.py + scripts/ci/agent_mention_sweep.py + [report] + fail_under = 100 + show_missing = True + EOF + export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" + python -m coverage erase + python -m coverage run -m pytest -q \ + tests/test_agent_mention_router.py \ + tests/test_agent_mention_sweep.py \ + tests/test_agent_mention_workflow_contract.py \ + tests/test_agent_mention_idempotency.py \ + tests/test_agent_mention_downstream_idempotency.py \ + tests/test_agent_mention_receipt_authority.py + python -m coverage report --fail-under=100 + python -m interrogate --fail-under=100 \ + scripts/ci/agent_mention_router.py \ + scripts/ci/agent_mention_sweep.py + python -m compileall -q scripts/ci tests + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 + test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 + git diff --check + + - name: Publish only with workflow-authorized maintainer token + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: feat/review-agent-mention-router-main + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test -n "$PUSH_TOKEN" || { echo 'PR_REVIEW_MERGE_TOKEN is required.' >&2; exit 1; } + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + find .github/workflows -maxdepth 1 -type f -name 'repair-pr787-*' -delete + rm -f \ + .github/pr787-payload-repair.trigger \ + scripts/ci/repair_pr787_payload_bound_once.py + git add -A + git diff --cached --check + git diff --cached --quiet && { echo 'No verified repair generated.' >&2; exit 1; } + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "fix(automation): bind invocation keys to complete payloads" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 75e21fbd4f1fdc68449d28db21eda615b883c041 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:08:31 +0900 Subject: [PATCH 131/138] chore(automation): remove unsafe PR-specific branch writer --- .../repair-pr787-final-payload-binding.yml | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 .github/workflows/repair-pr787-final-payload-binding.yml diff --git a/.github/workflows/repair-pr787-final-payload-binding.yml b/.github/workflows/repair-pr787-final-payload-binding.yml deleted file mode 100644 index 940b30af6..000000000 --- a/.github/workflows/repair-pr787-final-payload-binding.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Repair PR 787 final payload binding - -on: - push: - branches: - - feat/review-agent-mention-router-main - paths: - - .github/workflows/repair-pr787-final-payload-binding.yml - -permissions: - contents: read - -concurrency: - group: repair-pr787-final-payload-binding - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/feat/review-agent-mention-router-main' - permissions: - contents: read - runs-on: ubuntu-24.04 - timeout-minutes: 30 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply and verify complete payload binding - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test -f scripts/ci/repair_pr787_payload_bound_once.py - python scripts/ci/repair_pr787_payload_bound_once.py - cat >"${RUNNER_TEMP}/agent-mention-coveragerc" <<'EOF' - [run] - branch = True - include = - scripts/ci/agent_mention_router.py - scripts/ci/agent_mention_sweep.py - [report] - fail_under = 100 - show_missing = True - EOF - export COVERAGE_RCFILE="${RUNNER_TEMP}/agent-mention-coveragerc" - python -m coverage erase - python -m coverage run -m pytest -q \ - tests/test_agent_mention_router.py \ - tests/test_agent_mention_sweep.py \ - tests/test_agent_mention_workflow_contract.py \ - tests/test_agent_mention_idempotency.py \ - tests/test_agent_mention_downstream_idempotency.py \ - tests/test_agent_mention_receipt_authority.py - python -m coverage report --fail-under=100 - python -m interrogate --fail-under=100 \ - scripts/ci/agent_mention_router.py \ - scripts/ci/agent_mention_sweep.py - python -m compileall -q scripts/ci tests - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-noema-dispatch.yml)" -eq 1 - test "$(grep -c 'hmac.compare_digest' .github/workflows/agent-mention-opencode-dispatch.yml)" -eq 1 - git diff --check - - - name: Publish only with workflow-authorized maintainer token - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: feat/review-agent-mention-router-main - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test -n "$PUSH_TOKEN" || { echo 'PR_REVIEW_MERGE_TOKEN is required.' >&2; exit 1; } - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - find .github/workflows -maxdepth 1 -type f -name 'repair-pr787-*' -delete - rm -f \ - .github/pr787-payload-repair.trigger \ - scripts/ci/repair_pr787_payload_bound_once.py - git add -A - git diff --cached --check - git diff --cached --quiet && { echo 'No verified repair generated.' >&2; exit 1; } - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git commit -m "fix(automation): bind invocation keys to complete payloads" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From d22976c4cd418fae6f68b46700910ba58ada205c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:28:24 +0900 Subject: [PATCH 132/138] test(automation): bind complete review invocation payload --- ..._agent_mention_complete_payload_binding.py | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 tests/test_agent_mention_complete_payload_binding.py diff --git a/tests/test_agent_mention_complete_payload_binding.py b/tests/test_agent_mention_complete_payload_binding.py new file mode 100644 index 000000000..04562e93f --- /dev/null +++ b/tests/test_agent_mention_complete_payload_binding.py @@ -0,0 +1,197 @@ +"""Contracts for complete review-agent invocation payload binding.""" + +from __future__ import annotations + +import hashlib +import importlib.util +import json +import sys +from dataclasses import replace +from pathlib import Path +from types import ModuleType + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +ROUTER_PATH = ROOT / "scripts" / "ci" / "agent_mention_router.py" +NOEMA_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-noema-dispatch.yml" +OPENCODE_WORKFLOW = ROOT / ".github" / "workflows" / "agent-mention-opencode-dispatch.yml" + + +def _load_router() -> ModuleType: + """Load the router module from the pull-request source tree.""" + + module_name = "agent_mention_complete_payload_binding" + spec = importlib.util.spec_from_file_location(module_name, ROUTER_PATH) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def _event() -> dict: + """Return one complete trusted issue-comment event.""" + + return { + "repository": {"full_name": "ContextualWisdomLab/example"}, + "issue": { + "number": 17, + "pull_request": {"url": "https://api.github.test/pr/17"}, + }, + "comment": { + "id": 91, + "body": "@cwl-noema-review @opencode-agent review", + "author_association": "MEMBER", + "user": {"login": "maintainer", "type": "User"}, + }, + "pull_request": { + "state": "open", + "head": {"sha": "a" * 40}, + "base": {"ref": "main", "sha": "b" * 40}, + }, + } + + +def _digest(claim: dict[str, object]) -> str: + """Return the canonical SHA-256 digest used by wrapper workflows.""" + + canonical = json.dumps( + claim, + ensure_ascii=True, + separators=(",", ":"), + sort_keys=True, + ).encode("utf-8") + return hashlib.sha256(canonical).hexdigest() + + +def test_event_and_payloads_bind_exact_base_identity() -> None: + """The request and both wrapper payloads carry the immutable base SHA.""" + + router = _load_router() + request = router.parse_event(_event()) + assert request is not None + assert request.pull_request_base_branch == "main" + assert request.pull_request_base_sha == "b" * 40 + + for payload in ( + router.noema_payload(request)["client_payload"], + router.opencode_payload(request)["client_payload"], + ): + assert payload["base_branch"] == "main" + assert payload["pr_base_sha"] == "b" * 40 + + malformed = _event() + malformed["pull_request"]["base"]["sha"] = "not-a-sha" + with pytest.raises(ValueError, match="base SHA"): + router.parse_event(malformed) + + +def test_invocation_claim_binds_all_security_relevant_fields() -> None: + """Every mutable dispatch field participates in the canonical digest.""" + + router = _load_router() + request = router.parse_event(_event()) + assert request is not None + + noema_claim = router.agent_invocation_claim(request, "cwl-noema-review") + assert noema_claim == { + "actor": "maintainer", + "agent": "cwl-noema-review", + "base_branch": "main", + "base_sha": "b" * 40, + "comment_id": 91, + "head_sha": "a" * 40, + "pr_number": 17, + "repository": "ContextualWisdomLab/example", + } + + opencode_claim = router.agent_invocation_claim(request, "opencode-agent") + assert opencode_claim == { + "actor": "maintainer", + "agent": "opencode-agent", + "base_branch": "main", + "base_sha": "b" * 40, + "comment_id": 91, + "enable_auto_merge": False, + "head_sha": "a" * 40, + "merge_mode": "disabled", + "pr_number": 17, + "repository": "ContextualWisdomLab/example", + "review_dispatch_limit": "1", + "trigger_reviews": True, + "update_branches": False, + } + + noema_key = router.agent_invocation_key(request, "cwl-noema-review") + opencode_key = router.agent_invocation_key(request, "opencode-agent") + assert noema_key == _digest(noema_claim) + assert opencode_key == _digest(opencode_claim) + + changed_base = replace(request, pull_request_base_sha="c" * 40) + assert router.agent_invocation_key( + changed_base, "cwl-noema-review" + ) != noema_key + + for field, replacement in ( + ("trigger_reviews", False), + ("review_dispatch_limit", "2"), + ("enable_auto_merge", True), + ("update_branches", True), + ("merge_mode", "direct_or_auto"), + ): + altered = dict(opencode_claim) + altered[field] = replacement + assert _digest(altered) != opencode_key + + +def test_wrappers_recompute_complete_claim_before_ledger_access() -> None: + """Both wrappers fail closed before reusing an exact-name artifact claim.""" + + noema = NOEMA_WORKFLOW.read_text(encoding="utf-8") + opencode = OPENCODE_WORKFLOW.read_text(encoding="utf-8") + for workflow in (noema, opencode): + assert "PR_BASE_SHA:" in workflow + assert "github.event.client_payload.pr_base_sha" in workflow + assert '! [[ "$PR_BASE_SHA" =~ ^[0-9a-f]{40}$ ]]' in workflow + assert '"base_sha": os.environ["PR_BASE_SHA"]' in workflow + assert "hmac.compare_digest" in workflow + assert workflow.index("Validate exact invocation payload") < workflow.index( + "Inspect exact-name Actions artifact ledger" + ) + assert "--arg pr_base_sha \"$PR_BASE_SHA\"" in workflow + assert "pr_base_sha: $pr_base_sha" in workflow + + for field in ( + '"trigger_reviews": os.environ["TRIGGER_REVIEWS"] == "true"', + '"review_dispatch_limit": os.environ["REVIEW_DISPATCH_LIMIT"]', + '"enable_auto_merge": os.environ["ENABLE_AUTO_MERGE"] == "true"', + '"update_branches": os.environ["UPDATE_BRANCHES"] == "true"', + '"merge_mode": os.environ["MERGE_MODE"]', + ): + assert field in opencode + + assert noema.count('"base_sha": os.environ["PR_BASE_SHA"]') >= 2 + for field in ( + '"trigger_reviews": os.environ["TRIGGER_REVIEWS"] == "true"', + '"review_dispatch_limit": os.environ["REVIEW_DISPATCH_LIMIT"]', + '"enable_auto_merge": os.environ["ENABLE_AUTO_MERGE"] == "true"', + '"update_branches": os.environ["UPDATE_BRANCHES"] == "true"', + '"merge_mode": os.environ["MERGE_MODE"]', + ): + assert opencode.count(field) >= 2 + + +def test_no_pr_specific_writer_workflow_remains() -> None: + """Complete binding is implemented in canonical files, never a branch writer.""" + + forbidden = sorted( + str(path.relative_to(ROOT)) + for pattern in ( + "repair-pr787*.yml", + "*pr787*final*.yml", + "*agent-mention*repair*.yml", + ) + for path in (ROOT / ".github" / "workflows").glob(pattern) + ) + assert forbidden == [] From 0ffbb190ea70c68b443448b1290ec1f6151aa414 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:35:03 +0900 Subject: [PATCH 133/138] fix(automation): bind complete agent invocation claim --- scripts/ci/agent_mention_router.py | 71 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 8181b989a..bdb8ac3db 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -46,6 +46,7 @@ class MentionRequest: comment_id: int actor: str agents: tuple[str, ...] + pull_request_base_sha: str = "" class GitHubClient: @@ -154,7 +155,9 @@ def parse_event(event: dict[str, Any]) -> MentionRequest | None: repository_name = str(repository.get("full_name") or "").strip() actor = str(comment.get("user", {}).get("login") or "").strip() head_sha = str(pull_request.get("head", {}).get("sha") or "").strip() - base_branch = str(pull_request.get("base", {}).get("ref") or "").strip() + base = pull_request.get("base") or {} + base_branch = str(base.get("ref") or "").strip() + base_sha = str(base.get("sha") or "").strip() number = issue.get("number") comment_id = comment.get("id") if not REPOSITORY_RE.fullmatch(repository_name): @@ -171,6 +174,8 @@ def parse_event(event: dict[str, Any]) -> MentionRequest | None: raise ValueError("pull request head SHA is missing or invalid") if not BASE_BRANCH_RE.fullmatch(base_branch): raise ValueError("pull request base branch is missing or invalid") + if not HEAD_SHA_RE.fullmatch(base_sha): + raise ValueError("pull request base SHA is missing or invalid") if not ACTOR_RE.fullmatch(actor): raise ValueError("comment actor is missing or invalid") return MentionRequest( @@ -181,6 +186,7 @@ def parse_event(event: dict[str, Any]) -> MentionRequest | None: comment_id, actor, agents, + pull_request_base_sha=base_sha.lower(), ) @@ -220,26 +226,48 @@ def eligible_agents( return tuple(dispatchable), tuple(rejected) +def agent_invocation_claim( + request: MentionRequest, + agent: str, +) -> dict[str, object]: + """Return the complete canonical security claim for one agent dispatch.""" + + if agent not in MENTION_PATTERNS: + raise ValueError(f"unsupported agent: {agent}") + claim: dict[str, object] = { + "actor": request.actor, + "agent": agent, + "base_branch": request.pull_request_base_branch, + "base_sha": request.pull_request_base_sha, + "comment_id": request.comment_id, + "head_sha": request.pull_request_head_sha, + "pr_number": request.pull_request_number, + "repository": request.repository, + } + if agent == "opencode-agent": + claim.update( + { + "enable_auto_merge": False, + "merge_mode": "disabled", + "review_dispatch_limit": "1", + "trigger_reviews": True, + "update_branches": False, + } + ) + return claim + + def agent_invocation_key(request: MentionRequest, agent: str) -> str: """Return a deterministic opaque key for one exact agent invocation. - The key binds repository, pull request, exact head, base branch, requested - agent, source comment, and requesting actor. It contains no credential or - provider response and is safe to place in workflow and artifact names. + The key binds repository, pull request, exact head and base identities, + requested agent, source comment, requesting actor, and every downstream + behavior flag. It contains no credential or provider response and is safe + to place in workflow and artifact names. """ - if agent not in MENTION_PATTERNS: - raise ValueError(f"unsupported agent: {agent}") canonical = json.dumps( - { - "actor": request.actor, - "agent": agent, - "base_branch": request.pull_request_base_branch, - "comment_id": request.comment_id, - "head_sha": request.pull_request_head_sha, - "pr_number": request.pull_request_number, - "repository": request.repository, - }, + agent_invocation_claim(request, agent), ensure_ascii=True, separators=(",", ":"), sort_keys=True, @@ -351,6 +379,7 @@ def noema_payload(request: MentionRequest) -> dict[str, Any]: "target_repository": request.repository, "pr_number": request.pull_request_number, "pr_head_sha": request.pull_request_head_sha, + "pr_base_sha": request.pull_request_base_sha, "base_branch": request.pull_request_base_branch, "requested_agent": agent, "agent_invocation_key": agent_invocation_key(request, agent), @@ -364,18 +393,20 @@ def opencode_payload(request: MentionRequest) -> dict[str, Any]: """Return the durable review-only OpenCode wrapper dispatch body.""" agent = "opencode-agent" + claim = agent_invocation_claim(request, agent) return { "event_type": "agent-mention-opencode", "client_payload": { "target_repository": request.repository, "pr_number": request.pull_request_number, "pr_head_sha": request.pull_request_head_sha, + "pr_base_sha": request.pull_request_base_sha, "base_branch": request.pull_request_base_branch, - "trigger_reviews": True, - "review_dispatch_limit": "1", - "enable_auto_merge": False, - "update_branches": False, - "merge_mode": "disabled", + "trigger_reviews": claim["trigger_reviews"], + "review_dispatch_limit": claim["review_dispatch_limit"], + "enable_auto_merge": claim["enable_auto_merge"], + "update_branches": claim["update_branches"], + "merge_mode": claim["merge_mode"], "requested_agent": agent, "agent_invocation_key": agent_invocation_key(request, agent), "requested_by": request.actor, From 82fc692a6e995ca4c82db5c21693cecdf9deb91e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:37:26 +0900 Subject: [PATCH 134/138] fix(automation): bind Noema wrapper to exact base identity --- .github/workflows/agent-mention-noema-dispatch.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/agent-mention-noema-dispatch.yml b/.github/workflows/agent-mention-noema-dispatch.yml index b78d5a815..4912e5add 100644 --- a/.github/workflows/agent-mention-noema-dispatch.yml +++ b/.github/workflows/agent-mention-noema-dispatch.yml @@ -32,6 +32,7 @@ jobs: TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || '' }} PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + PR_BASE_SHA: ${{ github.event.client_payload.pr_base_sha || '' }} BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} @@ -44,6 +45,7 @@ jobs: ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$PR_BASE_SHA" =~ ^[0-9a-f]{40}$ ]] || ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || [[ "$BASE_BRANCH" == -* ]] || ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || @@ -63,6 +65,7 @@ jobs: "actor": os.environ["REQUESTED_BY"], "agent": os.environ["REQUESTED_AGENT"], "base_branch": os.environ["BASE_BRANCH"], + "base_sha": os.environ["PR_BASE_SHA"], "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), "head_sha": os.environ["PR_HEAD_SHA"], "pr_number": int(os.environ["PR_NUMBER"]), @@ -135,6 +138,7 @@ jobs: "actor": os.environ["REQUESTED_BY"], "agent": os.environ["REQUESTED_AGENT"], "base_branch": os.environ["BASE_BRANCH"], + "base_sha": os.environ["PR_BASE_SHA"], "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), "head_sha": os.environ["PR_HEAD_SHA"], "invocation_key": os.environ["INVOCATION_KEY"], @@ -169,6 +173,7 @@ jobs: --arg target_repository "$TARGET_REPOSITORY" \ --argjson pr_number "$PR_NUMBER" \ --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg pr_base_sha "$PR_BASE_SHA" \ --arg base_branch "$BASE_BRANCH" \ --arg requested_agent "$REQUESTED_AGENT" \ --arg agent_invocation_key "$INVOCATION_KEY" \ @@ -180,6 +185,7 @@ jobs: target_repository: $target_repository, pr_number: $pr_number, pr_head_sha: $pr_head_sha, + pr_base_sha: $pr_base_sha, base_branch: $base_branch, requested_agent: $requested_agent, agent_invocation_key: $agent_invocation_key, From 8ec28b8c70d397d134e6080eb9053d1f372ae33f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:39:44 +0900 Subject: [PATCH 135/138] fix(automation): bind OpenCode wrapper to complete payload --- .../agent-mention-opencode-dispatch.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/agent-mention-opencode-dispatch.yml b/.github/workflows/agent-mention-opencode-dispatch.yml index 676faac08..160b4723d 100644 --- a/.github/workflows/agent-mention-opencode-dispatch.yml +++ b/.github/workflows/agent-mention-opencode-dispatch.yml @@ -32,6 +32,7 @@ jobs: TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || '' }} PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} PR_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} + PR_BASE_SHA: ${{ github.event.client_payload.pr_base_sha || '' }} BASE_BRANCH: ${{ github.event.client_payload.base_branch || '' }} REQUESTED_BY: ${{ github.event.client_payload.requested_by || '' }} SOURCE_COMMENT_ID: ${{ github.event.client_payload.source_comment_id || '' }} @@ -49,6 +50,7 @@ jobs: ! [[ "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || ! [[ "$PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || + ! [[ "$PR_BASE_SHA" =~ ^[0-9a-f]{40}$ ]] || ! [[ "$BASE_BRANCH" =~ ^[A-Za-z0-9._/-]+$ ]] || [[ "$BASE_BRANCH" == -* ]] || ! [[ "$SOURCE_COMMENT_ID" =~ ^[1-9][0-9]*$ ]] || @@ -73,10 +75,16 @@ jobs: "actor": os.environ["REQUESTED_BY"], "agent": os.environ["REQUESTED_AGENT"], "base_branch": os.environ["BASE_BRANCH"], + "base_sha": os.environ["PR_BASE_SHA"], "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "enable_auto_merge": os.environ["ENABLE_AUTO_MERGE"] == "true", "head_sha": os.environ["PR_HEAD_SHA"], + "merge_mode": os.environ["MERGE_MODE"], "pr_number": int(os.environ["PR_NUMBER"]), "repository": os.environ["TARGET_REPOSITORY"], + "review_dispatch_limit": os.environ["REVIEW_DISPATCH_LIMIT"], + "trigger_reviews": os.environ["TRIGGER_REVIEWS"] == "true", + "update_branches": os.environ["UPDATE_BRANCHES"] == "true", }, ensure_ascii=True, separators=(",", ":"), @@ -145,11 +153,17 @@ jobs: "actor": os.environ["REQUESTED_BY"], "agent": os.environ["REQUESTED_AGENT"], "base_branch": os.environ["BASE_BRANCH"], + "base_sha": os.environ["PR_BASE_SHA"], "comment_id": int(os.environ["SOURCE_COMMENT_ID"]), + "enable_auto_merge": os.environ["ENABLE_AUTO_MERGE"] == "true", "head_sha": os.environ["PR_HEAD_SHA"], "invocation_key": os.environ["INVOCATION_KEY"], + "merge_mode": os.environ["MERGE_MODE"], "pr_number": int(os.environ["PR_NUMBER"]), "repository": os.environ["TARGET_REPOSITORY"], + "review_dispatch_limit": os.environ["REVIEW_DISPATCH_LIMIT"], + "trigger_reviews": os.environ["TRIGGER_REVIEWS"] == "true", + "update_branches": os.environ["UPDATE_BRANCHES"] == "true", } (claim_dir / "claim.json").write_text( json.dumps(claim, ensure_ascii=True, indent=2, sort_keys=True) + "\n", @@ -179,6 +193,7 @@ jobs: --arg target_repository "$TARGET_REPOSITORY" \ --argjson pr_number "$PR_NUMBER" \ --arg pr_head_sha "$PR_HEAD_SHA" \ + --arg pr_base_sha "$PR_BASE_SHA" \ --arg base_branch "$BASE_BRANCH" \ --arg requested_agent "$REQUESTED_AGENT" \ --arg agent_invocation_key "$INVOCATION_KEY" \ @@ -190,6 +205,7 @@ jobs: target_repository: $target_repository, pr_number: $pr_number, pr_head_sha: $pr_head_sha, + pr_base_sha: $pr_base_sha, base_branch: $base_branch, trigger_reviews: true, review_dispatch_limit: "1", From ae304b746695765b62d3b609d52afde151616b25 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:47:13 +0900 Subject: [PATCH 136/138] test(automation): align router fixtures with base SHA binding --- tests/test_agent_mention_router.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_agent_mention_router.py b/tests/test_agent_mention_router.py index 1c094df9a..4509d43f0 100644 --- a/tests/test_agent_mention_router.py +++ b/tests/test_agent_mention_router.py @@ -61,7 +61,7 @@ def event( "pull_request": { "state": "open", "head": {"sha": "a" * 40}, - "base": {"ref": "develop"}, + "base": {"ref": "develop", "sha": "b" * 40}, }, } @@ -106,6 +106,7 @@ def test_exact_mentions_and_parse_event() -> None: assert request.agents == ("cwl-noema-review", "opencode-agent") assert request.pull_request_head_sha == "a" * 40 assert request.pull_request_base_branch == "develop" + assert request.pull_request_base_sha == "b" * 40 assert module.exact_mentions("@opencode-agent-evil @cwl-noema-review2") == () @@ -153,6 +154,7 @@ def test_untrusted_receipt_marker_cannot_suppress_invocation() -> None: (("comment", "id"), 0, "comment id"), (("pull_request", "head", "sha"), "bad", "head SHA"), (("pull_request", "base", "ref"), "-bad", "base branch"), + (("pull_request", "base", "sha"), "bad", "base SHA"), (("comment", "user", "login"), "", "actor"), ], ) @@ -215,9 +217,11 @@ def test_eligible_agents_and_payloads() -> None: noema = module.noema_payload(request) assert noema["event_type"] == "agent-mention-noema" assert noema["client_payload"]["pr_head_sha"] == "a" * 40 + assert noema["client_payload"]["pr_base_sha"] == "b" * 40 opencode = module.opencode_payload(request) assert opencode["event_type"] == "agent-mention-opencode" assert opencode["client_payload"]["base_branch"] == "develop" + assert opencode["client_payload"]["pr_base_sha"] == "b" * 40 assert opencode["client_payload"]["merge_mode"] == "disabled" assert opencode["client_payload"]["enable_auto_merge"] is False assert opencode["client_payload"]["update_branches"] is False From 305a64d8eddc6126cff80eb1d549287818b38a11 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:47:43 +0900 Subject: [PATCH 137/138] test(automation): complete review regression request metadata --- tests/test_agent_mention_review_regressions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_agent_mention_review_regressions.py b/tests/test_agent_mention_review_regressions.py index 23e11d45a..1615ddd2b 100644 --- a/tests/test_agent_mention_review_regressions.py +++ b/tests/test_agent_mention_review_regressions.py @@ -36,6 +36,7 @@ def request(module: ModuleType, agents=("cwl-noema-review", "opencode-agent")): 91, "maintainer", agents, + pull_request_base_sha="b" * 40, ) @@ -82,7 +83,7 @@ def test_actor_and_allowlist_validation_are_wrapper_compatible() -> None: "pull_request": { "state": "open", "head": {"sha": "a" * 40}, - "base": {"ref": "main"}, + "base": {"ref": "main", "sha": "b" * 40}, }, } with pytest.raises(ValueError, match="actor"): From 4170e07535f3c46361535e6136136b8ba854b38f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 12:49:18 +0900 Subject: [PATCH 138/138] test(automation): enrich sweep PR fixtures with base SHA --- tests/test_agent_mention_sweep.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_agent_mention_sweep.py b/tests/test_agent_mention_sweep.py index d3b9ffe0a..0747bb02b 100644 --- a/tests/test_agent_mention_sweep.py +++ b/tests/test_agent_mention_sweep.py @@ -92,7 +92,7 @@ def live_pull(state: str = "open") -> dict: return { "state": state, "head": {"sha": "b" * 40}, - "base": {"ref": "main"}, + "base": {"ref": "main", "sha": "c" * 40}, } @@ -264,6 +264,7 @@ def test_build_requests_ignores_receipt_markers_and_skips_closed_pulls() -> None ("opencode-agent",), ("cwl-noema-review",), ] + assert {request.pull_request_base_sha for request in requests} == {"c" * 40} closed = FakeClient( {comments_endpoint: [comments], pull_endpoint: live_pull("closed")} ) @@ -295,6 +296,7 @@ def mention_request(number: int, comment_id: int, agent: str): comment_id, "maintainer", (agent,), + pull_request_base_sha="b" * 40, )